[CCCL] Add missing CCCL components: c2h, nvbench_helper, cmake, cudax, AGENTS.md

Added 863 files from NVIDIA/cccl sparse checkout:
- c2h/ (27 files): Catch2 test helpers — generators, validators, runner
- nvbench_helper/ (10 files): Benchmark harness utilities
- cmake/ (29 files): CMake presets and build helpers
- cudax/ (794 files): Experimental CUDA extensions
- AGENTS.md: NVIDIA's official AI agent instructions for CCCL
- CMakePresets.json: Standardized build configurations
- cccl-version.json: Version tracking

Also added CCCL_ASSET_MAP.md mapping all 4295 CCCL files to
competition value and PRD items.

cccl_upstream now covers 100% of competition-critical assets:
- 27 tuning headers (SM80/90/100 benchmark data)
- 32 dispatch headers (algorithm implementations)
- 60 Thrust examples (correctness verification)
- 217 CUB Catch2 tests (regression matrix)
- 153 CUB benchmarks (parameter space search)
- 18 CUB examples (API verification)
- 27 test helpers + benchmark harness
- 794 cudax experimental extensions
This commit is contained in:
muh-bot
2026-08-06 02:14:18 +00:00
parent b0d597363a
commit dedf08166a
864 changed files with 174321 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
include_guard(GLOBAL)
include(CheckCXXCompilerFlag)
macro(append_option_if_available _FLAG _LIST)
string(MAKE_C_IDENTIFIER "CXX_FLAG_${_FLAG}" _VAR)
check_cxx_compiler_flag(${_FLAG} ${_VAR})
if (${${_VAR}})
list(APPEND ${_LIST} ${_FLAG})
endif()
endmacro()

View File

