Skip to content

Commit a0ec74c

Browse files
authored
Centralize CPM logic. (#2495)
* Abstract and consolidate CPM calls. * Update CPM used in example projects.
1 parent bb001b7 commit a0ec74c

File tree

10 files changed

+2693
-1234
lines changed

10 files changed

+2693
-1234
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ if (CCCL_TOPLEVEL_PROJECT)
5353
include(cmake/CCCLBuildCompilerTargets.cmake)
5454
include(cmake/CCCLClangdCompileInfo.cmake)
5555
include(cmake/CCCLConfigureTarget.cmake)
56+
include(cmake/CCCLGetDependencies.cmake)
5657

5758
cccl_build_compiler_targets()
5859
endif()

cmake/CCCLGetDependencies.cmake

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
set(_cccl_cpm_file "${CMAKE_CURRENT_LIST_DIR}/CPM.cmake")
2+
3+
macro(cccl_get_boost)
4+
include("${_cccl_cpm_file}")
5+
CPMAddPackage("gh:boostorg/boost#boost-1.83.0")
6+
endmacro()
7+
8+
macro(cccl_get_catch2)
9+
include("${_cccl_cpm_file}")
10+
CPMAddPackage("gh:catchorg/[email protected]")
11+
endmacro()
12+
13+
macro(cccl_get_fmt)
14+
include("${_cccl_cpm_file}")
15+
CPMAddPackage("gh:fmtlib/fmt#11.0.1")
16+
endmacro()
17+
18+
macro(cccl_get_nvbench)
19+
include("${_cccl_cpm_file}")
20+
CPMAddPackage("gh:NVIDIA/nvbench#main")
21+
endmacro()
22+
23+
macro(cccl_get_nvtx)
24+
include("${_cccl_cpm_file}")
25+
CPMAddPackage(
26+
NAME NVTX
27+
GITHUB_REPOSITORY NVIDIA/NVTX
28+
GIT_TAG release-v3
29+
DOWNLOAD_ONLY
30+
SYSTEM
31+
)
32+
include("${NVTX_SOURCE_DIR}/c/nvtxImportedTargets.cmake")
33+
endmacro()

cub/cmake/CPM.cmake cmake/CPM.cmake

+134-17
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ if(NOT COMMAND cpm_message)
4242
endfunction()
4343
endif()
4444

45-
set(CURRENT_CPM_VERSION 0.38.5)
45+
set(CURRENT_CPM_VERSION 0.40.2)
4646

4747
get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
4848
if(CPM_DIRECTORY)
@@ -99,6 +99,12 @@ macro(cpm_set_policies)
9999
cmake_policy(SET CMP0135 NEW)
100100
set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
101101
endif()
102+
103+
# treat relative git repository paths as being relative to the parent project's remote
104+
if(POLICY CMP0150)
105+
cmake_policy(SET CMP0150 NEW)
106+
set(CMAKE_POLICY_DEFAULT_CMP0150 NEW)
107+
endif()
102108
endmacro()
103109
cpm_set_policies()
104110

@@ -294,12 +300,6 @@ function(CPMFindPackage)
294300
return()
295301
endif()
296302

297-
cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
298-
if(CPM_PACKAGE_ALREADY_ADDED)
299-
cpm_export_variables(${CPM_ARGS_NAME})
300-
return()
301-
endif()
302-
303303
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
304304

305305
if(NOT CPM_PACKAGE_FOUND)
@@ -391,8 +391,8 @@ function(cpm_parse_add_package_single_arg arg outArgs)
391391
# We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url
392392
# should do this at a later point
393393
else()
394-
# We should never get here. This is an assertion and hitting it means there's a bug in the code
395-
# above. A packageType was set, but not handled by this if-else.
394+
# We should never get here. This is an assertion and hitting it means there's a problem with the
395+
# code above. A packageType was set, but not handled by this if-else.
396396
message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'")
397397
endif()
398398

@@ -464,6 +464,72 @@ function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean)
464464

465465
endfunction()
466466

