Back to home page

EIC code displayed by LXR

 
 

    


Warning, /acts/docs/groups/detector_descr/runtime_geometry_modules.md is written in an unsupported language. File is not indexed.

0001 @defgroup geometry_module_loading Runtime geometry module loading
0002 @ingroup geometry
0003 @brief Loading tracking geometries from runtime shared libraries.
0004 
0005 This topic documents the runtime geometry module loading entry points:
0006 
0007 - @ref Acts::loadGeometryModule for modules that do not require user data.
0008 - @ref Acts::loadDD4hepGeometryModule for DD4hep-based modules.
0009 
0010 Both loaders validate module ABI compatibility before constructing the
0011 @ref Acts::TrackingGeometry, and keep the shared library loaded for the
0012 lifetime of the returned geometry object.
0013 
0014 ## Overview
0015 
0016 Runtime geometry modules allow tracking geometries to be compiled as
0017 independent shared libraries (`.so`/`.dylib`) and loaded at runtime without
0018 recompiling the host application. This is useful when:
0019 
0020 - The geometry changes frequently and recompiling the full framework is costly.
0021 - Different geometry variants need to be swapped at runtime.
0022 - The geometry is developed and distributed independently from the experiment
0023   framework.
0024 
0025 @note Runtime geometry modules rely on `dlopen`/`dlsym` and are
0026       only supported on Unix-like systems (Linux, macOS).
0027 
0028 ## The module ABI
0029 
0030 Every geometry module must export a single C-linkage entry point:
0031 
0032 ```c
0033 extern "C" const ActsGeometryModuleV1* acts_geometry_module_v1(void);
0034 ```
0035 
0036 The returned `ActsGeometryModuleV1` struct (defined in
0037 `Acts/Geometry/GeometryModule.h`) carries four fields:
0038 
0039 | Field              | Type                                      | Purpose                                                  |
0040 |--------------------|-------------------------------------------|----------------------------------------------------------|
0041 | `module_abi_tag`   | `const char*`                             | Build-time ABI tag matched against the host library      |
0042 | `user_data_type`   | `const char*`                             | Type name of the extra context the module needs, or null |
0043 | `build`            | `void* (*)(const void* user_data, const void* logger)` | Constructs the geometry; returns a heap-allocated `TrackingGeometry*` or null on failure |
0044 | `destroy`          | `void (*)(void* handle)`                  | Deletes the geometry object returned by `build`          |
0045 
0046 You never fill this struct manually. Use the provided helper macros instead
0047 (see @ref geometry_module_writing "Writing a geometry module" below).
0048 
0049 ## ABI compatibility
0050 
0051 Each ACTS build is tagged with an opaque string (`ACTS_GEOMETRY_MODULE_ABI_TAG`)
0052 that encodes the host library ABI. Plain geometry modules use that tag as-is
0053 and are matched against the tag compiled into `ActsCore`.
0054 
0055 DD4hep geometry modules use a DD4hep-specific extension of that tag:
0056 
0057 ```text
0058 ${ACTS_GEOMETRY_MODULE_ABI_TAG}|dd4hep-${DD4hep_VERSION}
0059 ```
0060 
0061 `loadDD4hepGeometryModule` matches `module_abi_tag` against the corresponding
0062 tag compiled into `Acts::PluginDD4hep`, so a DD4hep module must be built
0063 against both the same ACTS build and the same DD4hep version as the host
0064 plugin. Any mismatch causes an immediate `std::runtime_error`.
0065 
0066 ## Loading a module
0067 
0068 ### Plain module (no extra context)
0069 
0070 Include `Acts/Geometry/GeometryModuleLoader.hpp`, then:
0071 
0072 @snippet{trimleft} examples/geometry_module.cpp Load Plain Module
0073 
0074 ### DD4hep module
0075 
0076 Include `ActsPlugins/DD4hep/GeometryModuleLoader.hpp`, then:
0077 
0078 @snippet{trimleft} examples/geometry_module.cpp Load DD4hep Module
0079 
0080 The loader passes a pointer to `detector` through the opaque `void* user_data`
0081 argument. It validates that the module declares `user_data_type == "dd4hep::Detector"`;
0082 trying to load a plain module with `loadDD4hepGeometryModule` (or vice-versa)
0083 throws a descriptive `std::runtime_error`.
0084 
0085 @anchor geometry_module_writing
0086 ## Writing a geometry module
0087 
0088 ### Plain module
0089 
0090 1. Create a source file with a build function:
0091 
0092 @snippet{trimleft} examples/geometry_module_template.cpp Write Plain Module
0093 
0094 2. Register it in CMake using `acts_add_geometry_module`:
0095 
0096 @snippet{trimleft} CMakeLists.txt Plain Module CMake
0097 
0098 The CMake helper creates a `SHARED` library target, links it against
0099 `Acts::Core`, and injects the `ACTS_GEOMETRY_MODULE_ABI_TAG` compile definition
0100 required by `ACTS_DEFINE_GEOMETRY_MODULE`.
0101 
0102 ### DD4hep module
0103 
0104 1. Create a source file with a build function that takes a `dd4hep::Detector`:
0105 
0106 @snippet{trimleft} examples/geometry_module_template_dd4hep.cpp Write DD4hep Module
0107 
0108 2. Register it in CMake using `acts_add_dd4hep_geometry_module`:
0109 
0110 @snippet{trimleft} CMakeLists.txt DD4hep Module CMake
0111 
0112 This links against `Acts::PluginDD4hep` instead of `Acts::Core` and sets
0113 `ACTS_GEOMETRY_MODULE_ABI_TAG` to the DD4hep-specific tag derived from the
0114 installed ACTS tag plus `DD4hep_VERSION`.
0115 
0116 ## Lifetime management
0117 
0118 The `std::shared_ptr<TrackingGeometry>` returned by both loaders uses a custom
0119 deleter that:
0120 
0121 1. Calls `descriptor->destroy()` to delete the `TrackingGeometry` object via
0122    the module's own destructor (important for correct cross-boundary `delete`).
0123 2. Keeps a `shared_ptr<void>` to the `dlopen` handle alive, so the shared
0124    library is only unloaded **after** the geometry is destroyed — preventing
0125    use-after-unload of virtual dispatch tables or static data.
0126 
0127 ## Error handling
0128 
0129 All errors are reported as `std::runtime_error`. The loader performs several
0130 checks in order before invoking the build function:
0131 
0132 - **File not found.** The path is checked with `std::filesystem::exists` before
0133   calling `dlopen`. This gives a clearer error than the linker error that
0134   `dlopen` would produce for a missing file.
0135 
0136 - **`dlopen` failure.** If the operating system cannot load the shared library
0137   (e.g. missing transitive dependencies, wrong architecture), the error string
0138   from `dlerror` is included in the exception message.
0139 
0140 - **Missing entry point.** The loader looks up the symbol
0141   `acts_geometry_module_v1` via `dlsym`. If it is absent the module was either
0142   not built with `ACTS_DEFINE_GEOMETRY_MODULE` / `ACTS_DEFINE_DD4HEP_GEOMETRY_MODULE`,
0143   or the symbol was stripped or hidden by the linker.
0144 
0145 - **Null or incomplete descriptor.** The struct returned by the entry point must
0146   be non-null and have `module_abi_tag` set and both function-pointer fields (`build`, `destroy`)
0147   non-null. A null or partially initialized descriptor indicates a
0148   programming error in the module.
0149 
0150 - **ABI tag mismatch.** `module_abi_tag` is compared against the tag baked into
0151   the host loader library at its own build time (`ActsCore` for plain modules,
0152   `Acts::PluginDD4hep` for DD4hep modules). A mismatch means the module and the
0153   host were built from different ACTS or DD4hep versions and cannot safely
0154   interoperate. Rebuild the module against the same ACTS installation and, for
0155   DD4hep modules, the same DD4hep version.
0156 
0157 - **User-data type mismatch.** The `user_data_type` field in the descriptor is
0158   compared against the type the loader expects. If you call `loadGeometryModule`
0159   on a module that declares a `user_data_type` (i.e. it needs extra context such
0160   as a `dd4hep::Detector`), or call a typed loader (e.g. `loadDD4hepGeometryModule`)
0161   on a plain module, a `std::runtime_error` is thrown with a hint pointing to
0162   the correct loader to use.
0163 
0164 - **`build` returns null.** The module's build function returned a null pointer,
0165   which means it failed to construct the geometry. Exceptions thrown inside
0166   `build` are caught by the helper and logged via `ACTS_ERROR` before the null
0167   is returned, so check the log for the underlying cause.