File size: 9,064 Bytes
be11144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# 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(<prop_var> <target_name> <prop>)
#   - Checks the ${prop} target property on CUB 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 CUB target.
#   - <prop> 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(<target_name>)
#   - Defines ${target_name}_${prop} in the caller's scope, for `prop` in:
#     {DIALECT, PREFIX}. See above for details.
#
# cub_clone_target_properties(<dst_target> <src_target>)
#   - 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()
  endif()
endfunction()

# Get a cub property from a target and store it in var_name
# cub_get_target_property(<var_name> <target_name> [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:
  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()
  endforeach()

  # CMake added C++17 support for CUDA targets in 3.18:
  if (CUB_ENABLE_DIALECT_CPP17)
    cmake_minimum_required(VERSION 3.18)
  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)
      set(prefix "cub.cpp${dialect}")
      string(TOLOWER "${prefix}" prefix)
      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_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()
endfunction()