@@ -0,0 +1,53 @@
# Adds an executable target from SOURCES with standard CCCL configuration.
#
# By default, metatargets are created (e.g. target name foo.bar.baz will built by metatargets
# `foo` and `foo.bar`). This can be disabled with NO_METATARGETS. By default, the metatarget
# path is the same as the target name, but can be overridden with METATARGET_PATH
#
# If ADD_CTEST is specified, a CTest test is added with the same name as the target,
# which runs the executable with no arguments.
function(cccl_add_executable target_name)
set(options ADD_CTEST NO_METATARGETS NO_CLANG_TIDY)
set(oneValueArgs METATARGET_PATH DIALECT)
set(multiValueArgs SOURCES)
cmake_parse_arguments(
_cccl
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
if (_cccl_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unrecognized arguments: ${_cccl_UNPARSED_ARGUMENTS}")
endif()
if (NOT DEFINED _cccl_SOURCES)
message(FATAL_ERROR "cccl_add_executable requires SOURCES argument")
endif()
add_executable(${target_name} ${_cccl_SOURCES})
if (_cccl_DIALECT)
set(configure_args DIALECT "${_cccl_DIALECT}")
else()
set(configure_args)
endif()
cccl_configure_target(${target_name} ${configure_args})
if (_cccl_ADD_CTEST)
add_test(NAME ${target_name} COMMAND "$<TARGET_FILE:${target_name}>")
endif()
if (NOT _cccl_NO_METATARGETS)
set(metatarget_path ${target_name})
if (DEFINED _cccl_METATARGET_PATH)
set(metatarget_path ${_cccl_METATARGET_PATH})
endif()
cccl_ensure_metatargets(${target_name} METATARGET_PATH ${metatarget_path})
endif()
if (NOT _cccl_NO_CLANG_TIDY)
cccl_tidy_add_target(SOURCES ${_cccl_SOURCES})
endif()
endfunction()

View File

@@ -0,0 +1,6 @@
cccl_add_subdir_helper(
CCCL
# These component lists may be set by users to explicitly request subprojects:
REQUIRED_COMPONENTS "${CCCL_REQUIRED_COMPONENTS}"
OPTIONAL_COMPONENTS "${CCCL_OPTIONAL_COMPONENTS}"
)

View File

@@ -0,0 +1,75 @@
# project_name: The name of the project when calling `find_package`. Case sensitive.
# `PACKAGE_FILEBASE` the name of the project in the config files, ie. ${PACKAGE_FILEBASE}-config.cmake.
# `PACKAGE_PATH` the absolute path to the project's CMake package config files.
function(cccl_add_subdir_helper project_name)
set(options)
set(
oneValueArgs
PACKAGE_PATH
PACKAGE_FILEBASE
REQUIRED_COMPONENTS
OPTIONAL_COMPONENTS
)
set(multiValueArgs)
cmake_parse_arguments(
CCCL_SUBDIR
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
if (NOT DEFINED CCCL_SUBDIR_PACKAGE_FILEBASE)
string(TOLOWER "${project_name}" CCCL_SUBDIR_PACKAGE_FILEBASE)
endif()
if (NOT DEFINED CCCL_SUBDIR_PACKAGE_PATH)
set(
CCCL_SUBDIR_PACKAGE_PATH
"${CCCL_SOURCE_DIR}/lib/cmake/${CCCL_SUBDIR_PACKAGE_FILEBASE}"
)
endif()
set(
package_prefix
"${CCCL_SUBDIR_PACKAGE_PATH}/${CCCL_SUBDIR_PACKAGE_FILEBASE}"
)
set(CMAKE_FIND_PACKAGE_NAME ${project_name})
set(${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS)
if (DEFINED CCCL_SUBDIR_REQUIRED_COMPONENTS)
list(
APPEND ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS
${CCCL_SUBDIR_REQUIRED_COMPONENTS}
)
foreach (component IN LISTS CCCL_SUBDIR_REQUIRED_COMPONENTS)
set(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${component} TRUE)
endforeach()
endif()
if (DEFINED CCCL_SUBDIR_OPTIONAL_COMPONENTS)
list(
APPEND ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS
${CCCL_SUBDIR_OPTIONAL_COMPONENTS}
)
endif()
# This effectively does a `find_package` actually going through the find_package
# machinery. Using `find_package` works for the first configure, but creates
# inconsistencies during subsequent configurations when using CPM..
#
# More details are in the discussion at
# https://github.com/NVIDIA/libcudacxx/pull/242#discussion_r794003857
include("${package_prefix}-config-version.cmake")
include("${package_prefix}-config.cmake")
if (${project_name}_FOUND)
# Set the dir var so that later `find_package` calls work as expected.
set(
${project_name}_DIR
"${CCCL_SUBDIR_PACKAGE_PATH}"
CACHE PATH
"Path to ${project_name} package"
)
endif()
endfunction()

View File

@@ -0,0 +1,186 @@
include_guard(GLOBAL)
#[=======================================================================[.rst:
cccl_tidy_init
--------------
Initialize ``clang-tidy`` support and define the global ``cccl.tidy`` target. It must be
called before adding any CCCL ``clang-tidy`` targets.
Subsequent calls to this functions are no-ops.
Result Variables
^^^^^^^^^^^^^^^^
``CCCL_TIDY_INITIALIZED`` set to true in the parent scope.
#]=======================================================================]
function(cccl_tidy_init)
list(APPEND CMAKE_MESSAGE_CONTEXT "tidy_init")
if (CCCL_TIDY_INITIALIZED)
return()
endif()
find_program(CCCL_CLANG_TIDY clang-tidy REQUIRED)
execute_process(
COMMAND ${CCCL_CLANG_TIDY} --version
OUTPUT_VARIABLE version
ERROR_VARIABLE version
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY
)
message(STATUS "Found clang-tidy: ${CCCL_CLANG_TIDY} (${version})")
add_custom_target(cccl.tidy COMMENT "clang-tidy CCCL")
set(
CCCL_RUN_CLANG_TIDY_SCRIPT
"${CMAKE_CURRENT_BINARY_DIR}/run_clang_tidy.sh"
)
set(CCCL_RUN_CLANG_TIDY_SCRIPT "${CCCL_RUN_CLANG_TIDY_SCRIPT}" PARENT_SCOPE)
configure_file(
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/run_clang_tidy.sh.in"
"${CCCL_RUN_CLANG_TIDY_SCRIPT}"
@ONLY
)
# Do not set to cache; multiple separate instances of CCCL in a build should not
# conflict.
set(CCCL_TIDY_INITIALIZED TRUE)
set(CCCL_TIDY_INITIALIZED TRUE PARENT_SCOPE)
endfunction()
#[=======================================================================[.rst:
cccl_tidy_make_subproject_target
--------------------------------
Create a meta target per sub-project that depends on all the targets for that
subproject. It itself will depend on the ``cccl.tidy target``. For example, this will
create:
- cub.tidy
- libcudacxx.tidy
- thrust.tidy
etc. This allows running clang-tidy over just a subset of the repository.
The generated target name depends on the current value of ``PROJECT_NAME``.
Arguments
^^^^^^^^^
``result_var``
The variable in which to store the created target name.
#]=======================================================================]
function(cccl_tidy_make_subproject_target result_var)
list(APPEND CMAKE_MESSAGE_CONTEXT "tidy_make_subproject_target")
if (NOT CCCL_TIDY_INITIALIZED)
# For the cccl.tidy target
message(FATAL_ERROR "Must call cccl_tidy_init() first")
endif()
string(TOLOWER "${PROJECT_NAME}.tidy" target_name)
if (NOT TARGET "${target_name}")
add_custom_target("${target_name}" COMMENT "clang-tidy ${PROJECT_NAME}")
add_dependencies(cccl.tidy "${target_name}")
endif()
set(${result_var} "${target_name}" PARENT_SCOPE)
endfunction()
#[=======================================================================[.rst:
cccl_tidy_add_target
--------------------
Create per-source ``clang-tidy`` targets and attach them to both the global ``cccl.tidy``
target and per sub-project target (e.g. ``cub.tidy``)
.. note::
:command:`cccl_tidy_init` must be called before using this function to establish the
global ``cccl.tidy`` target.
If ``CCCL_ENABLE_CLANG_TIDY`` is false, this does nothing (except error-check the function
call signature).
Passing the same source file multiple times is allowed. A target is created for it only
once.
If ``SOURCES`` is empty, this function does nothing.
Arguments
^^^^^^^^^
``SOURCES``
List of source files to analyze. Paths may be absolute or relative. Relative paths are
resolved against ``CMAKE_CURRENT_SOURCE_DIR``.
#]=======================================================================]
function(cccl_tidy_add_target)
list(APPEND CMAKE_MESSAGE_CONTEXT "tidy_add_target")
set(options)
set(one_value_args)
set(multi_value_args SOURCES)
cmake_parse_arguments(
_cccl
"${options}"
"${one_value_args}"
"${multi_value_args}"
${ARGN}
)
if (_cccl_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unrecognized arguments: ${_cccl_UNPARSED_ARGUMENTS}")
endif()
# It is still possible to call this function even if clang-tidy has not been
# disabled. We handle this gracefully to avoid complicating the callsite.
#
# This must come before the CCCL_TIDY_INITIALIZED check because that is only called when
# CCCL_ENABLE_CLANG_TIDY is true.
if (NOT CCCL_ENABLE_CLANG_TIDY)
return()
endif()
if (NOT CCCL_TIDY_INITIALIZED)
message(FATAL_ERROR "Must call cccl_tidy_init() first")
endif()
cccl_tidy_make_subproject_target(subproject_target)
foreach (src IN LISTS _cccl_SOURCES)
cmake_path(SET src NORMALIZE "${src}")
if (NOT IS_ABSOLUTE "${src}")
cmake_path(SET src NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/${src}")
endif()
cmake_path(
RELATIVE_PATH src
BASE_DIRECTORY "${CCCL_SOURCE_DIR}"
OUTPUT_VARIABLE rel_src
)
string(MAKE_C_IDENTIFIER "${rel_src}" tidy_target)
set(tidy_target "${tidy_target}.tidy")
if (TARGET "${tidy_target}")
# We have seen this file before
continue()
endif()
add_custom_target(
"${tidy_target}"
DEPENDS "${src}" "${CCCL_RUN_CLANG_TIDY_SCRIPT}"
COMMAND ${CCCL_RUN_CLANG_TIDY_SCRIPT} "${src}"
COMMENT "clang-tidy ${rel_src}"
)
add_dependencies("${subproject_target}" "${tidy_target}")
endforeach()
endfunction()

View File

@@ -0,0 +1,262 @@
# This file defines the `cccl_build_compiler_targets()` function, which
# creates the following interface targets:
#
# cccl.compiler_interface
# - Interface target providing compiler-specific options needed to build
# CCCL's tests, examples, etc. for the current CMAKE_CUDA_STANDARD.
# This includes warning flags and the like.
# sccache cannot handle the -Fd option generating pdb files
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
option(CCCL_ENABLE_EXCEPTIONS "Enable exceptions within CCCL libraries." ON)
option(CCCL_ENABLE_RTTI "Enable RTTI within CCCL libraries." ON)
option(CCCL_ENABLE_WERROR "Treat warnings as errors for CCCL targets." ON)
option(
CCCL_ENABLE_PRAGMA_SYSTEM_HEADER
"When OFF, disables the system header pragma in CCCL headers so that their warnings are visible."
OFF
)
option(CCCL_ENABLE_PTXAS_WARNINGS "Enable ptxas warnings" OFF) # currently used only in CUB
function(
cccl_build_compiler_interface
interface_target
cuda_compile_options
cxx_compile_options
compile_defs
)
# We test to see if C++ compiler options exist using try-compiles in the CXX lang, and then reuse those flags as
# -Xcompiler flags for CUDA targets. This requires that the CXX compiler and CUDA_HOST compilers are the same when
# using nvcc.
if (CCCL_TOPLEVEL_PROJECT AND CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
set(cuda_host_matches_cxx_compiler FALSE)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.31)
set(
host_info
"${CMAKE_CUDA_HOST_COMPILER} (${CMAKE_CUDA_HOST_COMPILER_ID} ${CMAKE_CUDA_HOST_COMPILER_VERSION})"
)
set(
cxx_info
"${CMAKE_CXX_COMPILER} (${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION})"
)
if (
CMAKE_CUDA_HOST_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID
AND
CMAKE_CUDA_HOST_COMPILER_VERSION
VERSION_EQUAL
CMAKE_CXX_COMPILER_VERSION
)
set(cuda_host_matches_cxx_compiler TRUE)
endif()
else() # CMake < 3.31 doesn't have the CMAKE_CUDA_HOST_COMPILER_ID/VERSION variables
set(host_info "${CMAKE_CUDA_HOST_COMPILER}")
set(cxx_info "${CMAKE_CXX_COMPILER}")
if (CMAKE_CUDA_HOST_COMPILER STREQUAL CMAKE_CXX_COMPILER)
set(cuda_host_matches_cxx_compiler TRUE)
endif()
endif()
if (NOT cuda_host_matches_cxx_compiler)
message(
FATAL_ERROR
"CCCL developer builds require that CMAKE_CUDA_HOST_COMPILER matches "
"CMAKE_CXX_COMPILER when using nvcc:\n"
"CMAKE_CUDA_COMPILER: ${CMAKE_CUDA_COMPILER}\n"
"CMAKE_CUDA_HOST_COMPILER: ${host_info}\n"
"CMAKE_CXX_COMPILER: ${cxx_info}\n"
"Rerun cmake with \"-DCMAKE_CUDA_HOST_COMPILER=${CMAKE_CXX_COMPILER}\".\n"
"Alternatively, configure the CUDAHOSTCXX and CXX environment variables to match.\n"
)
endif()
endif()
add_library(${interface_target} INTERFACE)
foreach (cuda_option IN LISTS cuda_compile_options)
target_compile_options(
${interface_target}
INTERFACE $<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:${cuda_option}>
)
endforeach()
foreach (cxx_option IN LISTS cxx_compile_options)
target_compile_options(
${interface_target}
INTERFACE
$<$<COMPILE_LANGUAGE:CXX>:${cxx_option}>
$<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:-Xcompiler=${cxx_option}>
)
endforeach()
target_compile_definitions(${interface_target} INTERFACE ${compile_defs})
endfunction()
function(cccl_build_compiler_targets)
set(cuda_compile_options)
set(cxx_compile_options)
set(cxx_compile_definitions)
list(APPEND cuda_compile_options "-Xcudafe=--display_error_number")
list(APPEND cuda_compile_options "-Wno-deprecated-gpu-targets")
if (CCCL_ENABLE_WERROR)
list(APPEND cuda_compile_options "-Xcudafe=--promote_warnings")
endif()
if (CCCL_ENABLE_TILE)
list(APPEND cuda_compile_options "--enable-tile")
endif()
if (NOT CCCL_ENABLE_PRAGMA_SYSTEM_HEADER)
# Ensure that we build our tests without treating ourself as system header
list(APPEND cxx_compile_definitions "_CCCL_NO_SYSTEM_HEADER")
endif()
if (NOT CCCL_ENABLE_EXCEPTIONS)
list(APPEND cxx_compile_definitions "CCCL_DISABLE_EXCEPTIONS")
endif()
if (NOT CCCL_ENABLE_RTTI)
list(APPEND cxx_compile_definitions "CCCL_DISABLE_RTTI")
endif()
# if (CCCL_USE_LIBCXX)
# list(APPEND cxx_compile_options "-stdlib=libc++")
# list(APPEND cxx_compile_definitions "_ALLOW_UNSUPPORTED_LIBCPP=1")
# endif()
if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}")
list(APPEND cuda_compile_options "--use-local-env")
list(APPEND cxx_compile_options "/bigobj")
list(APPEND cxx_compile_definitions "_ENABLE_EXTENDED_ALIGNED_STORAGE")
list(APPEND cxx_compile_definitions "NOMINMAX")
append_option_if_available("/W4" cxx_compile_options)
# Treat all warnings as errors. This is only supported on Release builds,
# as `nv_exec_check_disable` doesn't seem to work with MSVC debug iterators
# and spurious warnings are emitted.
# See NVIDIA/thrust#1273, NVBug 3129879.
if (CCCL_ENABLE_WERROR)
if (CMAKE_BUILD_TYPE STREQUAL "Release")
append_option_if_available("/WX" cxx_compile_options)
endif()
endif()
# Suppress overly-pedantic/unavoidable warnings brought in with /W4:
# C4324: structure was padded due to alignment specifier
append_option_if_available("/wd4324" cxx_compile_options)
# C4505: unreferenced local function has been removed
# The CUDA `host_runtime.h` header emits this for
# `__cudaUnregisterBinaryUtil`.
append_option_if_available("/wd4505" cxx_compile_options)
# C4706: assignment within conditional expression
# MSVC doesn't provide an opt-out for this warning when the assignment is
# intentional. Clang will warn for these, but suppresses the warning when
# double-parentheses are used around the assignment. We'll let Clang catch
# unintentional assignments and suppress all such warnings on MSVC.
append_option_if_available("/wd4706" cxx_compile_options)
# MSVC STL assumes that `allocator_traits`'s allocator will use raw pointers,
# and the `__DECLSPEC_ALLOCATOR` macro causes issues with thrust's universal
# allocators:
# warning C4494: 'std::allocator_traits<_Alloc>::allocate' :
# Ignoring __declspec(allocator) because the function return type is not
# a pointer or reference
# See https://github.com/microsoft/STL/issues/696
append_option_if_available("/wd4494" cxx_compile_options)
# Get error messages with a little arrow indicating the error location more exactly
append_option_if_available("/diagnostics:caret" cxx_compile_options)
if (MSVC_TOOLSET_VERSION LESS 143)
# winbase.h(9572): warning C5105: macro expansion producing 'defined' has undefined behavior
append_option_if_available("/wd5105" cxx_compile_options)
endif()
else()
list(APPEND cuda_compile_options "-Wreorder")
if (CCCL_ENABLE_WERROR)
append_option_if_available("-Werror" cxx_compile_options)
endif()
append_option_if_available("-Wall" cxx_compile_options)
append_option_if_available("-Wextra" cxx_compile_options)
append_option_if_available("-Wreorder" cxx_compile_options)
append_option_if_available("-Winit-self" cxx_compile_options)
append_option_if_available("-Woverloaded-virtual" cxx_compile_options)
append_option_if_available("-Wcast-qual" cxx_compile_options)
append_option_if_available("-Wpointer-arith" cxx_compile_options)
append_option_if_available("-Wunused-local-typedefs" cxx_compile_options)
append_option_if_available("-Wvla" cxx_compile_options)
# Clang-only
append_option_if_available("-Wnvcc-compat" cxx_compile_options)
append_option_if_available("-Wimplicit-fallthrough" cxx_compile_options)
append_option_if_available(
"-fdiagnostics-show-template-tree"
cxx_compile_options
)
append_option_if_available("-Wignored-qualifiers" cxx_compile_options)
append_option_if_available(
"-Wmissing-field-initializers"
cxx_compile_options
)
# Inundated with error: ISO C++11 requires at least one argument for the "..." in a
# variadic macro for _CCCL_REQUIRES_EXPR(), so cannot enable this.
#
# append_option_if_available("-pedantic" cxx_compile_options)
append_option_if_available("-Wsign-compare" cxx_compile_options)
append_option_if_available(
"-Warray-bounds-pointer-arithmetic"
cxx_compile_options
)
append_option_if_available("-Wassign-enum" cxx_compile_options)
append_option_if_available("-Wformat-pedantic" cxx_compile_options)
append_option_if_available("-Walloc-size" cxx_compile_options)
append_option_if_available("-Walloc-zero" cxx_compile_options)
append_option_if_available("-Wtsan" cxx_compile_options)
append_option_if_available("-Wenum-conversion" cxx_compile_options)
append_option_if_available("-Wpacked" cxx_compile_options)
# Clang and GCC
append_option_if_available(
"-ftemplate-backtrace-limit=0"
cxx_compile_options
)
append_option_if_available("-fmacro-backtrace-limit=0" cxx_compile_options)
# Disable GNU extensions (flag is clang only)
append_option_if_available("-Wgnu" cxx_compile_options)
append_option_if_available("-Wno-gnu-line-marker" cxx_compile_options) # WAR 3916341
# Calling a variadic macro with zero args is a GNU extension until C++20,
# but the THRUST_PP_ARITY macro is used with zero args. Need to see if this
# is a real problem worth fixing.
append_option_if_available(
"-Wno-gnu-zero-variadic-macro-arguments"
cxx_compile_options
)
# This complains about functions in CUDA system headers when used with nvcc.
append_option_if_available("-Wno-unused-function" cxx_compile_options)
endif()
if ("GNU" STREQUAL "${CMAKE_CXX_COMPILER_ID}")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.3)
# GCC 7.3 complains about name mangling changes due to `noexcept`
# becoming part of the type system; we don't care.
append_option_if_available("-Wno-noexcept-type" cxx_compile_options)
endif()
endif()
cccl_build_compiler_interface(
cccl.compiler_interface
"${cuda_compile_options}"
"${cxx_compile_options}"
"${cxx_compile_definitions}"
)
# Clang-cuda only:
target_compile_options(
cccl.compiler_interface
INTERFACE
$<$<COMPILE_LANG_AND_ID:CUDA,Clang>:-Xclang=-fcuda-allow-variadic-functions>
$<$<COMPILE_LANG_AND_ID:CUDA,Clang>:-Wno-unknown-cuda-version>
)
endfunction()

View File

@@ -0,0 +1,122 @@
# This file provides utilities to handle special CMAKE_CUDA_ARCHITECTURES lists for CCCL.
#
# If CMAKE_CUDA_ARCHITECTURES is set to one of the following values, it will be replaced
# as described:
#
# 'all-cccl': All architectures known to the current NVCC above minimum_cccl_arch.
#
# 'all-major-cccl': All major architectures known to the current NVCC above minimum_cccl_arch,
# plus 'minimum_cccl_arch'.
#
# For example on 12.9:
# all: 50-real;52-real;53-real;60-real;61-real;62-real;70-real;72-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;103-real;120-real;121-real;121-virtual
# all-cccl: 75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;103-real;120-real;121-real;121-virtual
# all-major: 50-real;60-real;70-real;80-real;90-real;100-real;120-real;120-virtual
# all-major-cccl: 75-real;80-real;90-real;100-real;120-real;120-virtual
# We don't support arches below what the latest CTK release supports:
set(minimum_cccl_arch 75) # 13.x dropped below Turing
# Check CMAKE_CUDA_ARCHITECTURES for special CCCL values and update as described above.
function(cccl_check_cuda_architectures)
if (CMAKE_CUDA_ARCHITECTURES MATCHES "-cccl$")
message(
STATUS
"Detected special CCCL arch request: CMAKE_CUDA_ARCHITECTURES=${CMAKE_CUDA_ARCHITECTURES}"
)
_cccl_detect_nvcc_arch_support(arches)
_cccl_filter_to_supported_arches(arches)
if (CMAKE_CUDA_ARCHITECTURES STREQUAL "all-major-cccl")
_cccl_filter_to_all_major_cccl(arches)
elseif (CMAKE_CUDA_ARCHITECTURES STREQUAL "all-cccl")
# No further filtering needed, just use the arches as is.
else()
message(
FATAL_ERROR
"Invalid CMAKE_CUDA_ARCHITECTURES value: ${CMAKE_CUDA_ARCHITECTURES}"
)
endif()
_cccl_add_real_virtual_arch_tags(arches)
message(STATUS "Replacing with CMAKE_CUDA_ARCHITECTURES=${arches}")
set(
CMAKE_CUDA_ARCHITECTURES
"${arches}"
CACHE STRING
"CUDA architectures for CCCL"
FORCE
)
endif()
endfunction()
# Query nvcc --help to determine which architectures are supported.
function(_cccl_detect_nvcc_arch_support arches_var)
# cccl_get_cudatoolkit() is intentionally not used here.
find_package(CUDAToolkit)
if (NOT CUDAToolkit_FOUND)
message(
FATAL_ERROR
"CUDAToolkit not found, '${CMAKE_CUDA_ARCHITECTURES}' arch detection failed."
)
endif()
execute_process(
COMMAND "${CUDAToolkit_NVCC_EXECUTABLE}" --help
OUTPUT_VARIABLE nvcc_help_output
COMMAND_ERROR_IS_FATAL ANY
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX MATCHALL "compute_[0-9]+" supported_arches "${nvcc_help_output}")
string(REPLACE "compute_" "" supported_arches "${supported_arches}")
list(SORT supported_arches COMPARE NATURAL)
list(REMOVE_DUPLICATES supported_arches)
message(VERBOSE "NVCC supports: ${supported_arches}")
set(${arches_var} ${supported_arches} PARENT_SCOPE)
endfunction()
# Remove all arches < minimum_cccl_arch
function(_cccl_filter_to_supported_arches arches_var)
set(cccl_arches "")
foreach (arch IN LISTS ${arches_var})
if (arch GREATER_EQUAL minimum_cccl_arch)
list(APPEND cccl_arches ${arch})
endif()
endforeach()
message(VERBOSE "CCCL supported arches: ${cccl_arches}")
set(${arches_var} ${cccl_arches} PARENT_SCOPE)
endfunction()
# Convert all-cccl to all-major-cccl.
function(_cccl_filter_to_all_major_cccl arches_var)
set(major_arches "")
foreach (arch IN LISTS ${arches_var})
math(EXPR major "(${arch} / 10) * 10")
if (major LESS minimum_cccl_arch)
set(major "${minimum_cccl_arch}")
endif()
if (NOT major IN_LIST major_arches)
list(APPEND major_arches ${major})
endif()
endforeach()
message(VERBOSE "CCCL all-major arches: ${major_arches}")
set(${arches_var} ${major_arches} PARENT_SCOPE)
endfunction()
function(_cccl_add_real_virtual_arch_tags arches_var)
set(tagged_arches "")
list(POP_BACK ${arches_var} last_arch)
foreach (arch IN LISTS ${arches_var})
list(APPEND tagged_arches "${arch}-real")
endforeach()
list(APPEND tagged_arches "${last_arch}-real")
list(APPEND tagged_arches "${last_arch}-virtual")
message(VERBOSE "CCCL tagged arches: ${tagged_arches}")
set(${arches_var} ${tagged_arches} PARENT_SCOPE)
endfunction()

View File

@@ -0,0 +1,39 @@
# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Tell cmake to generate a json file of compile commands for clangd:
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Symlink the compile command output to the source dir, where clangd will find it.
set(compile_commands_file "${CMAKE_BINARY_DIR}/compile_commands.json")
set(compile_commands_link "${CMAKE_SOURCE_DIR}/compile_commands.json")
message(
STATUS
"Creating symlink from ${compile_commands_link} to ${compile_commands_file}..."
)
cccl_execute_non_fatal_process(
COMMAND "${CMAKE_COMMAND}" -E rm -f "${compile_commands_link}"
)
cccl_execute_non_fatal_process(
COMMAND "${CMAKE_COMMAND}" -E touch "${compile_commands_file}"
)
# gersemi: off
cccl_execute_non_fatal_process(
COMMAND
"${CMAKE_COMMAND}" -E create_symlink
"${compile_commands_file}"
"${compile_commands_link}"
)
# gersemi: on

View File

@@ -0,0 +1,66 @@
set(CCCL_EXECUTABLE_OUTPUT_DIR "${CCCL_BINARY_DIR}/bin")
set(CCCL_LIBRARY_OUTPUT_DIR "${CCCL_BINARY_DIR}/lib")
# Setup common properties for all test/example/etc targets.
function(cccl_configure_target target_name)
set(options)
set(oneValueArgs DIALECT)
set(multiValueArgs)
cmake_parse_arguments(
CCT
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
get_target_property(type ${target_name} TYPE)
set_target_properties(
${target_name}
PROPERTIES
# Disable compiler extensions:
CXX_EXTENSIONS OFF
CUDA_EXTENSIONS OFF
)
if (DEFINED CCT_DIALECT)
set(CMAKE_CXX_STANDARD ${CCT_DIALECT})
set(CMAKE_CUDA_STANDARD ${CCT_DIALECT})
endif()
set_target_properties(
${target_name}
PROPERTIES
CXX_STANDARD ${CMAKE_CXX_STANDARD}
CUDA_STANDARD ${CMAKE_CUDA_STANDARD}
CXX_STANDARD_REQUIRED ON
CUDA_STANDARD_REQUIRED ON
)
get_property(langs GLOBAL PROPERTY ENABLED_LANGUAGES)
set(dialect_features)
if (CUDA IN_LIST langs)
list(APPEND dialect_features cuda_std_${CMAKE_CUDA_STANDARD})
endif()
if (CXX IN_LIST langs)
list(APPEND dialect_features cxx_std_${CMAKE_CXX_STANDARD})
endif()
get_target_property(type ${target_name} TYPE)
if (${type} STREQUAL "INTERFACE_LIBRARY")
target_compile_features(${target_name} INTERFACE ${dialect_features})
else()
target_compile_features(${target_name} PUBLIC ${dialect_features})
endif()
if (NOT ${type} STREQUAL "INTERFACE_LIBRARY")
set_target_properties(
${target_name}
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CCCL_LIBRARY_OUTPUT_DIR}"
LIBRARY_OUTPUT_DIRECTORY "${CCCL_LIBRARY_OUTPUT_DIR}"
RUNTIME_OUTPUT_DIRECTORY "${CCCL_EXECUTABLE_OUTPUT_DIR}"
)
endif()
endfunction()

View File

@@ -0,0 +1,36 @@
# This file contains checks that ensure a supported build configuration is provided for CCCL.
# These checks are only enforced when building CCCL tests, examples, etc. and are not required
# for users of CCCL.
# The default CXX/CUDA standard to use if none is specified:
set(_cccl_default_dialect 17)
function(cccl_dev_build_checks)
# Similarly, we expect the CXX and CUDA standards to match, if either is set:
if (CMAKE_CXX_STANDARD OR CMAKE_CUDA_STANDARD)
if (NOT CMAKE_CXX_STANDARD EQUAL CMAKE_CUDA_STANDARD)
message(
FATAL_ERROR
"CCCL developer builds require that CMAKE_CXX_STANDARD matches "
"CMAKE_CUDA_STANDARD when either is set:\n"
"CMAKE_CXX_STANDARD: ${CMAKE_CXX_STANDARD}\n"
"CMAKE_CUDA_STANDARD: ${CMAKE_CUDA_STANDARD}\n"
"Rerun cmake with:\n"
"\t\"-DCMAKE_CUDA_STANDARD=<std> -DCMAKE_CXX_STANDARD=<std>\"."
)
endif()
else()
# Neither is set; initialize to a default of 20.
message(
VERBOSE
"Setting CMAKE_CXX_STANDARD and CMAKE_CUDA_STANDARD to CCCL default of ${_cccl_default_dialect}."
)
set(CMAKE_CXX_STANDARD ${_cccl_default_dialect})
set(CMAKE_CUDA_STANDARD ${_cccl_default_dialect})
set(CMAKE_CXX_STANDARD ${CMAKE_CXX_STANDARD} PARENT_SCOPE)
set(CMAKE_CUDA_STANDARD ${CMAKE_CUDA_STANDARD} PARENT_SCOPE)
endif()
message(STATUS "CMAKE_CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
message(STATUS "CMAKE_CUDA_STANDARD: ${CMAKE_CUDA_STANDARD}")
endfunction()

View File

@@ -0,0 +1,52 @@
# Adds "metatargets" using the target_name or METATARGET_PATH.
#
# A metatarget is a custom target that depends on its children targets. For example,
# a target named foo.bar.baz would create metatargets foo and foo.bar, where
# foo depends on foo.bar, and foo.bar depends on foo.bar.baz.
# This allows, for instance, `ninja cudax` to build all cudax.* targets, and `ninja cudax.test`
# to build all cudax.test.* targets.
function(cccl_ensure_metatargets target_name)
set(options)
set(oneValueArgs METATARGET_PATH)
set(multiValueArgs)
cmake_parse_arguments(
_cccl
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
if (_cccl_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unrecognized arguments: ${_cccl_UNPARSED_ARGUMENTS}")
endif()
if (NOT DEFINED _cccl_METATARGET_PATH)
set(_cccl_METATARGET_PATH ${target_name})
endif()
set(parent_path "")
set(current_path "")
string(REPLACE "." ";" path_parts "${_cccl_METATARGET_PATH}")
foreach (part IN LISTS path_parts)
if (current_path STREQUAL "")
set(current_path "${part}")
else()
set(current_path "${current_path}.${part}")
endif()
if (NOT TARGET ${current_path})
add_custom_target(${current_path})
endif()
if (NOT parent_path STREQUAL "")
add_dependencies(${parent_path} ${current_path})
endif()
set(parent_path ${current_path})
endforeach()
if (NOT target_name STREQUAL current_path)
add_dependencies(${current_path} ${target_name})
endif()
endfunction()

View File

@@ -0,0 +1,242 @@
# Usage:
# cccl_generate_header_tests(<target_name> <project_include_path>
# [cccl_configure_target options]
# [LANGUAGE <CXX|CUDA>]
# [HEADER_TEMPLATE <template>]
# [GLOBS <glob1> [glob2 ...]]
# [EXCLUDES <glob1> [glob2 ...]]
# [HEADERS <header1> [header2 ...]]
# [PER_HEADER_DEFINES
# DEFINE <definition> <regex> [<regex> ...]
# [DEFINE <definition> <regex> [<regex> ...]] ...]
# )
#
# Options:
# target_name: The name of the meta-target that will build this set of header tests.
# project_include_path: The path to the project's include directory, relative to <CCCL_SOURCE_DIR>.
# cccl_configure_target options: Options to pass to cccl_configure_target. Must appear before any other named arguments.
# LANGUAGE: The language to use for the header tests. Defaults to CUDA.
# HEADER_TEMPLATE: A file that will be used as a template for each header test. The template will be configured for each header.
# GLOBS: All files that match these globbing patterns will be included in the header tests, unless they also match EXCLUDES.
# EXCLUDES: Files that match these globbing patterns will be excluded from the header tests.
# HEADERS: An explicit list of headers to include in the header tests.
# PER_HEADER_DEFINES: A list of definitions to add to specific headers. Each definition is followed by one or more regexes that match the headers it should be applied to.
# NO_METATARGETS: If specified, metatargets will not be created for the header test targets.
#
# Notes:
# - The header globs are applied relative to <project_include_path>.
# - If no HEADER_TEMPLATE is provided, a default template will be used.
# - The HEADER_TEMPLATE will be configured for each header, with the following variables:
# - @header@: The path to the target header, relative to <project_include_path>.
option(
CCCL_COMPILE_TIME_SAVE_PREPROCESSED_TUS
"Save preprocessed generated one-include CUDA TUs for compile-time benchmarks."
OFF
)
option(
CCCL_COMPILE_TIME_GENERATE_DEVICE_TIME_TRACES
"Emit NVCC device time traces for compile-time benchmarks."
OFF
)
mark_as_advanced(
CCCL_COMPILE_TIME_SAVE_PREPROCESSED_TUS
CCCL_COMPILE_TIME_GENERATE_DEVICE_TIME_TRACES
)
function(cccl_generate_header_tests target_name project_include_path)
set(options NO_METATARGETS)
set(oneValueArgs LANGUAGE HEADER_TEMPLATE)
set(multiValueArgs GLOBS EXCLUDES HEADERS PER_HEADER_DEFINES)
cmake_parse_arguments(
CGHT
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
if (CGHT_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unrecognized arguments: ${CGHT_UNPARSED_ARGUMENTS}")
endif()
# Setup defaults
if (NOT DEFINED CGHT_LANGUAGE)
set(CGHT_LANGUAGE CUDA)
endif()
if (NOT DEFINED CGHT_HEADER_TEMPLATE)
set(CGHT_HEADER_TEMPLATE "${CCCL_SOURCE_DIR}/cmake/header_test.cu.in")
endif()
# Derived vars:
if (${CGHT_LANGUAGE} STREQUAL "C")
set(extension "c")
elseif (${CGHT_LANGUAGE} STREQUAL "CXX")
set(extension "cpp")
elseif (${CGHT_LANGUAGE} STREQUAL "CUDA")
set(extension "cu")
else()
message(FATAL_ERROR "Unsupported language: ${CGHT_LANGUAGE}")
endif()
set(cccl_configure_target_options ${CGHT_UNPARSED_ARGUMENTS})
set(base_path "${CCCL_SOURCE_DIR}/${project_include_path}")
# Prepend the basepath to all globbing expressions:
if (DEFINED CGHT_GLOBS)
set(globs)
foreach (glob IN LISTS CGHT_GLOBS)
list(APPEND globs "${base_path}/${glob}")
endforeach()
set(CGHT_GLOBS ${globs})
endif()
if (DEFINED CGHT_EXCLUDES)
set(excludes)
foreach (exclude IN LISTS CGHT_EXCLUDES)
list(APPEND excludes "${base_path}/${exclude}")
endforeach()
set(CGHT_EXCLUDES ${excludes})
endif()
# Determine header list
set(headers)
# Add globs:
if (DEFINED CGHT_GLOBS)
file(
GLOB_RECURSE headers
RELATIVE "${base_path}"
CONFIGURE_DEPENDS
${CGHT_GLOBS}
)
endif()
# Remove excludes:
if (DEFINED CGHT_EXCLUDES)
file(
GLOB_RECURSE header_excludes
RELATIVE "${base_path}"
CONFIGURE_DEPENDS
${CGHT_EXCLUDES}
)
list(REMOVE_ITEM headers ${header_excludes})
endif()
# Add explicit headers:
if (DEFINED CGHT_HEADERS)
list(APPEND headers ${CGHT_HEADERS})
endif()
# Cleanup:
list(REMOVE_DUPLICATES headers)
# Helper function for applying per-header defines:
# header: The original header filepath
# src: The generated source file for the header test
function(cght_apply_per_header_defines header src)
if (NOT DEFINED CGHT_PER_HEADER_DEFINES)
return()
endif()
set(current_definition)
foreach (item IN LISTS CGHT_PER_HEADER_DEFINES)
if (item STREQUAL "DEFINE")
# New definition
set(current_definition)
elseif (NOT current_definition)
# First item after DEFINE is the definition
set(current_definition "${item}")
else()
# Subsequent items are regexes to match against the header
if (header MATCHES ${item})
set_property(
SOURCE "${src}"
APPEND
PROPERTY COMPILE_DEFINITIONS "${current_definition}"
)
endif()
endif()
endforeach()
endfunction()
# Configure header templates:
set(header_srcs)
foreach (header IN LISTS headers)
set(
header_src
"${CMAKE_CURRENT_BINARY_DIR}/headers/${target_name}/${header}.${extension}"
)
configure_file("${CGHT_HEADER_TEMPLATE}" "${header_src}" @ONLY)
cght_apply_per_header_defines("${header}" "${header_src}")
# Compile-time benchmark workflows can ask generated one-include CUDA TUs to
# preserve preprocessed artifacts and/or emit NVCC device time traces.
if (
(
CCCL_COMPILE_TIME_SAVE_PREPROCESSED_TUS
OR CCCL_COMPILE_TIME_GENERATE_DEVICE_TIME_TRACES
)
AND CGHT_LANGUAGE STREQUAL "CUDA"
)
get_filename_component(header_src_dir "${header_src}" DIRECTORY)
if ("${CMAKE_CUDA_COMPILER_ID}" STREQUAL "NVIDIA")
if (CCCL_COMPILE_TIME_SAVE_PREPROCESSED_TUS)
set_property(
SOURCE "${header_src}"
APPEND
PROPERTY COMPILE_OPTIONS "--keep" "--keep-dir=${header_src_dir}"
)
endif()
if (CCCL_COMPILE_TIME_GENERATE_DEVICE_TIME_TRACES)
set(trace_id "${header}")
string(REPLACE "/" "__" trace_id "${trace_id}")
string(REPLACE "." "_" trace_id "${trace_id}")
set(
trace_dir
"${CMAKE_BINARY_DIR}/compile_time/raw_traces/${target_name}"
)
file(MAKE_DIRECTORY "${trace_dir}")
set_property(
SOURCE "${header_src}"
APPEND
PROPERTY
COMPILE_OPTIONS "--fdevice-time-trace=${trace_dir}/${trace_id}"
)
endif()
elseif (
CCCL_COMPILE_TIME_SAVE_PREPROCESSED_TUS
AND "${CMAKE_CUDA_COMPILER_ID}" STREQUAL "Clang"
)
set_property(
SOURCE "${header_src}"
APPEND
PROPERTY COMPILE_OPTIONS "-save-temps=obj"
)
endif()
endif()
list(APPEND header_srcs "${header_src}")
endforeach()
# Object library that compiles each header:
add_library(${target_name} OBJECT ${header_srcs})
cccl_configure_target(${target_name} ${cccl_configure_target_options})
if (NOT CGHT_NO_METATARGETS)
cccl_ensure_metatargets(${target_name})
endif()
# Check that all functions in headers are either template functions or inline:
set(link_target ${target_name}.link_check)
cccl_add_executable(
${link_target}
SOURCES "${CCCL_SOURCE_DIR}/cmake/link_check_main.cpp"
NO_METATARGETS
)
# Linking both ${target_name} and $<TARGET_OBJECTS:${target_name}> forces CMake to
# link the same objects twice. The compiler will complain about duplicate symbols if
# any functions are missing inline markup.
target_link_libraries(
${link_target}
PRIVATE #
${target_name}
$<TARGET_OBJECTS:${target_name}>
)
endfunction()

View File

@@ -0,0 +1,127 @@
set(_cccl_cpm_file "${CMAKE_CURRENT_LIST_DIR}/CPM.cmake")
set(_cccl_find_module_dir "${CMAKE_CURRENT_LIST_DIR}/find_modules")
macro(cccl_get_boost)
include("${_cccl_cpm_file}")
CPMAddPackage(
NAME Boost
GITHUB_REPOSITORY boostorg/boost
GIT_TAG "boost-1.83.0"
EXCLUDE_FROM_ALL TRUE
SYSTEM TRUE
GIT_SHALLOW TRUE
# Boost requests compatibility with obsolete CMake versions. Disable warning:
OPTIONS "CMAKE_POLICY_VERSION_MINIMUM 3.5"
)
endmacro()
# The CCCL Catch2Helper library:
macro(cccl_get_c2h)
if (NOT TARGET cccl.c2h)
add_subdirectory("${CCCL_SOURCE_DIR}/c2h" "${CCCL_BINARY_DIR}/c2h")
endif()
endmacro()
macro(cccl_get_catch2)
include("${_cccl_cpm_file}")
CPMAddPackage("gh:catchorg/Catch2@3.12.0")
endmacro()
macro(cccl_get_cccl)
find_package(
CCCL
CONFIG
REQUIRED
NO_DEFAULT_PATH # Only check the explicit HINTS below:
HINTS "${CCCL_SOURCE_DIR}/lib/cmake/cccl/"
)
endmacro()
macro(cccl_get_cub)
find_package(
CUB
CONFIG
REQUIRED
NO_DEFAULT_PATH # Only check the explicit HINTS below:
HINTS "${CCCL_SOURCE_DIR}/lib/cmake/cub/"
)
endmacro()
macro(cccl_get_cudatoolkit)
find_package(CUDAToolkit REQUIRED)
endmacro()
macro(cccl_get_cudax)
find_package(
cudax
CONFIG
REQUIRED
NO_DEFAULT_PATH # Only check the explicit HINTS below:
HINTS "${CCCL_SOURCE_DIR}/lib/cmake/cudax/"
)
endmacro()
macro(cccl_get_dlpack)
include("${_cccl_cpm_file}")
CPMAddPackage("gh:dmlc/dlpack#v1.2")
endmacro()
macro(cccl_get_libcudacxx)
find_package(
libcudacxx
CONFIG
REQUIRED
NO_DEFAULT_PATH # Only check the explicit HINTS below:
HINTS "${CCCL_SOURCE_DIR}/lib/cmake/libcudacxx/"
)
endmacro()
set(
CCCL_NVBENCH_SHA
"56d552687e6a462a812d6f046f5a85a07f13c9f3"
CACHE STRING
"SHA/tag to use for CCCL's NVBench."
)
mark_as_advanced(CCCL_NVBENCH_SHA)
macro(cccl_get_nvbench)
include("${_cccl_cpm_file}")
CPMAddPackage("gh:NVIDIA/nvbench#${CCCL_NVBENCH_SHA}")
endmacro()
# CCCL-specific NVBench utilities
macro(cccl_get_nvbench_helper)
if (NOT TARGET cccl.nvbench_helper)
add_subdirectory(
"${CCCL_SOURCE_DIR}/nvbench_helper"
"${CCCL_BINARY_DIR}/nvbench_helper"
)
endif()
endmacro()
macro(cccl_get_nvtx)
include("${_cccl_cpm_file}")
CPMAddPackage(
NAME NVTX
GITHUB_REPOSITORY NVIDIA/NVTX
GIT_TAG release-v3
DOWNLOAD_ONLY ON
SYSTEM ON
)
include("${NVTX_SOURCE_DIR}/c/nvtxImportedTargets.cmake")
endmacro()
macro(cccl_get_thrust)
find_package(
Thrust
CONFIG
REQUIRED
NO_DEFAULT_PATH # Only check the explicit HINTS below:
HINTS "${CCCL_SOURCE_DIR}/lib/cmake/thrust/"
)
endmacro()
macro(cccl_get_nccl)
list(APPEND CMAKE_MODULE_PATH "${_cccl_find_module_dir}")
find_package(NCCL ${ARGN})
list(POP_BACK CMAKE_MODULE_PATH)
endmacro()

View File

@@ -0,0 +1,39 @@
mark_as_advanced(
BUILD_TESTING
CATCH_BUILD_EXAMPLES
CATCH_BUILD_EXTRA_TESTS
CATCH_BUILD_STATIC_LIBRARY
CATCH_BUILD_TESTING
CATCH_ENABLE_COVERAGE
CATCH_ENABLE_WERROR
CATCH_INSTALL_DOCS
CATCH_INSTALL_HELPERS
CATCH_USE_VALGRIND
CLANG_FORMAT
CLANG_TIDY
CPM_DONT_CREATE_PACKAGE_LOCK
CPM_DONT_UPDATE_MODULE_PATH
CPM_DOWNLOAD_ALL
CPM_INCLUDE_ALL_IN_PACKAGE_LOCK
CPM_LOCAL_PACKAGES_ONLY
CPM_SOURCE_CACHE
CPM_USE_LOCAL_PACKAGES
CPM_USE_NAMED_CACHE_DIRECTORIES
CPPCHECK
CUB_DIR
FETCHCONTENT_BASE_DIR
FETCHCONTENT_FULLY_DISCONNECTED
FETCHCONTENT_QUIET
FETCHCONTENT_SOURCE_DIR_CATCH2
FETCHCONTENT_UPDATES_DISCONNECTED
FETCHCONTENT_UPDATES_DISCONNECTED_CATCH2
LIBCXX_CXX_ABI
LIT_EXTRA_ARGS
LLVM_DEFAULT_EXTERNAL_LIT
LLVM_DEFAULT_TARGET_TRIPLE
LLVM_EXTERNAL_LIT
LLVM_HOST_TRIPLE
LLVM_PATH
Thrust_DIR
libcudacxx_DIR
)

View File

@@ -0,0 +1,146 @@
# Bring in CMAKE_INSTALL_* vars
include(GNUInstallDirs)
# CCCL has no installable binaries, no need to build before installing:
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE)
# Usage:
# cccl_generate_install_rules(PROJECT_NAME DEFAULT_ENABLE
# [NO_HEADERS]
# [HEADER_SUBDIR <subdir1> [subdir2 ...]]
# [HEADERS_INCLUDE <pattern1> [pattern2 ...]]
# [HEADERS_EXCLUDE <pattern1> [pattern2 ...]]
# [PACKAGE]
# )
#
# Options:
# PROJECT_NAME: The case-sensitive name of the project. Used to generate the option flag.
# DEFAULT_ENABLE: Whether the install rules should be enabled by default.
# NO_HEADERS: If set, no install rules will be generated for headers.
# HEADERS_SUBDIRS: If set, a separate install rule will be generated for each subdirectory relative to the project dir.
# If not set, <CCCL_SOURCE_DIR>/<PROJECT_NAME_LOWER>/<PROJECT_NAME_LOWER> will be used.
# HEADERS_INCLUDE: A list of globbing patterns that match installable header files.
# HEADERS_EXCLUDE: A list of globbing patterns that match header files to exclude from installation.
# PACKAGE: If set, install the project's CMake package.
#
# Notes:
# - The generated cache option will be named <PROJECT_NAME>_ENABLE_INSTALL_RULES.
# - The header globs are applied relative to <CCCL_SOURCE_DIR>/<PROJECT_NAME_LOWER>/<SUBDIR>.
# - The cmake package is assumed to be located at <CCCL_SOURCE_DIR>/lib/cmake/<PROJECT_NAME_LOWER>.
# - If a <PROJECT_NAME_LOWER>-header-search.cmake.in file exists in the CMake package directory,
# it will be configured and installed.
#
function(cccl_generate_install_rules project_name enable_rules_by_default)
set(options PACKAGE NO_HEADERS)
set(oneValueArgs)
set(multiValueArgs HEADERS_SUBDIRS HEADERS_INCLUDE HEADERS_EXCLUDE)
cmake_parse_arguments(
CGIR
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
string(TOLOWER ${project_name} project_name_lower)
set(project_source_dir "${CCCL_SOURCE_DIR}/${project_name_lower}")
set(header_dest_dir "${CMAKE_INSTALL_INCLUDEDIR}")
set(package_source_dir "${CCCL_SOURCE_DIR}/lib/cmake/${project_name_lower}")
set(package_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/")
set(
header_search_template
"${package_source_dir}/${project_name_lower}-header-search.cmake.in"
)
set(
header_search_temporary
"${CCCL_BINARY_DIR}/${project_name_lower}-header-search.cmake"
)
if (NOT DEFINED CGIR_HEADERS_SUBDIRS)
set(CGIR_HEADERS_SUBDIRS "${project_name_lower}")
endif()
set(flag_name ${project_name}_ENABLE_INSTALL_RULES)
option(
${flag_name}
"Enable installation of ${project_name} files."
${enable_rules_by_default}
)
if (${flag_name})
# Headers:
if (NOT CGIR_NO_HEADERS)
foreach (subdir IN LISTS CGIR_HEADERS_SUBDIRS)
set(header_globs)
if (DEFINED CGIR_HEADERS_INCLUDE OR DEFINED CGIR_HEADERS_EXCLUDE)
set(header_globs "FILES_MATCHING")
foreach (header_glob IN LISTS CGIR_HEADERS_INCLUDE)
list(APPEND header_globs "PATTERN" "${header_glob}")
endforeach()
foreach (header_glob IN LISTS CGIR_HEADERS_EXCLUDE)
list(APPEND header_globs "PATTERN" "${header_glob}" "EXCLUDE")
endforeach()
endif()
install(
DIRECTORY "${project_source_dir}/${subdir}"
DESTINATION "${header_dest_dir}"
${header_globs}
)
endforeach()
endif()
# CMake package:
install(
DIRECTORY "${package_source_dir}"
DESTINATION "${package_dest_dir}"
REGEX .*header-search.cmake.* EXCLUDE
)
# Header search infra:
if (EXISTS "${header_search_template}")
# Need to configure a file to store the infix specified in
# CMAKE_INSTALL_INCLUDEDIR since it can be defined by the user
set(_CCCL_RELATIVE_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
if (_CCCL_RELATIVE_LIBDIR MATCHES "^${CMAKE_INSTALL_PREFIX}")
# libdir is an abs string that starts with prefix
string(LENGTH "${CMAKE_INSTALL_PREFIX}" to_remove)
string(SUBSTRING "${_CCCL_RELATIVE_LIBDIR}" ${to_remove} -1 relative)
# remove any leading "/""
string(REGEX REPLACE "^/(.)" "\\1" _CCCL_RELATIVE_LIBDIR "${relative}")
elseif (_CCCL_RELATIVE_LIBDIR MATCHES "^/")
message(
FATAL_ERROR
"CMAKE_INSTALL_LIBDIR ('${CMAKE_INSTALL_LIBDIR}') must be a relative path or an absolute path under CMAKE_INSTALL_PREFIX ('${CMAKE_INSTALL_PREFIX}')"
)
endif()
set(
install_location
"${_CCCL_RELATIVE_LIBDIR}/cmake/${project_name_lower}"
)
# Transform to a list of directories, replace each directory with "../"
# and convert back to a string
string(REGEX REPLACE "/" ";" from_install_prefix "${install_location}")
list(TRANSFORM from_install_prefix REPLACE ".+" "../")
list(JOIN from_install_prefix "" from_install_prefix)
configure_file(
"${header_search_template}"
"${header_search_temporary}"
@ONLY
)
install(
FILES "${header_search_temporary}"
DESTINATION "${install_location}"
)
endif()
endif()
endfunction()
include("${CMAKE_CURRENT_LIST_DIR}/install/cccl.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/install/cub.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/install/cudax.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/install/libcudacxx.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/install/thrust.cmake")

View File

@@ -0,0 +1,110 @@
# Further documentation and examples are provided in docs/cccl/development/testing.rst.
# The function below reads the filepath `src`, extracts the %PARAM% comments,
# and fills `all_variant_labels_var` with a list of `label1_value1.label2_value2...`
# strings, and puts the corresponding `DEFINITION=value1:DEFINITION=value2`
# entries into `all_variant_defs_var`.
function(
cccl_parse_variant_params
src
num_variants_var
all_variant_labels_var
all_variant_defs_var
)
file(READ "${src}" file_data)
set(param_regex "//[ ]+%PARAM%[ ]+([^ ]+)[ ]+([^ ]+)[ ]+([^\n]*)")
string(REGEX MATCHALL "${param_regex}" matches "${file_data}")
set(variant_labels)
set(variant_defs)
foreach (match IN LISTS matches)
string(REGEX MATCH "${param_regex}" unused "${match}")
set(def ${CMAKE_MATCH_1})
set(label ${CMAKE_MATCH_2})
set(values "${CMAKE_MATCH_3}")
string(REPLACE ":" ";" values "${values}")
# Build lists of test name suffixes (labels) and preprocessor definitions
# (defs) containing the cartesian product of all param values:
if (NOT variant_labels)
foreach (value IN LISTS values)
list(APPEND variant_labels ${label}_${value})
endforeach()
else()
set(tmp_labels)
foreach (old_label IN LISTS variant_labels)
foreach (value IN LISTS values)
list(APPEND tmp_labels ${old_label}.${label}_${value})
endforeach()
endforeach()
set(variant_labels "${tmp_labels}")
endif()
if (NOT variant_defs)
foreach (value IN LISTS values)
list(APPEND variant_defs ${def}=${value})
endforeach()
else()
set(tmp_defs)
foreach (old_def IN LISTS variant_defs)
foreach (value IN LISTS values)
list(APPEND tmp_defs ${old_def}:${def}=${value})
endforeach()
endforeach()
set(variant_defs "${tmp_defs}")
endif()
endforeach()
list(LENGTH variant_labels num_variants)
set(${num_variants_var} "${num_variants}" PARENT_SCOPE)
set(${all_variant_labels_var} "${variant_labels}" PARENT_SCOPE)
set(${all_variant_defs_var} "${variant_defs}" PARENT_SCOPE)
endfunction()
# Extracts the variant label and definitions for the given variant index and prepares them for use.
function(
cccl_get_variant_data
all_variant_labels_var
all_variant_defs_var
var_idx
label_var
defs_var
)
list(GET ${all_variant_labels_var} ${var_idx} label)
list(GET ${all_variant_defs_var} ${var_idx} defs)
string(REPLACE ":" ";" defs "${defs}")
list(APPEND defs "VAR_IDX=${var_idx}")
set(${label_var} "${label}" PARENT_SCOPE)
set(${defs_var} "${defs}" PARENT_SCOPE)
endfunction()
# Logs the detected variant info to CMake's VERBOSE output stream.
function(
cccl_log_variant_params
name_base
num_variants
all_variant_labels_var
all_variant_defs_var
)
# Verbose output:
if (num_variants GREATER 0)
message(VERBOSE "Detected ${num_variants} variants of '${name_base}':")
# Subtract 1 to support the inclusive endpoint of foreach(...RANGE...):
math(EXPR range_end "${num_variants} - 1")
foreach (var_idx RANGE ${range_end})
cccl_get_variant_data(
${all_variant_labels_var}
${all_variant_defs_var}
${var_idx}
label
defs
)
message(VERBOSE " ${var_idx}: ${label} ${defs}")
endforeach()
endif()
endfunction()

View File

@@ -0,0 +1,291 @@
# SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Passes all args directly to execute_process while setting up the following
# results variables and propagating them to the caller's scope:
#
# - cccl_process_exit_code
# - cccl_process_stdout
# - cccl_process_stderr
#
# If the command
# is not successful (e.g. the last command does not return zero), a non-fatal
# warning is printed.
function(cccl_execute_non_fatal_process)
# Skip parsing this function's signature -- it is handled by .gersemi/ext/cccl.py.
# gersemi: ignore
execute_process(
${ARGN}
RESULT_VARIABLE cccl_process_exit_code
OUTPUT_VARIABLE cccl_process_stdout
ERROR_VARIABLE cccl_process_stderr
)
if (NOT cccl_process_exit_code EQUAL 0)
message(
WARNING
"execute_process failed with non-zero exit code: ${cccl_process_exit_code}\n"
"${ARGN}\n"
"stdout:\n${cccl_process_stdout}\n"
"stderr:\n${cccl_process_stderr}\n"
)
endif()
set(cccl_process_exit_code "${cccl_process_exit_code}" PARENT_SCOPE)
set(cccl_process_stdout "${cccl_process_stdout}" PARENT_SCOPE)
set(cccl_process_stderr "${cccl_process_stderr}" PARENT_SCOPE)
endfunction()
# Add a build-and-test CTest.
# - full_test_name_var will be set to the full name of the test.
# - name_prefix is the prefix of the test's name (e.g. `cccl.test.cmake`)
# - subdir is the relative path to the test project directory.
# - test_id is used to generate a unique name for this test, allowing the
# subdir to be reused.
# - CTEST_COMMAND is the command to use for running CTest [optional]
# - Any additional args will be passed to the project configure step.
function(cccl_add_compile_test full_test_name_var name_prefix subdir test_id)
set(options)
set(oneValueArgs CTEST_COMMAND)
set(multiValueArgs)
cmake_parse_arguments(
cccl_compile_test
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
if (NOT DEFINED cccl_compile_test_CTEST_COMMAND)
set(cccl_compile_test_CTEST_COMMAND "${CMAKE_CTEST_COMMAND}")
endif()
set(test_name ${name_prefix}.${subdir}.${test_id})
set(src_dir "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}/${test_id}")
add_test(
NAME ${test_name}
# gersemi: off
COMMAND
"${cccl_compile_test_CTEST_COMMAND}"
--build-and-test "${src_dir}" "${build_dir}"
--build-generator "${CMAKE_GENERATOR}"
--build-options ${cccl_compile_test_UNPARSED_ARGUMENTS}
--test-command "${cccl_compile_test_CTEST_COMMAND}" --output-on-failure
# gersemi: on
)
set(${full_test_name_var} ${test_name} PARENT_SCOPE)
endfunction()
# cccl_add_xfail_compile_target_test(
# <target_name>
# [TEST_NAME <test_name>]
# [ERROR_REGEX <regex>]
# [SOURCE_FILE <source_file>]
# [ERROR_REGEX_LABEL <error_string>]
# [ERROR_NUMBER <error_number>]
# [ERROR_NUMBER_TARGET_NAME_REGEX <regex>]
# )
#
# Given a configured build target that is expected to fail to compile:
# - Mark the target as excluded from the `all` target.
# - Create a CTest test that compiles the target. If TEST_NAME is provided, it is used.
# Otherwise, the target_name is used as the test name.
# - When the test runs, it passes if exactly one of the following conditions is met:
# - A provided / detected error regex matches the compilation output, ignoring exit code.
# - No error regex is provided / detected, and the compilation fails.
#
# An error regex may be explicitly provided via ERROR_REGEX, or it may be
# detected by scanning the SOURCE_FILE for a specially formatted comment.
#
# If ERROR_REGEX_LABEL is provided, the SOURCE_FILE will read, looking for a comment of the form:
#
# // <ERROR_REGEX_LABEL> {{"error_regex"}}
#
# An error number may be appended to the ERROR_REGEX_LABEL in the comment:
#
# // <ERROR_REGEX_LABEL>-<error_number> {{"error_regex"}}
#
# If ERROR_NUMBER_TARGET_NAME_REGEX is specified, the regex is used to capture
# the error_number from the target name. If target_name is
# "cccl.test.my_test.err_5.foo_3" and ERROR_NUMBER_TARGET_NAME_REGEX is
# "\\.err_([0-9]+)", the captured error number "5."
#
# // <ERROR_REGEX_LABEL>-<captured_error_number> {{"error_regex"}}
#
# If ERROR_NUMBER is provided, ERROR_NUMBER_TARGET_NAME_REGEX is ignored.
# If ERROR_NUMBER_TARGET_NAME_REGEX is provided but does not match, a plain ERROR_REGEX_LABEL is used.
#
# If both SOURCE_FILE and ERROR_REGEX_LABEL are provided, the source file will be added to the
# current directory's CMAKE_CONFIGURE_DEPENDS to ensure that changes to the file will re-trigger CMake.
function(cccl_add_xfail_compile_target_test target_name)
set(options)
set(
oneValueArgs
TEST_NAME
ERROR_REGEX
SOURCE_FILE
ERROR_REGEX_LABEL
ERROR_NUMBER
ERROR_NUMBER_TARGET_NAME_REGEX
)
set(multiValueArgs)
cmake_parse_arguments(
cccl_xfail
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
if (cccl_xfail_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unparsed arguments: ${cccl_xfail_UNPARSED_ARGUMENTS}")
endif()
set(test_name "${target_name}")
if (DEFINED cccl_xfail_TEST_NAME)
set(test_name "${cccl_xfail_TEST_NAME}")
endif()
set(regex)
if (DEFINED cccl_xfail_ERROR_REGEX)
set(regex "${cccl_xfail_ERROR_REGEX}")
elseif (
DEFINED cccl_xfail_SOURCE_FILE
AND DEFINED cccl_xfail_ERROR_REGEX_LABEL
)
get_filename_component(src_absolute "${cccl_xfail_SOURCE_FILE}" ABSOLUTE)
set(error_label_regex "${cccl_xfail_ERROR_REGEX_LABEL}")
# Cache all error label matches (with and without error numbers) as global properties.
# This avoids re-reading and re-parsing the source file multiple times if multiple
# tests are added for the same source file. Properties are used instead of cache variables
# to ensure that the source is not cached in between CMake executions.
string(MD5 source_filename_md5 "${src_absolute}")
set(error_cache_property "_cccl_xfail_error_cache_${source_filename_md5}")
get_property(error_cache_set GLOBAL PROPERTY "${error_cache_property}" SET)
if (error_cache_set)
get_property(error_cache GLOBAL PROPERTY "${error_cache_property}")
else()
file(READ "${src_absolute}" source_contents)
string(
REGEX MATCHALL
"//[ \t]*${error_label_regex}(-[0-9]+)?[ \t]*{{\"([^\"]+)\"}}"
error_cache
"${source_contents}"
)
set_property(GLOBAL PROPERTY "${error_cache_property}" "${error_cache}")
endif()
# Changes to the source file should re-run CMake to pick-up new error specs:
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS "${src_absolute}"
)
set(error_number)
if (DEFINED cccl_xfail_ERROR_NUMBER)
set(error_number "${cccl_xfail_ERROR_NUMBER}")
elseif (DEFINED cccl_xfail_ERROR_NUMBER_TARGET_NAME_REGEX)
string(
REGEX MATCH
"${cccl_xfail_ERROR_NUMBER_TARGET_NAME_REGEX}"
matched
${target_name}
)
if (matched)
set(error_number "${CMAKE_MATCH_1}")
endif()
endif()
# Look for a labeled error with the specific error number.
if (NOT "${error_number}" STREQUAL "") # Check strings to allow "0"
string(
REGEX MATCH
"//[ \t]*${error_label_regex}-${error_number}[ \t]*{{\"([^\"]+)\"}}"
matched
"${error_cache}"
)
if (matched)
set(regex "${CMAKE_MATCH_1}")
endif()
endif()
if (NOT regex)
# Look for a labeled error without an error number.
string(
REGEX MATCH
"//[ \t]*${error_label_regex}[ \t]*{{\"([^\"]+)\"}}"
matched
"${error_cache}"
)
if (matched)
set(regex "${CMAKE_MATCH_1}")
endif()
endif()
endif()
message(VERBOSE "CCCL: Adding XFAIL test: ${test_name}")
if (regex)
message(VERBOSE "CCCL: with expected regex: '${regex}'")
endif()
set_target_properties(${test_target} PROPERTIES EXCLUDE_FROM_ALL true)
# The same target may be reused for multiple tests, and the output file
# may exist if using a regex to check for warnings. Add a setup fixture to
# delete the output file before each test run.
if (NOT TEST ${target_name}.clean)
add_test(
NAME ${target_name}.clean
# gersemi: off
COMMAND
"${CMAKE_COMMAND}" -E rm -f
"$<TARGET_FILE:${target_name}>"
"$<TARGET_OBJECTS:${target_name}>"
# gersemi: on
)
set_tests_properties(
${test_name}.clean
PROPERTIES FIXTURES_SETUP ${target_name}.clean
)
endif()
add_test(
NAME ${test_name}
# gersemi: off
COMMAND
"${CMAKE_COMMAND}"
--build "${CMAKE_BINARY_DIR}"
--target ${test_target}
--config $<CONFIGURATION>
# gersemi: on
)
set_tests_properties(
${test_name}
PROPERTIES FIXTURES_CLEANUP ${target_name}.clean
)
if (regex)
set_tests_properties(
${test_name}
PROPERTIES PASS_REGULAR_EXPRESSION "${regex}"
)
else()
set_tests_properties(${test_name} PROPERTIES WILL_FAIL true)
endif()
endfunction()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
## This CMake script parses the output of ctest and prints a formatted list
## of individual test runtimes, sorted longest first.
##
## ctest > ctest_log
## cmake -DLOGFILE=ctest_log \
## -DMINSEC=10 \
## -P PrintCTestRunTimes.cmake
##
################################################################################
cmake_minimum_required(VERSION 3.15)
# Prepend the string with "0" until the string length equals the specified width
function(pad_string_with_zeros string_var width)
# gersemi: ignore
set(local_string "${${string_var}}")
string(LENGTH "${local_string}" size)
while(size LESS width)
string(PREPEND local_string "0")
string(LENGTH "${local_string}" size)
endwhile()
set(${string_var} "${local_string}" PARENT_SCOPE)
endfunction()
################################################################################
if (NOT LOGFILE)
message(FATAL_ERROR "Missing -DLOGFILE=<ctest output> argument.")
endif()
if (NOT DEFINED MINSEC)
set(MINSEC 10)
endif()
set(num_below_thresh 0)
# Check if logfile exists
if (NOT EXISTS "${LOGFILE}")
message(FATAL_ERROR "LOGFILE does not exist ('${LOGFILE}').")
endif()
# gersemi: off
string(JOIN "" regex
"[0-9]+/[0-9]+[ ]+Test[ ]+#"
"([0-9]+)" # Test ID
":[ ]+"
"([^ ]+)" # Test Name
"[ ]*\\.+[ ]*\\**[ ]*"
"([^ ]+)" # Result
"[ ]+"
"([0-9]+)" # Seconds
"\\.[0-9]+[ ]+sec"
)
# gersemi: on
message(DEBUG "LOGFILE: ${LOGFILE}")
message(DEBUG "MINSEC: ${MINSEC}")
message(DEBUG "regex: ${regex}")
# Read the logfile and generate a map / keylist
set(keys)
file(STRINGS "${LOGFILE}" lines)
foreach (line ${lines})
# Parse each build time
string(REGEX MATCH "${regex}" _DUMMY "${line}")
if (CMAKE_MATCH_COUNT EQUAL 4)
# gersemi: off
set(test_id "${CMAKE_MATCH_1}")
set(test_name "${CMAKE_MATCH_2}")
set(test_result "${CMAKE_MATCH_3}")
set(tmp "${CMAKE_MATCH_4}") # floor(runtime_seconds)
# gersemi: on
if (tmp LESS MINSEC)
math(EXPR num_below_thresh "${num_below_thresh} + 1")
continue()
endif()
# Compute human readable time
# gersemi: off
math(EXPR days "${tmp} / (60 * 60 * 24)")
math(EXPR tmp "${tmp} - (${days} * 60 * 60 * 24)")
math(EXPR hours "${tmp} / (60 * 60)")
math(EXPR tmp "${tmp} - (${hours} * 60 * 60)")
math(EXPR minutes "${tmp} / (60)")
math(EXPR tmp "${tmp} - (${minutes} * 60)")
math(EXPR seconds "${tmp}")
# gersemi: on
# Format time components
pad_string_with_zeros(days 3)
pad_string_with_zeros(hours 2)
pad_string_with_zeros(minutes 2)
pad_string_with_zeros(seconds 2)
# Construct table entry
# Later values in the file for the same command overwrite earlier entries
string(MAKE_C_IDENTIFIER "${test_id}" key)
string(
JOIN " | "
ENTRY_${key}
"${days}d ${hours}h ${minutes}m ${seconds}s"
"${test_result}"
"${test_id}: ${test_name}"
)
# Record the key:
list(APPEND keys "${key}")
endif()
endforeach()
list(REMOVE_DUPLICATES keys)
# Build the entry list:
set(entries)
foreach (key ${keys})
list(APPEND entries "${ENTRY_${key}}")
endforeach()
if (NOT entries)
message(STATUS "LOGFILE contained no test times ('${LOGFILE}').")
endif()
# Sort in descending order:
list(SORT entries ORDER DESCENDING)
# Dump table:
foreach (entry ${entries})
message(STATUS ${entry})
endforeach()
if (num_below_thresh GREATER 0)
message(STATUS "${num_below_thresh} additional tests took < ${MINSEC}s each.")
endif()

View File

@@ -0,0 +1,108 @@
## This CMake script parses a .ninja_log file (LOGFILE) and prints a list of
## build/link times, sorted longest first.
##
## cmake -DLOGFILE=<.ninja_log file> \
## -P PrintNinjaBuildTimes.cmake
##
## If LOGFILE is omitted, the current directory's .ninja_log file is used.
################################################################################
cmake_minimum_required(VERSION 3.15)
# Prepend the string with "0" until the string length equals the specified width
function(pad_string_with_zeros string_var width)
# gersemi: ignore
set(local_string "${${string_var}}")
string(LENGTH "${local_string}" size)
while(size LESS width)
string(PREPEND local_string "0")
string(LENGTH "${local_string}" size)
endwhile()
set(${string_var} "${local_string}" PARENT_SCOPE)
endfunction()
################################################################################
if (NOT LOGFILE)
set(LOGFILE ".ninja_log")
endif()
# Check if logfile exists
if (NOT EXISTS "${LOGFILE}")
message(FATAL_ERROR "LOGFILE does not exist ('${LOGFILE}').")
endif()
# Read the logfile and generate a map / keylist
set(keys)
file(STRINGS "${LOGFILE}" lines)
foreach (line ${lines})
# Parse each build time
string(
REGEX MATCH
"^([0-9]+)\t([0-9]+)\t[0-9]+\t([^\t]+)+\t[0-9a-fA-F]+$"
_DUMMY
"${line}"
)
if (CMAKE_MATCH_COUNT EQUAL 3)
set(start_ms ${CMAKE_MATCH_1})
set(end_ms ${CMAKE_MATCH_2})
set(command "${CMAKE_MATCH_3}")
math(EXPR runtime_ms "${end_ms} - ${start_ms}")
# Compute human readable time
# gersemi: off
math(EXPR days "${runtime_ms} / (1000 * 60 * 60 * 24)")
math(EXPR runtime_ms "${runtime_ms} - (${days} * 1000 * 60 * 60 * 24)")
math(EXPR hours "${runtime_ms} / (1000 * 60 * 60)")
math(EXPR runtime_ms "${runtime_ms} - (${hours} * 1000 * 60 * 60)")
math(EXPR minutes "${runtime_ms} / (1000 * 60)")
math(EXPR runtime_ms "${runtime_ms} - (${minutes} * 1000 * 60)")
math(EXPR seconds "${runtime_ms} / 1000")
math(EXPR milliseconds "${runtime_ms} - (${seconds} * 1000)")
# gersemi: on
# Format time components
pad_string_with_zeros(days 3)
pad_string_with_zeros(hours 2)
pad_string_with_zeros(minutes 2)
pad_string_with_zeros(seconds 2)
pad_string_with_zeros(milliseconds 3)
# Construct table entry
# Later values in the file for the same command overwrite earlier entries
string(MAKE_C_IDENTIFIER "${command}" key)
set(
ENTRY_${key}
"${days}d ${hours}h ${minutes}m ${seconds}s ${milliseconds}ms | ${command}"
)
# Record the key:
list(APPEND keys "${key}")
endif()
endforeach()
list(REMOVE_DUPLICATES keys)
# Build the entry list:
set(entries)
foreach (key ${keys})
list(APPEND entries "${ENTRY_${key}}")
endforeach()
if (NOT entries)
message(FATAL_ERROR "LOGFILE contained no build entries ('${LOGFILE}').")
endif()
# Sort in descending order:
list(SORT entries)
list(REVERSE entries)
# Dump table:
message(STATUS "-----------------------+----------------------------")
message(STATUS "Time | Command ")
message(STATUS "-----------------------+----------------------------")
foreach (entry ${entries})
message(STATUS ${entry})
endforeach()

View File

@@ -0,0 +1,120 @@
#===----------------------------------------------------------------------===##
#
# Part of CUDA Experimental in CUDA C++ Core Libraries,
# under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
#
#===----------------------------------------------------------------------===##
#[=======================================================================[.rst:
FindNCCL
--------
Find NCCL
Imported targets
^^^^^^^^^^^^^^^^
This module defines the following :prop_tgt:`IMPORTED` target(s):
``NCCL::nccl``
The NCCL library, if found.
Result variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
``NCCL_FOUND``
True if NCCL is found.
``NCCL_INCLUDE_DIRS``
The include directories needed to use NCCL.
``NCCL_LIBRARIES``
The libraries needed to useNCCL.
``NCCL_VERSION_STRING``
The version of the NCCL library found. [OPTIONAL]
#]=======================================================================]
# Prefer using a Config module if it exists for this project
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
# Also search CUDA paths for good measure
if (CUDAToolkit_ROOT)
list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT})
endif()
find_package(NCCL CONFIG QUIET)
if (NCCL_FOUND)
find_package_handle_standard_args(NCCL DEFAULT_MSG NCCL_CONFIG)
return()
endif()
find_path(NCCL_INCLUDE_DIR NAMES nccl.h)
if (NOT NCCL_LIBRARY)
find_library(NCCL_LIBRARY_RELEASE NAMES nccl)
find_library(NCCL_LIBRARY_DEBUG NAMES nccld)
include(${CMAKE_ROOT}/Modules/SelectLibraryConfigurations.cmake)
select_library_configurations(NCCL)
unset(NCCL_FOUND) # incorrectly set by select_library_configurations
endif()
find_package_handle_standard_args(
NCCL
FOUND_VAR NCCL_FOUND
REQUIRED_VARS NCCL_LIBRARY NCCL_INCLUDE_DIR
VERSION_VAR NCCL_VERSION
)
if (NCCL_FOUND)
set(NCCL_INCLUDE_DIRS ${NCCL_INCLUDE_DIR})
if (NOT NCCL_LIBRARIES)
set(NCCL_LIBRARIES ${NCCL_LIBRARY})
endif()
if (NOT TARGET NCCL::nccl)
add_library(NCCL::nccl UNKNOWN IMPORTED GLOBAL)
set_target_properties(
NCCL::nccl
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${NCCL_INCLUDE_DIRS}"
)
if (NCCL_LIBRARY_RELEASE)
set_property(
TARGET NCCL::nccl
APPEND
PROPERTY IMPORTED_CONFIGURATIONS RELEASE
)
set_target_properties(
NCCL::nccl
PROPERTIES IMPORTED_LOCATION_RELEASE "${NCCL_LIBRARY_RELEASE}"
)
endif()
if (NCCL_LIBRARY_DEBUG)
set_property(
TARGET NCCL::nccl
APPEND
PROPERTY IMPORTED_CONFIGURATIONS DEBUG
)
set_target_properties(
NCCL::nccl
PROPERTIES IMPORTED_LOCATION_DEBUG "${NCCL_LIBRARY_DEBUG}"
)
endif()
if (NOT NCCL_LIBRARY_RELEASE AND NOT NCCL_LIBRARY_DEBUG)
set_property(
TARGET NCCL::nccl
APPEND
PROPERTY IMPORTED_LOCATION "${NCCL_LIBRARY}"
)
endif()
endif()
endif()

View File

@@ -0,0 +1,89 @@
// This source file checks that:
// 1) Header <@header@> compiles without error.
// 2) Common macro collisions with platform/system headers are avoided.
// 3) half/bf16 aren't included when these are explicitly disabled.
// Define CCCL_HEADER_MACRO_CHECK(macro, header), which emits a diagnostic indicating
// a potential macro collision and halts.
//
// Hacky way to build a string, but it works on all tested platforms.
#define CCCL_HEADER_MACRO_CHECK(MACRO, HEADER) \
CCCL_HEADER_MACRO_CHECK_IMPL( \
Identifier MACRO should not be used from Thrust headers due to conflicts with HEADER macros.)
// Use raw platform macros instead of the CCCL macros since we
// don't want to #include any headers other than the one being tested.
//
// This is only implemented for MSVC/GCC/Clang.
#if defined(_MSC_VER) // MSVC
// Fake up an error for MSVC
# define CCCL_HEADER_MACRO_CHECK_IMPL(msg) \
/* Print message that looks like an error: */ \
__pragma(message(__FILE__ ":" CCCL_HEADER_MACRO_CHECK_IMPL0(__LINE__) ": error: " #msg)) \
\
static_assert(false, #msg); /* abort compilation due to static_assert or syntax error */
# define CCCL_HEADER_MACRO_CHECK_IMPL0(x) CCCL_HEADER_MACRO_CHECK_IMPL1(x)
# define CCCL_HEADER_MACRO_CHECK_IMPL1(x) #x
#elif defined(__clang__) || defined(__GNUC__)
// GCC/clang are easy:
# define CCCL_HEADER_MACRO_CHECK_IMPL(msg) CCCL_HEADER_MACRO_CHECK_IMPL0(GCC error #msg)
# define CCCL_HEADER_MACRO_CHECK_IMPL0(expr) _Pragma(#expr)
#endif // msvc vs. the world
// May be defined to skip macro check for certain configurations.
#ifndef CCCL_IGNORE_HEADER_MACRO_CHECKS
// complex.h conflicts
# define I CCCL_HEADER_MACRO_CHECK('I', complex.h)
// windows.h conflicts
# define small CCCL_HEADER_MACRO_CHECK('small', windows.h)
// We can't enable these checks without breaking some builds -- some standard
// library implementations unconditionally `#undef` these macros, which then
// causes random failures later.
// Leaving these commented out as a warning: Here be dragons.
// #define min(...) CCCL_HEADER_MACRO_CHECK('min', windows.h)
// #define max(...) CCCL_HEADER_MACRO_CHECK('max', windows.h)
# ifdef _WIN32
// On Windows, make sure any include of Windows.h (e.g. via NVTX) does not define the checked macros
# define WIN32_LEAN_AND_MEAN
# endif // _WIN32
// termios.h conflicts (NVIDIA/thrust#1547)
# define B0 CCCL_HEADER_MACRO_CHECK("B0", termios.h)
#endif // CCCL_IGNORE_HEADER_MACRO_CHECKS
#include <@header@>
#if defined(CCCL_DISABLE_NVFP8_SUPPORT)
# if defined(__CUDA_FP8_TYPES_EXIST__)
# error We should not include cuda_fp8.h when FP8 support is disabled
# endif // __CUDA_FP16_TYPES_EXIST__
#endif // CCCL_DISABLE_BF16_SUPPORT
#if defined(CCCL_DISABLE_BF16_SUPPORT)
# if defined(__CUDA_BF16_TYPES_EXIST__)
# error We should not include cuda_bf16.h when BF16 support is disabled
# endif // __CUDA_BF16_TYPES_EXIST__
# if defined(__CUDA_FP8_TYPES_EXIST__)
# error We should not include cuda_fp8.h when BF16 support is disabled
# endif // __CUDA_FP16_TYPES_EXIST__
#endif // CCCL_DISABLE_BF16_SUPPORT
#if defined(CCCL_DISABLE_FP16_SUPPORT)
# if defined(__CUDA_FP8_TYPES_EXIST__)
# error We should not include cuda_fp8.h when half support is disabled
# endif // __CUDA_FP16_TYPES_EXIST__
# if defined(__CUDA_FP16_TYPES_EXIST__)
# error We should not include cuda_fp16.h when half support is disabled
# endif // __CUDA_FP16_TYPES_EXIST__
# if defined(__CUDA_BF16_TYPES_EXIST__)
# error We should not include cuda_bf16.h when half support is disabled
# endif // __CUDA_BF16_TYPES_EXIST__
#endif // CCCL_DISABLE_FP16_SUPPORT

View File

@@ -0,0 +1 @@
cccl_generate_install_rules(CCCL ${CCCL_TOPLEVEL_PROJECT} NO_HEADERS PACKAGE)

View File

@@ -0,0 +1,6 @@
cccl_generate_install_rules(
CUB
${CCCL_TOPLEVEL_PROJECT}
HEADERS_INCLUDE "*.cuh"
PACKAGE
)

View File

@@ -0,0 +1,7 @@
cccl_generate_install_rules(
cudax
${CCCL_ENABLE_CUDAX}
HEADERS_SUBDIRS "include/cuda"
HEADERS_INCLUDE "*.cuh"
PACKAGE
)

View File

@@ -0,0 +1,8 @@
cccl_generate_install_rules(
libcudacxx
${CCCL_TOPLEVEL_PROJECT}
HEADERS_SUBDIRS "include/cuda" "include/nv"
HEADERS_INCLUDE "*"
HEADERS_EXCLUDE "CMakeLists.txt"
PACKAGE
)

View File

@@ -0,0 +1,6 @@
cccl_generate_install_rules(
Thrust
${CCCL_TOPLEVEL_PROJECT}
HEADERS_INCLUDE "*.h" "*.inl"
PACKAGE
)

View File

@@ -0,0 +1,4 @@
int main()
{
return 0;
}

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eou pipefail
clang_tidy_args=()
if test -n "${CCCL_CLANG_TIDY_ARGS:+x}"; then
mapfile -t clang_tidy_args < <(echo "${CCCL_CLANG_TIDY_ARGS}" | tr ' ' '\n' | sort -u)
fi
set -x
"@CCCL_CLANG_TIDY@" \
--use-color \
--quiet \
--extra-arg='-Wno-error=unused-command-line-argument' \
--extra-arg='-D_CCCL_CLANG_TIDY_INVOKED=1' \
-p '@CMAKE_BINARY_DIR@' \
"${clang_tidy_args[@]}" \
"$@"