@@ -84,7 +84,9 @@ function(generate_target_and_root_library target)
8484 endif ()
8585 list (APPEND headers ${habs} )
8686 get_filename_component (hName ${habs} NAME )
87- configure_file (${habs} "${CMAKE_BINARY_DIR} /include/${hName} " )
87+ execute_process (
88+ COMMAND "${CMAKE_COMMAND} " -E copy_if_different "${habs} " "${CMAKE_BINARY_DIR} /include/${hName} "
89+ OUTPUT_QUIET ERROR_QUIET )
8890 endforeach ()
8991
9092
@@ -249,12 +251,44 @@ function(make_target_root_dictionary target)
249251
250252 set (includeDirs $<REMOVE_DUPLICATES :$<TARGET_PROPERTY :${target} ,INCLUDE_DIRECTORIES >>)
251253
252- # add a custom command to generate the dictionary using rootcling
254+ # Write the list of input headers to a cmake file at configure time.
255+ # The build-time stamp script reads this file to compute content hashes,
256+ # avoiding semicolon/shell-escaping issues when passing long lists via -D.
257+ set (_headersListFile ${CMAKE_CURRENT_BINARY_DIR} /${dictionary} _headers_list.cmake)
258+ set (_headersListContent "set(DICT_HEADERS\n " )
259+ foreach (_h ${headers} )
260+ string (APPEND _headersListContent " \" ${_h} \"\n " )
261+ endforeach ()
262+ string (APPEND _headersListContent ")\n " )
263+ file (WRITE "${_headersListFile} .tmp" "${_headersListContent} " )
264+ execute_process (
265+ COMMAND "${CMAKE_COMMAND} " -E copy_if_different
266+ "${_headersListFile} .tmp" "${_headersListFile} "
267+ OUTPUT_QUIET ERROR_QUIET )
268+ file (REMOVE "${_headersListFile} .tmp" )
269+
270+ set (stampFile ${CMAKE_CURRENT_BINARY_DIR} /${dictionary} _headers.stamp)
271+
272+ # Step 1: Update stamp only when header CONTENT changes (not just mtime).
273+ # This prevents rootcling from rerunning after git pull or cmake reconfigure
274+ # when header content is actually unchanged.
275+ # cmake-format: off
276+ add_custom_command (
277+ OUTPUT ${stampFile}
278+ COMMAND ${CMAKE_COMMAND}
279+ "-DHEADERS_LIST_FILE=${_headersListFile} "
280+ "-DSTAMP_FILE=${stampFile} "
281+ -P "${CMAKE_SOURCE_DIR} /cmake/modules/update_dict_stamp.cmake"
282+ DEPENDS ${headers}
283+ VERBATIM
284+ COMMENT "Checking header content for ${dictionary} " )
285+ # cmake-format: on
286+
287+ # Step 2: Run rootcling only when stamp changes (i.e., header CONTENT changed).
253288 # cmake-format: off
254- set (space " " )
255- #message(STATUS " Adding dictionary ${dictionaryFile} to target ${target}")
256289 add_custom_command (
257290 OUTPUT ${dictionaryFile} ${pcmFile} ${rootmapFile}
291+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR} /${pcmBase}
258292 VERBATIM
259293 COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${LD_LIBRARY_PATH} :$ENV{LD_LIBRARY_PATH} "
260294 ${ROOT_rootcling_CMD}
@@ -267,7 +301,7 @@ function(make_target_root_dictionary target)
267301 ${headers}
268302 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR} /${pcmBase} ${pcmFile}
269303 COMMAND_EXPAND_LISTS
270- DEPENDS ${headers } )
304+ DEPENDS ${stampFile } )
271305 # cmake-format: on
272306
273307 # add dictionary source to the target sources and suppress warnings
0 commit comments