467+
# Add PATCH_COMMAND to CPM_ARGS_UNPARSED_ARGUMENTS. This method consumes a list of files in ARGN
468+
# then generates a `PATCH_COMMAND` appropriate for `ExternalProject_Add()`. This command is appended
469+
# to the parent scope's `CPM_ARGS_UNPARSED_ARGUMENTS`.
470+
function(cpm_add_patches)
471+
# Return if no patch files are supplied.
472+
if(NOT ARGN)
473+
return()
474+
endif()
475+
476+
# Find the patch program.
477+
find_program(PATCH_EXECUTABLE patch)
478+
if(WIN32 AND NOT PATCH_EXECUTABLE)
479+
# The Windows git executable is distributed with patch.exe. Find the path to the executable, if
480+
# it exists, then search `../usr/bin` and `../../usr/bin` for patch.exe.
481+
find_package(Git QUIET)
482+
if(GIT_EXECUTABLE)
483+
get_filename_component(extra_search_path ${GIT_EXECUTABLE} DIRECTORY)
484+
get_filename_component(extra_search_path_1up ${extra_search_path} DIRECTORY)
485+
get_filename_component(extra_search_path_2up ${extra_search_path_1up} DIRECTORY)
486+
find_program(
487+
PATCH_EXECUTABLE patch HINTS "${extra_search_path_1up}/usr/bin"
488+
"${extra_search_path_2up}/usr/bin"
489+
)
490+
endif()
491+
endif()
492+
if(NOT PATCH_EXECUTABLE)
493+
message(FATAL_ERROR "Couldn't find `patch` executable to use with PATCHES keyword.")
494+
endif()
495+
496+
# Create a temporary
497+
set(temp_list ${CPM_ARGS_UNPARSED_ARGUMENTS})
498+
499+
# Ensure each file exists (or error out) and add it to the list.
500+
set(first_item True)
501+
foreach(PATCH_FILE ${ARGN})
502+
# Make sure the patch file exists, if we can't find it, try again in the current directory.
503+
if(NOT EXISTS "${PATCH_FILE}")
504+
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}")
505+
message(FATAL_ERROR "Couldn't find patch file: '${PATCH_FILE}'")
506+
endif()
507+
set(PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}")
508+
endif()
509+
510+
# Convert to absolute path for use with patch file command.
511+
get_filename_component(PATCH_FILE "${PATCH_FILE}" ABSOLUTE)
512+
513+
# The first patch entry must be preceded by "PATCH_COMMAND" while the following items are
514+
# preceded by "&&".
515+
if(first_item)
516+
set(first_item False)
517+
list(APPEND temp_list "PATCH_COMMAND")
518+
else()
519+
list(APPEND temp_list "&&")
520+
endif()
521+
# Add the patch command to the list
522+
list(APPEND temp_list "${PATCH_EXECUTABLE}" "-p1" "<" "${PATCH_FILE}")
523+
endforeach()
524+
525+
# Move temp out into parent scope.
526+
set(CPM_ARGS_UNPARSED_ARGUMENTS
527+
${temp_list}
528+
PARENT_SCOPE
529+
)
530+
531+
endfunction()
532+
467533
# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload
468534
# FetchContent calls. As these are internal cmake properties, this method should be used carefully
469535
# and may need modification in future CMake versions. Source:
@@ -534,9 +600,10 @@ function(CPMAddPackage)
534600
GIT_SHALLOW
535601
EXCLUDE_FROM_ALL
536602
SOURCE_SUBDIR
603+
CUSTOM_CACHE_KEY
537604
)
538605

539-
set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND)
606+
set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND PATCHES)
540607

541608
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
542609

@@ -627,6 +694,7 @@ function(CPMAddPackage)
627694
SOURCE_DIR "${PACKAGE_SOURCE}"
628695
EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}"
629696
SYSTEM "${CPM_ARGS_SYSTEM}"
697+
PATCHES "${CPM_ARGS_PATCHES}"
630698
OPTIONS "${CPM_ARGS_OPTIONS}"
631699
SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}"
632700
DOWNLOAD_ONLY "${DOWNLOAD_ONLY}"
@@ -682,6 +750,8 @@ function(CPMAddPackage)
682750
set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps)
683751
endif()
684752

