Skip to content

Commit 594345f

Browse files
committed
[CMake] Speed up copying of headers.
To copy headers to the build tree, ROOT was creating one target per header. Headers are copied in packs of 100 (Windows doesn't support very long command lines). This significantly reduces the number of CMake targets and speeds up the build. A simple test that only moves headers: make -j6 move_headers New Old 1st invocation 10.7 s 34.5 s 2nd invocation 2.7 s 3.8 s Fix #14953.
1 parent 43f2c11 commit 594345f

File tree

3 files changed

+71
-28
lines changed

3 files changed

+71
-28
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ foreach(DIR_TO_COPY ${DIRECTORIES_TO_COPY})
328328
PATTERN tutorials/hsimple.root EXCLUDE)
329329
endforeach()
330330

331-
332331
add_subdirectory (interpreter)
333332

334333
# Update etc/gitinfo.txt for every build.
@@ -375,6 +374,10 @@ endif()
375374
ROOT_ADD_TEST_SUBDIRECTORY(test)
376375
ROOT_ADD_TEST_SUBDIRECTORY(tutorials)
377376

377+
# Each subdirectory added above will register headers to be copied to the build tree.
378+
# Here, the copy targets are created:
379+
ROOT_CREATE_HEADER_COPY_TARGETS()
380+
378381
get_property(__allHeaders GLOBAL PROPERTY ROOT_HEADER_TARGETS)
379382
get_property(__allBuiltins GLOBAL PROPERTY ROOT_BUILTIN_TARGETS)
380383
add_custom_target(move_headers ALL DEPENDS ${__allHeaders} ${__allBuiltins} gitinfotxt)

builtins/nlohmann/CMakeLists.txt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,11 @@ string(REGEX REPLACE ".+NLOHMANN_JSON_VERSION_PATCH[ ]+([0-9]+).*$" "\\1" JSON_V
1111
set(nlohmann_json_VERSION "${JSON_VERSION_MAJOR}.${JSON_VERSION_MINOR}.${JSON_VERSION_PATCH}" PARENT_SCOPE)
1212
unset(JSON_H)
1313

14-
add_custom_command(
15-
OUTPUT ${CMAKE_BINARY_DIR}/include/nlohmann/json.hpp
16-
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/builtins/nlohmann/json.hpp ${CMAKE_BINARY_DIR}/include/nlohmann/json.hpp
17-
COMMENT "Copying nlohmann/json.hpp header to ${CMAKE_BINARY_DIR}/include"
14+
add_custom_target(builtin_nlohmann_json ALL
15+
BYPRODUCTS ${CMAKE_BINARY_DIR}/include/nlohmann/json.hpp
16+
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/builtins/nlohmann/json.hpp ${CMAKE_BINARY_DIR}/include/nlohmann/json.hpp
1817
DEPENDS ${CMAKE_SOURCE_DIR}/builtins/nlohmann/json.hpp)
19-
20-
add_custom_target(builtin_nlohmann_json_incl DEPENDS ${CMAKE_BINARY_DIR}/include/nlohmann/json.hpp)
21-
22-
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_TARGETS builtin_nlohmann_json_incl)
18+
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_TARGETS builtin_nlohmann_json)
2319

2420
install(FILES ${CMAKE_SOURCE_DIR}/builtins/nlohmann/json.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/nlohmann/)
2521

cmake/modules/RootMacros.cmake

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,7 +1217,9 @@ function(ROOT_FIND_DIRS_WITH_HEADERS result_dirs)
12171217
endfunction()
12181218

