Skip to content

Commit

Permalink
Enable multiconfig builds.
Browse files Browse the repository at this point in the history
Fixes NVIDIA#1159.

Also fixes or works around these issues:
- WAR NVIDIA#1167: Disable arches 53, 62, 72 by default.
- Fixes NVIDIA#1168: Set RUN_SERIAL on OpenMP tests.
- WAR ccache/ccache#598:
  nvcc flags `s/-Werror all-warnings/-Xcudafe --promote_warnings/g`
- WAR NVIDIA#1174: remove warning promotion from tbb.cuda targets.
- WAR NVIDIA#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.
  • Loading branch information
alliepiper committed Jun 8, 2020
1 parent 311f3d8 commit c678e37
Show file tree
Hide file tree
Showing 15 changed files with 1,037 additions and 620 deletions.
654 changes: 37 additions & 617 deletions CMakeLists.txt

Large diffs are not rendered by default.

146 changes: 146 additions & 0 deletions cmake/ThrustBuildCompilerTargets.cmake
Original file line number Diff line number Diff line change
@@ -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 "'<anonymous>' 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
$<$<COMPILE_LANGUAGE:CXX>:${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:
$<$<AND:$<COMPILE_LANGUAGE:CUDA>,$<CUDA_COMPILER_ID:NVIDIA>>:-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...
$<$<AND:$<COMPILE_LANGUAGE:CUDA>,$<CUDA_COMPILER_ID:NVIDIA>>:-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
$<$<AND:$<COMPILE_LANGUAGE:CUDA>,$<CUDA_COMPILER_ID:NVIDIA>>:-Xcudafe=--promote_warnings>
)
endfunction()
238 changes: 238 additions & 0 deletions cmake/ThrustBuildTargetList.cmake
Original file line number Diff line number Diff line change
@@ -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(<prop_var> <target_name> <prop>)
# - Checks the ${prop} target property on thrust target ${target_name}
# and sets the ${prop_var} variable in the caller's scope.
# - <prop_var> is any valid cmake identifier.
# - <target_name> is the name of a thrust target.
# - <prop> 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(<target_name>)
# - Defines ${target_name}_${prop} in the caller's scope, for `prop` in:
# HOST, DEVICE, DIALECT, PREFIX. See above for details.
#
# thrust_clone_target_properties(<dst_target> <src_target>)
# - 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(<var_name> <target_name> [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()
Loading

0 comments on commit c678e37

Please sign in to comment.