753+
cpm_add_patches(${CPM_ARGS_PATCHES})
754+
685755
if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND)
686756
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND})
687757
elseif(DEFINED CPM_ARGS_SOURCE_DIR)
@@ -704,7 +774,10 @@ function(CPMAddPackage)
704774
string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
705775
set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS})
706776
list(SORT origin_parameters)
707-
if(CPM_USE_NAMED_CACHE_DIRECTORIES)
777+
if(CPM_ARGS_CUSTOM_CACHE_KEY)
778+
# Application set a custom unique directory name
779+
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY})
780+
elseif(CPM_USE_NAMED_CACHE_DIRECTORIES)
708781
string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG")
709782
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME})
710783
else()
@@ -792,14 +865,38 @@ function(CPMAddPackage)
792865
)
793866

794867
if(NOT CPM_SKIP_FETCH)
868+
# CMake 3.28 added EXCLUDE, SYSTEM (3.25), and SOURCE_SUBDIR (3.18) to FetchContent_Declare.
869+
# Calling FetchContent_MakeAvailable will then internally forward these options to
870+
# add_subdirectory. Up until these changes, we had to call FetchContent_Populate and
871+
# add_subdirectory separately, which is no longer necessary and has been deprecated as of 3.30.
872+
set(fetchContentDeclareExtraArgs "")
873+
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.28.0")
874+
if(${CPM_ARGS_EXCLUDE_FROM_ALL})
875+
list(APPEND fetchContentDeclareExtraArgs EXCLUDE_FROM_ALL)
876+
endif()
877+
if(${CPM_ARGS_SYSTEM})
878+
list(APPEND fetchContentDeclareExtraArgs SYSTEM)
879+
endif()
880+
if(DEFINED CPM_ARGS_SOURCE_SUBDIR)
881+
list(APPEND fetchContentDeclareExtraArgs SOURCE_SUBDIR ${CPM_ARGS_SOURCE_SUBDIR})
882+
endif()
883+
# For CMake version <3.28 OPTIONS are parsed in cpm_add_subdirectory
884+
if(CPM_ARGS_OPTIONS AND NOT DOWNLOAD_ONLY)
885+
foreach(OPTION ${CPM_ARGS_OPTIONS})
886+
cpm_parse_option("${OPTION}")
887+
set(${OPTION_KEY} "${OPTION_VALUE}")
888+
endforeach()
889+
endif()
890+
endif()
795891
cpm_declare_fetch(
796-
"${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}" "${PACKAGE_INFO}" "${CPM_ARGS_UNPARSED_ARGUMENTS}"
892+
"${CPM_ARGS_NAME}" ${fetchContentDeclareExtraArgs} "${CPM_ARGS_UNPARSED_ARGUMENTS}"
797893
)
798-
cpm_fetch_package("${CPM_ARGS_NAME}" populated)
894+
895+
cpm_fetch_package("${CPM_ARGS_NAME}" ${DOWNLOAD_ONLY} populated ${CPM_ARGS_UNPARSED_ARGUMENTS})
799896
if(CPM_SOURCE_CACHE AND download_directory)
800897
file(LOCK ${download_directory}/../cmake.lock RELEASE)
801898
endif()
802-
if(${populated})
899+
if(${populated} AND ${CMAKE_VERSION} VERSION_LESS "3.28.0")
803900
cpm_add_subdirectory(
804901
"${CPM_ARGS_NAME}"
805902
"${DOWNLOAD_ONLY}"
@@ -910,7 +1007,7 @@ function(CPMGetPackageVersion PACKAGE OUTPUT)
9101007
endfunction()
9111008

9121009
# declares a package in FetchContent_Declare
913-
function(cpm_declare_fetch PACKAGE VERSION INFO)
1010+
function(cpm_declare_fetch PACKAGE)
9141011
if(${CPM_DRY_RUN})
9151012
cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)")
9161013
return()
@@ -986,7 +1083,7 @@ endfunction()
9861083

