This directory holds meson.build, included from the top-level build with subdir('meson'). It resolves every
external dependency GEMC links against and configures the bundled CMake subprojects (assimp, yaml-cpp). This
README documents how the three shared-with-CLAS12 dependencies — Qt6, CLHEP, and Geant4 — are loaded, and how
this repository acts as the producer of the Geant4 pkg-config files that downstream GEMC projects consume.
The companion consumer is clas12-systems/meson/README.md: read both together, because the Geant4 handling only
makes sense as a producer/consumer pair.
The top-level project() sets the build defaults for both direct meson setup and CI. The former core.ini
native file is removed. The active settings are preserved: C++17, static GEMC libraries, static selection from
both-library targets, prefer_static=true, b_lundef=false, and b_asneeded=false. The existing libdir=lib
default is retained. The commented LTO, static PIC, and executable PIE settings are not added as defaults.
Builds that previously omitted the native file now use these settings too. prefer_static=true prefers archives
for dependencies without an explicit static choice; explicit shared requests such as Qt, Linux SQLite, and
zlib still take precedence. b_lundef=false permits unresolved plugin symbols at link time, and
b_asneeded=false retains shared dependencies even when the linker sees no direct symbol reference.
Override any default with a command-line -D option. CI still selects shared GEMC libraries for sanitizer and
profile builds. Existing build directories configured with --native-file=core.ini retain that path and need
a fresh setup after removal. Use a new build directory and repeat the desired prefix, build type, and feature
options, omitting --native-file=core.ini.
GEMC (src) is the root of the dependency graph. It is built and installed against a specific Geant4 / CLHEP,
and it records that choice in pkg-config files it installs into its own prefix:
srcgeneratesgeant4.pcandgeant4_core.pc(Geant4 ships no pkg-config file of its own) and installs them into<prefix>/lib/pkgconfig.srcalso installsgemc.pcdescribing the GEMC libraries and their private static-link needs.- Downstream projects (e.g.
clas12-systems, which builds dlopen-able digitization plugins) do not re-derive Geant4 fromgeant4-config. They resolvegeant4_corestraight from the installed GEMC'slib/pkgconfig, so the plugins are always built against the exact Geant4 GEMC itself uses. See the consumer README for how that lookup finds the GEMC prefix from thegemcbinary onPATH.
This is why the Geant4 code in the two repositories looks different: they play different roles. src is the
only place that runs geant4-config and builds the full -lG4* link line; clas12-systems only consumes the
resulting .pc.
Loaded with the qt6 meson module. Qt is requested as shared (static : false) because supported package
managers ship Qt only as shared runtime libraries; asking for static archives just produces fallback warnings
and does not actually make Qt static. Includes are marked include_type : 'system' so Qt headers stay
warning-free.
- Required modules:
Core,Gui,Widgets,OpenGLWidgets— the GUI cannot build without them. Svgis probed optionally. No GEMC source includes a QtSvg header; it is used only at run time to rasterize the toolbar button icons through the "SVG" image-format plugin. When missing, the GUI still builds and buttons fall back to empty icons — so it only warns.Chartsis a real compile/link dependency (gAnalysisView.ccincludes<QtCharts/...>). It is probed optionally: when present,-DGEMC_HAS_QTCHARTSis defined and the analysis view is built; when absent, GEMC still builds and the GUI analysis page shows a placeholder.
Qt6 exists only in src. clas12-systems has no GUI and therefore no Qt dependency at all.
clhep_deps = dependency('clhep', version : '>=2.4.7.1', include_type : 'system')Resolved through pkg-config (module name clhep), minimum version 2.4.7.1, includes treated as system. It is
attached to essentially every GEMC module library and to the gemc binary.
CLHEP is loaded shared here — no static : true. This is deliberate and is the one intentional difference
from clas12-systems, which forces static : true:
- In
src, GEMC and Geant4 must share a single copy of CLHEP's stateful globals — most importantly theHepRandomengine singleton that Geant4 uses for all random numbers. One sharedlibCLHEPguarantees exactly one RNG engine for the whole process. - Forcing CLHEP static would be actively harmful in the shared / sanitizer / profile build (
use_sharedl, see below): each of the ~30 GEMC module.sos would embed its own copy of CLHEP's globals, giving multiple diverging RNG states and triggering ASan/UBSan ODR-violation reports. That reintroduces exactly the duplicate-symbol class of problemuse_sharedlexists to avoid. clas12-systemsforces static for an unrelated, loader-specific reason: its plugins must carry no@rpath/libCLHEP*dependency or thedlopenfails. GEMC's executable has no such problem — it resolveslibCLHEPat run time via Geant4's rpath.
Conclusion from the analysis: do not make CLHEP static in src. If a self-contained default binary were
ever an explicit goal, the only safe form would be conditional — static : not use_sharedl — keeping the
shared and sanitizer builds on shared CLHEP. The payoff is marginal, so the current shared setup stands.
gemc.pc still records --libs --static clhep under libraries_private regardless of this flag, so
downstream static-link information is present either way.
Geant4 ships no pkg-config file, so src builds its own and installs them for downstream use.
- Find
geant4-config.$G4INSTALL/bin/geant4-configis preferred when$G4INSTALLis set (the module layout), otherwise ageant4-configonPATH. Missing → hard error. - Generate the
.pcfiles.meson/g4_pkgconfig.pywritesgeant4.pcandgeant4_core.pcinto the build tree (<build>/pkgconfig). They live in the build tree, not the install prefix, so a freshrm -rf buildregenerates them cleanly — important when switching Geant4 versions. - Resolve them via pkg-config with an augmented
PKG_CONFIG_PATH(meson.build cannot mutate thepkg_config_pathoption ordependency()'s environment, so pkg-config is run directly and the result wrapped indeclare_dependency). Both.pcare checked for>=11.3.2and for agreement with the activegeant4-configversion. - Turn each
-lG4*into a cachedcpp.find_libraryobject. A shared cache makes the full set (geant4) and the core set (geant4_core) point at the same library objects. This lets meson deduplicate the Geant4 archives across the whole link graph — rawdeclare_dependencylink_args are never deduplicated, so with dozens of static modules each carrying the Geant4 link line, GNU ld would reprocess every large archive on each repeat and the link would crawl. - Two dependency objects.
geant4_dep(full,-isystemincludes) drives the GUI/vis targets;geant4_core_dep(core, plain-I) drives everything else. On Linux,geant4_depsalso pulls in the X11/GLX stack forG4OpenGL. - Install the
.pcfiles into<prefix>/lib/pkgconfigvia an install script (they are generated build-tree files). This is the step that makes the producer/consumer model work:clas12-systemsreadsgeant4_core.pcfrom here.
Static Geant4 and Assimp both bundle pugixml. Upcoming in the next release, the Assimp target compiles with
-Dpugi=gemc_assimp_pugi, giving its bundled XML parser a distinct namespace and preventing duplicate symbols
when both archives are linked into GEMC. The definition applies to all Assimp sources, including XML importers,
and is private to that target; GEMC, yaml-cpp, and Geant4 do not receive it.
use_sharedl = (sanitize != 'none') or (get_option('default_library') == 'shared')- Default build: GEMC modules are static
.aarchives, linked once into thegemcexecutable. A staticlink_withlibrary forwards its dependencies' link args, so plugins/examples receive only the compile/include part ofthis_depsto avoid duplicate-lflags. use_sharedlbuild (sanitizer ordefault_library=shared, the profile/CI path): each module is a self-contained shared library that does not forward those link args, so the fullthis_depsmust be passed to plugins and examples instead.
Static linking of CLHEP and the bundled CMake subprojects interacts badly with the use_sharedl shape
(duplicate symbols / duplicated global state across shared objects), which is the core reason CLHEP is kept
shared — see the CLHEP section above.
opengl,sqlite3,expat(Geant4's GIDI/XML parsing needs it under static Geant4),zlib(shared, to avoid linking the static system archive),threads.ROOTis optional: probed viaroot-config, wrapped indeclare_dependency; disabled features degrade gracefully unless-Droot=enabledforces it.- CMake subprojects
assimpandyaml-cppare configured throughcmake.subproject_options(). yaml-cpp headers are part of GEMC's public API (goption.hincludesyaml-cpp/yaml.h), so they are installed alongside the GEMC headers.