Current Factory Issues

There are currently conflicting constraints that cause issues with Witold Pokorski's G4PhysicsConstructorRegistry
class, which is used by g4alt::G4PhysListFactory, the genericPL example (any any instance of directly using xyzzy, and some of the G4 DNA examples.

The goal is to have everything work correctly in all cases whether the code is built for static libraries or shared libraries, granular or global libraries, and on Unix and Windows platforms.

 #include "G4PhysicsConstructorRegistry.hh" 
+// G4RegisterPhysicsConstructors.icc is necessary for static builds
+#include "G4RegisterPhysicsConstructors.icc" 
# the following are direct use of G4PhysicsConstructorRegistry for their own "PhysicsList" 

#include "G4GenericPhysicsList.hh"  // <=== because this  //    G4VModularPhysicsList* phys = new G4GenericPhysicsList(MyConstr);  // <=== even though this  G4VModularPhysicsList* phys = new Shielding();

example-ext-persistency-p03 "G4GenericPhysicsList.hh"  G4VModularPhysicsList* phys = new G4GenericPhysicsList(MyConstr);

Overall Goal and Technique

  • The G4PhysicsConstructorRegistry is a convenient means of getting physics constructor (phys_ctor) objects without needing to include all the headers and explicitly creating them.
  • It relies on a mechanism where a bit of code in the individual phys_ctor "compilation unit" (i.e. .cc file turned into a .o) registers the method for creating an object of the class with the G4PhysicsConstructorRegistry.
  • This is forced when the "compilation unit" is loaded by initializing a (externally visible) global variable; the act of initializing causes code to do the registration, making the class available via the G4PhysicsConstructorRegistry.
  • This works as long as the "compilation unit" gets loaded into memory ... always the case of shared object libraries
  • But in the case of static libraries the "compilation unit" isn't included (linked) in the executable unless something in it is referenced by other code already part of the executable.
  • To accomplish this, one can either:
    • force the loading of the whole (static) library
      • there is no facility for doing this on Windows, just on the Unix platforms
      • this loads everything, even if one isn't using the G4PhysicsConstructorRegistry facility
    • add a reference to each of the (externally visible) global variables for each phys_ctor to something that is linked in
  • Some time ago G4 was relying on the first of those; there was a special case in the CMakeLists.txt file for the libG4physicslists.a library to force the whole archive to be loaded
  • This still left the Windows case unresolved. And it is unclear whether the gmake granular builds worked either.
  • So the code was switched to use the second method.
  • The "obvious" place to make these references is in the "compilation unit" for G4PhysicsConstructorRegistry itself; the macro lines there look like:
  • This solves the problem for static builds on both Unix and Windows platforms when building global libraries with cmake
  • Alas, it introduces an implicit circular link between libG4phys_ctor_factory.a and various other libG4Phys_ctor* libraries when building the granular libraries (i.e. the default gmake build)

State as of G4.10.4 initial release

  • To solve this issue, I'm proposing to remove the G4_REFERENCE_PHYSCONSTR_FACTORY macro calls from and move them into G4RegisterPhysicsConstructors.icc
  • These macros expand to code like:
              class physics_constructor; \
              extern const G4PhysicsConstructorFactory<G4Xyzzy>& G4XyzzyFactory; \
              const G4PhysicsConstructorFactory<G4Xyzzy>& G4XyzzyFactoryRef##REGREF = G4XyzzyFactory; 
    • where the G4_DECLARE_PHYSCONSTR_FACTORY(G4Xyzzy); macro in the individual phys_ctor has created
              const G4PhysicsConstructorFactory<G4Xyzzyr>& G4XyzzyFactory = \
    • so the DECLARE creates a globally visible G4XyzzyFactory symbol that the REFERENCE macro references.
  • This code expansion is why I'm proposing this as G4RegisterPhysicsConstructors.icc, rather than .hh
  • Then to make all the static builds work for all cases, we need G4RegisterPhysicsConstructors.icc to be included into a "compilation unit" whenever the G4PhysicsConstructorRegistry is used as a source of phys_ctors (but not in the compilation of the individual phys_ctors themselves).
  • All the known cases are:
    • Witek's G4GenericPhysicsList
    • my g4alt::G4PhysListFactory
    • some of the G4 DNA examples, DICOM example, and persistency-p03

Proposed change circa 2018-02-18

  • So, to summarize, this proposed change to the DNA examples simply ensures that the registry gets filled.
  • In the future all use of G4PhysicsConstructorRegistry (other than phys_ctors) needs to be accompanied by the use of G4RegisterPhysicsConstructors.icc for static builds to work correctly.
  • New standard phys_ctors need to be declared in G4RegisterPhysicsConstructors.icc
  • User specific phys_ctors either need to be explicitly linked in via the linking command for static builds or something that is linked in needs to use the G4_REFERENCE_PHYSCONSTR_FACTORY() macro. The later does not require that the phys_ctor's header be included, it just needs the name.

I have tested this on Linux with { shared vs. static } ⊗ { global (cmake) vs. granular (gmake} } builds. For the cmake builds they pass the ctests. For the gmake builds I've exercised the three examples/extended/physicslists/ cases (one uses the G4GenericPhysicsList and another the g4alt::G4PhysListFactory). In this regard there is nothing special about the DNA examples that should cause issues for granular vs. global

After 2018-02-28 changes

Windows fails ... in cases Unix doesn't.