VTKmWrappers.cmake 16.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
##============================================================================
##  Copyright (c) Kitware, Inc.
##  All rights reserved.
##  See LICENSE.txt for details.
##  This software is distributed WITHOUT ANY WARRANTY; without even
##  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
##  PURPOSE.  See the above copyright notice for more information.
##
##  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
##  Copyright 2014 UT-Battelle, LLC.
##  Copyright 2014 Los Alamos National Security.
##
##  Under the terms of Contract DE-NA0003525 with NTESS,
##  the U.S. Government retains certain rights in this software.
##
##  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
##  Laboratory (LANL), the U.S. Government retains certain rights in
##  this software.
##============================================================================

include(CMakeParseArguments)

23
include(VTKmDeviceAdapters)
24
include(VTKmCPUVectorization)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#-----------------------------------------------------------------------------
# Utility to build a kit name from the current directory.
function(vtkm_get_kit_name kitvar)
  # Will this always work?  It should if ${CMAKE_CURRENT_SOURCE_DIR} is
  # built from ${VTKm_SOURCE_DIR}.
  string(REPLACE "${VTKm_SOURCE_DIR}/" "" dir_prefix ${CMAKE_CURRENT_SOURCE_DIR})
  string(REPLACE "/" "_" kit "${dir_prefix}")
  set(${kitvar} "${kit}" PARENT_SCOPE)
  # Optional second argument to get dir_prefix.
  if (${ARGC} GREATER 1)
    set(${ARGV1} "${dir_prefix}" PARENT_SCOPE)
  endif (${ARGC} GREATER 1)
endfunction(vtkm_get_kit_name)

#-----------------------------------------------------------------------------
41
function(vtkm_pyexpander_generated_file generated_file_name)
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  # If pyexpander is available, add targets to build and check
  if(PYEXPANDER_FOUND AND PYTHONINTERP_FOUND)
    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}.checked
      COMMAND ${CMAKE_COMMAND}
        -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
        -DPYEXPANDER_COMMAND=${PYEXPANDER_COMMAND}
        -DSOURCE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name}
        -DGENERATED_FILE=${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}
        -P ${VTKm_CMAKE_MODULE_PATH}/VTKmCheckPyexpander.cmake
      MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name}.in
      DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name}
      COMMENT "Checking validity of ${generated_file_name}"
      )
    add_custom_target(check_${generated_file_name} ALL
      DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}.checked
      )
  endif()
60
61
endfunction(vtkm_pyexpander_generated_file)

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#-----------------------------------------------------------------------------
function(vtkm_compile_as_cuda output)
  # We cant use set_source_files_properties(<> PROPERTIES LANGUAGE "CUDA")
  # for the following reasons:
  #
  # 1. As of CMake 3.10 MSBuild cuda language support has a bug where files
  #    aren't passed to nvcc with the explicit '-x cu' flag which will cause
  #    them to be compiled without CUDA actually enabled.
  # 2. If the source file is used by multiple targets(libraries/executable)
  #    they will all see the source file marked as being CUDA. This will cause
  #    tests / examples that reuse sources with different backends to use CUDA
  #    by mistake
  #
  # The result of this is that instead we will use file(GENERATE ) to construct
  # a proxy cu file
  set(_cuda_srcs )
78
79
80
81
82
83
84
85
86
87
88
89
  foreach(_to_be_cuda_file ${ARGN})
    get_filename_component(_fname_ext "${_to_be_cuda_file}" EXT)
    if(_fname_ext STREQUAL ".cu")
      list(APPEND _cuda_srcs "${_to_be_cuda_file}")
    else()
      get_filename_component(_cuda_fname "${_to_be_cuda_file}" NAME_WE)
      get_filename_component(_not_cuda_fullpath "${_to_be_cuda_file}" ABSOLUTE)
      list(APPEND _cuda_srcs "${CMAKE_CURRENT_BINARY_DIR}/${_cuda_fname}.cu")
      file(GENERATE
            OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_cuda_fname}.cu
            CONTENT "#include \"${_not_cuda_fullpath}\"")
    endif()
90
91
92
93
  endforeach()
  set(${output} ${_cuda_srcs} PARENT_SCOPE)
endfunction()

94
95
96
97
#-----------------------------------------------------------------------------
function(vtkm_add_header_build_test name dir_prefix use_cuda)
  set(hfiles ${ARGN})

98
99
100
101
102
103
  set(ext "cxx")
  if(use_cuda)
    set(ext "cu")
  endif()

  set(valid_hfiles )
104
  set(srcs)
105
  foreach (header ${hfiles})
106
    get_source_file_property(cant_be_tested ${header} VTKm_CANT_BE_HEADER_TESTED)
107
    if( cant_be_tested )
108
      get_filename_component(headername ${header} NAME_WE)
