[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:
11
cccl_upstream/cmake/AppendOptionIfAvailable.cmake
Normal file
11
cccl_upstream/cmake/AppendOptionIfAvailable.cmake
Normal 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()
|
||||
53
cccl_upstream/cmake/CCCLAddExecutable.cmake
Normal file
53
cccl_upstream/cmake/CCCLAddExecutable.cmake
Normal 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()
|
||||
6
cccl_upstream/cmake/CCCLAddSubdir.cmake
Normal file
6
cccl_upstream/cmake/CCCLAddSubdir.cmake
Normal 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}"
|
||||
)
|
||||
75
cccl_upstream/cmake/CCCLAddSubdirHelper.cmake
Normal file
75
cccl_upstream/cmake/CCCLAddSubdirHelper.cmake
Normal 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()
|
||||
186
cccl_upstream/cmake/CCCLAddTidyTarget.cmake
Normal file
186
cccl_upstream/cmake/CCCLAddTidyTarget.cmake
Normal 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()
|
||||
262
cccl_upstream/cmake/CCCLBuildCompilerTargets.cmake
Normal file
262
cccl_upstream/cmake/CCCLBuildCompilerTargets.cmake
Normal 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()
|
||||
122
cccl_upstream/cmake/CCCLCheckCudaArchitectures.cmake
Normal file
122
cccl_upstream/cmake/CCCLCheckCudaArchitectures.cmake
Normal 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()
|
||||
39
cccl_upstream/cmake/CCCLClangdCompileInfo.cmake
Normal file
39
cccl_upstream/cmake/CCCLClangdCompileInfo.cmake
Normal 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
|
||||
66
cccl_upstream/cmake/CCCLConfigureTarget.cmake
Normal file
66
cccl_upstream/cmake/CCCLConfigureTarget.cmake
Normal 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()
|
||||
36
cccl_upstream/cmake/CCCLDevBuildChecks.cmake
Normal file
36
cccl_upstream/cmake/CCCLDevBuildChecks.cmake
Normal 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()
|
||||
52
cccl_upstream/cmake/CCCLEnsureMetaTargets.cmake
Normal file
52
cccl_upstream/cmake/CCCLEnsureMetaTargets.cmake
Normal 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()
|
||||
242
cccl_upstream/cmake/CCCLGenerateHeaderTests.cmake
Normal file
242
cccl_upstream/cmake/CCCLGenerateHeaderTests.cmake
Normal 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()
|
||||
127
cccl_upstream/cmake/CCCLGetDependencies.cmake
Normal file
127
cccl_upstream/cmake/CCCLGetDependencies.cmake
Normal 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()
|
||||
39
cccl_upstream/cmake/CCCLHideThirdPartyOptions.cmake
Normal file
39
cccl_upstream/cmake/CCCLHideThirdPartyOptions.cmake
Normal 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
|
||||
)
|
||||
146
cccl_upstream/cmake/CCCLInstallRules.cmake
Normal file
146
cccl_upstream/cmake/CCCLInstallRules.cmake
Normal 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")
|
||||
110
cccl_upstream/cmake/CCCLTestParams.cmake
Normal file
110
cccl_upstream/cmake/CCCLTestParams.cmake
Normal 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()
|
||||
291
cccl_upstream/cmake/CCCLUtilities.cmake
Normal file
291
cccl_upstream/cmake/CCCLUtilities.cmake
Normal 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()
|
||||
1297
cccl_upstream/cmake/CPM.cmake
Normal file
1297
cccl_upstream/cmake/CPM.cmake
Normal file
File diff suppressed because it is too large
Load Diff
135
cccl_upstream/cmake/PrintCTestRunTimes.cmake
Normal file
135
cccl_upstream/cmake/PrintCTestRunTimes.cmake
Normal 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()
|
||||
108
cccl_upstream/cmake/PrintNinjaBuildTimes.cmake
Normal file
108
cccl_upstream/cmake/PrintNinjaBuildTimes.cmake
Normal 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()
|
||||
120
cccl_upstream/cmake/find_modules/FindNCCL.cmake
Normal file
120
cccl_upstream/cmake/find_modules/FindNCCL.cmake
Normal 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()
|
||||
89
cccl_upstream/cmake/header_test.cu.in
Normal file
89
cccl_upstream/cmake/header_test.cu.in
Normal 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
|
||||
1
cccl_upstream/cmake/install/cccl.cmake
Normal file
1
cccl_upstream/cmake/install/cccl.cmake
Normal file
@@ -0,0 +1 @@
|
||||
cccl_generate_install_rules(CCCL ${CCCL_TOPLEVEL_PROJECT} NO_HEADERS PACKAGE)
|
||||
6
cccl_upstream/cmake/install/cub.cmake
Normal file
6
cccl_upstream/cmake/install/cub.cmake
Normal file
@@ -0,0 +1,6 @@
|
||||
cccl_generate_install_rules(
|
||||
CUB
|
||||
${CCCL_TOPLEVEL_PROJECT}
|
||||
HEADERS_INCLUDE "*.cuh"
|
||||
PACKAGE
|
||||
)
|
||||
7
cccl_upstream/cmake/install/cudax.cmake
Normal file
7
cccl_upstream/cmake/install/cudax.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
cccl_generate_install_rules(
|
||||
cudax
|
||||
${CCCL_ENABLE_CUDAX}
|
||||
HEADERS_SUBDIRS "include/cuda"
|
||||
HEADERS_INCLUDE "*.cuh"
|
||||
PACKAGE
|
||||
)
|
||||
8
cccl_upstream/cmake/install/libcudacxx.cmake
Normal file
8
cccl_upstream/cmake/install/libcudacxx.cmake
Normal 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
|
||||
)
|
||||
6
cccl_upstream/cmake/install/thrust.cmake
Normal file
6
cccl_upstream/cmake/install/thrust.cmake
Normal file
@@ -0,0 +1,6 @@
|
||||
cccl_generate_install_rules(
|
||||
Thrust
|
||||
${CCCL_TOPLEVEL_PROJECT}
|
||||
HEADERS_INCLUDE "*.h" "*.inl"
|
||||
PACKAGE
|
||||
)
|
||||
4
cccl_upstream/cmake/link_check_main.cpp
Normal file
4
cccl_upstream/cmake/link_check_main.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
18
cccl_upstream/cmake/run_clang_tidy.sh.in
Executable file
18
cccl_upstream/cmake/run_clang_tidy.sh.in
Executable 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[@]}" \
|
||||
"$@"
|
||||
Reference in New Issue
Block a user