From c678e3787a3a93380e14d5085c81e7cebb15caa8 Mon Sep 17 00:00:00 2001 From: Allison Vacanti Date: Thu, 21 May 2020 20:57:38 -0400 Subject: [PATCH] Enable multiconfig builds. Fixes #1159. Also fixes or works around these issues: - WAR #1167: Disable arches 53, 62, 72 by default. - Fixes #1168: Set RUN_SERIAL on OpenMP tests. - WAR ccache/ccache#598: nvcc flags `s/-Werror all-warnings/-Xcudafe --promote_warnings/g` - WAR #1174: remove warning promotion from tbb.cuda targets. - WAR #976: Add options to enable/disable tests, examples, header_tests: - THRUST_ENABLE_TESTING - THRUST_ENABLE_EXAMPLES - THRUST_ENABLE_HEADER_TESTING Summary: - Bump CMake to 3.15 - Needed for CUDA_COMPILER_ID generator expression. - Removed workarounds for older CMake versions. - Removed warning flag specific to for C++98. - Dialects are now configured through target properties. Add new THRUST_CPP_DIALECT option for single config mode, and remove logic that modified CMAKE_CXX_STANDARD and CMAKE_CUDA_STANDARD. - Move testing related CMake code to `testing/CMakeLists.txt` - Move example related CMake code to `examples/CMakeLists.txt` - Move header testing related CMake code to `cmake/ThrustHeaderTesting.cmake` - Move CUDA configuration logic to `cmake/ThrustCUDAConfig.cmake`. - Explicitly `include(cmake/*.cmake)` files rather than searching CMAKE_MODULE_PATH -- we only want to use the ones in the repo. - Added ThrustMultiConfig.cmake - Handle MultiConfig (and single config) logic. - Added ThrustBuildTargetList.cmake - Builds the THRUST_TARGETS list, which contains one interface target for each enabled host/device/dialect configuration. - Added ThrustBuildCompilerTargets.cmake - Move warning flag, etc setup into it, bind compile interfaces to targets instead of global variables. - Renamed common_variables.cmake to ThrustCommonVariables.cmake - Removed THRUST_TREAT_FILE_AS_CXX - This worked by setting a cmake SOURCE_FILE property, which no longer works since multiconfig may build the same source file with both CXX and CUDA. - Instead, the `.cu` files are wrapped in a `.cpp` file that does nothing but include the `.cu` file. The `.cpp` files are then added to the CXX targets as sources. - See `cmake/ThrustUtilities.cmake` for implementation. - Fix bug in thrust-config.cmake where an internal var was not cached as expected. --- CMakeLists.txt | 654 ++----------------------- cmake/ThrustBuildCompilerTargets.cmake | 146 ++++++ cmake/ThrustBuildTargetList.cmake | 238 +++++++++ cmake/ThrustCUDAConfig.cmake | 92 ++++ cmake/ThrustCommonVariables.cmake | 1 + cmake/ThrustHeaderTesting.cmake | 119 +++++ cmake/ThrustMultiConfig.cmake | 110 +++++ cmake/ThrustUtilities.cmake | 12 + cmake/common_variables.cmake | 1 - cmake/header_test.in | 2 +- cmake/run_example.cmake | 2 +- cmake/wrap_source_file.cpp.in | 1 + examples/CMakeLists.txt | 106 ++++ testing/CMakeLists.txt | 170 +++++++ thrust/cmake/thrust-config.cmake | 3 + 15 files changed, 1037 insertions(+), 620 deletions(-) create mode 100644 cmake/ThrustBuildCompilerTargets.cmake create mode 100644 cmake/ThrustBuildTargetList.cmake create mode 100644 cmake/ThrustCUDAConfig.cmake create mode 100644 cmake/ThrustCommonVariables.cmake create mode 100644 cmake/ThrustHeaderTesting.cmake create mode 100644 cmake/ThrustMultiConfig.cmake create mode 100644 cmake/ThrustUtilities.cmake delete mode 100644 cmake/common_variables.cmake create mode 100644 cmake/wrap_source_file.cpp.in create mode 100644 examples/CMakeLists.txt create mode 100644 testing/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index a4f1cf0985..d84f0cb665 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,16 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) project(Thrust NONE) -set(THRUST_SOURCE "${CMAKE_SOURCE_DIR}") -include(cmake/common_variables.cmake) +include(cmake/AppendOptionIfAvailable.cmake) +include(cmake/ThrustBuildCompilerTargets.cmake) +include(cmake/ThrustBuildTargetList.cmake) +include(cmake/ThrustCommonVariables.cmake) +include(cmake/ThrustMultiConfig.cmake) +include(cmake/ThrustUtilities.cmake) + +# Add cache string options for CMAKE_BUILD_TYPE and default to RelWithDebInfo. if ("" STREQUAL "${CMAKE_BUILD_TYPE}") set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build." FORCE) @@ -14,19 +20,9 @@ if ("" STREQUAL "${CMAKE_BUILD_TYPE}") ) endif () -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) - set(CMAKE_CONFIGURE_DEPENDS CONFIGURE_DEPENDS) -endif () - -list(INSERT CMAKE_MODULE_PATH 0 "${PROJECT_SOURCE_DIR}/cmake") -include(AppendOptionIfAvailable) - -# Please note this also sets the default for the CUDA C++ version; see the comment below. -set(CMAKE_CXX_STANDARD 14 CACHE STRING "The C++ version to be used.") +# Disable compiler extensions: set(CMAKE_CXX_EXTENSIONS OFF) -message(STATUS "C++ Standard version: ${CMAKE_CXX_STANDARD}") - # Temporary hacks to make Feta work; this requires you to define # `CMAKE_CUDA_COMPILER_ID=Feta` and `CMAKE_CUDA_COMPILER_FORCED`. if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") @@ -55,6 +51,8 @@ if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") " ${CMAKE_CUDA_FLAGS} -o ") endif () +# This must appear after any changes to CMAKE_CXX_COMPILER or else CMake will +# delete the cache and reconfigure from scratch. enable_language(CXX) # We don't set CMAKE_CUDA_HOST_COMPILER for Feta; if we do, CMake tries to @@ -71,129 +69,18 @@ if (NOT "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}") endif () -set(THRUST_TARGET_FLAGS) -macro(add_flag_option flag docstring default) - set(opt "THRUST_${flag}") - option(${opt} "${docstring}" "${default}") - mark_as_advanced(${opt}) - if (${${opt}}) - list(APPEND THRUST_TARGET_FLAGS ${flag}) - 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) -add_flag_option(IGNORE_CUB_VERSION_CHECK "Don't warn about mismatched CUB versions." OFF) - -# Use our find_package config to assemble the Thrust library components we need: -find_package(Thrust REQUIRED CONFIG - NO_DEFAULT_PATH # Only check the explicit HINTS below: - HINTS - "${CMAKE_CURRENT_LIST_DIR}" -) -thrust_create_target(Thrust FROM_OPTIONS ${THRUST_TARGET_FLAGS}) -thrust_debug_target(Thrust "${THRUST_VERSION}") +thrust_configure_multiconfig() +thrust_build_target_list() thrust_update_system_found_flags() -message(STATUS "CPP system found? ${THRUST_CPP_FOUND}") +message(STATUS "CPP system found? ${THRUST_CPP_FOUND}") message(STATUS "CUDA system found? ${THRUST_CUDA_FOUND}") -message(STATUS "TBB system found? ${THRUST_TBB_FOUND}") -message(STATUS "OMP system found? ${THRUST_OMP_FOUND}") - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - enable_language(CUDA) - - # Force CUDA C++ standard to be the same as the C++ standard used. - # - # Now, CMake is unaligned with reality on standard versions: https://gitlab.kitware.com/cmake/cmake/issues/18597 - # which means that using standard CMake methods, it's impossible to actually sync the CXX and CUDA versions for pre-11 - # versions of C++; CUDA accepts 98 but translates that to 03, while CXX doesn't accept 03 (and doesn't translate that to 03). - # In case this gives You, dear user, any trouble, please escalate the above CMake bug, so we can support reality properly. - if (DEFINED CMAKE_CUDA_STANDARD) - message(WARNING "You've set CMAKE_CUDA_STANDARD; please note that this variable is ignored, and CMAKE_CXX_STANDARD" - " is used as the C++ standard version for both C++ and CUDA.") - endif() - unset(CMAKE_CUDA_STANDARD CACHE) - set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD}) +message(STATUS "TBB system found? ${THRUST_TBB_FOUND}") +message(STATUS "OMP system found? ${THRUST_OMP_FOUND}") - set(THRUST_HIGHEST_COMPUTE_ARCH 75) - set(THRUST_KNOWN_COMPUTE_ARCHS 30 32 35 50 52 53 60 61 62 70 72 75) - - set(OPTION_INIT OFF) - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set(OPTION_INIT ON) - endif () - option(THRUST_DISABLE_ARCH_BY_DEFAULT "If ON, then all CUDA architectures are disabled on the initial CMake run." - ${OPTION_INIT}) - - set(OPTION_INIT ON) - if (THRUST_DISABLE_ARCH_BY_DEFAULT) - set(OPTION_INIT OFF) - endif () - - if (NOT ${THRUST_HIGHEST_COMPUTE_ARCH} IN_LIST THRUST_KNOWN_COMPUTE_ARCHS) - message(FATAL_ERROR "When changing the highest compute version, don't forget to add it to the list!") - endif () - - set(NUMBER_OF_ARCHS_ENABLED 0) - foreach (COMPUTE_ARCH IN LISTS THRUST_KNOWN_COMPUTE_ARCHS) - option(THRUST_ENABLE_COMPUTE_${COMPUTE_ARCH} "Enable code generation for tests for sm_${COMPUTE_ARCH}" ${OPTION_INIT}) - if (THRUST_ENABLE_COMPUTE_${COMPUTE_ARCH}) - math(EXPR NUMBER_OF_ARCHS_ENABLED "${NUMBER_OF_ARCHS_ENABLED}+1") - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - if (NOT ${NUMBER_OF_ARCHS_ENABLED} EQUAL 1) - message(FATAL_ERROR "Feta does not support compilation for multiple device architectures at once.") - endif () - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gpu=cc${COMPUTE_ARCH}") - else () - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode arch=compute_${COMPUTE_ARCH},code=sm_${COMPUTE_ARCH}") - endif () - set(COMPUTE_MESSAGE "${COMPUTE_MESSAGE} sm_${COMPUTE_ARCH}") - endif () - endforeach () - - if (NOT "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - option(THRUST_ENABLE_COMPUTE_FUTURE "Enable code generation for tests for compute_${THRUST_HIGHEST_COMPUTE_ARCH}" ${OPTION_INIT}) - if (THRUST_ENABLE_COMPUTE_FUTURE) - set(CMAKE_CUDA_FLAGS - "${CMAKE_CUDA_FLAGS} -gencode arch=compute_${THRUST_HIGHEST_COMPUTE_ARCH},code=compute_${THRUST_HIGHEST_COMPUTE_ARCH}") - set(COMPUTE_MESSAGE "${COMPUTE_MESSAGE} compute_${THRUST_HIGHEST_COMPUTE_ARCH}") - endif () - endif () - - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - # Today: - # * NVCC accepts CUDA C++ in .cu files but not .cpp files. - # * Feta accepts CUDA C++ in .cpp files but not .cu files. - # TODO: This won't be necessary in the future. - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -cppsuffix=cu") - set(THRUST_TREAT_FILE_AS_CXX "") - endif () - - # RDC is off by default in NVCC and on by default in Feta. Turning off RDC - # isn't currently supported by Feta. So, we default to RDC off for NVCC and - # RDC on for Feta. - set(OPTION_INIT OFF) - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set(OPTION_INIT ON) - endif () - - option(THRUST_ENABLE_TESTS_WITH_RDC - "Build all Thrust tests with RDC; tests that require RDC are not affected by this option." - ${OPTION_INIT}) - - option(THRUST_ENABLE_EXAMPLES_WITH_RDC - "Build all Thrust examples with RDC; examples which require RDC are not affected by this option." - ${OPTION_INIT}) - - message("-- Enabled CUDA architectures:${COMPUTE_MESSAGE}") -endif () - -if ("TBB" STREQUAL "${THRUST_DEVICE_SYSTEM}") - # There's a ton of these in the TBB backend, even though the code is correct. - # TODO: silence these warnings in code instead - append_option_if_available("-Wno-unused-parameter" THRUST_CXX_WARNINGS) -endif () +if (THRUST_CUDA_FOUND) + include(cmake/ThrustCUDAConfig.cmake) +endif() if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.00) @@ -207,491 +94,24 @@ if ("GNU" STREQUAL "${CMAKE_CXX_COMPILER_ID}") endif () endif () -if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}") - # TODO Enable /Wall - append_option_if_available("/WX" THRUST_CXX_WARNINGS) - - # Disabled loss-of-data conversion warnings. - # TODO Re-enable. - append_option_if_available("/wd4244" THRUST_CXX_WARNINGS) - append_option_if_available("/wd4267" THRUST_CXX_WARNINGS) - - # Suppress numeric conversion-to-bool warnings. - # TODO Re-enable. - append_option_if_available("/wd4800" THRUST_CXX_WARNINGS) - - # Disable warning about applying unary operator- to unsigned type. - append_option_if_available("/wd4146" THRUST_CXX_WARNINGS) - - # 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" THRUST_CXX_WARNINGS) - - # Some of the async tests require /bigobj to fit all their sections into the - # object files: - append_option_if_available("/bigobj" THRUST_CXX_WARNINGS) - - # "Oh right, this is Visual Studio." - add_compile_definitions("NOMINMAX") - - set(THRUST_TREAT_FILE_AS_CXX "/TP") -else () - append_option_if_available("-Werror" THRUST_CXX_WARNINGS) - append_option_if_available("-Wall" THRUST_CXX_WARNINGS) - append_option_if_available("-Wextra" THRUST_CXX_WARNINGS) - append_option_if_available("-Winit-self" THRUST_CXX_WARNINGS) - append_option_if_available("-Woverloaded-virtual" THRUST_CXX_WARNINGS) - append_option_if_available("-Wcast-qual" THRUST_CXX_WARNINGS) - append_option_if_available("-Wno-cast-align" THRUST_CXX_WARNINGS) - append_option_if_available("-Wno-long-long" THRUST_CXX_WARNINGS) - append_option_if_available("-Wno-variadic-macros" THRUST_CXX_WARNINGS) - append_option_if_available("-Wno-unused-function" THRUST_CXX_WARNINGS) - append_option_if_available("-Wno-unused-variable" THRUST_CXX_WARNINGS) - - set(THRUST_TREAT_FILE_AS_CXX "-x c++") -endif () - -if ("GNU" STREQUAL "${CMAKE_CXX_COMPILER_ID}") - if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5) - # In GCC 4.4, the CUDA backend's kernel launch templates cause - # impossible-to-decipher "'' is used uninitialized in this - # function" warnings, so we disable uninitialized variable warnings. - append_option_if_available("-Wno-uninitialized" THRUST_CXX_WARNINGS) - endif () - - if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.5) - # This isn't available until GCC 4.3, and misfires on TMP code until - # GCC 4.5. - append_option_if_available("-Wlogical-op" THRUST_CXX_WARNINGS) - endif () - - 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" THRUST_CXX_WARNINGS) - endif () - - if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1 AND CMAKE_CXX_STANDARD EQUAL 98) - # thrust::complex can't really be made trivially copyable in pre-11. - # Disable a warning about a non-trivially-copyable type being memmoved that was added to GCC 8. - append_option_if_available("-Wno-class-memaccess" THRUST_CXX_WARNINGS) - endif () -endif () - -if (("Clang" STREQUAL "${CMAKE_CXX_COMPILER_ID}") OR - ("XL" STREQUAL "${CMAKE_CXX_COMPILER_ID}")) - # xlC and Clang warn about unused parameters in uninstantiated templates. - # This causes xlC to choke on the OMP backend, which is mostly #ifdef'd out - # (and thus has unused parameters) when you aren't using it. - append_option_if_available("-Wno-unused-parameters" THRUST_CXX_WARNINGS) -endif () - -if ("Clang" STREQUAL "${CMAKE_CXX_COMPILER_ID}") - # -Wunneeded-internal-declaration misfires in the unit test framework - # on older versions of Clang. - append_option_if_available("-Wno-unneeded-internal-declaration" THRUST_CXX_WARNINGS) -endif () - -foreach (CXX_OPTION IN LISTS THRUST_CXX_WARNINGS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_OPTION}") -endforeach () - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - if ("NVIDIA" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - foreach (CXX_OPTION IN LISTS THRUST_CXX_WARNINGS) - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=${CXX_OPTION}") - endforeach () - set(CMAKE_CUDA_FLAGS - "${CMAKE_CUDA_FLAGS} -Werror all-warnings -Xcudafe --display_error_number") - endif () -endif () - -# For every public header, build a translation unit containing `#include
` -# to let the compiler try to figure out warnings in that header if it is not otherwise -# included in tests, and also to verify if the headers are modular enough. -# .inl files are not globbed for, because they are not supposed to be used as public -# entrypoints. -list(APPEND THRUST_HEADER_GLOBS thrust/*.h) -list(APPEND THRUST_HEADER_EXCLUDE_SYSTEMS_GLOBS thrust/system/*/*) - -string(TOLOWER ${THRUST_HOST_SYSTEM} THRUST_HOST_SYSTEM_LOWERCASE) -list(APPEND THRUST_HEADER_SYSTEMS_GLOBS thrust/system/${THRUST_HOST_SYSTEM_LOWERCASE}/*) - -string(TOLOWER ${THRUST_DEVICE_SYSTEM} THRUST_DEVICE_SYSTEM_LOWERCASE) -list(APPEND THRUST_HEADER_SYSTEMS_GLOBS thrust/system/${THRUST_DEVICE_SYSTEM_LOWERCASE}/*) - -list(APPEND THRUST_HEADER_EXCLUDE_DETAILS_GLOBS thrust/detail/*) -list(APPEND THRUST_HEADER_EXCLUDE_DETAILS_GLOBS thrust/*/detail/*) -list(APPEND THRUST_HEADER_EXCLUDE_DETAILS_GLOBS thrust/*/*/detail/*) - -# Get all .h files... -file( - GLOB_RECURSE THRUST_HEADERS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_GLOBS} -) - -# ...then remove all system specific headers... -file( - GLOB_RECURSE THRUST_HEADER_EXCLUDE_SYSTEMS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_EXCLUDE_SYSTEMS_GLOBS} -) -list(REMOVE_ITEM THRUST_HEADERS ${THRUST_HEADER_EXCLUDE_SYSTEMS}) - -# ...then add all headers specific to the selected host and device systems back again... -file( - GLOB_RECURSE THRUST_SYSTEMS_HEADERS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_SYSTEMS_GLOBS} -) -list(APPEND THRUST_HEADERS ${THRUST_SYSTEMS_HEADERS}) - -# ...and remove all the detail headers (also removing the detail headers from the selected systems). -file( - GLOB_RECURSE THRUST_HEADER_EXCLUDE_DETAILS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_EXCLUDE_DETAILS_GLOBS} -) -list(REMOVE_ITEM THRUST_HEADERS ${THRUST_HEADER_EXCLUDE_DETAILS}) - -# List of headers that aren't implemented for all backends, but are implemented for CUDA. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CUDA - async/copy.h - async/for_each.h - async/reduce.h - async/sort.h - async/transform.h - event.h - future.h -) - -# List of headers that aren't implemented for all backends, but are implemented for CPP. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CPP -) - -# List of headers that aren't implemented for all backends, but are implemented for TBB. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_TBB -) - -# List of headers that aren't implemented for all backends, but are implemented for OMP. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_OMP -) - -# List of all partially implemented headers. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS - emptylistguard - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CUDA} - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CPP} - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_TBB} - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_OMP} -) - -list(REMOVE_DUPLICATES THRUST_PARTIALLY_IMPLEMENTED_HEADERS) - -foreach (THRUST_HEADER IN LISTS THRUST_HEADERS) - if ("${THRUST_HEADER}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED_HEADERS) - # This header is partially implemented on _some_ backends... - if (NOT "${THRUST_HEADER}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED_HEADERS_${THRUST_DEVICE_SYSTEM}) - # ...but not on the selected one. - continue() - endif () - endif () - - set(THRUST_HEADER_TEST_EXT .cpp) - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - set(THRUST_HEADER_TEST_EXT .cu) - endif () +option(THRUST_ENABLE_HEADER_TESTING "Test that all public headers compile." "ON") +option(THRUST_ENABLE_TESTING "Build Thrust testing suite." "ON") +option(THRUST_ENABLE_EXAMPLES "Build Thrust examples." "ON") - set(SOURCE_NAME headers/${THRUST_HEADER}${THRUST_HEADER_TEST_EXT}) - configure_file(cmake/header_test.in ${SOURCE_NAME}) +if (THRUST_ENABLE_HEADER_TESTING) + include(cmake/ThrustHeaderTesting.cmake) +endif() - list(APPEND THRUST_HEADER_TEST_SOURCES ${SOURCE_NAME}) -endforeach () - -add_library(header-test OBJECT ${THRUST_HEADER_TEST_SOURCES}) -target_link_libraries(header-test PUBLIC Thrust) - -include(CTest) -enable_testing() - -# Handle tests. - -set(THRUST_TEST_RUN_ARGUMENTS - -DTHRUST_SOURCE=${CMAKE_SOURCE_DIR} - -P "${CMAKE_SOURCE_DIR}/cmake/run_test.cmake") - -list(APPEND THRUST_TESTFRAMEWORK_FILES testing/unittest/testframework.cu) -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TESTFRAMEWORK_FILES testing/unittest/cuda/testframework.cu) -else () - # When CUDA is disabled, explain to CMake that testframework.cu is actually a C++ file. - set_source_files_properties(testing/unittest/testframework.cu - PROPERTIES - LANGUAGE CXX - COMPILE_FLAGS "${THRUST_TREAT_FILE_AS_CXX}") -endif () - -add_library(thrust_testframework STATIC ${THRUST_TESTFRAMEWORK_FILES}) -target_link_libraries(thrust_testframework PUBLIC Thrust) -target_include_directories( - thrust_testframework - PRIVATE ${PROJECT_SOURCE_DIR}/testing -) - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(thrust_testframework - PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF) -endif () - -list(APPEND THRUST_TEST_GLOBS testing/*.cu) -list(APPEND THRUST_TEST_GLOBS testing/*.cpp) - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TEST_GLOBS testing/cuda/*.cu) -elseif ("CPP" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TEST_GLOBS testing/cpp/*.cu) - list(APPEND THRUST_TEST_GLOBS testing/cpp/*.cpp) -elseif ("OMP" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TEST_GLOBS testing/omp/*.cu) - list(APPEND THRUST_TEST_GLOBS testing/omp/*.cpp) -endif () - -file( - GLOB THRUST_TESTS - RELATIVE ${PROJECT_SOURCE_DIR}/testing - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_TEST_GLOBS} -) - -# List of tests that aren't implemented for all backends, but are implemented for CUDA. -set(THRUST_PARTIALLY_IMPLEMENTED_CUDA - async_copy - async_for_each - async_reduce - async_reduce_into - async_sort - async_transform - event - future -) - -# List of tests that aren't implemented for all backends, but are implemented for CPP. -set(THRUST_PARTIALLY_IMPLEMENTED_CPP -) - -# List of tests that aren't implemented for all backends, but are implemented for TBB. -set(THRUST_PARTIALLY_IMPLEMENTED_TBB -) - -# List of tests that aren't implemented for all backends, but are implemented for OMP. -set(THRUST_PARTIALLY_IMPLEMENTED_OMP -) - -# List of all partially implemented tests. -set(THRUST_PARTIALLY_IMPLEMENTED - ${THRUST_PARTIALLY_IMPLEMENTED_CUDA} - ${THRUST_PARTIALLY_IMPLEMENTED_CPP} - ${THRUST_PARTIALLY_IMPLEMENTED_TBB} - ${THRUST_PARTIALLY_IMPLEMENTED_OMP} -) - -list(REMOVE_DUPLICATES THRUST_PARTIALLY_IMPLEMENTED) - -# Handle tests. - -foreach (THRUST_TEST_SOURCE IN LISTS THRUST_TESTS) - # TODO: Per-test flags. - - set(THRUST_TEST_CREATION_ADDITIONAL) - set(THRUST_TEST_ADD_TO_CTEST ON) - - get_filename_component(THRUST_TEST_CATEGORY ${THRUST_TEST_SOURCE} DIRECTORY) - if (NOT ("" STREQUAL "${THRUST_TEST_CATEGORY}")) - set(THRUST_TEST_CATEGORY "${THRUST_TEST_CATEGORY}.") - endif () - - get_filename_component(THRUST_TEST_NAME ${THRUST_TEST_SOURCE} NAME_WE) - - if ("${THRUST_TEST_NAME}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED) - # This test is partially implemented on _some_ backends... - if (NOT "${THRUST_TEST_NAME}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED_${THRUST_DEVICE_SYSTEM}) - # ...but not on the selected one. - set(THRUST_TEST_CREATION_ADDITIONAL EXCLUDE_FROM_ALL) - set(THRUST_TEST_ADD_TO_CTEST OFF) - endif () - endif () - - set(THRUST_TEST "thrust.test.${THRUST_TEST_CATEGORY}${THRUST_TEST_NAME}") - - if (NOT "CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - # Test files are generally .cu; if CUDA is not enabled, CMake doesn't know what to - # do with them. But since they are pretty much just C++, we can compile them with - # non-nvcc C++ compilers... but we need to tell CMake that they are, in fact, just C++. - set_source_files_properties(${PROJECT_SOURCE_DIR}/testing/${THRUST_TEST_SOURCE} - PROPERTIES - LANGUAGE CXX - COMPILE_FLAGS "${THRUST_TREAT_FILE_AS_CXX}") - endif () - - add_executable( - ${THRUST_TEST} - ${THRUST_TEST_CREATION_ADDITIONAL} - # THRUST_TEST_CREATION_ADDITIONAL is actually a CMake keyword (sometimes). - ${PROJECT_SOURCE_DIR}/testing/${THRUST_TEST_SOURCE} - ) - - target_include_directories( - ${THRUST_TEST} - PRIVATE ${PROJECT_SOURCE_DIR}/testing - ) - - target_link_libraries(${THRUST_TEST} thrust_testframework) - - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_TEST} - PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF) - endif () - - # All the CUDA-specific ones will test device-side launch (aka calling parallel - # algorithms from device code), which requires the CUDA device-side runtime, - # which requires RDC, so these always need to be built with RDC. - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND - (THRUST_ENABLE_TESTS_WITH_RDC OR "${THRUST_TEST_CATEGORY}" STREQUAL "cuda")) - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_TEST} - PROPERTIES COMPILE_FLAGS "-gpu=rdc") - else () - set_target_properties(${THRUST_TEST} - PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - endif () - endif () - - if (THRUST_TEST_ADD_TO_CTEST) - add_test(NAME ${THRUST_TEST} - COMMAND ${CMAKE_COMMAND} - -DTHRUST_BINARY=$ - ${THRUST_TEST_RUN_ARGUMENTS}) - endif () -endforeach () - -# Handle examples. - -option(THRUST_EXAMPLE_FILECHECK_PATH "Path to the LLVM FileCheck utility." "") - -set(THRUST_EXAMPLE_FILECHECK_ENABLED OFF) -if (NOT "" STREQUAL "${THRUST_EXAMPLE_FILECHECK_PATH}") - execute_process( - COMMAND "${THRUST_EXAMPLE_FILECHECK_PATH}" "${THRUST_FILECHECK_DATA_PATH}/thrust.sanity.filecheck" - INPUT_FILE "${CMAKE_SOURCE_DIR}/cmake/sanity" - RESULT_VARIABLE THRUST_FILECHECK_RESULT - ) - - if ("0" STREQUAL "${THRUST_FILECHECK_RESULT}") - set(THRUST_EXAMPLE_FILECHECK_ENABLED ON) - message("-- FileCheck enabled: ${THRUST_EXAMPLE_FILECHECK_PATH}") - endif () -endif () - -list(APPEND THRUST_EXAMPLE_GLOBS examples/*.cu) -list(APPEND THRUST_EXAMPLE_GLOBS examples/*.cpp) - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_EXAMPLE_GLOBS examples/cuda/*.cu) -elseif ("OMP" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_EXAMPLE_GLOBS examples/omp/*.cu) - list(APPEND THRUST_EXAMPLE_GLOBS examples/omp/*.cpp) -endif () - -if (CMAKE_VERSION VERSION_LESS 3.12) - file( - GLOB THRUST_EXAMPLES - RELATIVE ${PROJECT_SOURCE_DIR}/examples - ${THRUST_EXAMPLE_GLOBS} - CONFIGURE_DEPENDS - ) -else () - file( - GLOB THRUST_EXAMPLES - RELATIVE ${PROJECT_SOURCE_DIR}/examples - ${THRUST_EXAMPLE_GLOBS} - ) -endif () - -set(THRUST_EXAMPLE_RUN_ARGUMENTS - -DTHRUST_SOURCE=${CMAKE_SOURCE_DIR} - -DTHRUST_FILECHECK_ENABLED=${THRUST_EXAMPLE_FILECHECK_ENABLED} - -DTHRUST_FILECHECK=${THRUST_EXAMPLE_FILECHECK_PATH} - -P "${CMAKE_SOURCE_DIR}/cmake/run_example.cmake") - -foreach (THRUST_EXAMPLE_SOURCE IN LISTS THRUST_EXAMPLES) - # TODO: Per-example flags. - - get_filename_component(THRUST_EXAMPLE_CATEGORY ${THRUST_EXAMPLE_SOURCE} DIRECTORY) - if (NOT ("" STREQUAL "${THRUST_EXAMPLE_CATEGORY}")) - set(THRUST_EXAMPLE_CATEGORY "${THRUST_EXAMPLE_CATEGORY}.") - endif () - - get_filename_component(THRUST_EXAMPLE_NAME ${THRUST_EXAMPLE_SOURCE} NAME_WE) - - set(THRUST_EXAMPLE "thrust.example.${THRUST_EXAMPLE_CATEGORY}${THRUST_EXAMPLE_NAME}") - - if (NOT "CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - # Example files are generally .cu; if CUDA is not enabled, CMake doesn't know what to - # do with them. But since they are pretty much just C++, we can compile them with - # non-nvcc C++ compilers... but we need to tell CMake that they are, in fact, just C++. - set_source_files_properties(${PROJECT_SOURCE_DIR}/examples/${THRUST_EXAMPLE_SOURCE} - PROPERTIES - LANGUAGE CXX - COMPILE_FLAGS "${THRUST_TREAT_FILE_AS_CXX}") - endif () - - add_executable( - ${THRUST_EXAMPLE} - ${PROJECT_SOURCE_DIR}/examples/${THRUST_EXAMPLE_SOURCE} - ) - - target_include_directories( - ${THRUST_EXAMPLE} - PRIVATE ${PROJECT_SOURCE_DIR}/examples - ) - - target_link_libraries(${THRUST_EXAMPLE} Thrust) - - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF) - endif () - - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND THRUST_ENABLE_EXAMPLES_WITH_RDC) - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES COMPILE_FLAGS "-gpu=rdc") - else () - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - endif () - endif () +# Both testing and examples use ctest +if (THRUST_ENABLE_TESTING OR THRUST_ENABLE_EXAMPLES) + include(CTest) + enable_testing() +endif() - if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}") - # Some examples use unsafe APIs (e.g. fopen) that MSVC will complain about - # unless this is set: - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES COMPILE_DEFINITIONS "_CRT_SECURE_NO_WARNINGS") - endif() +if (THRUST_ENABLE_TESTING) + add_subdirectory(testing) +endif() - add_test(NAME ${THRUST_EXAMPLE} - COMMAND ${CMAKE_COMMAND} - -DTHRUST_EXAMPLE=${THRUST_EXAMPLE} - -DTHRUST_BINARY=$ - ${THRUST_EXAMPLE_RUN_ARGUMENTS}) -endforeach () +if (THRUST_ENABLE_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/cmake/ThrustBuildCompilerTargets.cmake b/cmake/ThrustBuildCompilerTargets.cmake new file mode 100644 index 0000000000..394789e4f5 --- /dev/null +++ b/cmake/ThrustBuildCompilerTargets.cmake @@ -0,0 +1,146 @@ +# +# This file defines the `thrust_build_compiler_targets()` function, which +# creates the following interface targets: +# +# thrust.compiler_interface +# - Interface target providing compiler-specific options needed to build +# Thrust's tests, examples, etc. +# +# thrust.promote_cudafe_warnings +# - Interface target that adds warning promotion for NVCC cudafe invocations. +# - Only exists to work around github issue #1174 on tbb.cuda configurations. +# - May be combined with thrust.compiler_interface when #1174 is fully resolved. + +function(thrust_build_compiler_targets) + set(cxx_compile_definitions) + set(cxx_compile_options) + + thrust_update_system_found_flags() + + if (THRUST_TBB_FOUND) + # There's a ton of these in the TBB backend, even though the code is correct. + # TODO: silence these warnings in code instead + append_option_if_available("-Wno-unused-parameter" cxx_compile_options) + endif() + + if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}") + # TODO Enable /Wall + append_option_if_available("/WX" cxx_compile_options) + + # Disabled loss-of-data conversion warnings. + # TODO Re-enable. + append_option_if_available("/wd4244" cxx_compile_options) + append_option_if_available("/wd4267" cxx_compile_options) + + # Suppress numeric conversion-to-bool warnings. + # TODO Re-enable. + append_option_if_available("/wd4800" cxx_compile_options) + + # Disable warning about applying unary operator- to unsigned type. + append_option_if_available("/wd4146" 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) + + # Some of the async tests require /bigobj to fit all their sections into the + # object files: + append_option_if_available("/bigobj" cxx_compile_options) + + # "Oh right, this is Visual Studio." + list(APPEND cxx_compile_definitions "NOMINMAX") + else() + append_option_if_available("-Werror" cxx_compile_options) + append_option_if_available("-Wall" cxx_compile_options) + append_option_if_available("-Wextra" 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("-Wno-cast-align" cxx_compile_options) + append_option_if_available("-Wno-long-long" cxx_compile_options) + append_option_if_available("-Wno-variadic-macros" cxx_compile_options) + append_option_if_available("-Wno-unused-function" cxx_compile_options) + append_option_if_available("-Wno-unused-variable" cxx_compile_options) + endif() + + if ("GNU" STREQUAL "${CMAKE_CXX_COMPILER_ID}") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5) + # In GCC 4.4, the CUDA backend's kernel launch templates cause + # impossible-to-decipher "'' is used uninitialized in this + # function" warnings, so we disable uninitialized variable warnings. + append_option_if_available("-Wno-uninitialized" cxx_compile_options) + endif() + + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.5) + # This isn't available until GCC 4.3, and misfires on TMP code until + # GCC 4.5. + append_option_if_available("-Wlogical-op" cxx_compile_options) + endif() + + 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() + + if (("Clang" STREQUAL "${CMAKE_CXX_COMPILER_ID}") OR + ("XL" STREQUAL "${CMAKE_CXX_COMPILER_ID}")) + # xlC and Clang warn about unused parameters in uninstantiated templates. + # This causes xlC to choke on the OMP backend, which is mostly #ifdef'd out + # (and thus has unused parameters) when you aren't using it. + append_option_if_available("-Wno-unused-parameters" cxx_compile_options) + endif() + + if ("Clang" STREQUAL "${CMAKE_CXX_COMPILER_ID}") + # -Wunneeded-internal-declaration misfires in the unit test framework + # on older versions of Clang. + append_option_if_available("-Wno-unneeded-internal-declaration" cxx_compile_options) + endif() + + if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + # Today: + # * NVCC accepts CUDA C++ in .cu files but not .cpp files. + # * Feta accepts CUDA C++ in .cpp files but not .cu files. + # TODO: This won't be necessary in the future. + list(APPEND cxx_compile_options -cppsuffix=cu) + endif() + + add_library(thrust.compiler_interface INTERFACE) + + foreach (cxx_option IN LISTS cxx_compile_options) + target_compile_options(thrust.compiler_interface INTERFACE + $<$:${cxx_option}> + # Only use -Xcompiler with NVCC, not Feta. + # + # CMake can't split genexs, so this can't be formatted better :( + # This is: + # if (using CUDA and CUDA_COMPILER is NVCC) add -Xcompiler=opt: + $<$,$>:-Xcompiler=${cxx_option}> + ) + endforeach() + + foreach (cxx_definition IN LISTS cxx_compile_definitions) + # Add these for both CUDA and CXX targets: + target_compile_definitions(thrust.compiler_interface INTERFACE + ${cxx_definition} + ) + endforeach() + + # Display warning numbers from nvcc cudafe errors: + target_compile_options(thrust.compiler_interface INTERFACE + # If using CUDA w/ NVCC... + $<$,$>:-Xcudafe=--display_error_number> + ) + + # This is kept separate for Github issue #1174. + add_library(thrust.promote_cudafe_warnings INTERFACE) + target_compile_options(thrust.promote_cudafe_warnings INTERFACE + $<$,$>:-Xcudafe=--promote_warnings> + ) +endfunction() diff --git a/cmake/ThrustBuildTargetList.cmake b/cmake/ThrustBuildTargetList.cmake new file mode 100644 index 0000000000..4bb2bdfdb8 --- /dev/null +++ b/cmake/ThrustBuildTargetList.cmake @@ -0,0 +1,238 @@ +# This file provides utilities for building and working with thrust +# configuration targets. +# +# THRUST_TARGETS +# - Built by the calling the `thrust_build_target_list()` function. +# - Each item is the name of a thrust interface target that is configured for a +# certain combination of host/device/dialect. +# +# thrust_build_target_list() +# - Creates the THRUST_TARGETS list. +# +# The following functions can be used to test/set metadata on a thrust target: +# +# thrust_get_target_property( ) +# - Checks the ${prop} target property on thrust target ${target_name} +# and sets the ${prop_var} variable in the caller's scope. +# - is any valid cmake identifier. +# - is the name of a thrust target. +# - is one of the following: +# - HOST: The host system. Valid values: CPP, OMP, TBB. +# - DEVICE: The device system. Valid values: CUDA, CPP, OMP, TBB. +# - 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. +# +# thrust_get_target_properties() +# - Defines ${target_name}_${prop} in the caller's scope, for `prop` in: +# HOST, DEVICE, DIALECT, PREFIX. See above for details. +# +# thrust_clone_target_properties( ) +# - Set the HOST, DEVICE, 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 thrust target +# to ensure that dialect information is updated correctly, e.g. +# `thrust_clone_target_properties(${my_thrust_test} ${some_thrust_target})` + +define_property(TARGET PROPERTY _THRUST_HOST + BRIEF_DOCS "A target's host system: CPP, TBB, or OMP." + FULL_DOCS "A target's host system: CPP, TBB, or OMP." +) +define_property(TARGET PROPERTY _THRUST_DEVICE + BRIEF_DOCS "A target's device system: CUDA, CPP, TBB, or OMP." + FULL_DOCS "A target's device system: CUDA, CPP, TBB, or OMP." +) +define_property(TARGET PROPERTY _THRUST_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 _THRUST_PREFIX + BRIEF_DOCS "A prefix describing the config, eg. 'thrust.cpp.cuda.cpp14'." + FULL_DOCS "A prefix describing the config, eg. 'thrust.cpp.cuda.cpp14'." +) + +function(thrust_set_target_properties target_name host device dialect prefix) + set_property(TARGET ${target_name} PROPERTY _THRUST_HOST ${host}) + set_property(TARGET ${target_name} PROPERTY _THRUST_DEVICE ${device}) + set_property(TARGET ${target_name} PROPERTY _THRUST_DIALECT ${dialect}) + set_property(TARGET ${target_name} PROPERTY _THRUST_PREFIX ${prefix}) + + get_target_property(type ${target_name} TYPE) + if (NOT ${type} STREQUAL "INTERFACE_LIBRARY") + set_property(TARGET ${target_name} PROPERTY CXX_STANDARD ${dialect}) + set_property(TARGET ${target_name} PROPERTY CUDA_STANDARD ${dialect}) + endif() +endfunction() + +# Get a thrust property from a target and store it in var_name +# thrust_get_target_property( [HOST|DEVICE|DIALECT|PREFIX] +macro(thrust_get_target_property prop_var target_name prop) + get_property(${prop_var} TARGET ${target_name} PROPERTY _THRUST_${prop}) +endmacro() + +# Defines the following string variables in the caller's scope: +# - ${target_name}_HOST +# - ${target_name}_DEVICE +# - ${target_name}_DIALECT +# - ${target_name}_PREFIX +macro(thrust_get_target_properties target_name) + thrust_get_target_property(${target_name}_HOST ${target_name} HOST) + thrust_get_target_property(${target_name}_DEVICE ${target_name} DEVICE) + thrust_get_target_property(${target_name}_DIALECT ${target_name} DIALECT) + thrust_get_target_property(${target_name}_PREFIX ${target_name} PREFIX) +endmacro() + +# Set one target's THRUST_* properties to match another target +function(thrust_clone_target_properties dst_target src_target) + thrust_get_target_properties(${src_target}) + thrust_set_target_properties(${dst_target} + ${${src_target}_HOST} + ${${src_target}_DEVICE} + ${${src_target}_DIALECT} + ${${src_target}_PREFIX} + ) +endfunction() + +# Set ${var_name} to TRUE or FALSE in the caller's scope +function(_thrust_is_config_valid var_name host device dialect) + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_${host} AND + THRUST_MULTICONFIG_ENABLE_SYSTEM_${device} AND + THRUST_MULTICONFIG_ENABLE_DIALECT_CPP${dialect} AND + "${host}_${device}" IN_LIST THRUST_MULTICONFIG_WORKLOAD_${THRUST_MULTICONFIG_WORKLOAD}_CONFIGS) + set(${var_name} TRUE PARENT_SCOPE) + else() + set(${var_name} FALSE PARENT_SCOPE) + endif() +endfunction() + +function(_thrust_init_target_list) + set(THRUST_TARGETS "" CACHE INTERNAL "" FORCE) +endfunction() + +function(_thrust_add_target_to_target_list target_name host device dialect prefix) + thrust_set_target_properties(${target_name} ${host} ${device} ${dialect} ${prefix}) + + target_link_libraries(${target_name} INTERFACE + thrust.compiler_interface + ) + + # Workaround Github issue #1174. cudafe promote TBB header warnings to + # errors, even when they're -isystem includes. + if ((NOT host STREQUAL "TBB") OR (NOT device STREQUAL "CUDA")) + target_link_libraries(${target_name} INTERFACE + thrust.promote_cudafe_warnings + ) + endif() + + set(THRUST_TARGETS ${THRUST_TARGETS} ${target_name} CACHE INTERNAL "" FORCE) + + set(label "${host}.${device}.cpp${dialect}") + string(TOLOWER "${label}" label) + message(STATUS "Enabling configuration: ${label}") +endfunction() + +function(_thrust_build_target_list_multiconfig) + # Find thrust and all of the required systems: + set(req_systems) + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_CUDA) + list(APPEND req_systems CUDA) + endif() + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_CPP) + list(APPEND req_systems CPP) + endif() + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_TBB) + list(APPEND req_systems TBB) + endif() + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_OMP) + list(APPEND req_systems OMP) + endif() + + find_package(Thrust REQUIRED CONFIG + NO_DEFAULT_PATH # Only check the explicit path in HINTS: + HINTS "${Thrust_SOURCE_DIR}" + COMPONENTS ${req_systems} + ) + + # This must be called after backends are loaded but + # before _thrust_add_target_to_target_list. + thrust_build_compiler_targets() + + # Build THRUST_TARGETS + foreach(host IN LISTS THRUST_HOST_SYSTEM_OPTIONS) + foreach(device IN LISTS THRUST_DEVICE_SYSTEM_OPTIONS) + foreach(dialect IN LISTS THRUST_CPP_DIALECT_OPTIONS) + _thrust_is_config_valid(config_valid ${host} ${device} ${dialect}) + if (config_valid) + set(prefix "thrust.${host}.${device}.cpp${dialect}") + string(TOLOWER "${prefix}" prefix) + + # Configure a thrust interface target for this host/device + set(target_name "${prefix}") + thrust_create_target(${target_name} + HOST ${host} + DEVICE ${device} + ${THRUST_TARGET_FLAGS} + ) + + # Set configuration metadata for this thrust interface target: + _thrust_add_target_to_target_list(${target_name} + ${host} ${device} ${dialect} ${prefix} + ) + endif() + endforeach() # dialects + endforeach() # devices + endforeach() # hosts + + list(LENGTH THRUST_TARGETS count) + message(STATUS "${count} unique host.device.dialect configurations generated") +endfunction() + +function(_thrust_build_target_list_singleconfig) + thrust_create_target(thrust FROM_OPTIONS ${THRUST_TARGET_FLAGS}) + thrust_debug_target(thrust "${THRUST_VERSION}") + + set(host ${THRUST_HOST_SYSTEM}) + set(device ${THRUST_DEVICE_SYSTEM}) + set(dialect ${THRUST_CPP_DIALECT}) + set(prefix "thrust") # single config + + # This depends on the backends loaded by thrust_create_target, and must + # be called before _thrust_add_target_to_target_list. + thrust_build_compiler_targets() + + _thrust_add_target_to_target_list(thrust ${host} ${device} ${dialect} ${prefix}) +endfunction() + +# Build a ${THRUST_TARGETS} list containing target names for all +# requested configurations +function(thrust_build_target_list) + # Clear the list of targets: + _thrust_init_target_list() + + # Generic config flags: + set(THRUST_TARGET_FLAGS) + macro(add_flag_option flag docstring default) + set(opt "THRUST_${flag}") + option(${opt} "${docstring}" "${default}") + mark_as_advanced(${opt}) + if (${${opt}}) + list(APPEND THRUST_TARGET_FLAGS ${flag}) + 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) + add_flag_option(IGNORE_CUB_VERSION_CHECK "Don't warn about mismatched CUB versions." OFF) + + if (THRUST_ENABLE_MULTICONFIG) + _thrust_build_target_list_multiconfig() + else() + _thrust_build_target_list_singleconfig() + endif() + + # Create meta targets for each config: + foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + add_custom_target(${config_prefix}.all) + endforeach() +endfunction() diff --git a/cmake/ThrustCUDAConfig.cmake b/cmake/ThrustCUDAConfig.cmake new file mode 100644 index 0000000000..5a68f9aa2d --- /dev/null +++ b/cmake/ThrustCUDAConfig.cmake @@ -0,0 +1,92 @@ +enable_language(CUDA) + +set(THRUST_HIGHEST_COMPUTE_ARCH 75) +set(THRUST_KNOWN_COMPUTE_ARCHS 30 32 35 50 52 53 60 61 62 70 72 75) + +# These archs cause link issues when used with RDC and are disabled by default +# See issue #1167. +set(THRUST_DEFAULT_DISABLE_SM_53 TRUE) +set(THRUST_DEFAULT_DISABLE_SM_62 TRUE) +set(THRUST_DEFAULT_DISABLE_SM_72 TRUE) + +set(OPTION_INIT OFF) +if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set(OPTION_INIT ON) +endif() +option(THRUST_DISABLE_ARCH_BY_DEFAULT + "If ON, then all CUDA architectures are disabled on the initial CMake run." + ${OPTION_INIT} +) + +set(OPTION_INIT ON) +if (THRUST_DISABLE_ARCH_BY_DEFAULT) + set(OPTION_INIT OFF) +endif() + +if (NOT ${THRUST_HIGHEST_COMPUTE_ARCH} IN_LIST THRUST_KNOWN_COMPUTE_ARCHS) + message(FATAL_ERROR + "When changing the highest compute version, don't forget to add it to the list!" + ) +endif() + +set(NUMBER_OF_ARCHS_ENABLED 0) +foreach (COMPUTE_ARCH IN LISTS THRUST_KNOWN_COMPUTE_ARCHS) + if (THRUST_DEFAULT_DISABLE_SM_${COMPUTE_ARCH}) + set(arch_init OFF) + else() + set(arch_init ${OPTION_INIT}) + endif() + option(THRUST_ENABLE_COMPUTE_${COMPUTE_ARCH} + "Enable code generation for tests for sm_${COMPUTE_ARCH}" + ${arch_init} + ) + if (THRUST_ENABLE_COMPUTE_${COMPUTE_ARCH}) + math(EXPR NUMBER_OF_ARCHS_ENABLED "${NUMBER_OF_ARCHS_ENABLED}+1") + if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + if (NOT ${NUMBER_OF_ARCHS_ENABLED} EQUAL 1) + message(FATAL_ERROR + "Feta does not support compilation for multiple device architectures " + "at once." + ) + endif() + set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gpu=cc${COMPUTE_ARCH}") + else() + set(CMAKE_CUDA_FLAGS + "${CMAKE_CUDA_FLAGS} -gencode arch=compute_${COMPUTE_ARCH},code=sm_${COMPUTE_ARCH}" + ) + endif() + set(COMPUTE_MESSAGE "${COMPUTE_MESSAGE} sm_${COMPUTE_ARCH}") + endif() +endforeach() + +if (NOT "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + option(THRUST_ENABLE_COMPUTE_FUTURE + "Enable code generation for tests for compute_${THRUST_HIGHEST_COMPUTE_ARCH}" + ${OPTION_INIT} + ) + if (THRUST_ENABLE_COMPUTE_FUTURE) + set(CMAKE_CUDA_FLAGS + "${CMAKE_CUDA_FLAGS} -gencode arch=compute_${THRUST_HIGHEST_COMPUTE_ARCH},code=compute_${THRUST_HIGHEST_COMPUTE_ARCH}") + set(COMPUTE_MESSAGE "${COMPUTE_MESSAGE} compute_${THRUST_HIGHEST_COMPUTE_ARCH}") + endif() +endif() + +# RDC is off by default in NVCC and on by default in Feta. Turning off RDC +# isn't currently supported by Feta. So, we default to RDC off for NVCC and +# RDC on for Feta. +set(OPTION_INIT OFF) +if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set(OPTION_INIT ON) +endif() + +option(THRUST_ENABLE_TESTS_WITH_RDC + "Build all Thrust tests with RDC; tests that require RDC are not affected by this option." + ${OPTION_INIT} +) + +option(THRUST_ENABLE_EXAMPLES_WITH_RDC + "Build all Thrust examples with RDC; examples which require RDC are not affected by this option." + ${OPTION_INIT} +) + +message(STATUS "Enabled CUDA architectures:${COMPUTE_MESSAGE}") diff --git a/cmake/ThrustCommonVariables.cmake b/cmake/ThrustCommonVariables.cmake new file mode 100644 index 0000000000..cdbff53667 --- /dev/null +++ b/cmake/ThrustCommonVariables.cmake @@ -0,0 +1 @@ +set(THRUST_FILECHECK_DATA_PATH "${Thrust_SOURCE_DIR}/internal/test") diff --git a/cmake/ThrustHeaderTesting.cmake b/cmake/ThrustHeaderTesting.cmake new file mode 100644 index 0000000000..81c6e3174e --- /dev/null +++ b/cmake/ThrustHeaderTesting.cmake @@ -0,0 +1,119 @@ +# For every public header, build a translation unit containing `#include
` +# to let the compiler try to figure out warnings in that header if it is not otherwise +# included in tests, and also to verify if the headers are modular enough. +# .inl files are not globbed for, because they are not supposed to be used as public +# entrypoints. + +foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_host ${thrust_target} HOST) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + + string(TOLOWER "${config_host}" host_lower) + string(TOLOWER "${config_device}" device_lower) + + # GLOB ALL THE THINGS + set(headers_globs thrust/*.h) + set(headers_exclude_systems_globs thrust/system/*/*) + set(headers_systems_globs + thrust/system/${host_lower}/* + thrust/system/${device_lower}/* + ) + set(headers_exclude_details_globs + thrust/detail/* + thrust/*/detail/* + thrust/*/*/detail/* + ) + + # Get all .h files... + file(GLOB_RECURSE headers + RELATIVE "${Thrust_SOURCE_DIR}/thrust" + CONFIGURE_DEPENDS + ${headers_globs} + ) + + # ...then remove all system specific headers... + file(GLOB_RECURSE headers_exclude_systems + RELATIVE "${Thrust_SOURCE_DIR}/thrust" + CONFIGURE_DEPENDS + ${headers_exclude_systems_globs} + ) + list(REMOVE_ITEM headers ${headers_exclude_systems}) + + # ...then add all headers specific to the selected host and device systems back again... + file(GLOB_RECURSE headers_systems + RELATIVE ${Thrust_SOURCE_DIR}/thrust + CONFIGURE_DEPENDS + ${headers_systems_globs} + ) + list(APPEND headers ${headers_systems}) + + # ...and remove all the detail headers (also removing the detail headers from the selected systems). + file(GLOB_RECURSE headers_exclude_details + RELATIVE "${Thrust_SOURCE_DIR}/thrust" + CONFIGURE_DEPENDS + ${headers_exclude_details_globs} + ) + list(REMOVE_ITEM headers ${headers_exclude_details}) + + # List of headers that aren't implemented for all backends, but are implemented for CUDA. + set(partially_implemented_CUDA + async/copy.h + async/for_each.h + async/reduce.h + async/sort.h + async/transform.h + event.h + future.h + ) + + # List of headers that aren't implemented for all backends, but are implemented for CPP. + set(partially_implemented_CPP + ) + + # List of headers that aren't implemented for all backends, but are implemented for TBB. + set(partially_implemented_TBB + ) + + # List of headers that aren't implemented for all backends, but are implemented for OMP. + set(partially_implemented_OMP + ) + + # List of all partially implemented headers. + set(partially_implemented + ${partially_implemented_CUDA} + ${partially_implemented_CPP} + ${partially_implemented_TBB} + ${partially_implemented_OMP} + ) + list(REMOVE_DUPLICATES partially_implemented) + + set(headertest_srcs) + + foreach (header IN LISTS headers) + if ("${header}" IN_LIST partially_implemented) + # This header is partially implemented on _some_ backends... + if (NOT "${header}" IN_LIST partially_implemented_${config_device}) + # ...but not on the selected one. + continue() + endif() + endif() + + set(headertest_src_ext .cpp) + if ("CUDA" STREQUAL "${config_device}") + set(headertest_src_ext .cu) + endif() + + set(headertest_src "headers/${config_prefix}/${header}${headertest_src_ext}") + configure_file("${Thrust_SOURCE_DIR}/cmake/header_test.in" "${headertest_src}") + + list(APPEND headertest_srcs "${headertest_src}") + endforeach() + + set(headertest_target ${config_prefix}.headers) + add_library(${headertest_target} OBJECT ${headertest_srcs}) + target_link_libraries(${headertest_target} PUBLIC ${thrust_target}) + thrust_clone_target_properties(${headertest_target} ${thrust_target}) + + add_dependencies(${config_prefix}.all ${headertest_target}) +endforeach() diff --git a/cmake/ThrustMultiConfig.cmake b/cmake/ThrustMultiConfig.cmake new file mode 100644 index 0000000000..5193ef5e12 --- /dev/null +++ b/cmake/ThrustMultiConfig.cmake @@ -0,0 +1,110 @@ +# This file defines thrust_configure_multiconfig(), which sets up and handles +# the MultiConfig options that allow multiple host/device/dialect configurations +# to be generated from a single thrust build. + +function(thrust_configure_multiconfig) + option(THRUST_ENABLE_MULTICONFIG "Enable multiconfig options for coverage testing." OFF) + + # Dialects: + set(THRUST_CPP_DIALECT_OPTIONS + 11 14 17 + CACHE INTERNAL "C++ dialects supported by Thrust." FORCE + ) + + if (THRUST_ENABLE_MULTICONFIG) + # Handle dialect options: + foreach (dialect IN LISTS THRUST_CPP_DIALECT_OPTIONS) + set(default_value OFF) + if (dialect EQUAL 14) # Default to just 14 on: + set(default_value ON) + endif() + option(THRUST_MULTICONFIG_ENABLE_DIALECT_CPP${dialect} + "Generate C++${dialect} build configurations." + ${default_value} + ) + endforeach() + + # Systems: + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_CPP "Generate build configurations that use CPP." ON) + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_CUDA "Generate build configurations that use CUDA." ON) + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_OMP "Generate build configurations that use OpenMP." OFF) + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_TBB "Generate build configurations that use TBB." OFF) + + # Workload: + # - `SMALL`: [3 configs] Minimal coverage and validation of each device system against the `CPP` host. + # - `MEDIUM`: [6 configs] Cheap extended coverage. + # - `LARGE`: [8 configs] Expensive extended coverage. Include all useful build configurations. + # - `FULL`: [12 configs] The complete cross product of all possible build configurations. + # + # Config | Workloads | Value | Expense | Note + # ---------|-----------|------------|-----------|----------------------------- + # CPP/CUDA | F L M S | Essential | Expensive | Validates CUDA against CPP + # CPP/OMP | F L M S | Essential | Cheap | Validates OMP against CPP + # CPP/TBB | F L M S | Essential | Cheap | Validates TBB against CPP + # CPP/CPP | F L M | Important | Cheap | Tests CPP as device + # OMP/OMP | F L M | Important | Cheap | Tests OMP as host + # TBB/TBB | F L M | Important | Cheap | Tests TBB as host + # TBB/CUDA | F L | Important | Expensive | Validates TBB/CUDA interop + # OMP/CUDA | F L | Important | Expensive | Validates OMP/CUDA interop + # TBB/OMP | F | Not useful | Cheap | Mixes CPU-parallel systems + # OMP/TBB | F | Not useful | Cheap | Mixes CPU-parallel systems + # TBB/CPP | F | Not Useful | Cheap | Parallel host, serial device + # OMP/CPP | F | Not Useful | Cheap | Parallel host, serial device + + set(THRUST_MULTICONFIG_WORKLOAD SMALL CACHE STRING + "Limit host/device configs: SMALL (up to 3 h/d combos per dialect), MEDIUM(6), LARGE(8), FULL(12)" + ) + set_property(CACHE THRUST_MULTICONFIG_WORKLOAD PROPERTY STRINGS + SMALL MEDIUM LARGE FULL + ) + set(THRUST_MULTICONFIG_WORKLOAD_SMALL_CONFIGS + CPP_OMP CPP_TBB CPP_CUDA + CACHE INTERNAL "Host/device combos enabled for SMALL workloads." FORCE + ) + set(THRUST_MULTICONFIG_WORKLOAD_MEDIUM_CONFIGS + ${THRUST_MULTICONFIG_WORKLOAD_SMALL_CONFIGS} + CPP_CPP TBB_TBB OMP_OMP + CACHE INTERNAL "Host/device combos enabled for MEDIUM workloads." FORCE + ) + set(THRUST_MULTICONFIG_WORKLOAD_LARGE_CONFIGS + ${THRUST_MULTICONFIG_WORKLOAD_MEDIUM_CONFIGS} + OMP_CUDA TBB_CUDA + CACHE INTERNAL "Host/device combos enabled for LARGE workloads." FORCE + ) + set(THRUST_MULTICONFIG_WORKLOAD_FULL_CONFIGS + ${THRUST_MULTICONFIG_WORKLOAD_LARGE_CONFIGS} + OMP_CPP TBB_CPP OMP_TBB TBB_OMP + CACHE INTERNAL "Host/device combos enabled for FULL workloads." FORCE + ) + + # Hide the single config options if they exist from a previous run: + if (DEFINED THRUST_HOST_SYSTEM) + set_property(CACHE THRUST_HOST_SYSTEM PROPERTY TYPE INTERNAL) + set_property(CACHE THRUST_DEVICE_SYSTEM PROPERTY TYPE INTERNAL) + endif() + if (DEFINED THRUST_CPP_DIALECT) + set_property(CACHE THRUST_CPP_DIALECT PROPERTY TYPE INTERNAL) + endif() + + else() # Single config: + # Restore system option visibility if these cache options already exist + # from a previous run. + if (DEFINED THRUST_HOST_SYSTEM) + set_property(CACHE THRUST_HOST_SYSTEM PROPERTY TYPE STRING) + set_property(CACHE THRUST_DEVICE_SYSTEM PROPERTY TYPE STRING) + endif() + + set(THRUST_CPP_DIALECT 14 + CACHE STRING "The C++ standard to target: ${THRUST_CPP_DIALECT_OPTIONS}" + ) + set_property(CACHE THRUST_CPP_DIALECT + PROPERTY STRINGS + ${THRUST_CPP_DIALECT_OPTIONS} + ) + + find_package(Thrust REQUIRED CONFIG + NO_DEFAULT_PATH # Only check the explicit path in HINTS: + HINTS "${Thrust_SOURCE_DIR}" + ) + endif() +endfunction() diff --git a/cmake/ThrustUtilities.cmake b/cmake/ThrustUtilities.cmake new file mode 100644 index 0000000000..870b450f95 --- /dev/null +++ b/cmake/ThrustUtilities.cmake @@ -0,0 +1,12 @@ +# Given a cu_file (e.g. foo/bar.cu) relative to CMAKE_CURRENT_SOURCE_DIR +# and a thrust_target, create a cpp file that includes the .cu file, and set +# ${cpp_file_var} in the parent scope to the full path of the new file. The new +# file will be generated in: +# ${CMAKE_CURRENT_BINARY_DIR}//${cu_file}.cpp +function(thrust_wrap_cu_in_cpp cpp_file_var cu_file thrust_target) + thrust_get_target_property(prefix ${thrust_target} PREFIX) + set(wrapped_source_file "${CMAKE_CURRENT_SOURCE_DIR}/${cu_file}") + set(cpp_file "${CMAKE_CURRENT_BINARY_DIR}/${prefix}/${cu_file}.cpp") + configure_file("${Thrust_SOURCE_DIR}/cmake/wrap_source_file.cpp.in" "${cpp_file}") + set(${cpp_file_var} "${cpp_file}" PARENT_SCOPE) +endfunction() diff --git a/cmake/common_variables.cmake b/cmake/common_variables.cmake deleted file mode 100644 index 2ff72eb53f..0000000000 --- a/cmake/common_variables.cmake +++ /dev/null @@ -1 +0,0 @@ -set(THRUST_FILECHECK_DATA_PATH "${THRUST_SOURCE}/internal/test") diff --git a/cmake/header_test.in b/cmake/header_test.in index 4c8ec00f55..c9d7104d48 100644 --- a/cmake/header_test.in +++ b/cmake/header_test.in @@ -1,3 +1,3 @@ #define THRUST_CPP11_REQUIRED_NO_ERROR #define THRUST_MODERN_GCC_REQUIRED_NO_ERROR -#include +#include diff --git a/cmake/run_example.cmake b/cmake/run_example.cmake index d51152d1e2..3085e59053 100644 --- a/cmake/run_example.cmake +++ b/cmake/run_example.cmake @@ -1,4 +1,4 @@ -include("${THRUST_SOURCE}/cmake/common_variables.cmake") +include("${THRUST_SOURCE}/cmake/ThrustCommonVariables.cmake") if (THRUST_FILECHECK_ENABLED) set(DATA_FILE "${THRUST_FILECHECK_DATA_PATH}/${THRUST_EXAMPLE}.filecheck") diff --git a/cmake/wrap_source_file.cpp.in b/cmake/wrap_source_file.cpp.in new file mode 100644 index 0000000000..3015238cc6 --- /dev/null +++ b/cmake/wrap_source_file.cpp.in @@ -0,0 +1 @@ +#include <${wrapped_source_file}> diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000..f8e80601e2 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,106 @@ +option(THRUST_EXAMPLE_FILECHECK_PATH "Path to the LLVM FileCheck utility." "") + +set(THRUST_EXAMPLE_FILECHECK_ENABLED OFF) +if (NOT "" STREQUAL "${THRUST_EXAMPLE_FILECHECK_PATH}") + execute_process( + COMMAND "${THRUST_EXAMPLE_FILECHECK_PATH}" "${THRUST_FILECHECK_DATA_PATH}/thrust.sanity.filecheck" + INPUT_FILE "${Thrust_SOURCE_DIR}/cmake/sanity" + RESULT_VARIABLE THRUST_FILECHECK_RESULT + ) + + if ("0" STREQUAL "${THRUST_FILECHECK_RESULT}") + set(THRUST_EXAMPLE_FILECHECK_ENABLED ON) + message("-- FileCheck enabled: ${THRUST_EXAMPLE_FILECHECK_PATH}") + endif() +endif() + +foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + + set(example_globs + *.cu + *.cpp + ) + + if ("CUDA" STREQUAL "${config_device}") + list(APPEND example_globs cuda/*.cu) + elseif ("CPP" STREQUAL "${config_device}") + list(APPEND example_globs cpp/*.cu cpp/*.cpp) + elseif ("OMP" STREQUAL "${config_device}") + list(APPEND example_globs omp/*.cu omp/*.cpp) + elseif ("TBB" STREQUAL "${config_device}") + list(APPEND example_globs tbb/*.cu tbb/*.cpp) + endif() + + file(GLOB example_srcs + RELATIVE "${CMAKE_CURRENT_LIST_DIR}" + CONFIGURE_DEPENDS + ${example_globs} + ) + + # Meta target that builds all examples for this configuration: + set(config_meta_target ${config_prefix}.examples) + add_custom_target(${config_meta_target}) + add_dependencies(${config_prefix}.all ${config_meta_target}) + + foreach(example_src IN LISTS example_srcs) + get_filename_component(example_subdir "${example_src}" DIRECTORY) + if (example_subdir) + string(APPEND example_subdir ".") + endif() + + get_filename_component(example_name ${example_src} NAME_WE) + set(example_target "${config_prefix}.example.${example_subdir}${example_name}") + + if ("CUDA" STREQUAL "${config_device}") + set(real_example_src "${example_src}") + else() + # Wrap the .cu file in .cpp for non-CUDA backends + thrust_wrap_cu_in_cpp(real_example_src "${example_src}" ${thrust_target}) + endif() + + add_executable(${example_target} ${real_example_src}) + target_link_libraries(${example_target} ${thrust_target}) + target_include_directories(${example_target} PRIVATE "${Thrust_SOURCE_DIR}/examples") + thrust_clone_target_properties(${example_target} ${thrust_target}) + + add_dependencies(${config_meta_target} ${example_target}) + + # Meta target that builds this example in all configurations: + set(example_meta_target thrust.meta.example.${example_subdir}${example_name}) + if (NOT TARGET ${example_meta_target}) + add_custom_target(${example_meta_target}) + endif() + add_dependencies(${example_meta_target} ${example_target}) + + if ("CUDA" STREQUAL "${config_device}" AND + "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${example_target} PROPERTIES + CUDA_RESOLVE_DEVICE_SYMBOLS OFF + ) + endif() + + if ("CUDA" STREQUAL "${config_device}" AND THRUST_ENABLE_EXAMPLES_WITH_RDC) + if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${example_target} PROPERTIES + COMPILE_FLAGS "-gpu=rdc" + ) + else() + set_target_properties(${example_target} PROPERTIES + CUDA_SEPARABLE_COMPILATION ON + ) + endif() + endif() + + add_test(NAME ${example_target} + COMMAND "${CMAKE_COMMAND}" + "-DTHRUST_EXAMPLE=${example_target}" + "-DTHRUST_BINARY=$" + "-DTHRUST_SOURCE=${Thrust_SOURCE_DIR}" + "-DTHRUST_FILECHECK_ENABLED=${THRUST_EXAMPLE_FILECHECK_ENABLED}" + "-DTHRUST_FILECHECK=${THRUST_EXAMPLE_FILECHECK_PATH}" + -P "${Thrust_SOURCE_DIR}/cmake/run_example.cmake" + ) + endforeach() +endforeach() diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt new file mode 100644 index 0000000000..01dd75cff3 --- /dev/null +++ b/testing/CMakeLists.txt @@ -0,0 +1,170 @@ +function(thrust_create_framework_target target_name thrust_target) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + + if ("CUDA" STREQUAL "${config_device}") + set(framework_srcs + "unittest/testframework.cu" + "unittest/cuda/testframework.cu" + ) + else() + # Wrap the cu file inside a .cpp file for non-CUDA builds + thrust_wrap_cu_in_cpp(framework_srcs "unittest/testframework.cu" ${thrust_target}) + endif() + + add_library(${target_name} STATIC ${framework_srcs}) + target_link_libraries(${target_name} PUBLIC ${thrust_target}) + target_include_directories(${target_name} PRIVATE "${Thrust_SOURCE_DIR}/testing") + thrust_clone_target_properties(${target_name} ${thrust_target}) + + if ("CUDA" STREQUAL "${config_device}" AND + "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${target_name} PROPERTIES + CUDA_RESOLVE_DEVICE_SYMBOLS OFF) + endif() +endfunction() + +foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_host ${thrust_target} HOST) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + set(config_systems ${config_host} ${config_device}) + + set(framework_target ${config_prefix}.test.framework) + thrust_create_framework_target(${framework_target} ${thrust_target}) + + set(test_globs + *.cu + *.cpp + ) + + if ("CUDA" STREQUAL "${config_device}") + list(APPEND test_globs cuda/*.cu) + elseif ("CPP" STREQUAL "${config_device}") + list(APPEND test_globs cpp/*.cu cpp/*.cpp) + elseif ("OMP" STREQUAL "${config_device}") + list(APPEND test_globs omp/*.cu omp/*.cpp) + elseif ("TBB" STREQUAL "${config_device}") + list(APPEND test_globs tbb/*.cu tbb/*.cpp) + endif() + + file(GLOB test_srcs + RELATIVE "${CMAKE_CURRENT_LIST_DIR}" + CONFIGURE_DEPENDS + ${test_globs} + ) + + # List of tests that aren't implemented for all backends, but are implemented for CUDA. + set(partially_implemented_CUDA + async_copy + async_for_each + async_reduce + async_reduce_into + async_sort + async_transform + event + future + ) + + # List of tests that aren't implemented for all backends, but are implemented for CPP. + set(partially_implemented_CPP + ) + + # List of tests that aren't implemented for all backends, but are implemented for TBB. + set(partially_implemented_TBB + ) + + # List of tests that aren't implemented for all backends, but are implemented for OMP. + set(partially_implemented_OMP + ) + + # List of all partially implemented tests. + set(partially_implemented + ${partially_implemented_CUDA} + ${partially_implemented_CPP} + ${partially_implemented_TBB} + ${partially_implemented_OMP} + ) + list(REMOVE_DUPLICATES partially_implemented) + + # Meta target that builds all tests for this configuration: + set(config_meta_target ${config_prefix}.tests) + add_custom_target(${config_meta_target}) + add_dependencies(${config_prefix}.all ${config_meta_target}) + + foreach(test_src IN LISTS test_srcs) + get_filename_component(test_name ${test_src} NAME_WE) + if ("${test_name}" IN_LIST partially_implemented) + # This test is partially implemented on _some_ backends... + if (NOT "${test_name}" IN_LIST partially_implemented_${config_device}) + # ...but not on the selected one. + continue() + endif() + endif() + + get_filename_component(test_subdir "${test_src}" DIRECTORY) + set(test_category ${test_subdir}) + if (test_category) + string(APPEND test_category ".") + endif() + + if ("CUDA" STREQUAL "${config_device}") + set(real_test_src "${test_src}") + else() + # Wrap the .cu file in .cpp for non-CUDA backends + thrust_wrap_cu_in_cpp(real_test_src "${test_src}" ${thrust_target}) + endif() + + set(test_target "${config_prefix}.test.${test_category}${test_name}") + + add_executable(${test_target} "${real_test_src}") + target_link_libraries(${test_target} ${framework_target}) + target_include_directories(${test_target} PRIVATE "${Thrust_SOURCE_DIR}/testing") + thrust_clone_target_properties(${test_target} ${thrust_target}) + + add_dependencies(${config_meta_target} ${test_target}) + + # Meta target that builds this tests in all configurations: + set(test_meta_target thrust.meta.test.${test_category}${test_name}) + if (NOT TARGET ${test_meta_target}) + add_custom_target(${test_meta_target}) + endif() + add_dependencies(${test_meta_target} ${test_target}) + + if ("CUDA" STREQUAL "${config_device}" AND + "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${test_target} PROPERTIES + CUDA_RESOLVE_DEVICE_SYMBOLS OFF + ) + endif() + + # All the CUDA-specific ones will test device-side launch (aka calling parallel + # algorithms from device code), which requires the CUDA device-side runtime, + # which requires RDC, so these always need to be built with RDC. + if ("CUDA" STREQUAL "${config_device}" AND + (THRUST_ENABLE_TESTS_WITH_RDC OR "${test_subdir}" STREQUAL "cuda")) + if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${test_target} PROPERTIES + COMPILE_FLAGS "-gpu=rdc" + ) + else() + set_target_properties(${test_target} PROPERTIES + CUDA_SEPARABLE_COMPILATION ON + ) + endif() + endif() + + add_test(NAME ${test_target} + COMMAND "${CMAKE_COMMAND}" + "-DTHRUST_BINARY=$" + "-DTHRUST_SOURCE=${Thrust_SOURCE_DIR}" + -P "${Thrust_SOURCE_DIR}/cmake/run_test.cmake" + ) + + if ("OMP" IN_LIST config_systems) + # Multiple simultaneous OMP processes don't play nicely together and + # runtime skyrockets when multiple OMP tests are run in parallel. Tell + # CTest to force these to run in serial. + set_tests_properties(${test_target} PROPERTIES RUN_SERIAL ON) + endif() + endforeach() +endforeach() diff --git a/thrust/cmake/thrust-config.cmake b/thrust/cmake/thrust-config.cmake index 4795a86f36..06b2435b7c 100644 --- a/thrust/cmake/thrust-config.cmake +++ b/thrust/cmake/thrust-config.cmake @@ -626,6 +626,9 @@ if (NOT TARGET Thrust::Thrust) _thrust_declare_interface_alias(Thrust::Thrust _Thrust_Thrust) # Strip out the 'thrust/cmake/' from '[thrust_include_path]/thrust/cmake/': get_filename_component(_THRUST_INCLUDE_DIR "../.." ABSOLUTE BASE_DIR "${_THRUST_CMAKE_DIR}") + set(_THRUST_INCLUDE_DIR "${_THRUST_INCLUDE_DIR}" + CACHE INTERNAL "Location of thrust headers." + ) target_include_directories(_Thrust_Thrust INTERFACE "${_THRUST_INCLUDE_DIR}") thrust_debug_target(Thrust::Thrust "${THRUST_VERSION}" internal) endif()