109
110
111
112
113
114
115
116
117
118
119
120

      #By using file generate we will not trigger CMake execution when
      #a header gets touched
      file(GENERATE
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/TB_${headername}.${ext}
        CONTENT "
//mark that we are including headers as test for completeness.
//This is used by headers that include thrust to properly define a proper
//device backend / system
#define VTKM_TEST_HEADER_BUILD
#include <${dir_prefix}/${headername}.h>"
        )
121
      list(APPEND srcs ${src})
122
      list(APPEND valid_hfiles ${header})
123
    endif()
124
125
126
127
128
  endforeach()

  set_source_files_properties(${valid_hfiles}
    PROPERTIES HEADER_FILE_ONLY TRUE
    )
129
130
131
132
133
134
135
136

  #only attempt to add a test build executable if we have any headers to
  #test. this might not happen when everything depends on thrust.
  list(LENGTH srcs num_srcs)
  if (${num_srcs} EQUAL 0)
    return()
  endif()

137
138
139
140
141
  if(TARGET TestBuild_${name})
    #If the target already exists just add more sources to it
    target_sources(TestBuild_${name} PRIVATE ${srcs})
  else()
    add_library(TestBuild_${name} STATIC ${srcs} ${valid_hfiles})
142
143
    # Send the libraries created for test builds to their own directory so as to
    # not pollute the directory with useful libraries.
144
145
    set_property(TARGET TestBuild_${name} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}/testbuilds)
    set_property(TARGET TestBuild_${name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}/testbuilds)
146

147
    target_link_libraries(TestBuild_${name} PRIVATE vtkm_compiler_flags)
148
149
150
151
152

    if(TARGET vtkm::tbb)
      #make sure that we have the tbb include paths when tbb is enabled.
      target_link_libraries(TestBuild_${name} PRIVATE vtkm::tbb)
    endif()
153
154
155
156

    if(TARGET vtkm_diy)
      target_link_libraries(TestBuild_${name} PRIVATE vtkm_diy)
    endif()
157

158

159
160
161
162
  endif()

endfunction()

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
#-----------------------------------------------------------------------------
function(vtkm_generate_export_header lib_name)
  # Get the location of this library in the directory structure
  # export headers work on the directory structure more than the lib_name
  vtkm_get_kit_name(kit_name dir_prefix)

  # Now generate a header that holds the macros needed to easily export
  # template classes. This
  string(TOUPPER ${kit_name} BASE_NAME_UPPER)
  set(EXPORT_MACRO_NAME "${BASE_NAME_UPPER}")

  set(EXPORT_IS_BUILT_STATIC 0)
  get_target_property(is_static ${lib_name} TYPE)
  if(${is_static} STREQUAL "STATIC_LIBRARY")
    #If we are building statically set the define symbol
    set(EXPORT_IS_BUILT_STATIC 1)
  endif()
  unset(is_static)

  get_target_property(EXPORT_IMPORT_CONDITION ${lib_name} DEFINE_SYMBOL)
  if(NOT EXPORT_IMPORT_CONDITION)
    #set EXPORT_IMPORT_CONDITION to what the DEFINE_SYMBOL would be when
    #building shared
    set(EXPORT_IMPORT_CONDITION ${kit_name}_EXPORTS)
  endif()


  configure_file(
191
      ${VTKm_SOURCE_DIR}/CMake/VTKmExportHeaderTemplate.h.in
192
193
194
      ${VTKm_BINARY_DIR}/include/${dir_prefix}/${kit_name}_export.h
    @ONLY)

195
196
197
198
199
  if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
    install(FILES ${VTKm_BINARY_DIR}/include/${dir_prefix}/${kit_name}_export.h
      DESTINATION ${VTKm_INSTALL_INCLUDE_DIR}/${dir_prefix}
      )
  endif()
200
201
202
203

endfunction(vtkm_generate_export_header)

function(vtkm_install_headers dir_prefix)
204
205
206
207
208
209
  if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
    set(hfiles ${ARGN})
    install(FILES ${hfiles}
      DESTINATION ${VTKm_INSTALL_INCLUDE_DIR}/${dir_prefix}
      )
  endif()
210
211
212
213
214
215
216
217
endfunction(vtkm_install_headers)


#-----------------------------------------------------------------------------
function(vtkm_declare_headers)
  #TODO: look at the testable and cuda options
  set(options CUDA)
  set(oneValueArgs TESTABLE)
218
  set(multiValueArgs EXCLUDE_FROM_TESTING)
219
220
221
222
223
  cmake_parse_arguments(VTKm_DH "${options}"
    "${oneValueArgs}" "${multiValueArgs}"
    ${ARGN}
    )

