diff --git a/cmake/modules/lcgsoft-macros.cmake b/cmake/modules/lcgsoft-macros.cmake
index 33da2e953cd5d6bb9db63405b383de5e63dc2fbd..d6e14597ee732b6110e0ac0c2c74f8f49712b566 100644
--- a/cmake/modules/lcgsoft-macros.cmake
+++ b/cmake/modules/lcgsoft-macros.cmake
@@ -850,13 +850,13 @@ function(LCG_get_environment name var)
     if(_path)
       set(_path  ${_path}:${${dep}_home}/bin)
       set(_cmake ${_cmake}:${${dep}_home})
-      set(_pkg   ${_pkg}:${${dep}_home}/lib/pkgconfig)
+      set(_pkg   ${_pkg}:${${dep}_home}/lib64/pkgconfig:${${dep}_home}/lib/pkgconfig)
       set(_python ${_python}:${${dep}_home}/lib/python${Python_config_version_twodigit}/site-packages)
       set(_libpath ${_libpath}:${${dep}_home}/lib64:${${dep}_home}/lib)
     else()
       set(_path PATH=${${dep}_home}/bin)
       set(_cmake CMAKE_PREFIX_PATH=${${dep}_home})
-      set(_pkg PKG_CONFIG_PATH=${${dep}_home}/lib/pkgconfig)
+      set(_pkg PKG_CONFIG_PATH=${${dep}_home}/lib64/pkgconfig:${${dep}_home}/lib/pkgconfig)
       set(_python PYTHONPATH=${${dep}_home}/lib/python${Python_config_version_twodigit}/site-packages)
       set(_libpath LD_LIBRARY_PATH=${${dep}_home}/lib64:${${dep}_home}/lib)
     endif()
diff --git a/cmake/scripts/argparse.py b/cmake/scripts/argparse2.py
similarity index 100%
rename from cmake/scripts/argparse.py
rename to cmake/scripts/argparse2.py
diff --git a/cmake/scripts/create_bundle.py b/cmake/scripts/create_bundle.py
index e04e86d6d06e65e4dcd509bd1a222ef54b4178f7..ed86588857dc4d5f9b3677efe2fcedcd1a14aebb 100755
--- a/cmake/scripts/create_bundle.py
+++ b/cmake/scripts/create_bundle.py
@@ -5,7 +5,10 @@ import shutil
 import sys
 import time
 import logging
-import argparse
+try:
+    import argparse
+except ImportError:
+    import argparse2 as argparse
 
 class InstallBundle(object):
     def __init__(self, prefix, blacklist=[], greylist=[]):
diff --git a/cmake/scripts/create_lcg_view.py b/cmake/scripts/create_lcg_view.py
index fc6fa8f45bc52338a1d922bb1809a668f617975b..f775b54ca806f5d63ffc548cd4b197aee17df173 100755
--- a/cmake/scripts/create_lcg_view.py
+++ b/cmake/scripts/create_lcg_view.py
@@ -17,7 +17,11 @@
 #    --loglevel LEVEL                 Change logging level
 #    --version                        show program's version number and exit
 
-import argparse
+try:
+    import argparse
+except ImportError:
+    import argparse2 as argparse
+
 import glob
 import logging
 import os
diff --git a/cmake/scripts/create_lcg_view_setup_sh.in b/cmake/scripts/create_lcg_view_setup_sh.in
index de344113509f0d508f8a4a7fb182f4d80fbc0055..ab3d23fc51a75f6138f19afede354eeadf841922 100644
--- a/cmake/scripts/create_lcg_view_setup_sh.in
+++ b/cmake/scripts/create_lcg_view_setup_sh.in
@@ -109,6 +109,8 @@ if [ -x $thisdir/bin/root ]; then
     else
         JUPYTER_PATH=${thisdir}/etc/notebook:$JUPYTER_PATH; export JUPYTER_PATH
     fi
+    export CPPYY_BACKEND_LIBRARY=$ROOTSYS/lib/libcppyy_backend`python -c "import sys; print('{0}_{1}'.format(*sys.version_info))"`
+    export CLING_STANDARD_PCH=none
 fi
 
 #---then Gaudi
diff --git a/cmake/scripts/install_binary_repository.py b/cmake/scripts/install_binary_repository.py
index 69e3a29144e5f21944bf3e8e7b5be459b195cf7f..1debc7673b4e814b9206c9e06d4c76285ebf937a 100755
--- a/cmake/scripts/install_binary_repository.py
+++ b/cmake/scripts/install_binary_repository.py
@@ -6,7 +6,12 @@ Version 1.0
 """
 #-------------------------------------------------------------------------------
 from __future__ import print_function
-import argparse, os, sys, tarfile, subprocess, shutil, glob
+import os, sys, tarfile, subprocess, shutil, glob
+try:
+    import argparse
+except ImportError:
+    import argparse2 as argparse
+
 if sys.version_info[0] >= 3 :
   import urllib.request as urllib2
 else:
diff --git a/cmake/scripts/install_binary_tarfile.py b/cmake/scripts/install_binary_tarfile.py
index 9fec8f9e6a97286b71ed9eba8b2c380a1100637d..901581d5e45e9a17c4c7c596a0db4ff2f6981ae0 100755
--- a/cmake/scripts/install_binary_tarfile.py
+++ b/cmake/scripts/install_binary_tarfile.py
@@ -7,7 +7,12 @@ Version 1.0
 
 #-------------------------------------------------------------------------------
 from __future__ import print_function
-import argparse, os, sys, tarfile, subprocess, shutil
+import os, sys, tarfile, subprocess, shutil
+try:
+    import argparse
+except ImportError:
+    import argparse2 as argparse
+
 if sys.version_info[0] >= 3 :
   import urllib.request as urllib2
 else:
diff --git a/cmake/scripts/lockfile.py b/cmake/scripts/lockfile.py
index ec0386955c04191801ee9b7678abab803a653acf..081afaa80d6d378cd96d66c7815b3cd9a8f53aed 100755
--- a/cmake/scripts/lockfile.py
+++ b/cmake/scripts/lockfile.py
@@ -7,7 +7,10 @@ Version 1.0
 
 from __future__ import print_function
 import os, sys, time, socket, errno, shutil
-import argparse
+try:
+    import argparse
+except ImportError:
+    import argparse2 as argparse
 
 parser = argparse.ArgumentParser()
 parser.add_argument('-v', '--version', action='version', version='1.0', help='display the version number and exit')
diff --git a/cmake/scripts/purge_binary_repository.py b/cmake/scripts/purge_binary_repository.py
index 1c5a2304e26fbffdcba02b381bc8290a8a741d56..4da8ed9a8b5d302fb3bb1b28fcd41dba979c14fc 100755
--- a/cmake/scripts/purge_binary_repository.py
+++ b/cmake/scripts/purge_binary_repository.py
@@ -6,7 +6,11 @@ Version 1.0
 """
 #-------------------------------------------------------------------------------
 from __future__ import print_function
-import argparse, os, sys, glob, time
+import os, sys, glob, time
+try:
+    import argparse
+except ImportError:
+    import argparse2 as argparse
 
 def creation_date(path_to_file):
   stat = os.stat(path_to_file)
diff --git a/cmake/toolchain/heptools-dev-base.cmake b/cmake/toolchain/heptools-dev-base.cmake
index 0a35708565be6f8452cf7dd5b451749eb2933947..9cba6e2aa3de1ae292ab1926224f5f1d3bb576a5 100644
--- a/cmake/toolchain/heptools-dev-base.cmake
+++ b/cmake/toolchain/heptools-dev-base.cmake
@@ -113,7 +113,7 @@ if(${LCG_OS}${LCG_OSVERS} MATCHES centos7|ubuntu)
   endif()
 endif()
 
-LCG_AA_project(DD4hep                  01-12-01                                 )
+LCG_AA_project(DD4hep                  01-13                                    )
 
 # Externals
 LCG_external_package(lcgenv            1.3.14                                   )