9871084
# downloads a previously declared package via FetchContent and exports the variables
9881085
# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope
989-
function(cpm_fetch_package PACKAGE populated)
1086+
function(cpm_fetch_package PACKAGE DOWNLOAD_ONLY populated)
9901087
set(${populated}
9911088
FALSE
9921089
PARENT_SCOPE
@@ -1001,7 +1098,24 @@ function(cpm_fetch_package PACKAGE populated)
10011098
string(TOLOWER "${PACKAGE}" lower_case_name)
10021099

10031100
if(NOT ${lower_case_name}_POPULATED)
1004-
FetchContent_Populate(${PACKAGE})
1101+
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.28.0")
1102+
if(DOWNLOAD_ONLY)
1103+
# MakeAvailable will call add_subdirectory internally which is not what we want when
1104+
# DOWNLOAD_ONLY is set. Populate will only download the dependency without adding it to the
1105+
# build
1106+
FetchContent_Populate(
1107+
${PACKAGE}
1108+
SOURCE_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-src"
1109+
BINARY_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build"
1110+
SUBBUILD_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild"
1111+
${ARGN}
1112+
)
1113+
else()
1114+
FetchContent_MakeAvailable(${PACKAGE})
1115+
endif()
1116+
else()
1117+
FetchContent_Populate(${PACKAGE})
1118+
endif()
10051119
set(${populated}
10061120
TRUE
10071121
PARENT_SCOPE
@@ -1095,12 +1209,15 @@ function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT)
10951209
DOWNLOAD_ONLY
10961210
GITHUB_REPOSITORY
10971211
GITLAB_REPOSITORY
1212+
BITBUCKET_REPOSITORY
10981213
GIT_REPOSITORY
10991214
SOURCE_DIR
11001215
FIND_PACKAGE_ARGUMENTS
11011216
NO_CACHE
11021217
SYSTEM
11031218
GIT_SHALLOW
1219+
EXCLUDE_FROM_ALL
1220+
SOURCE_SUBDIR
11041221
)
11051222
set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND)
11061223
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

cub/benchmarks/nvbench_helper/CMakeLists.txt

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Fetch nvbench
2-
CPMAddPackage("gh:NVIDIA/nvbench#main")
1+
cccl_get_catch2()
2+
cccl_get_nvbench()
33

44
add_library(nvbench_helper OBJECT nvbench_helper/nvbench_helper.cuh
55
nvbench_helper/nvbench_helper.cu)
@@ -13,13 +13,12 @@ target_link_libraries(nvbench_helper PUBLIC CUB::CUB
1313
target_include_directories(nvbench_helper PUBLIC "${CMAKE_CURRENT_LIST_DIR}/nvbench_helper")
1414
set_target_properties(nvbench_helper PROPERTIES CUDA_STANDARD 17 CXX_STANDARD 17)
1515

16-
CPMAddPackage("gh:catchorg/[email protected]")
1716

1817
option(CUB_ENABLE_NVBENCH_HELPER_TESTS "Enable tests for nvbench_helper" OFF)
1918
mark_as_advanced(CUB_ENABLE_NVBENCH_HELPER_TESTS)
2019

2120
if (CUB_ENABLE_NVBENCH_HELPER_TESTS)
22-
CPMAddPackage(NAME Boost VERSION 1.83.0 GITHUB_REPOSITORY "boostorg/boost" GIT_TAG "boost-1.83.0")
21+
cccl_get_boost()
2322

2423
function(add_nvbench_helper_test device_system)
2524
set(nvbench_helper_test_target nvbench_helper.test.${device_system})

cub/test/CMakeLists.txt

+2-11
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,8 @@ else()
1818
)
1919
endif()
2020

21-
include("${CUB_SOURCE_DIR}/cmake/CPM.cmake")
22-
CPMAddPackage("gh:catchorg/[email protected]")
23-
24-
CPMAddPackage(
25-
NAME NVTX
26-
GITHUB_REPOSITORY NVIDIA/NVTX
27-
GIT_TAG release-v3
28-
DOWNLOAD_ONLY
29-
SYSTEM
30-
)
31-
include("${NVTX_SOURCE_DIR}/c/nvtxImportedTargets.cmake")
21+
cccl_get_catch2()
22+
cccl_get_nvtx()
3223

3324
find_package(CUDAToolkit)
3425

0 commit comments

Comments
 (0)