224
225
226
227
228
229
230
231
  #The testable keyword allows the caller to turn off the header testing,
  #mainly used so that backends can be installed even when they can't be
  #built on the machine.
  #Since this is an optional property not setting it means you do want testing
  if(NOT DEFINED VTKm_DH_TESTABLE)
      set(VTKm_DH_TESTABLE ON)
  endif()

232
  set(hfiles ${VTKm_DH_UNPARSED_ARGUMENTS} ${VTKm_DH_EXCLUDE_FROM_TESTING})
233
234
  vtkm_get_kit_name(name dir_prefix)

235
236
  #only do header testing if enable testing is turned on
  if (VTKm_ENABLE_TESTING AND VTKm_DH_TESTABLE)
237
238
239
240
    set_source_files_properties(${VTKm_DH_EXCLUDE_FROM_TESTING}
      PROPERTIES VTKm_CANT_BE_HEADER_TESTED TRUE
      )

241
242
243
244
    vtkm_add_header_build_test(
      "${name}" "${dir_prefix}" "${VTKm_DH_CUDA}" ${hfiles})
  endif()

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  vtkm_install_headers("${dir_prefix}" ${hfiles})
endfunction(vtkm_declare_headers)

#-----------------------------------------------------------------------------
# Add a VTK-m library. The name of the library will match the "kit" name
# (e.g. vtkm_rendering) unless the NAME argument is given.
#
# vtkm_library(
#   [NAME <name>]
#   SOURCES <source_list>
#   TEMPLATE_SOURCES <.hxx >
#   HEADERS <header list>
#   [WRAP_FOR_CUDA <source_list>]
#   )
function(vtkm_library)
  set(oneValueArgs NAME)
  set(multiValueArgs SOURCES HEADERS TEMPLATE_SOURCES WRAP_FOR_CUDA)
  cmake_parse_arguments(VTKm_LIB
    "${options}" "${oneValueArgs}" "${multiValueArgs}"
    ${ARGN}
    )

  if(NOT VTKm_LIB_NAME)
    message(FATAL_ERROR "vtkm library must have an explicit name")
  endif()
  set(lib_name ${VTKm_LIB_NAME})

272
  if(TARGET vtkm::cuda)
273
274
    vtkm_compile_as_cuda(cu_srcs ${VTKm_LIB_WRAP_FOR_CUDA})
    set(VTKm_LIB_WRAP_FOR_CUDA ${cu_srcs})
275
276
277
278
279
280
281
282
283
  endif()


  add_library(${lib_name}
              ${VTKm_LIB_SOURCES}
              ${VTKm_LIB_HEADERS}
              ${VTKm_LIB_TEMPLATE_SOURCES}
              ${VTKm_LIB_WRAP_FOR_CUDA}
              )
284

285
  #specify where to place the built library
