Skip to content

Commit ce90419

Browse files
feat: dlopen-based geometry *module* support (#5253)
This PR adds a (completely optional) mechanism to compile a geometry *module*. This module exposes a C API to construct a tracking geometry and send it to a host program over a shared library boundary opened via `dlopen`. The host library manages lifetime of the geomerty transparently.
1 parent 17accde commit ce90419

29 files changed

Lines changed: 1108 additions & 14 deletions

.github/workflows/builds.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,10 @@ jobs:
117117
- name: Downstream build
118118
run: cmake --build build-downstream
119119

120-
- name: Downstream run
121-
run: ./build-downstream/bin/ShowActsVersion
120+
- name: Downstream tests
121+
run: >
122+
CI/dependencies/run.sh .env
123+
ctest --test-dir build-downstream --output-on-failure
122124
123125
linux_examples_test:
124126
runs-on: ubuntu-latest
@@ -318,8 +320,8 @@ jobs:
318320
- name: Downstream build
319321
run: cmake --build build-downstream
320322

321-
- name: Downstream run
322-
run: ./build-downstream/bin/ShowActsVersion
323+
- name: Downstream tests
324+
run: ctest --test-dir build-downstream --output-on-failure
323325

324326
macos:
325327
runs-on: macos-26
@@ -406,8 +408,8 @@ jobs:
406408
- name: Downstream build
407409
run: cmake --build build-downstream
408410

409-
- name: Downstream run
410-
run: ./build-downstream/bin/ShowActsVersion
411+
- name: Downstream tests
412+
run: ctest --test-dir build-downstream --output-on-failure
411413

412414
external_eic-shell:
413415
runs-on: ubuntu-latest

.gitlab-ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ build_linux_ubuntu:
253253
# Downstream build
254254
- cmake --build build-downstream
255255

256-
# Downstream run
257-
- ./build-downstream/bin/ShowActsVersion
256+
# Downstream tests
257+
- ctest --test-dir build-downstream --output-on-failure
258258

259259
after_script:
260260
- !reference [.spack_cleanup, after_script]
@@ -369,8 +369,8 @@ linux_physmon:
369369
# Downstream build
370370
- cmake --build build-downstream
371371

372-
# Downstream run
373-
- ./build-downstream/bin/ShowActsVersion
372+
# Downstream tests
373+
- ctest --test-dir build-downstream --output-on-failure
374374

375375
after_script:
376376
- !reference [.spack_cleanup, after_script]

CI/check_unused_files.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ def main():
7575
"Core/include/Acts/EventData/detail/ParameterTraits.hpp",
7676
"Core/include/Acts/Seeding/PathSeeder.hpp",
7777
"Tests/CommonHelpers/include/ActsTests/CommonHelpers/TestSpacePoint.hpp",
78+
"GeometryModule.h",
79+
"runtime_geometry_modules.md",
7880
)
7981