@@ -144,7 +144,7 @@ LCG_external_package(backports_abc     0.5
 LCG_external_package(benchmark         1.5.0                                    )
 LCG_external_package(bison             3.3.2                                    )
 #LCG_external_package(blas              3.8.0.netlib                             )
-LCG_external_package(blas              0.3.9.openblas                           )
+LCG_external_package(blas              0.3.10.openblas                          )
 LCG_external_package(bleach            3.1.0                                    )
 LCG_external_package(brotli            1.0.7                                    )
 LCG_external_package(bzip2             1.0.6                                    )
@@ -174,7 +174,7 @@ LCG_external_package(colorcet          2.0.2
 LCG_external_package(configparser      3.7.4                                    )
 LCG_external_package(CouchDB           1.2                                      )
 LCG_external_package(coverage          4.5.3                                    )
-LCG_external_package(cppgsl            3.0.1                                    )
+LCG_external_package(cppgsl            3.1.0                                    )
 LCG_external_package(CppUnit           1.14.0                 author=1.14.0     )
 LCG_external_package(cpymad            1.4.1                                    )
 LCG_external_package(cryptography      2.7                                      )
@@ -187,10 +187,10 @@ if(NOT ${LCG_OS} STREQUAL mac)
   LCG_external_package(cx_oracle         7.1.3                                    )
 endif()
 LCG_external_package(cycler            0.10.0                                   )
-LCG_external_package(cython            0.29.16                                  )
+LCG_external_package(cython            0.29.20                                  )
 LCG_external_package(dask              1.2.2                                    )
 if(NOT ${LCG_OS} STREQUAL mac)
-  LCG_external_package(Davix           0.7.3                                    )
+  LCG_external_package(Davix           0.7.6                                    )
 endif()
 LCG_external_package(decorator         4.3.2                                    )
 LCG_external_package(defusedxml        0.6.0                                    )
@@ -204,7 +204,7 @@ LCG_external_package(eigen             3.3.7
 LCG_external_package(elasticsearch     6.3.0                                    )
 LCG_external_package(entrypoints       0.3                                      )
 LCG_external_package(expat             2.2.6                                    )
-LCG_external_package(fastjet           3.3.2                                    )
+LCG_external_package(fastjet           3.3.4                                    )
 LCG_external_package(fftw              3.3.8                     fftw3          )
 LCG_external_package(fjcontrib         1.044                                    )
 LCG_external_package(flake8            3.7.8                                    )
@@ -306,7 +306,7 @@ LCG_external_package(joblib            0.14.0
 LCG_external_package(jpeg              v6b                                      )
 LCG_external_package(jpype             0.6.3                                    )
 LCG_external_package(jsonc             0.12                                     )
-LCG_external_package(jsoncpp           1.8.4                                    )
+LCG_external_package(jsoncpp           1.9.3                                    )
 LCG_external_package(jsonmcpp          3.6.1                                    )
 LCG_external_package(jsonschema        3.0.1                                    )
 LCG_external_package(pyjson5           0.9.1                                    )
@@ -328,7 +328,7 @@ LCG_external_package(libedit           3.1
 LCG_external_package(libevent          2.1.11                                   )
 LCG_external_package(libffi            3.2.1                                    )
 LCG_external_package(libgeotiff        1.5.1                                    )
-LCG_external_package(libgit2           0.28.2                                   )
+LCG_external_package(libgit2           1.0.1                                    )
 LCG_external_package(libpqxx           7.1.1                                    )
 LCG_external_package(libsodium         1.0.18                                   )
 LCG_external_package(libsvm            3.23                                     )
@@ -338,7 +338,7 @@ if( NOT ${LCG_OS} MATCHES ubuntu|mac )
 endif()
 LCG_external_package(libxml2           2.9.9                                    )
 LCG_external_package(libxslt           1.1.33                                   )
-LCG_external_package(LCIO              02.13.03                                 )
+LCG_external_package(LCIO              02.14.02                                 )
 LCG_external_package(logilabcommon     1.4.2                                    )
 LCG_external_package(lwtnn             2.8.1                                    )
 LCG_external_package(lxml              4.3.3                                    )
@@ -524,13 +524,13 @@ if(${LCG_OS} STREQUAL slc OR ${LCG_OS} STREQUAL centos OR ${LCG_OS}${LCG_OSVERS}
 endif()
 LCG_external_package(spdlog            1.5.0                                    )
 LCG_external_package(sqlalchemy        1.2.10                                   )
-LCG_external_package(sqlite            3280000                                  )
+LCG_external_package(sqlite            3320300                                  )
 LCG_external_package(statsmodels       0.10.2                                   )
 LCG_external_package(stomppy           3.1.3                                    )
 LCG_external_package(storm             0.23                                     )
 LCG_external_package(swig              3.0.12          author=3.0.12            )
 LCG_external_package(sympy             1.4                                      )
-LCG_external_package(tbb               2020_U1                                  )
+LCG_external_package(tbb               2020_U2                                  )
 LCG_external_package(tblib             1.4.0                                    )
 #LCG_external_package(tcmalloc          2.4                                      )
 if(NOT ${LCG_OS}${LCG_OSVERS} STREQUAL slc6)
@@ -569,7 +569,7 @@ LCG_external_package(uproot_methods    0.7.1
 LCG_external_package(urllib3           1.25.3                                   )
 LCG_external_package(uuid              1.42                                     )
 if(NOT ${LCG_OS} STREQUAL mac)
-  LCG_external_package(valgrind        3.15.0                                   )
+  LCG_external_package(valgrind        3.16.1                                   )
 endif()
 LCG_external_package(Vc                1.4.1                                    )
 LCG_external_package(vcversioner       2.16.0.0                                 )
@@ -591,7 +591,7 @@ if(NOT ${LCG_OS} STREQUAL mac)
   LCG_external_package(xgboost           0.90                                     )
 endif()
 LCG_external_package(xqilla            2.3.3                                    )
-LCG_external_package(xrootd            4.12.2                                   )
+LCG_external_package(xrootd            4.12.3                                   )
 LCG_external_package(xz                5.0.4                                    )
 LCG_external_package(yamlcpp           0.6.3                                    )
 LCG_external_package(zeromq            4.3.2                                    )
diff --git a/cmake/toolchain/heptools-dev-generators.cmake b/cmake/toolchain/heptools-dev-generators.cmake
index 9e46f614f6d5a78d29665b6869e48a64f2e5eb4b..f89c13aa6ac4ce54635a25291b5ca109bb5f6c22 100644
--- a/cmake/toolchain/heptools-dev-generators.cmake
+++ b/cmake/toolchain/heptools-dev-generators.cmake
@@ -18,7 +18,7 @@ LCG_external_package(syscalc           1.1.7          ${MCGENPATH}/syscalc)
 
 LCG_external_package(madgraph5amc      2.7.2          ${MCGENPATH}/madgraph5amc)
 
-LCG_external_package(lhapdf            6.2.3          ${MCGENPATH}/lhapdf       )
+LCG_external_package(lhapdf            6.3.0          ${MCGENPATH}/lhapdf       )
 
 LCG_external_package(powheg-box-v2     r3043.lhcb    ${MCGENPATH}/powheg-box-v2 author=r3043  )
 
@@ -80,7 +80,7 @@ LCG_external_package(professor         2.3.2          ${MCGENPATH}/professor
 
 LCG_external_package(jhu               5.6.3          ${MCGENPATH}/jhu          )
 
-LCG_external_package(log4cpp           2.8.3p1         ${MCGENPATH}/log4cpp     )
+LCG_external_package(log4cpp           2.9.1          ${MCGENPATH}/log4cpp     )
 
 LCG_external_package(rapidsim          1.4.4          ${MCGENPATH}/rapidsim     )
 
diff --git a/cmake/toolchain/heptools-hsf.cmake b/cmake/toolchain/heptools-hsf.cmake
index a5760f5d2c34e1ce3bb0eaf53f3726edcae66928..97526c04c26d68c5faba023e94d77d18398c0a6b 100644
--- a/cmake/toolchain/heptools-hsf.cmake
+++ b/cmake/toolchain/heptools-hsf.cmake
@@ -5,8 +5,7 @@ include(heptools-dev-base)
 include(heptools-dev-generators)
 
 #---Overwrites-----------------------------------------------------
-LCG_external_package(ROOT           v6.20.02 )
-LCG_external_package(hepmc3         3.0.0    )
+LCG_external_package(ROOT           v6.22.00 )
 
 if(${LCG_OS} MATCHES mac)  # AppleClang is more strict on C++17 deprecated functionality
   LCG_remove_package(sherpa)
diff --git a/documentation/packages.json b/documentation/packages.json
index e78c209a2e3f3d32cd45a7ce632c0f58e46db337..2e1288d836c01c3a488c9168f5b178b8d70bc542 100644
--- a/documentation/packages.json
+++ b/documentation/packages.json
@@ -39,16 +39,6 @@
         "license": null, 
         "name": "colorcet"
     }, 
-    {
-        "category": null, 
-        "contacts": [], 
-        "description": null, 
-        "fullname": "", 
-        "homepage": null, 
-        "language": null, 
-        "license": null, 
-        "name": "gflags"
-    }, 
     {
         "category": null, 
         "contacts": [], 
@@ -4151,6 +4141,16 @@
         "license": "GPL", 
         "name": "gettext"
     }, 
+    {
+        "category": "Tool", 
+        "contacts": [], 
+        "description": "Gflags, the commandline flags library used within Google", 
+        "fullname": "Gflags", 
+        "homepage": "https://github.com/gflags/gflags", 
+        "language": "C++", 
+        "license": "BSD3c", 
+        "name": "gflags"
+    }, 
     {
         "category": "Other", 
         "contacts": [], 
diff --git a/documentation/releases.json b/documentation/releases.json
index 58f608a41cb5873e81d8127c85774c238ff1b7dd..73a2e6c26c2bb07f33f4ea96389718aa905b2467 100644
--- a/documentation/releases.json
+++ b/documentation/releases.json
@@ -59,6 +59,10 @@
         "extra_notes": null, 
         "version": "97apython3"
     }, 
+    {
+        "extra_notes": null, 
+        "version": "97a_LHCB_2"
+    }, 
     {
         "extra_notes": null, 
         "version": "97a_LHCB_1"
@@ -207,6 +211,10 @@
         "extra_notes": null, 
         "version": "89"
     }, 
+    {
+        "extra_notes": null, 
+        "version": "88b"
+    }, 
     {
         "extra_notes": null, 
         "version": "88a"
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index fd7bdf63b93339a710b1d9234354f301a50c784d..5d0230ce9009a559f80c182c47f2e388a274ac57 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -745,7 +745,11 @@ LCGPackage_Add(
   IF tbb_native_version MATCHES "^4._.*" THEN
     URL ${GenURL}/tbb${tbb_native_version}oss_src.tgz
   ELSE
-    URL ${GenURL}/tbb${tbb_native_version}.tar.gz
+    IF tbb_native_version STRGREATER "2020_U1" THEN
+       URL ${GenURL}/oneTBB-${tbb_native_version}.tar.gz
+    ELSE
+       URL ${GenURL}/tbb${tbb_native_version}.tar.gz
+    ENDIF
   ENDIF
   CONFIGURE_COMMAND <VOID>
   BUILD_COMMAND ${MAKE} ${tbb_build_options}
@@ -2278,10 +2282,12 @@ LCGPackage_Add(
           IF NOT APPLE THEN
           COMMAND ${CMAKE_COMMAND} -E copy_directory <INSTALL_DIR>/${_LIBDIR}/R/library/IRkernel/kernelspec <INSTALL_DIR>/share/jupyter/kernels/ir
           ENDIF
+          COMMAND ${CMAKE_COMMAND} -E make_directory <INSTALL_DIR>/etc
+          COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/etc/Renviron <INSTALL_DIR>/etc/Renviron
   LIST_SEPARATOR SEMICOLON
   BUILD_IN_SOURCE 1
   DEPENDS ${R_DEPS} IF LCG_OS STREQUAL mac THEN openssl ELSE cairo ENDIF
-  REVISION 5
+  REVISION 6
 )
 
 #---ocaml-----------------------------------------------------------------------
@@ -2660,6 +2666,8 @@ LCGPackage_Add(
              -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
              -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
              -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
+             -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_gflags_LIB=ON
+  REVISION 1
 )
 
 #---gflags---------------------------------------------------------------------
diff --git a/generators/CMakeLists.txt b/generators/CMakeLists.txt
index 6596ed22ab855774c4b5bca16efd76e347bc3f26..a06e7ff93139ff87e245893f053ec3cc721f64ac 100644
--- a/generators/CMakeLists.txt
+++ b/generators/CMakeLists.txt
@@ -214,10 +214,11 @@ LCGPackage_Add(
   ENDIF
 )
 
-#---Rivet-----------------------------------------------------------------------------------------
+#---rivet-----------------------------------------------------------------------------------------
 LCGPackage_Add(
   rivet
   URL ${gen_url}/Rivet-<VERSION>.tar.bz2
+  ENVIRONMENT LIBRARY_PATH=${FORTRAN_LIBRARY_DIR}
   IF NOT <VERSION> VERSION_LESS 2.6.2 THEN
       CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rivet/gsl.m4 <SOURCE_DIR>/m4 
                 COMMAND autoreconf --install --force
@@ -242,7 +243,6 @@ LCGPackage_Add(
             --with-gsl=${GSL_home}
           ENDIF
           IF <VERSION> VERSION_GREATER 2.9.9 THEN
-            --with-fastjet=${fastjet_home}
             --with-fjcontrib=${fjcontrib_home}
           ENDIF
           --with-lcgtag=${LCG_platform}
@@ -2013,7 +2013,7 @@ LCGPackage_Add(
  BUILD_COMMAND ${MAKE}
        COMMAND $ENV{SHELL} -c "${CMAKE_SOURCE_DIR}/cmake/scripts/static2shared.sh build/libFH.a"
  INSTALL_COMMAND ${MAKE}  -j 1 install
-         COMMAND ${CMAKE_COMMAND} -E copy build/libFH.so <INSTALL_DIR>/${LIBDIR_DEFAULT}/
+         COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/build/libFH.so <INSTALL_DIR>/${LIBDIR_DEFAULT}/
  BUILD_IN_SOURCE 1
 )
 
diff --git a/generators/patches/feynhiggs-2.16.0.patch b/generators/patches/feynhiggs-2.16.0.patch
new file mode 100644
index 0000000000000000000000000000000000000000..0cb1cf370eb2737ae97481910696a7ba50c9c833
--- /dev/null
+++ b/generators/patches/feynhiggs-2.16.0.patch
@@ -0,0 +1,33 @@
+--- configure.orig	2018-08-29 14:57:46.500082106 +0200
++++ configure	2020-07-13 13:07:34.853530407 +0200
+@@ -293,8 +293,8 @@
+ CONF_CFLAGS+=" $CONF_BITS"
+ CONF_CXXFLAGS+=" $CONF_BITS"
+ 
+-test "$CONF_OS$CONF_BITS" = "Linux-m64" && CONF_LIBDIRSUFFIX=64
+-
++## patch to avoid lib64 directory for Ubuntu/Debian
++test "$CONF_OS$CONF_BITS" = "Linux-m64" && test ! -f /etc/debian_version && CONF_LIBDIRSUFFIX=64
+ 
+ ## does f77 support REAL*16?
+ 
+--- makefile.in.orig	2020-01-15 10:01:18.171956613 +0100
++++ makefile.in	2020-07-13 13:12:55.597988694 +0200
+@@ -44,11 +44,12 @@
+ 	  $(BLD)/PDG.h "$(INCLUDEDIR)"
+ 	strip $(FHBIN)
+ 	cp -p $(FHBIN) $(BLD)/fcc "$(BINDIR)"
+-	test ! -f $(MFHBIN) || { \
+-	  test -z "$(EXE)" || ldd $(MFHBIN) | awk '/\/usr\/bin\/cyg/ { system("cp -p " $$3 " $(BINDIR)/"); }' ; \
+-	  strip $(MFHBIN) ; \
+-	  cp -p $(MFHBIN) $(BINDIR); \
+-	}
++# Commented out in previous versions. GG 13/7/2020
++# 	test ! -f $(MFHBIN) || { \
++# 	  test -z "$(EXE)" || ldd $(MFHBIN) | awk '/\/usr\/bin\/cyg/ { system("cp -p " $$3 " $(BINDIR)/"); }' ; \
++# 	  strip $(MFHBIN) ; \
++# 	  cp -p $(MFHBIN) $(BINDIR); \
++# 	}
+ 
+ force: $(BLD)/version.h
+ 
diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt
index c618f3cb9f724c72f8f0d806d8c48dd05ac6a29c..72ac114aa47c0797d2b7881ba6165ca6977bb987 100644
--- a/projects/CMakeLists.txt
+++ b/projects/CMakeLists.txt
@@ -66,10 +66,13 @@ if(ROOT_native_version)
                  ELSE
                    -Dpyroot=ON
                  ENDIF
-                 IF Python_native_version VERSION_GREATER 3 THEN
+                 IF ROOT_version VERSION_LESS 6.22 AND Python_native_version VERSION_GREATER 3 THEN
                    -Dpython3=ON
                    -Dpython_version=3
                  ENDIF
+                 IF ROOT_version VERSION_GREATER_EQUAL 6.22 THEN
+                   -DPYTHON_EXECUTABLE=${Python_home}/bin/python
+                 ENDIF
                  -Dbuiltin_lz4=ON
                  -Dbuiltin_pcre=ON
                  -Dbuiltin_xxhash=ON
@@ -379,30 +382,20 @@ add_custom_target(Geant4-externals
 #---LCIO-----------------------------------------------------------------------------------------------
 LCGPackage_add(
   LCIO
-  #SVN_REPOSITORY svn://svn.freehep.org/lcio/tags/<LCIO_native_version> --quiet
-  #UPDATE_COMMAND <VOID>
   URL ${GenURL}/LCIO-${LCIO_native_version}.tar.gz
-  CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+  CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+             -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+             -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
+             -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
+             -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
              -DLCIO_GENERATE_HEADERS=off
              -DBUILD_ROOTDICT=ON
              -DROOT_DIR=${ROOT_home}
-             IF LCG_CPP11 THEN
-             -DCMAKE_CXX_FLAGS=-std=c++11
-             ENDIF
-             IF LCG_CPP1Y THEN
-             -DCMAKE_CXX_FLAGS=-std=c++1y
-             ENDIF
-             IF LCG_CPP14 THEN
-             -DCMAKE_CXX_FLAGS=-std=c++14
-             ENDIF
-             IF LCG_CPP17 THEN
-	         -DCMAKE_CXX_FLAGS=-std=c++17
-             ENDIF
   BUILD_COMMAND ${MAKE} ROOTSYS=${ROOT_home}
   INSTALL_COMMAND ${MAKE} install
           COMMAND ${EXEC} bash -c "mkdir -p <INSTALL_DIR>/lib/cmake/LCIO"
           COMMAND ${EXEC} bash -c "cp -n -r <INSTALL_DIR>/*.cmake <INSTALL_DIR>/lib/cmake/LCIO"
-  DEPENDS ROOT
+  DEPENDS ROOT clhep
 )
 
 #---VecGeom------------------------------------------------------------------------------------------
diff --git a/projects/patches/ROOT-v6.22.00.patch b/projects/patches/ROOT-v6.22.00.patch
index 30fbc2ecc4a53defa427c85e456bdc47f8ca94ff..384d0b488048be56f93a4810b2e6bec9043aa4e4 100644
--- a/projects/patches/ROOT-v6.22.00.patch
+++ b/projects/patches/ROOT-v6.22.00.patch
@@ -23,3 +23,822 @@
     if (fd->isOverloadedOperator())
        property |= kIsOperator;
     if (llvm::isa<clang::CXXConversionDecl>(fd))
+
+From efa71aa238aadb040ca634634be14dde850595c5 Mon Sep 17 00:00:00 2001
+From: Enric Tejedor Saavedra <enric.tejedor.saavedra@cern.ch>
+Date: Wed, 8 Jul 2020 17:40:30 +0200
+Subject: [PATCH] [ROOT-10872][PyROOT] Update Dispatcher to prevent use of
+ deleted copy constructor
+
+---
+ .../cppyy/CPyCppyy/src/CPPConstructor.cxx     | 114 +++++++
+ .../cppyy/CPyCppyy/src/CPPConstructor.h       |  15 +
+ .../pyroot/cppyy/CPyCppyy/src/CPPScope.cxx    |   9 +-
+ bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.h |   3 +-
+ bindings/pyroot/cppyy/CPyCppyy/src/Cppyy.h    |   4 +
+ .../pyroot/cppyy/CPyCppyy/src/Dispatcher.cxx  | 320 ++++++++++++++----
+ .../pyroot/cppyy/CPyCppyy/src/Dispatcher.h    |   5 +-
+ .../cppyy/CPyCppyy/src/ProxyWrappers.cxx      |  15 +-
+ .../pyroot/cppyy/CPyCppyy/src/ProxyWrappers.h |   4 +-
+ .../clingwrapper/src/clingwrapper.cxx         |  28 ++
+ .../clingwrapper/src/cpp_cppyy.h              |   4 +
+ 11 files changed, 435 insertions(+), 86 deletions(-)
+
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.cxx
+index 4e46363bd43..32a47c182d9 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.cxx
++++ bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.cxx
+@@ -11,6 +11,10 @@
+ // Standard
+ #include <string>
+ 
++//- data _____________________________________________________________________
++namespace CPyCppyy {
++    extern PyObject* gNullPtrObject;
++}
+ 
+ //- protected members --------------------------------------------------------
+ bool CPyCppyy::CPPConstructor::InitExecutor_(Executor*& executor, CallContext*)
+@@ -143,6 +147,116 @@ PyObject* CPyCppyy::CPPConstructor::Call(
+ }
+ 
+ 
++//----------------------------------------------------------------------------
++CPyCppyy::CPPMultiConstructor::CPPMultiConstructor(Cppyy::TCppScope_t scope, Cppyy::TCppMethod_t method) :
++    CPPConstructor(scope, method)
++{
++    fNumBases = Cppyy::GetNumBases(scope);
++}
++
++//----------------------------------------------------------------------------
++CPyCppyy::CPPMultiConstructor::CPPMultiConstructor(const CPPMultiConstructor& s) :
++    CPPConstructor(s), fNumBases(s.fNumBases)
++{
++}
++
++//----------------------------------------------------------------------------
++CPyCppyy::CPPMultiConstructor& CPyCppyy::CPPMultiConstructor::operator=(const CPPMultiConstructor& s)
++{
++    if (this != &s) {
++        CPPConstructor::operator=(s);
++        fNumBases = s.fNumBases;
++    }
++    return *this;
++}
++
++//----------------------------------------------------------------------------
++PyObject* CPyCppyy::CPPMultiConstructor::Call(
++    CPPInstance*& self, PyObject* _args, PyObject* kwds, CallContext* ctxt)
++{
++// By convention, initialization parameters of multiple base classes are grouped
++// by target base class. Here, we disambiguate and put in "sentinel" parameters
++// that allow the dispatcher to propagate them.
++
++// Three options supported:
++//  0. empty args: default constructor call
++//  1. fNumBases tuples, each handed to individual constructors
++//  2. less than fNumBases, assuming (void) for the missing base constructors
++//  3. normal arguments, going to the first base only
++
++    Py_INCREF(_args);
++    PyObject* args = _args;
++
++    if (PyTuple_CheckExact(args) && PyTuple_GET_SIZE(args)) {   // case 0. falls through
++        Py_ssize_t nArgs = PyTuple_GET_SIZE(args);
++
++        bool isAllTuples = true;
++        Py_ssize_t nArgsTot = 0;
++        for (Py_ssize_t i = 0; i < nArgs; ++i) {
++            PyObject* argi = PyTuple_GET_ITEM(args, i);
++            if (!PyTuple_CheckExact(argi)) {
++                isAllTuples = false;
++                break;
++            }
++            nArgsTot += PyTuple_GET_SIZE(argi);
++        }
++
++        if (isAllTuples) {
++        // copy over the arguments, while filling in the sentinels (case 1. & 2.), with
++        // just sentinels for the remaining (void) calls (case 2.)
++            PyObject* newArgs = PyTuple_New(nArgsTot + fNumBases - 1);
++            Py_ssize_t idx = 0;
++            for (Py_ssize_t i = 0; i < nArgs; ++i) {
++                if (i != 0) {
++                // add sentinel
++                    Py_INCREF(gNullPtrObject);
++                    PyTuple_SET_ITEM(newArgs, idx, gNullPtrObject);
++                    idx += 1;
++                }
++
++                PyObject* argi = PyTuple_GET_ITEM(args, i);
++                for (Py_ssize_t j = 0; j < PyTuple_GET_SIZE(argi); ++j) {
++                    PyObject* item = PyTuple_GET_ITEM(argi, j);
++                    Py_INCREF(item);
++                    PyTuple_SET_ITEM(newArgs, idx, item);
++                    idx += 1;
++                }
++            }
++
++        // add final sentinels as needed
++            while (idx < (nArgsTot+fNumBases-1)) {
++                Py_INCREF(gNullPtrObject);
++                PyTuple_SET_ITEM(newArgs, idx, gNullPtrObject);
++                idx += 1;
++            }
++
++            Py_DECREF(args);
++            args = newArgs;
++        } else {                                               // case 3. add sentinels
++        // copy arguments as-is, then add sentinels at the end
++            PyObject* newArgs = PyTuple_New(PyTuple_GET_SIZE(args) + fNumBases - 1);
++            for (Py_ssize_t i = 0; i < nArgs; ++i) {
++                PyObject* item = PyTuple_GET_ITEM(args, i);
++                Py_INCREF(item);
++                PyTuple_SET_ITEM(newArgs, i, item);
++            }
++            for (Py_ssize_t i = 0; i < fNumBases - 1; ++i) {
++                Py_INCREF(gNullPtrObject);
++                PyTuple_SET_ITEM(newArgs, i+nArgs, gNullPtrObject);
++            }
++            Py_DECREF(args);
++            args = newArgs;
++        }
++    }
++
++    PyObject* result = CPPConstructor::Call(self, args, kwds, ctxt);
++    Py_DECREF(args);
++    return result;
++}
++
++
++
++
+ //----------------------------------------------------------------------------
+ PyObject* CPyCppyy::CPPAbstractClassConstructor::Call(
+     CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt)
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.h b/bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.h
+index f07bb9b966c..349ecf91092 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.h
++++ bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.h
+@@ -24,6 +24,21 @@ class CPPConstructor : public CPPMethod {
+ };
+ 
+ 
++// specialization for multiple inheritance disambiguation
++class CPPMultiConstructor : public CPPConstructor {
++public:
++    CPPMultiConstructor(Cppyy::TCppScope_t scope, Cppyy::TCppMethod_t method);
++    CPPMultiConstructor(const CPPMultiConstructor&);
++    CPPMultiConstructor& operator=(const CPPMultiConstructor&);
++
++public:
++    virtual PyObject* Call(CPPInstance*&, PyObject*, PyObject*, CallContext* = nullptr);
++
++private:
++    Py_ssize_t fNumBases;
++};
++
++
+ // specializations of prohibiting constructors
+ class CPPAbstractClassConstructor : public CPPConstructor {
+ public:
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.cxx
+index 4a0be8e6c6e..18b48d670c7 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.cxx
++++ bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.cxx
+@@ -254,9 +254,12 @@ static PyObject* pt_new(PyTypeObject* subtype, PyObject* args, PyObject* kwds)
+             Py_ssize_t sz = PyDict_Size(dct);
+             if (0 < sz && !Cppyy::IsNamespace(result->fCppType)) {
+                 result->fFlags |= CPPScope::kIsPython;
+-                if (!InsertDispatcher(result, dct)) {
+-                    if (!PyErr_Occurred())
+-                         PyErr_Warn(PyExc_RuntimeWarning, (char*)"no python-side overrides supported");
++		if (1 < PyTuple_GET_SIZE(PyTuple_GET_ITEM(args, 1)))
++                    result->fFlags |= CPPScope::kIsMultiCross;
++		std::ostringstream errmsg;
++                if (!InsertDispatcher(result, PyTuple_GET_ITEM(args, 1), dct, errmsg)) {
++                    PyErr_Format(PyExc_TypeError, "no python-side overrides supported (%s)", errmsg.str().c_str());
++                    return nullptr;
+                 } else {
+                 // the direct base can be useful for some templates, such as shared_ptrs,
+                 // so make it accessible (the __cpp_cross__ data member also signals that
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.h b/bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.h
+index a9e2f8c0e02..289abcc66ae 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.h
++++ bindings/pyroot/cppyy/CPyCppyy/src/CPPScope.h
+@@ -43,7 +43,8 @@ class CPPScope {
+         kIsException     = 0x0004,
+         kIsSmart         = 0x0008,
+         kIsPython        = 0x0010,
+-        kIsInComplete    = 0x0020 };
++        kIsMultiCross    = 0x0020,
++        kIsInComplete    = 0x0040 };
+ 
+ public:
+     PyHeapTypeObject  fType;
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Cppyy.h b/bindings/pyroot/cppyy/CPyCppyy/src/Cppyy.h
+index e50e13ebc0e..ea4d222050d 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/Cppyy.h
++++ bindings/pyroot/cppyy/CPyCppyy/src/Cppyy.h
+@@ -208,6 +208,8 @@ namespace Cppyy {
+     CPPYY_IMPORT
+     bool IsPublicMethod(TCppMethod_t method);
+     CPPYY_IMPORT
++    bool IsProtectedMethod(TCppMethod_t method);
++    CPPYY_IMPORT
+     bool IsConstructor(TCppMethod_t method);
+     CPPYY_IMPORT
+     bool IsDestructor(TCppMethod_t method);
+@@ -230,6 +232,8 @@ namespace Cppyy {
+     CPPYY_IMPORT
+     bool IsPublicData(TCppScope_t scope, TCppIndex_t idata);
+     CPPYY_IMPORT
++    bool IsProtectedData(TCppScope_t scope, TCppIndex_t idata);
++    CPPYY_IMPORT
+     bool IsStaticData(TCppScope_t scope, TCppIndex_t idata);
+     CPPYY_IMPORT
+     bool IsConstData(TCppScope_t scope, TCppIndex_t idata);
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.cxx
+index b56bb54d1f9..50b0de4b850 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.cxx
++++ bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.cxx
+@@ -42,7 +42,7 @@ static inline void InjectMethod(Cppyy::TCppMethod_t method, const std::string& m
+ #else
+     code << "    PyObject* mtPyName = PyUnicode_FromString(\"" << mtCppName << "\");\n"
+ #endif
+-            "    PyObject* pyresult = PyObject_CallMethodObjArgs((PyObject*)m_self, mtPyName";
++            "    PyObject* pyresult = PyObject_CallMethodObjArgs((PyObject*)_internal_self, mtPyName";
+     for (Cppyy::TCppIndex_t i = 0; i < nArgs; ++i)
+         code << ", pyargs[" << i << "]";
+     code << ", NULL);\n    Py_DECREF(mtPyName);\n";
+@@ -52,27 +52,120 @@ static inline void InjectMethod(Cppyy::TCppMethod_t method, const std::string& m
+ }
+ 
+ //----------------------------------------------------------------------------
+-bool CPyCppyy::InsertDispatcher(CPPScope* klass, PyObject* dct)
++namespace {
++    struct BaseInfo {
++        BaseInfo(Cppyy::TCppType_t t, std::string&& bn, std::string&& bns) :
++            btype(t), bname(bn), bname_scoped(bns) {}
++        Cppyy::TCppType_t btype;
++        std::string bname;
++        std::string bname_scoped;
++    };
++
++    typedef std::vector<BaseInfo> BaseInfos_t;
++    typedef std::vector<Cppyy::TCppMethod_t> Ctors_t;
++    typedef std::vector<Ctors_t> AllCtors_t;
++    typedef std::vector<std::pair<Cppyy::TCppMethod_t, size_t>> CtorInfos_t;
++} // unnamed namespace
++
++static void build_constructors(
++    const std::string& derivedName, const BaseInfos_t& base_infos, const AllCtors_t& ctors,
++    std::ostringstream& code, const CtorInfos_t& methods = CtorInfos_t{}, size_t idx = 0)
++{
++    if (idx < ctors.size()) {
++        for (const auto& method : ctors[idx]) {
++             size_t argsmin = (size_t)Cppyy::GetMethodReqArgs(method);
++             size_t argsmax = (size_t)Cppyy::GetMethodNumArgs(method);
++             for (size_t i = argsmin; i <= argsmax; ++i) {
++                 CtorInfos_t methods1{methods};
++                 methods1.emplace_back(method, i);
++                 build_constructors(derivedName, base_infos, ctors, code, methods1, idx+1);
++             }
++        }
++    } else {
++    // this is as deep as we go; start writing
++        code << "  " << derivedName << "(";
++
++    // declare arguments
++        std::vector<size_t> arg_tots; arg_tots.reserve(methods.size());
++        for (Ctors_t::size_type i = 0; i < methods.size(); ++i) {
++            const auto& cinfo = methods[i];
++            if (i != 0 && (arg_tots.back() || 1 < arg_tots.size())) code << ", ";
++            size_t nArgs = cinfo.second;
++            arg_tots.push_back(i == 0 ? nArgs : nArgs+arg_tots.back());
++
++            if (i != 0) code << "__cppyy_internal::Sep*";
++            size_t offset = (i != 0 ? arg_tots[i-1] : 0);
++            for (size_t j = 0; j < nArgs; ++j) {
++                if (i != 0 || j != 0) code << ", ";
++                code << Cppyy::GetMethodArgType(cinfo.first, j) << " a" << (j+offset);
++            }
++        }
++        code << ") : ";
++
++    // pass arguments to base constructors
++        for (BaseInfos_t::size_type i = 0; i < base_infos.size(); ++i) {
++            if (i != 0) code << ", ";
++            code << base_infos[i].bname << "(";
++            size_t first = (i != 0 ? arg_tots[i-1] : 0);
++            for (size_t j = first; j < arg_tots[i]; ++j) {
++                if (j != first) code << ", ";
++                bool isRValue = CPyCppyy::Utility::Compound(\
++                    Cppyy::GetMethodArgType(methods[i].first, j-first)) == "&&";
++                if (isRValue) code << "std::move(";
++                code << "a" << j;
++                if (isRValue) code << ")";
++            }
++            code << ")";
++        }
++        code << " {}\n";
++    }
++}
++
++bool CPyCppyy::InsertDispatcher(CPPScope* klass, PyObject* bases, PyObject* dct, std::ostringstream& err)
+ {
+ // Scan all methods in dct and where it overloads base methods in klass, create
+ // dispatchers on the C++ side. Then interject the dispatcher class.
+-    if (Cppyy::IsNamespace(klass->fCppType) || !PyDict_Check(dct)) {
+-        PyErr_Format(PyExc_TypeError,
+-            "%s not an acceptable base: is namespace or has no dict", Cppyy::GetScopedFinalName(klass->fCppType).c_str());
++
++    if (!PyTuple_Check(bases) || !PyTuple_GET_SIZE(bases) || !dct || !PyDict_Check(dct)) {
++        err << "internal error: expected tuple of bases and proper dictionary";
+         return false;
+     }
+ 
+-    if (!Cppyy::HasVirtualDestructor(klass->fCppType)) {
+-        PyErr_Format(PyExc_TypeError,
+-            "%s not an acceptable base: no virtual destructor", Cppyy::GetScopedFinalName(klass->fCppType).c_str());
++    if (!Utility::IncludePython()) {
++        err << "failed to include Python.h";
+         return false;
+     }
+ 
+-    if (!Utility::IncludePython())
++// collect all bases, error checking the hierarchy along the way
++    const Py_ssize_t nBases = PyTuple_GET_SIZE(bases);
++    BaseInfos_t base_infos; base_infos.reserve(nBases);
++    for (Py_ssize_t ibase = 0; ibase < nBases; ++ibase) {
++        Cppyy::TCppType_t basetype = ((CPPScope*)PyTuple_GET_ITEM(bases, ibase))->fCppType;
++
++        if (!basetype) {
++            err << "base class is incomplete";
++            break;
++        }
++
++        if (Cppyy::IsNamespace(basetype)) {
++            err << Cppyy::GetScopedFinalName(basetype) << " is a namespace";
++            break;
++        }
++
++        if (!Cppyy::HasVirtualDestructor(basetype)) {
++            const std::string& bname = Cppyy::GetScopedFinalName(basetype);
++            PyErr_Warn(PyExc_RuntimeWarning, (char*)("class \""+bname+"\" has no virtual destructor").c_str());
++        }
++
++        base_infos.emplace_back(
++            basetype, TypeManip::template_base(Cppyy::GetFinalName(basetype)), Cppyy::GetScopedFinalName(basetype));
++    }
++
++    if ((Py_ssize_t)base_infos.size() != nBases)
+         return false;
+ 
+-    const std::string& baseName       = TypeManip::template_base(Cppyy::GetFinalName(klass->fCppType));
+-    const std::string& baseNameScoped = Cppyy::GetScopedFinalName(klass->fCppType);
++// TODO: check deep hierarchy for multiple inheritance
++    bool isDeepHierarchy = klass->fCppType && base_infos.front().btype != klass->fCppType;
+ 
+ // once classes can be extended, should consider re-use; for now, since derived
+ // python classes can differ in what they override, simply use different shims
+@@ -86,14 +179,20 @@ bool CPyCppyy::InsertDispatcher(CPPScope* klass, PyObject* dct)
+ 
+ // start class declaration
+     code << "namespace __cppyy_internal {\n"
+-         << "class " << derivedName << " : public ::" << baseNameScoped << " {\n"
+-            "  CPyCppyy::DispatchPtr m_self;\n"
+-            "public:\n";
++         << "class " << derivedName << " : ";
++    for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
++        if (ibase != 0) code << ", ";
++        code << "public ::" << base_infos[ibase].bname_scoped;
++    }
++    code << " {\n";
++    if (!isDeepHierarchy)
++        code << "protected:\n  CPyCppyy::DispatchPtr _internal_self;\n";
++    code << "public:\n";
+ 
+ // add a virtual destructor for good measure
+     code << "  virtual ~" << derivedName << "() {}\n";
+ 
+-// methods: first collect all callables, then get overrides from base class, for
++// methods: first collect all callables, then get overrides from base classes, for
+ // those that are still missing, search the hierarchy
+     PyObject* clbs = PyDict_New();
+     PyObject* items = PyDict_Items(dct);
+@@ -106,101 +205,176 @@ bool CPyCppyy::InsertDispatcher(CPPScope* klass, PyObject* dct)
+     if (PyDict_DelItem(clbs, PyStrings::gInit) != 0)
+         PyErr_Clear();
+ 
+-// simple case: methods from current class
+-    bool has_default = false;
+-    bool has_cctor = false;
++// protected methods and data need their access changed in the C++ trampoline and then
++// exposed on the Python side; so, collect their names as we go along
++    std::vector<std::string> protected_names;
++
++// simple case: methods from current class (collect constructors along the way)
++    int has_default = 0;
++    int has_cctor = 0;
+     bool has_constructors = false;
+-    const Cppyy::TCppIndex_t nMethods = Cppyy::GetNumMethods(klass->fCppType);
+-    for (Cppyy::TCppIndex_t imeth = 0; imeth < nMethods; ++imeth) {
+-        Cppyy::TCppMethod_t method = Cppyy::GetMethod(klass->fCppType, imeth);
+-
+-        if (Cppyy::IsConstructor(method)) {
+-            has_constructors = true;
+-            Cppyy::TCppIndex_t nreq = Cppyy::GetMethodReqArgs(method);
+-            if (nreq == 0)
+-                has_default = true;
+-            else if (nreq == 1) {
+-                if (TypeManip::clean_type(Cppyy::GetMethodArgType(method, 0), false) == baseNameScoped)
+-                    has_cctor = true;
++    AllCtors_t ctors{base_infos.size()};
++    for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
++        const auto& binfo = base_infos[ibase];
++
++        const Cppyy::TCppIndex_t nMethods = Cppyy::GetNumMethods(binfo.btype);
++        bool cctor_found = false, default_found = false, any_ctor_found = false;
++        for (Cppyy::TCppIndex_t imeth = 0; imeth < nMethods; ++imeth) {
++            Cppyy::TCppMethod_t method = Cppyy::GetMethod(binfo.btype, imeth);
++
++            if (Cppyy::IsConstructor(method)) {
++                any_ctor_found = true;
++                if (Cppyy::IsPublicMethod(method) || Cppyy::IsProtectedMethod(method)) {
++                    Cppyy::TCppIndex_t nreq = Cppyy::GetMethodReqArgs(method);
++                    if (nreq == 0) default_found = true;
++                    else if (!cctor_found && nreq == 1) {
++                        const std::string& argtype = Cppyy::GetMethodArgType(method, 0);
++                        if (Utility::Compound(argtype) == "&" && TypeManip::clean_type(argtype, false) == binfo.bname_scoped)
++                            cctor_found = true;
++                    }
++                    ctors[ibase].push_back(method);
++                }
++                continue;
++            }
++
++            std::string mtCppName = Cppyy::GetMethodName(method);
++            PyObject* key = CPyCppyy_PyText_FromString(mtCppName.c_str());
++            int contains = PyDict_Contains(dct, key);
++            if (contains == -1) PyErr_Clear();
++            if (contains != 1) {
++                Py_DECREF(key);
++
++            // if the method is protected, we expose it with a 'using'
++                if (Cppyy::IsProtectedMethod(method)) {
++                    protected_names.push_back(mtCppName);
++                    code << "  using " << binfo.bname << "::" << mtCppName << ";\n";
++                }
++
++                continue;
+             }
+-            continue;
+-        }
+ 
+-        std::string mtCppName = Cppyy::GetMethodName(method);
+-        PyObject* key = CPyCppyy_PyText_FromString(mtCppName.c_str());
+-        int contains = PyDict_Contains(dct, key);
+-        if (contains == -1) PyErr_Clear();
+-        if (contains != 1) {
++            InjectMethod(method, mtCppName, code);
++
++            if (PyDict_DelItem(clbs, key) != 0)
++                PyErr_Clear();        // happens for overloads
+             Py_DECREF(key);
+-            continue;
+         }
+ 
+-        InjectMethod(method, mtCppName, code);
+-
+-        if (PyDict_DelItem(clbs, key) != 0)
+-            PyErr_Clear();        // happens for overloads
+-        Py_DECREF(key);
++    // count the cctors and default ctors to determine whether each base has one
++        if (cctor_found   || (!cctor_found && !any_ctor_found))   has_cctor   += 1;
++        if (default_found || (!default_found && !any_ctor_found)) has_default += 1;
++        if (any_ctor_found) has_constructors = true;
+     }
+ 
+ // try to locate left-overs in base classes
+-    if (PyDict_Size(clbs)) {
+-        size_t nbases = Cppyy::GetNumBases(klass->fCppType);
+-        for (size_t ibase = 0; ibase < nbases; ++ibase) {
+-            Cppyy::TCppScope_t tbase = (Cppyy::TCppScope_t)Cppyy::GetScope( \
+-                Cppyy::GetBaseName(klass->fCppType, ibase));
+-
+-            PyObject* keys = PyDict_Keys(clbs);
+-            for (Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); ++i) {
+-            // TODO: should probably invert this looping; but that makes handling overloads clunky
+-                PyObject* key = PyList_GET_ITEM(keys, i);
+-                std::string mtCppName = CPyCppyy_PyText_AsString(key);
+-                const auto& v = Cppyy::GetMethodIndicesFromName(tbase, mtCppName);
+-                for (auto idx : v)
+-                    InjectMethod(Cppyy::GetMethod(tbase, idx), mtCppName, code);
+-                if (!v.empty()) {
+-                    if (PyDict_DelItem(clbs, key) != 0) PyErr_Clear();
++    for (const auto& binfo : base_infos) {
++        if (PyDict_Size(clbs)) {
++            size_t nbases = Cppyy::GetNumBases(binfo.btype);
++            for (size_t ibase = 0; ibase < nbases; ++ibase) {
++                Cppyy::TCppScope_t tbase = (Cppyy::TCppScope_t)Cppyy::GetScope( \
++                    Cppyy::GetBaseName(binfo.btype, ibase));
++
++                PyObject* keys = PyDict_Keys(clbs);
++                for (Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); ++i) {
++                // TODO: should probably invert this looping; but that makes handling overloads clunky
++                    PyObject* key = PyList_GET_ITEM(keys, i);
++                    std::string mtCppName = CPyCppyy_PyText_AsString(key);
++                    const auto& v = Cppyy::GetMethodIndicesFromName(tbase, mtCppName);
++                    for (auto idx : v)
++                        InjectMethod(Cppyy::GetMethod(tbase, idx), mtCppName, code);
++                    if (!v.empty()) {
++                        if (PyDict_DelItem(clbs, key) != 0) PyErr_Clear();
++                    }
+                 }
+-             }
+-             Py_DECREF(keys);
++                Py_DECREF(keys);
++            }
+         }
+     }
+     Py_DECREF(clbs);
+ 
+-// constructors: most are simply inherited, for use by the Python derived class
+-    code << "  using " << baseName << "::" << baseName << ";\n";
++// constructors: build up from the argument types of the base class, for use by the Python
++// derived class (inheriting with/ "using" does not work b/c base class constructors may
++// have been deleted),
++    build_constructors(derivedName, base_infos, ctors, code);
+ 
+ // for working with C++ templates, additional constructors are needed to make
+ // sure the python object is properly carried, but they can only be generated
+ // if the base class supports them
+-    if (has_default || !has_constructors)
+-        code << "  " << derivedName << "() {}\n"
+-             << "  " << derivedName << "(PyObject* pyobj) : m_self(pyobj) {}\n";
+-    if (has_default || has_cctor || !has_constructors) {
++    if (1 < nBases && (!has_constructors || has_default == nBases))
++        code << "  " << derivedName << "() {}\n";
++    if (!has_constructors || has_cctor == nBases) {
+         code << "  " << derivedName << "(const " << derivedName << "& other) : ";
+-        if (has_cctor)
+-            code << baseName << "(other), ";
+-        code << "m_self(other.m_self, this) {}\n";
++        for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
++            if (ibase != 0) code << ", ";
++            code << base_infos[ibase].bname << "(other)";
++        }
++        if (!isDeepHierarchy) {
++            if (has_cctor) code << ", ";
++            else code << " : ";
++            code << "_internal_self(other._internal_self, this)";
++        }
++        code << " {}\n";
+     }
+ 
+ // destructor: default is fine
+ 
++// pull in data members that are protected
++    bool setPublic = false;
++    for (const auto& binfo : base_infos) {
++        Cppyy::TCppIndex_t nData = Cppyy::GetNumDatamembers(binfo.btype);
++        for (Cppyy::TCppIndex_t idata = 0; idata < nData; ++idata) {
++            if (Cppyy::IsProtectedData(binfo.btype, idata)) {
++                const std::string dm_name = Cppyy::GetDatamemberName(binfo.btype, idata);
++                if (dm_name != "_internal_self") {
++                    protected_names.push_back(Cppyy::GetDatamemberName(binfo.btype, idata));
++                    if (!setPublic) {
++                        code << "public:\n";
++                        setPublic = true;
++                    }
++                    code << "  using " << binfo.bname << "::" << protected_names.back() << ";\n";
++                }
++            }
++        }
++    }
++
+ // finish class declaration
+     code << "};\n}";
+ 
+ // finally, compile the code
+-    if (!Cppyy::Compile(code.str()))
++    if (!Cppyy::Compile(code.str())) {
++        err << "failed to compile the dispatcher code";
+         return false;
++    }
+ 
+ // keep track internally of the actual C++ type (this is used in
+ // CPPConstructor to call the dispatcher's one instead of the base)
+     Cppyy::TCppScope_t disp = Cppyy::GetScope("__cppyy_internal::"+derivedName);
+-    if (!disp) return false;
++    if (!disp) {
++        err << "failed to retrieve the internal dispatcher";
++        return false;
++    }
+     klass->fCppType = disp;
+ 
+ // at this point, the dispatcher only lives in C++, as opposed to regular classes
+ // that are part of the hierarchy in Python, so create it, which will cache it for
+ // later use by e.g. the MemoryRegulator
+-    PyObject* disp_proxy = CPyCppyy::CreateScopeProxy(disp);
++    unsigned int flags = (unsigned int)(klass->fFlags & CPPScope::kIsMultiCross);
++    PyObject* disp_proxy = CPyCppyy::CreateScopeProxy(disp, flags);
++    if (flags) ((CPPScope*)disp_proxy)->fFlags |= CPPScope::kIsMultiCross;
++
++// finally, to expose protected members, copy them over from the C++ dispatcher base
++// to the Python dictionary (the C++ dispatcher's Python proxy is not a base of the
++// Python class to keep the inheritance tree intact)
++    for (const auto& name : protected_names) {
++         PyObject* disp_dct = PyObject_GetAttr(disp_proxy, PyStrings::gDict);
++         PyObject* pyf = PyMapping_GetItemString(disp_dct, (char*)name.c_str());
++         if (pyf) {
++             PyObject_SetAttrString((PyObject*)klass, (char*)name.c_str(), pyf);
++             Py_DECREF(pyf);
++         }
++         Py_DECREF(disp_dct);
++    }
++
+     Py_XDECREF(disp_proxy);
+ 
+     return true;
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.h b/bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.h
+index a9281117e1a..f8d4dc57131 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.h
++++ bindings/pyroot/cppyy/CPyCppyy/src/Dispatcher.h
+@@ -1,12 +1,15 @@
+ #ifndef CPYCPPYY_DISPATCHER_H
+ #define CPYCPPYY_DISPATCHER_H
+ 
++// Standard
++#include <sstream>
++
+ namespace CPyCppyy {
+ 
+ class CPPScope;
+ 
+ // helper that inserts dispatchers for virtual methods
+-bool InsertDispatcher(CPPScope* klass, PyObject* dct);
++bool InsertDispatcher(CPPScope* klass, PyObject* bases, PyObject* dct, std::ostringstream& err);
+ 
+ } // namespace CPyCppyy
+ 
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.cxx
+index 8ea89a21ff1..cb819487b9e 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.cxx
++++ bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.cxx
+@@ -141,7 +141,7 @@ static inline void sync_templates(
+     Py_DECREF(pyname);
+ }
+ 
+-static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject* pyclass)
++static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject* pyclass, const unsigned int flags)
+ {
+ // Collect methods and data for the given scope, and add them to the given python
+ // proxy object.
+@@ -226,7 +226,10 @@ static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject* pyclass)
+             mtName = "__init__";
+             hasConstructor = true;
+             if (!isAbstract)
+-                pycall = new CPPConstructor(scope, method);
++		if (flags & CPPScope::kIsMultiCross) {
++                    pycall = new CPPMultiConstructor(scope, method);
++                } else
++                    pycall = new CPPConstructor(scope, method);
+             else
+                 pycall = new CPPAbstractClassConstructor(scope, method);
+         } else                               // member function
+@@ -484,14 +487,14 @@ PyObject* CPyCppyy::GetScopeProxy(Cppyy::TCppScope_t scope)
+ }
+ 
+ //----------------------------------------------------------------------------
+-PyObject* CPyCppyy::CreateScopeProxy(Cppyy::TCppScope_t scope)
++PyObject* CPyCppyy::CreateScopeProxy(Cppyy::TCppScope_t scope, const unsigned flags)
+ {
+ // Convenience function with a lookup first through the known existing proxies.
+     PyObject* pyclass = GetScopeProxy(scope);
+     if (pyclass)
+         return pyclass;
+ 
+-    return CreateScopeProxy(Cppyy::GetScopedFinalName(scope));
++    return CreateScopeProxy(Cppyy::GetScopedFinalName(scope), nullptr, flags);
+ }
+ 
+ //----------------------------------------------------------------------------
+@@ -506,7 +509,7 @@ PyObject* CPyCppyy::CreateScopeProxy(PyObject*, PyObject* args)
+ }
+ 
+ //----------------------------------------------------------------------------
+-PyObject* CPyCppyy::CreateScopeProxy(const std::string& name, PyObject* parent)
++PyObject* CPyCppyy::CreateScopeProxy(const std::string& name, PyObject* parent, const unsigned flags)
+ {
+ // Build a python shadow class for the named C++ class or namespace.
+ 
+@@ -670,7 +673,7 @@ PyObject* CPyCppyy::CreateScopeProxy(const std::string& name, PyObject* parent)
+ 
+     // fill the dictionary, if successful
+         if (pyscope) {
+-            if (BuildScopeProxyDict(klass, pyscope)) {
++            if (BuildScopeProxyDict(klass, pyscope, flags)) {
+             // something failed in building the dictionary
+                 Py_DECREF(pyscope);
+                 pyscope = nullptr;
+diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.h b/bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.h
+index a462064fa35..bf905f35260 100644
+--- bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.h
++++ bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.h
+@@ -9,10 +9,10 @@ namespace CPyCppyy {
+ 
+ // construct a Python shadow class for the named C++ class
+ PyObject* GetScopeProxy(Cppyy::TCppScope_t);
+-PyObject* CreateScopeProxy(Cppyy::TCppScope_t);
++PyObject* CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags = 0);
+ PyObject* CreateScopeProxy(PyObject*, PyObject* args);
+ PyObject* CreateScopeProxy(
+-    const std::string& scope_name, PyObject* parent = nullptr);
++    const std::string& scope_name, PyObject* parent = nullptr, const unsigned flags = 0);
+ 
+ // C++ exceptions form a special case b/c they have to derive from BaseException
+ PyObject* CreateExcScopeProxy(PyObject* pyscope, PyObject* pyname, PyObject* parent);
+diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx
+index ba4e7ad6bac..ae52fbe635c 100644
+--- bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx
++++ bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx
+@@ -1763,6 +1763,15 @@ bool Cppyy::IsPublicMethod(TCppMethod_t method)
+     return false;
+ }
+ 
++bool Cppyy::IsProtectedMethod(TCppMethod_t method)
++{
++    if (method) {
++        TFunction* f = m2f(method);
++        return f->Property() & kIsProtected;
++    }
++    return false;
++}
++
+ bool Cppyy::IsConstructor(TCppMethod_t method)
+ {
+     if (method) {
+@@ -1954,6 +1963,17 @@ bool Cppyy::IsPublicData(TCppScope_t scope, TCppIndex_t idata)
+     return m->Property() & kIsPublic;
+ }
+ 
++bool Cppyy::IsProtectedData(TCppScope_t scope, TCppIndex_t idata)
++{
++    if (scope == GLOBAL_HANDLE)
++        return true;
++    TClassRef& cr = type_from_handle(scope);
++    if (cr->Property() & kIsNamespace)
++        return true;
++    TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
++    return m->Property() & kIsProtected;
++}
++
+ bool Cppyy::IsStaticData(TCppScope_t scope, TCppIndex_t idata)
+ {
+     if (scope == GLOBAL_HANDLE)
+@@ -2469,6 +2489,10 @@ int cppyy_is_publicmethod(cppyy_method_t method) {
+     return (int)Cppyy::IsPublicMethod((Cppyy::TCppMethod_t)method);
+ }
+ 
++int cppyy_is_protectedmethod(cppyy_method_t method) {
++    return (int)Cppyy::IsProtectedMethod((Cppyy::TCppMethod_t)method);
++}
++
+ int cppyy_is_constructor(cppyy_method_t method) {
+     return (int)Cppyy::IsConstructor((Cppyy::TCppMethod_t)method);
+ }
+@@ -2510,6 +2534,10 @@ int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index) {
+     return (int)Cppyy::IsPublicData(type, datamember_index);
+ }
+ 
++int cppyy_is_protecteddata(cppyy_type_t type, cppyy_index_t datamember_index) {
++    return (int)Cppyy::IsProtectedData(type, datamember_index);
++}
++
+ int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index) {
+     return (int)Cppyy::IsStaticData(type, datamember_index);
+ }
+diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h
+index b22a36fc961..e9fd3b26ab8 100644
+--- bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h
++++ bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h
+@@ -205,6 +205,8 @@ namespace Cppyy {
+     RPY_EXPORTED
+     bool IsPublicMethod(TCppMethod_t method);
+     RPY_EXPORTED
++    bool IsProtectedMethod(TCppMethod_t method);
++    RPY_EXPORTED
+     bool IsConstructor(TCppMethod_t method);
+     RPY_EXPORTED
+     bool IsDestructor(TCppMethod_t method);
+@@ -227,6 +229,8 @@ namespace Cppyy {
+     RPY_EXPORTED
+     bool IsPublicData(TCppScope_t scope, TCppIndex_t idata);
+     RPY_EXPORTED
++    bool IsProtectedData(TCppScope_t scope, TCppIndex_t idata);
++    RPY_EXPORTED
+     bool IsStaticData(TCppScope_t scope, TCppIndex_t idata);
+     RPY_EXPORTED
+     bool IsConstData(TCppScope_t scope, TCppIndex_t idata);
\ No newline at end of file