286
287
288
  set_property(TARGET ${lib_name} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
  set_property(TARGET ${lib_name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
  set_property(TARGET ${lib_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH})
289

290
  if(VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
291
292
    set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
    set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden")
293
294
  endif()

295
296
297
  # Setup the SOVERSION and VERSION information for this vtkm library
  set_property(TARGET ${lib_name} PROPERTY VERSION ${VTKm_VERSION})
  set_property(TARGET ${lib_name} PROPERTY SOVERSION 1)
298

299
300
301
302
303
304
305
306
307
308
  # Support custom library suffix names, for other projects wanting to inject
  # their own version numbers etc.
  if(DEFINED VTKm_CUSTOM_LIBRARY_SUFFIX)
    set(_lib_suffix "${VTKm_CUSTOM_LIBRARY_SUFFIX}")
  else()
    set(_lib_suffix "-${VTKm_VERSION_MAJOR}.${VTKm_VERSION_MINOR}")
  endif()
  set_property(TARGET ${lib_name} PROPERTY OUTPUT_NAME ${lib_name}${_lib_suffix})

  #generate the export header and install it
309
  vtkm_generate_export_header(${lib_name})
310
311

  #test and install the headers
312
313
314
  vtkm_declare_headers(${VTKm_LIB_HEADERS}
                       EXCLUDE_FROM_TESTING ${VTKm_LIB_TEMPLATE_SOURCES}
                       )
315
316

  #install the library itself
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  install(TARGETS ${lib_name}
    EXPORT ${VTKm_EXPORT_NAME}
    ARCHIVE DESTINATION ${VTKm_INSTALL_LIB_DIR}
    LIBRARY DESTINATION ${VTKm_INSTALL_LIB_DIR}
    RUNTIME DESTINATION ${VTKm_INSTALL_BIN_DIR}
    )

endfunction(vtkm_library)

#-----------------------------------------------------------------------------
# Declare unit tests, which should be in the same directory as a kit
# (package, module, whatever you call it).  Usage:
#
# vtkm_unit_tests(
#   NAME
#   SOURCES <source_list>
#   BACKEND <type>
#   LIBRARIES <dependent_library_list>
#   TEST_ARGS <argument_list>
336
#   <options>
337
#   )
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#
# [BACKEND]: mark all source files as being compiled with the proper defines
#            to make this backend the default backend
#            If the backend is specified as CUDA it will also imply all
#            sources should be treated as CUDA sources
#            The backend name will also be added to the executable name
#            so you can test multiple backends easily
#
# [LIBRARIES] : extra libraries that this set of tests need to link too
#
# [TEST_ARGS] : arguments that should be passed on the command line to the
#               test executable
#
# Supported <options> are documented below. These can be specified for
# all tests or for individual tests. When specifying these for individual tests,
# simply add them after the test name in the <source_list> separated by a comma.
# e.g. `UnitTestMultiBlock,MPI`.
#
# Supported <options> are
# * MPI : the test(s) will be executed using `mpirun`.
#
359
function(vtkm_unit_tests)
360
361
362
363
  if (NOT VTKm_ENABLE_TESTING)
    return()
  endif()

364
  set(options MPI)
365
366
367
368
369
370
  set(oneValueArgs BACKEND NAME)
  set(multiValueArgs SOURCES LIBRARIES TEST_ARGS)
  cmake_parse_arguments(VTKm_UT
    "${options}" "${oneValueArgs}" "${multiValueArgs}"
    ${ARGN}
    )
371
372
  vtkm_parse_test_options(VTKm_UT_SOURCES "${options}" ${VTKm_UT_SOURCES})

373
374
  set(test_prog )
  set(backend ${VTKm_UT_BACKEND})
375
376

  if(VTKm_UT_NAME)
377
378
379
380
381
382
383
    set(test_prog "${VTKm_UT_NAME}")
  else()
    vtkm_get_kit_name(kit)
    set(test_prog "UnitTests_${kit}")
  endif()
  if(VTKm_UT_BACKEND)
    string(APPEND test_prog "_${backend}")
384
385
  endif()

386
387
388
389
  #the creation of the test source list needs to occur before the labeling as
  #cuda. This is so that we get the correctly named entry points generated
  #
  create_test_sourcelist(test_sources ${test_prog}.cxx ${VTKm_UT_SOURCES})
390
  if(backend STREQUAL "CUDA")
391
392
    vtkm_compile_as_cuda(cu_srcs ${VTKm_UT_SOURCES})
    set(VTKm_UT_SOURCES ${cu_srcs})
393
  endif()
394

395
  add_executable(${test_prog} ${test_prog}.cxx ${VTKm_UT_SOURCES})
396
397
398
  set_property(TARGET ${test_prog} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
  set_property(TARGET ${test_prog} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH})
  set_property(TARGET ${test_prog} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH})
399

400
  target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES})
401

402
  if(VTKm_UT_NO_TESTS)
403
404
405
406
407
408
    return()
  endif()

  #determine the timeout for all the tests based on the backend. CUDA tests
  #generally require more time because of kernel generation.
  set(timeout 180)
409
  if(backend STREQUAL "CUDA")
410
411
412
413
    set(timeout 1500)
  endif()
  foreach (test ${VTKm_UT_SOURCES})
    get_filename_component(tname ${test} NAME_WE)
414
    add_test(NAME ${tname}${backend}
415
416
      COMMAND ${test_prog} ${tname} ${VTKm_UT_TEST_ARGS}
      )
417
    set_tests_properties("${tname}${backend}" PROPERTIES TIMEOUT ${timeout})
418
419
420
421
  endforeach (test)

endfunction(vtkm_unit_tests)

422
423
424
# -----------------------------------------------------------------------------
# vtkm_parse_test_options(varname options)
#   INTERNAL: Parse options specified for individual tests.
425
#
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
#   Parses the arguments to separate out options specified after the test name
#   separated by a comma e.g.
#
#   TestName,Option1,Option2
#
#   For every option in options, this will set _TestName_Option1,
#   _TestName_Option2, etc in the parent scope.
#
function(vtkm_parse_test_options varname options)
  set(names)
  foreach(arg IN LISTS ARGN)
    set(test_name ${arg})
    set(test_options)
    if(test_name AND "x${test_name}" MATCHES "^x([^,]*),(.*)$")
      set(test_name "${CMAKE_MATCH_1}")
      string(REPLACE "," ";" test_options "${CMAKE_MATCH_2}")
    endif()
    foreach(opt IN LISTS test_options)
      list(FIND options "${opt}" index)
      if(index EQUAL -1)
        message(WARNING "Unknown option '${opt}' specified for test '${test_name}'")
      else()
        set(_${test_name}_${opt} TRUE PARENT_SCOPE)
      endif()
    endforeach()
    list(APPEND names ${test_name})
  endforeach()
  set(${varname} ${names} PARENT_SCOPE)
endfunction()