# This file provides utilities for building and working with CUB # configuration targets. # # CUB_TARGETS # - Built by the calling the `cub_build_target_list()` function. # - Each item is the name of a CUB interface target that is configured for a # certain build configuration. Currently only C++ standard dialect is # considered. # # cub_build_target_list() # - Creates the CUB_TARGETS list. # # The following functions can be used to test/set metadata on a CUB target: # # cub_get_target_property( ) # - Checks the ${prop} target property on CUB target ${target_name} # and sets the ${prop_var} variable in the caller's scope. # - is any valid cmake identifier. # - is the name of a CUB target. # - is one of the following: # - DIALECT: The C++ dialect. Valid values: 11, 14, 17. # - PREFIX: A unique prefix that should be used to name all # targets/tests/examples that use this configuration. # # cub_get_target_properties() # - Defines ${target_name}_${prop} in the caller's scope, for `prop` in: # {DIALECT, PREFIX}. See above for details. # # cub_clone_target_properties( ) # - Set the {DIALECT, PREFIX} metadata on ${dst_target} to match # ${src_target}. See above for details. # - This *MUST* be called on any targets that link to another CUB target # to ensure that dialect information is updated correctly, e.g. # `cub_clone_target_properties(${my_cub_test} ${some_cub_target})` # Dialects: set(CUB_CPP_DIALECT_OPTIONS 11 14 17 CACHE INTERNAL "C++ dialects supported by CUB." FORCE ) define_property(TARGET PROPERTY _CUB_DIALECT BRIEF_DOCS "A target's C++ dialect: 11, 14, or 17." FULL_DOCS "A target's C++ dialect: 11, 14, or 17." ) define_property(TARGET PROPERTY _CUB_PREFIX BRIEF_DOCS "A prefix describing the config, eg. 'cub.cpp14'." FULL_DOCS "A prefix describing the config, eg. 'cub.cpp14'." ) function(cub_set_target_properties target_name dialect prefix) set_target_properties(${target_name} PROPERTIES _CUB_DIALECT ${dialect} _CUB_PREFIX ${prefix} ) get_target_property(type ${target_name} TYPE) if (NOT ${type} STREQUAL "INTERFACE_LIBRARY") set_target_properties(${target_name} PROPERTIES CXX_STANDARD ${dialect} CUDA_STANDARD ${dialect} ARCHIVE_OUTPUT_DIRECTORY "${CUB_LIBRARY_OUTPUT_DIR}" LIBRARY_OUTPUT_DIRECTORY "${CUB_LIBRARY_OUTPUT_DIR}" RUNTIME_OUTPUT_DIRECTORY "${CUB_EXECUTABLE_OUTPUT_DIR}" ) # CMake still emits errors about empty CUDA_ARCHITECTURES when CMP0104 # is set to OLD. This suppresses the errors for good. if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18) set_target_properties(${target_name} PROPERTIES CUDA_ARCHITECTURES OFF ) endif() if ("NVCXX" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") set_target_properties(${target_name} PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF ) endif() endif() endfunction() # Get a cub property from a target and store it in var_name # cub_get_target_property( [DIALECT|PREFIX] macro(cub_get_target_property prop_var target_name prop) get_property(${prop_var} TARGET ${target_name} PROPERTY _CUB_${prop}) endmacro() # Defines the following string variables in the caller's scope: # - ${target_name}_DIALECT # - ${target_name}_PREFIX macro(cub_get_target_properties target_name) cub_get_target_property(${target_name}_DIALECT ${target_name} DIALECT) cub_get_target_property(${target_name}_PREFIX ${target_name} PREFIX) endmacro() # Set one target's _CUB_* properties to match another target function(cub_clone_target_properties dst_target src_target) cub_get_target_properties(${src_target}) cub_set_target_properties(${dst_target} ${${src_target}_DIALECT} ${${src_target}_PREFIX} ) endfunction() # Set ${var_name} to TRUE or FALSE in the caller's scope function(_cub_is_config_valid var_name dialect) if (CUB_ENABLE_DIALECT_CPP${dialect}) set(${var_name} TRUE PARENT_SCOPE) else() set(${var_name} FALSE PARENT_SCOPE) endif() endfunction() function(_cub_init_target_list) set(CUB_TARGETS "" CACHE INTERNAL "" FORCE) endfunction() function(_cub_add_target_to_target_list target_name dialect prefix) cub_set_target_properties(${target_name} ${dialect} ${prefix}) target_link_libraries(${target_name} INTERFACE CUB::CUB cub.compiler_interface ) if (TARGET cub.thrust) target_link_libraries(${target_name} INTERFACE cub.thrust) endif() set(CUB_TARGETS ${CUB_TARGETS} ${target_name} CACHE INTERNAL "" FORCE) set(label "cpp${dialect}") string(TOLOWER "${label}" label) message(STATUS "Enabling CUB configuration: ${label}") endfunction() # Build a ${CUB_TARGETS} list containing target names for all # requested configurations function(cub_build_target_list) # Clear the list of targets: _cub_init_target_list() # Handle dialect options: set(num_dialects_enabled 0) foreach (dialect IN LISTS CUB_CPP_DIALECT_OPTIONS) if (CUB_IN_THRUST) # Just use Thrust's settings: if (THRUST_ENABLE_MULTICONFIG) set(CUB_ENABLE_DIALECT_CPP${dialect} ${THRUST_MULTICONFIG_ENABLE_DIALECT_CPP${dialect}} ) else() set(val OFF) if (dialect EQUAL ${THRUST_CPP_DIALECT}) set(val ON) endif() set(CUB_ENABLE_DIALECT_CPP${dialect} ${val}) endif() else() # Create CMake options: set(default_value OFF) if (dialect EQUAL 14) # Default to just 14 on: set(default_value ON) endif() option(CUB_ENABLE_DIALECT_CPP${dialect} "Generate C++${dialect} build configurations." ${default_value} ) endif() if (CUB_ENABLE_DIALECT_CPP${dialect}) math(EXPR num_dialects_enabled "${num_dialects_enabled} + 1") endif() endforeach() # Ensure that only one C++ dialect is enabled when dialect info is hidden: if ((NOT CUB_ENABLE_CPP_DIALECT_IN_NAMES) AND (NOT num_dialects_enabled EQUAL 1)) message(FATAL_ERROR "Only one CUB_ENABLE_DIALECT_CPP## option allowed when " "CUB_ENABLE_CPP_DIALECT_IN_NAMES is OFF." ) endif() # CMake fixed C++17 support for NVCC + MSVC targets in 3.18.3: if (CUB_ENABLE_DIALECT_CPP17) cmake_minimum_required(VERSION 3.18.3) endif() # Supported versions of MSVC do not distinguish between C++11 and C++14. # Warn the user that they may be generating a ton of redundant targets. if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}" AND CUB_ENABLE_DIALECT_CPP11) message(WARNING "Supported versions of MSVC (2017+) do not distinguish between C++11 " "and C++14. The requested C++11 targets will be built with C++14." ) endif() # Generic config flags: macro(add_flag_option flag docstring default) set(cub_opt "CUB_${flag}") if (CUB_IN_THRUST) set(thrust_opt "THRUST_${flag}") # Use thrust's settings: set(${cub_opt} ${${thrust_opt}}) else() option(${cub_opt} "${docstring}" "${default}") mark_as_advanced(${cub_opt}) endif() endmacro() add_flag_option(IGNORE_DEPRECATED_CPP_DIALECT "Don't warn about any deprecated C++ standards and compilers." OFF) add_flag_option(IGNORE_DEPRECATED_CPP_11 "Don't warn about deprecated C++11." OFF) add_flag_option(IGNORE_DEPRECATED_COMPILER "Don't warn about deprecated compilers." OFF) # Build cub.compiler_interface with warning flags, etc # This must be called before _cub_add_target_to_target_list. cub_build_compiler_targets() # Set up the CUB target while testing out our find_package scripts. find_package(CUB REQUIRED CONFIG NO_DEFAULT_PATH # Only check the explicit path in HINTS: HINTS "${CUB_SOURCE_DIR}" ) # TODO # Some of the iterators and unittests depend on thrust. We should break the # cyclical dependency by migrating CUB's Thrust bits into Thrust. find_package(Thrust ${CUB_VERSION} EXACT CONFIG HINTS "../../" # Check if we are in thrust/dependencies/cub ) if (Thrust_FOUND) thrust_set_CUB_target(CUB::CUB) thrust_create_target(cub.thrust HOST CPP DEVICE CUDA) else() message(STATUS "Thrust was not found. Set CMake variable 'Thrust_DIR' to the " "thrust-config.cmake file of a Thrust ${CUB_VERSION} installation to " "enable additional testing." ) endif() # Build CUB_TARGETS foreach(dialect IN LISTS CUB_CPP_DIALECT_OPTIONS) _cub_is_config_valid(config_valid ${dialect}) if (config_valid) if (NOT CUB_ENABLE_CPP_DIALECT_IN_NAMES) set(prefix "cub") else() set(prefix "cub.cpp${dialect}") endif() set(target_name "${prefix}") add_library(${target_name} INTERFACE) # Set configuration metadata for this cub interface target: _cub_add_target_to_target_list(${target_name} ${dialect} ${prefix}) endif() endforeach() # dialects list(LENGTH CUB_TARGETS count) message(STATUS "${count} unique cub.dialect configurations generated") # Top level meta-target. Makes it easier to just build CUB targets when # building both CUB and Thrust. Add all project files here so IDEs will be # aware of them. This will not generate build rules. file(GLOB_RECURSE all_sources RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "${CUB_SOURCE_DIR}/cub/*.cuh" ) # Add a cub.all target that builds all configs. if (NOT CUB_ENABLE_CPP_DIALECT_IN_NAMES) add_custom_target(cub.all) else() add_custom_target(cub.all SOURCES ${all_sources}) # Create meta targets for each config: foreach(cub_target IN LISTS CUB_TARGETS) cub_get_target_property(config_prefix ${cub_target} PREFIX) add_custom_target(${config_prefix}.all) add_dependencies(cub.all ${config_prefix}.all) endforeach() endif() endfunction()