12191219
#---------------------------------------------------------------------------------------------------
1220-
#---ROOT_INSTALL_HEADERS([dir1 dir2 ...] OPTIONS [options])
1220+
#---ROOT_INSTALL_HEADERS([dir1 dir2 ...] [FILTER <regex>])
1221+
# Glob for headers in the folder where this target is defined, and install them in
1222+
# <buildDir>/include
12211223
#---------------------------------------------------------------------------------------------------
12221224
function(ROOT_INSTALL_HEADERS)
12231225
CMAKE_PARSE_ARGUMENTS(ARG "OPTIONS" "" "FILTER" ${ARGN})
@@ -1232,35 +1234,77 @@ function(ROOT_INSTALL_HEADERS)
12321234
set (options ${options} REGEX "${f}" EXCLUDE)
12331235
endforeach()
12341236
set (filter "(${filter})")
1237+
set(include_files "")
12351238
foreach(d ${dirs})
12361239
install(DIRECTORY ${d} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
12371240
COMPONENT headers
12381241
${options})
12391242
string(REGEX REPLACE "(.*)/$" "\\1" d ${d})
1240-
ROOT_GLOB_FILES(include_files
1243+
ROOT_GLOB_FILES(globbed_files
12411244
RECURSE
1242-
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/${d}
1245+
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
12431246
FILTER ${filter}
12441247
${d}/*.h ${d}/*.hxx ${d}/*.icc )
1245-
foreach (include_file ${include_files})
1246-
set (src ${CMAKE_CURRENT_SOURCE_DIR}/${d}/${include_file})
1247-
set (dst ${CMAKE_BINARY_DIR}/include/${include_file})
1248-
add_custom_command(
1249-
OUTPUT ${dst}
1250-
COMMAND ${CMAKE_COMMAND} -E copy ${src} ${dst}
1251-
COMMENT "Copying header ${src} to ${CMAKE_BINARY_DIR}/include"
1252-
DEPENDS ${src})
1253-
list(APPEND dst_list ${dst})
1254-
endforeach()
1248+
list(APPEND include_files ${globbed_files})
1249+
endforeach()
1250+
1251+
string(REPLACE ${CMAKE_SOURCE_DIR} "" target_name ${CMAKE_CURRENT_SOURCE_DIR})
1252+
string(REPLACE / _ target_name "copy_header_${target_name}")
1253+
string(REGEX REPLACE "_$" "" target_name ${target_name})
1254+
1255+
# Register the files to be copied for each target directory (e.g. include/ include/ROOT include/v7/inc/ ...)
1256+
list(REMOVE_DUPLICATES include_files)
1257+
list(TRANSFORM include_files REPLACE "(.*)/[^/]*" "\\1/" OUTPUT_VARIABLE subdirs)
1258+
list(REMOVE_DUPLICATES subdirs)
1259+
foreach(subdir ${subdirs})
1260+
set(input_files ${include_files})
1261+
list(FILTER input_files INCLUDE REGEX "^${subdir}[^/]*$")
1262+
set(output_files ${input_files})
1263+
1264+
string(REGEX REPLACE ".*/*inc/" "" destination ${subdir})
1265+
1266+
list(TRANSFORM input_files PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
1267+
list(TRANSFORM output_files REPLACE ".*/" "${CMAKE_BINARY_DIR}/include/${destination}")
1268+
1269+
set(destination destination_${destination})
1270+
1271+
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_COPY_LISTS ${destination})
1272+
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_INPUT_${destination} ${input_files})
1273+
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_OUTPUT_${destination} ${output_files})
12551274
endforeach()
1256-
if (dst_list)
1257-
string(REPLACE ${CMAKE_SOURCE_DIR} "" tgt ${CMAKE_CURRENT_SOURCE_DIR})
1258-
string(MAKE_C_IDENTIFIER move_header${tgt} tgt)
1259-
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_TARGETS ${tgt})
1260-
add_custom_target(${tgt} DEPENDS ${dst_list})
1261-
endif()
12621275
endfunction()
12631276

1277+
#---------------------------------------------------------------------------------------------------
1278+
#--- ROOT_CREATE_HEADER_COPY_TARGETS
1279+
# Creates a target to copy all headers that have been registered for copy in ROOT_INSTALL_HEADERS
1280+
#---------------------------------------------------------------------------------------------------
1281+
macro(ROOT_CREATE_HEADER_COPY_TARGETS)
1282+
get_property(HEADER_COPY_LISTS GLOBAL PROPERTY ROOT_HEADER_COPY_LISTS)
1283+
list(REMOVE_DUPLICATES HEADER_COPY_LISTS)
1284+
foreach(COPY_LIST ${HEADER_COPY_LISTS})
1285+
get_property(inputs GLOBAL PROPERTY ROOT_HEADER_INPUT_${COPY_LIST})
1286+
get_property(outputs GLOBAL PROPERTY ROOT_HEADER_OUTPUT_${COPY_LIST})
1287+
1288+
string(REPLACE "destination_" "${CMAKE_BINARY_DIR}/include/" destination ${COPY_LIST})
1289+
1290+
list(LENGTH inputs LIST_LENGTH)
1291+
# Windows doesn't support long command lines, so split them in packs:
1292+
foreach(RANGE_START RANGE 0 ${LIST_LENGTH} 100)
1293+
list(SUBLIST outputs ${RANGE_START} 100 sub_outputs)
1294+
list(SUBLIST inputs ${RANGE_START} 100 sub_inputs)
1295+
list(LENGTH sub_outputs SUB_LENGTH)
1296+
if(NOT SUB_LENGTH EQUAL 0)
1297+
add_custom_command(OUTPUT ${sub_outputs}
1298+
COMMAND ${CMAKE_COMMAND} -E copy ${sub_inputs} ${destination}
1299+
COMMENT "Copy headers for ${destination} ${RANGE_START}"
1300+
DEPENDS ${sub_inputs})
1301+
endif()
1302+
endforeach()
1303+
file(MAKE_DIRECTORY ${destination})
1304+
set_property(GLOBAL APPEND PROPERTY ROOT_HEADER_TARGETS ${outputs})
1305+
endforeach()
1306+
endmacro()
1307+
12641308
#---------------------------------------------------------------------------------------------------
12651309
#---ROOT_STANDARD_LIBRARY_PACKAGE(libname
12661310
# [NO_INSTALL_HEADERS] : don't install headers for this package

0 commit comments

Comments
 (0)