8082
suffix_header = (

Core/CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ target_sources(ActsCore PRIVATE src/ActsVersion.cpp)
1010

1111
target_compile_features(ActsCore PUBLIC ${ACTS_CXX_STANDARD_FEATURE})
1212

13+
set(ACTS_GEOMETRY_MODULE_CAPI 1)
14+
set(_acts_geometry_module_abi_tag
15+
"acts-${Acts_VERSION}|sys-${CMAKE_SYSTEM_NAME}|arch-${CMAKE_SYSTEM_PROCESSOR}|cxx-${CMAKE_CXX_COMPILER_ID}-${CMAKE_CXX_COMPILER_VERSION}|capi-${ACTS_GEOMETRY_MODULE_CAPI}"
16+
)
17+
set(ACTS_GEOMETRY_MODULE_ABI_TAG
18+
"${_acts_geometry_module_abi_tag}"
19+
CACHE INTERNAL
20+
"ACTS geometry module ABI tag"
21+
)
22+
1323
target_include_directories(
1424
ActsCore
1525
PUBLIC
@@ -19,6 +29,14 @@ target_include_directories(
1929
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
2030
)
2131
target_link_libraries(ActsCore PUBLIC Boost::boost Eigen3::Eigen)
32+
if(CMAKE_DL_LIBS)
33+
target_link_libraries(ActsCore PRIVATE ${CMAKE_DL_LIBS})
34+
endif()
35+
36+
target_compile_definitions(
37+
ActsCore
38+
PRIVATE ACTS_GEOMETRY_MODULE_ABI_TAG="${_acts_geometry_module_abi_tag}"
39+
)
2240

2341
if(ACTS_PARAMETER_DEFINITIONS_HEADER)
2442
target_compile_definitions(
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#pragma once
10+
11+
struct ActsGeometryModuleV1 {
12+
const char* module_abi_tag;
13+
const char* user_data_type;
14+
void* (*build)(const void* user_data, const void* logger);
15+
void (*destroy)(void* handle);
16+
};
17+
18+
extern "C" const ActsGeometryModuleV1* acts_geometry_module_v1(void);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#pragma once
10+
11+
#include "Acts/Geometry/GeometryModule.h"
12+
#include "Acts/Geometry/TrackingGeometry.hpp"
13+
14+
#include <memory>
15+
16+
namespace Acts::detail {
17+
using BuildFunction = std::unique_ptr<TrackingGeometry> (*)(const Logger&);
18+
const ActsGeometryModuleV1* getGeometryModule(const char* module_abi_tag,
19+
const char* user_data_type,
20+
BuildFunction buildFunc);
21+
// Low-level shared helper: accepts a raw build function pointer matching the
22+
// C ABI struct's .build field. Handles static struct init and destroy.
23+
const ActsGeometryModuleV1* getGeometryModuleFromRaw(
24+
const char* module_abi_tag, const char* user_data_type,
25+
void* (*buildFunc)(const void*, const void*));
26+
} // namespace Acts::detail
27+
28+
// Internal — do not use directly.
29+
#define ACTS_IMPL_GEOMETRY_MODULE_ENTRY(get_module_expr) \
30+
extern "C" const ActsGeometryModuleV1* acts_geometry_module_v1(void) { \
31+
return (get_module_expr); \
32+
}
33+
34+
// Emit a clear error only when the macro is actually expanded without the tag,
35+
// rather than at include time — Acts internal code includes this header too.
36+
#ifdef ACTS_GEOMETRY_MODULE_ABI_TAG
37+
#define ACTS_DEFINE_GEOMETRY_MODULE(build_function) \
38+
ACTS_IMPL_GEOMETRY_MODULE_ENTRY(Acts::detail::getGeometryModule( \
39+
ACTS_GEOMETRY_MODULE_ABI_TAG, nullptr, (build_function)))
40+
#else
41+
#define ACTS_DEFINE_GEOMETRY_MODULE(build_function) \
42+
static_assert(false, \
43+
"ACTS_GEOMETRY_MODULE_ABI_TAG must be provided via " \
44+
"CMake (use acts_add_geometry_module).")
45+
#endif
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#pragma once
10+
11+
#if !defined(__unix__) && !defined(__APPLE__)
12+
#error \
13+
"Runtime geometry modules are only supported on Unix-like systems (Linux, macOS)."
14+
#endif
15+
16+
#include "Acts/Utilities/Logger.hpp"
17+
18+
#include <filesystem>
19+
#include <memory>
20+
21+
namespace Acts {
22+
23+
class TrackingGeometry;
24+
25+
/// Load a module shared library, validate ABI compatibility, build and return
26+
/// the tracking geometry. The returned deleter keeps the module loaded until
27+
/// the geometry is destroyed. Throws if the module requires user data (e.g.
28+
/// a DD4hep module) — use the appropriate typed loader instead.
29+
/// @param modulePath Path to the geometry module shared library.
30+
/// @param logger Logger instance used by the module loader.
31+
/// @return Shared pointer to the loaded tracking geometry.
32+
std::shared_ptr<TrackingGeometry> loadGeometryModule(
33+
const std::filesystem::path& modulePath,
34+
const Logger& logger = getDummyLogger());
35+
36+
namespace detail {
37+
/// Low-level loader used by typed wrappers (e.g. loadDD4hepGeometryModule).
38+
/// Validates that the module's ABI tag matches \a expectedAbiTag.
39+
/// Validates that the module's user_data_type matches \a expectedUserDataType
40+
/// (nullptr means the module must declare no user data requirement).
41+
std::shared_ptr<TrackingGeometry> loadGeometryModuleImpl(
42+
const std::filesystem::path& modulePath, const char* expectedAbiTag,
43+
const char* expectedUserDataType, const void* userData,
44+
const Logger& logger);
45+
} // namespace detail
46+
47+
} // namespace Acts

Core/src/Geometry/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ target_sources(
1616
GenericApproachDescriptor.cpp
1717
GenericCuboidVolumeBounds.cpp
1818
GeometryIdentifier.cpp
19+
GeometryModuleHelper.cpp
20+
GeometryModuleLoader.cpp
1921
GlueVolumesDescriptor.cpp
2022
Layer.cpp
2123
LayerArrayCreator.cpp
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#include "Acts/Geometry/GeometryModuleHelper.hpp"
10+
11+
#include "Acts/Geometry/GeometryModule.h"
12+
#include "Acts/Geometry/TrackingGeometry.hpp"
13+
#include "Acts/Utilities/Logger.hpp"
14+
15+
#include <exception>
16+
#include <memory>
17+
18+
namespace Acts::detail {
19+
20+
const ActsGeometryModuleV1* getGeometryModuleFromRaw(
21+
const char* module_abi_tag, const char* user_data_type,
22+
void* (*buildFunc)(const void*, const void*)) {
23+
static const ActsGeometryModuleV1 s_module = {
24+
.module_abi_tag = module_abi_tag,
25+
.user_data_type = user_data_type,
26+
.build = buildFunc,
27+
.destroy =
28+
[](void* handle) noexcept {
29+
if (handle == nullptr) {
30+
return;
31+
}
32+
33+
delete static_cast<TrackingGeometry*>(handle);
34+
},
35+
};
36+
37+
return &s_module;
38+
}
39+
40+
const ActsGeometryModuleV1* getGeometryModule(const char* module_abi_tag,
41+
const char* user_data_type,
42+
BuildFunction buildFunc) {
43+
static BuildFunction s_buildFunc = buildFunc;
44+
45+
return getGeometryModuleFromRaw(
46+
module_abi_tag, user_data_type,
47+
[](const void* /*userData*/, const void* loggerPtr) noexcept -> void* {
48+
if (loggerPtr == nullptr) {
49+
return nullptr;
50+
}
51+
const auto& logger = *static_cast<const Logger*>(loggerPtr);
52+
try {
53+
return s_buildFunc(logger).release();
54+
} catch (const std::exception& e) {
55+
ACTS_ERROR("Failed to build geometry module: " << e.what());
56+
return nullptr;
57+
} catch (...) {
58+
ACTS_ERROR("Failed to build geometry module");
59+
return nullptr;
60+
}
61+
});
62+
}
63+
64+
} // namespace Acts::detail

0 commit comments

Comments
 (0)