Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 07:46:40

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Geometry/GeometryModuleLoader.hpp"
0010 
0011 #include "Acts/Geometry/GeometryModule.h"
0012 #include "Acts/Geometry/TrackingGeometry.hpp"
0013 
0014 #include <cstring>
0015 #include <format>
0016 #include <stdexcept>
0017 
0018 #include <dlfcn.h>
0019 
0020 #ifndef ACTS_GEOMETRY_MODULE_ABI_TAG
0021 #error \
0022     "ACTS_GEOMETRY_MODULE_ABI_TAG must be provided by CMake when building ActsCore."
0023 #endif
0024 
0025 namespace {
0026 
0027 using GeometryModuleEntryPointV1 = const ActsGeometryModuleV1* (*)(void);
0028 
0029 std::shared_ptr<void> openSharedLibrary(const std::filesystem::path& path) {
0030   if (!std::filesystem::exists(path)) {
0031     throw std::runtime_error(
0032         std::format("Geometry module file does not exist: {}", path.string()));
0033   }
0034 
0035   void* rawHandle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
0036   if (rawHandle == nullptr) {
0037     const char* error = ::dlerror();
0038     throw std::runtime_error(std::format(
0039         "Failed to load geometry module '{}': {}", path.string(), error));
0040   }
0041   return std::shared_ptr<void>(rawHandle, [](void* handle) {
0042     if (handle != nullptr) {
0043       ::dlclose(handle);
0044     }
0045   });
0046 }
0047 
0048 GeometryModuleEntryPointV1 resolveEntrypointV1(
0049     const std::filesystem::path& path, const std::shared_ptr<void>& library) {
0050   ::dlerror();
0051   void* symbol = ::dlsym(library.get(), "acts_geometry_module_v1");
0052   if (const char* error = ::dlerror(); error != nullptr) {
0053     throw std::runtime_error(
0054         std::format("Failed to resolve acts_geometry_module_v1 in '{}': {}",
0055                     path.string(), error));
0056   }
0057   if (symbol == nullptr) {
0058     throw std::runtime_error(std::format(
0059         "Entry point acts_geometry_module_v1 resolved to nullptr in '{}'",
0060         path.string()));
0061   }
0062   return reinterpret_cast<GeometryModuleEntryPointV1>(symbol);
0063 }
0064 
0065 const char* geometryModuleHostAbiTag() noexcept {
0066   return ACTS_GEOMETRY_MODULE_ABI_TAG;
0067 }
0068 
0069 }  // namespace
0070 
0071 namespace Acts::detail {
0072 
0073 std::shared_ptr<TrackingGeometry> loadGeometryModuleImpl(
0074     const std::filesystem::path& modulePath, const char* expectedAbiTag,
0075     const char* expectedUserDataType, const void* userData,
0076     const Logger& logger) {
0077   auto library = openSharedLibrary(modulePath);
0078   auto entryPoint = resolveEntrypointV1(modulePath, library);
0079   const ActsGeometryModuleV1* descriptor = entryPoint();
0080   if (descriptor == nullptr) {
0081     throw std::runtime_error("Geometry module descriptor is null");
0082   }
0083   if (descriptor->module_abi_tag == nullptr || descriptor->build == nullptr ||
0084       descriptor->destroy == nullptr) {
0085     throw std::runtime_error("Geometry module descriptor is incomplete");
0086   }
0087   if (expectedAbiTag == nullptr) {
0088     throw std::runtime_error("Expected geometry module ABI tag is null");
0089   }
0090   if (std::strcmp(descriptor->module_abi_tag, expectedAbiTag) != 0) {
0091     throw std::runtime_error(std::format(
0092         "Geometry module ABI mismatch: module='{}' host='{}' path='{}'",
0093         descriptor->module_abi_tag, expectedAbiTag, modulePath.string()));
0094   }
0095 
0096   // Validate user_data_type: both sides must agree on whether userData is
0097   // needed and what type it is.
0098   if (const char* actualType = descriptor->user_data_type;
0099       !((expectedUserDataType == nullptr && actualType == nullptr) ||
0100         (expectedUserDataType != nullptr && actualType != nullptr &&
0101          std::strcmp(actualType, expectedUserDataType) == 0))) {
0102     if (actualType == nullptr) {
0103       throw std::runtime_error(std::format(
0104           "Geometry module '{}' does not require user data; "
0105           "use loadGeometryModule(path, logger) without extra context",
0106           modulePath.string()));
0107     } else if (expectedUserDataType == nullptr) {
0108       throw std::runtime_error(std::format(
0109           "Geometry module '{}' requires user data of type '{}'; "
0110           "use the appropriate typed loader (e.g. loadDD4hepGeometryModule)",
0111           modulePath.string(), actualType));
0112     } else {
0113       throw std::runtime_error(
0114           std::format("Geometry module '{}' user_data_type mismatch: "
0115                       "expected '{}', module declares '{}'",
0116                       modulePath.string(), expectedUserDataType, actualType));
0117     }
0118   }
0119 
0120   void* rawHandle = descriptor->build(userData, &logger);
0121   if (rawHandle == nullptr) {
0122     throw std::runtime_error("Geometry module build returned null handle");
0123   }
0124 
0125   auto destroyFn = descriptor->destroy;
0126   return std::shared_ptr<TrackingGeometry>(
0127       static_cast<TrackingGeometry*>(rawHandle),
0128       [destroyFn, library = std::move(library)](TrackingGeometry* geometry) {
0129         destroyFn(static_cast<void*>(geometry));
0130       });
0131 }
0132 
0133 }  // namespace Acts::detail
0134 
0135 namespace Acts {
0136 
0137 std::shared_ptr<TrackingGeometry> loadGeometryModule(
0138     const std::filesystem::path& modulePath, const Logger& logger) {
0139   return detail::loadGeometryModuleImpl(modulePath, geometryModuleHostAbiTag(),
0140                                         nullptr, nullptr, logger);
0141 }
0142 
0143 }  // namespace Acts