From cf5e52b6c4e3eb57ccf7d4510f7e2838a3f0ba9e Mon Sep 17 00:00:00 2001 From: Oliver Lantwin Date: Fri, 6 Feb 2026 15:22:59 +0100 Subject: [PATCH] refactor: use modern ROOT dictionary generation in ship_add_library --- CMakeLists.txt | 4 + cmake/modules/ShipMacros.cmake | 129 ++++++++++++++++++++------------- 2 files changed, 81 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dcd1aa747..cbca2be62a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ cmake_minimum_required(VERSION 3.20.0 FATAL_ERROR) # CMP0028 and CMP0074 are already NEW at cmake_minimum_required 3.20. +# CMP0118 (3.20): GENERATED sources visible across directories. +cmake_policy(SET CMP0118 NEW) # CMP0144 (3.27): use _ROOT variables in find_package. if(POLICY CMP0144) cmake_policy(SET CMP0144 NEW) @@ -18,6 +20,8 @@ endif() project(FairShip VERSION 0.0.0 LANGUAGES CXX) +include(GNUInstallDirs) + # C++17 required by ROOT 6.36 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/cmake/modules/ShipMacros.cmake b/cmake/modules/ShipMacros.cmake index 473ffe769b..dfc3d65629 100644 --- a/cmake/modules/ShipMacros.cmake +++ b/cmake/modules/ShipMacros.cmake @@ -30,8 +30,7 @@ FairRoot's scope-variable-driven ``GENERATE_LIBRARY()`` macro. by replacing ``.cxx`` with ``.h``. ``LINKDEF`` - Path to the ROOT LinkDef header (relative to ``CMAKE_CURRENT_SOURCE_DIR`` - or absolute). + Path to the ROOT LinkDef header (relative to ``CMAKE_CURRENT_SOURCE_DIR``). ``DEPENDENCIES`` Link dependencies — target names, library file paths, or variable-based @@ -47,6 +46,9 @@ The current source directory is always added as a PUBLIC include directory with a ``BUILD_INTERFACE`` / ``INSTALL_INTERFACE`` generator expression, so dependents of the library automatically receive its include path. +Dictionary generation invokes ROOT's rootcling directly and reads include +directories from target properties via generator expressions. + #]=======================================================================] function(ship_add_library) @@ -66,52 +68,6 @@ function(ship_add_library) # --- Derive headers from sources (.cxx -> .h) --- CHANGE_FILE_EXTENSION(*.cxx *.h _hdrs "${ARG_SOURCES}") - install(FILES ${_hdrs} DESTINATION include) - - # --- Prepare scope variables for FairRoot's dictionary macros --- - set(LIBRARY_NAME ${ARG_NAME}) - set(HDRS ${_hdrs}) - set(DICTIONARY ${CMAKE_CURRENT_BINARY_DIR}/G__${ARG_NAME}Dict.cxx) - set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) - - # Build INCLUDE_DIRECTORIES for rootcling: own source dir + extras + - # source dirs of FairShip dependency targets. - set(INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_SOURCE_DIR} - ${ARG_INCLUDE_DIRECTORIES} - ) - set(SYSTEM_INCLUDE_DIRECTORIES ${ARG_SYSTEM_INCLUDE_DIRECTORIES}) - - foreach(_dep IN LISTS ARG_DEPENDENCIES) - if(TARGET ${_dep}) - get_target_property(_dep_src ${_dep} SOURCE_DIR) - if(_dep_src) - list(APPEND INCLUDE_DIRECTORIES ${_dep_src}) - endif() - endif() - endforeach() - - # --- Dictionary generation --- - set(_all_srcs ${ARG_SOURCES}) - - if(ARG_LINKDEF) - if(IS_ABSOLUTE "${ARG_LINKDEF}") - set(LINKDEF "${ARG_LINKDEF}") - else() - set(LINKDEF "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_LINKDEF}") - endif() - - if(COMMAND FAIRROOT_GENERATE_DICTIONARY) - FAIRROOT_GENERATE_DICTIONARY() - else() - ROOT_GENERATE_DICTIONARY() - endif() - - list(APPEND _all_srcs ${DICTIONARY}) - set_source_files_properties(${DICTIONARY} PROPERTIES - COMPILE_FLAGS "-Wno-old-style-cast" - ) - endif() # --- Resolve dependencies --- set(_resolved_deps) @@ -126,9 +82,44 @@ function(ship_add_library) endif() endforeach() - # --- Create library --- - add_library(${ARG_NAME} SHARED ${_all_srcs}) - target_link_libraries(${ARG_NAME} ${_resolved_deps}) + # --- Dictionary generation setup (before add_library) --- + # We generate the dictionary using rootcling and add it to library sources + # directly, similar to the old GENERATE_LIBRARY macro approach. + set(_all_srcs ${ARG_SOURCES}) + if(ARG_LINKDEF) + set(_dict_basename G__${ARG_NAME}) + set(_dict_file ${CMAKE_CURRENT_BINARY_DIR}/${_dict_basename}.cxx) + set(_pcm_base ${_dict_basename}_rdict.pcm) + set(_pcm_file ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${_pcm_base}) + set(_rootmap_file ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/lib${ARG_NAME}.rootmap) + + # Collect headers with absolute paths for rootcling + # Also extract directories for include paths (matches fairroot_target_root_dictionary) + set(_abs_headers) + set(_hdr_dirs) + foreach(_h ${_hdrs}) + get_filename_component(_abs_h ${_h} ABSOLUTE) + list(APPEND _abs_headers ${_abs_h}) + get_filename_component(_hdr_dir ${_abs_h} DIRECTORY) + list(APPEND _hdr_dirs ${_hdr_dir}) + endforeach() + get_filename_component(_abs_linkdef ${ARG_LINKDEF} ABSOLUTE) + list(REMOVE_DUPLICATES _hdr_dirs) + + # Include directories for rootcling - will use generator expression after target exists + set(_inc_dirs_genex $) + + # Add dictionary to sources + list(APPEND _all_srcs ${_dict_file}) + set_source_files_properties(${_dict_file} PROPERTIES + GENERATED TRUE + COMPILE_FLAGS "-Wno-old-style-cast" + ) + endif() + + # --- Create library with ALL sources including dictionary --- + add_library(${ARG_NAME} SHARED ${_all_srcs} ${_hdrs}) + target_link_libraries(${ARG_NAME} PUBLIC ${_resolved_deps}) set_target_properties(${ARG_NAME} PROPERTIES ${PROJECT_LIBRARY_PROPERTIES}) # --- Target-based include propagation --- @@ -148,5 +139,39 @@ function(ship_add_library) ) endif() - install(TARGETS ${ARG_NAME} DESTINATION lib) + # --- Dictionary generation command (after target exists for generator expressions) --- + if(ARG_LINKDEF) + # Add header directories as private include directories for dictionary compilation + # (matches fairroot_target_root_dictionary behaviour) + target_include_directories(${ARG_NAME} PRIVATE ${_hdr_dirs}) + + add_custom_command( + OUTPUT ${_dict_file} ${_pcm_file} ${_rootmap_file} + VERBATIM + COMMAND ${CMAKE_COMMAND} -E env + "LD_LIBRARY_PATH=${ROOT_LIBRARY_DIR}:$ENV{LD_LIBRARY_PATH}" + $ + -f ${_dict_file} + -inlineInputHeader + -rmf ${_rootmap_file} + -rml $ + "$<$:-I$-I>>" + "$<$>:-D$,$-D>>" + ${_abs_headers} + ${_abs_linkdef} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${_pcm_base} ${_pcm_file} + COMMAND_EXPAND_LISTS + DEPENDS ${_abs_headers} ${_abs_linkdef} + ) + # Ensure ROOT::RIO is linked + get_property(_libs TARGET ${ARG_NAME} PROPERTY INTERFACE_LINK_LIBRARIES) + if(NOT ROOT::RIO IN_LIST _libs) + target_link_libraries(${ARG_NAME} PUBLIC ROOT::RIO) + endif() + install(FILES ${_rootmap_file} ${_pcm_file} DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() + + install(TARGETS ${ARG_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES ${_hdrs} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) endfunction()