VTKmWrappers.cmake 16.9 KB
Newer Older
1 2 3 4
##============================================================================
##  Copyright (c) Kitware, Inc.
##  All rights reserved.
##  See LICENSE.txt for details.
5
##
6 7 8 9 10 11 12
##  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.
##============================================================================

include(CMakeParseArguments)

13
include(VTKmDeviceAdapters)
14
include(VTKmCPUVectorization)
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

#-----------------------------------------------------------------------------
# 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)

#-----------------------------------------------------------------------------
31
function(vtkm_pyexpander_generated_file generated_file_name)
32 33 34 35 36 37 38 39 40
  # 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}
41
        -P ${VTKm_CMAKE_MODULE_PATH}/testing/VTKmCheckPyexpander.cmake
42 43 44 45 46 47 48 49
      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()
50 51
endfunction(vtkm_pyexpander_generated_file)

52
#-----------------------------------------------------------------------------
53 54 55 56 57
# This function is not needed by the core infrastructure of VTK-m
# as we now require CMake 3.11 on windows, and for tests we compile a single
# executable for all backends, instead of compiling for each backend.
# It is currently kept around so that examples which haven't been updated
# continue to work
58
function(vtkm_compile_as_cuda output)
luz.paz's avatar
luz.paz committed
59
  # We can't use set_source_files_properties(<> PROPERTIES LANGUAGE "CUDA")
60 61 62 63 64 65 66 67 68 69 70 71 72
  # 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 )
73 74 75 76 77 78 79 80 81 82 83 84
  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()
85 86 87 88
  endforeach()
  set(${output} ${_cuda_srcs} PARENT_SCOPE)
endfunction()

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
#-----------------------------------------------------------------------------
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(
117
      ${VTKm_SOURCE_DIR}/CMake/VTKmExportHeaderTemplate.h.in
118 119 120
      ${VTKm_BINARY_DIR}/include/${dir_prefix}/${kit_name}_export.h
    @ONLY)

121 122 123 124 125
  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()
126 127 128

endfunction(vtkm_generate_export_header)

129
#-----------------------------------------------------------------------------
130
function(vtkm_install_headers dir_prefix)
131 132 133 134 135 136
  if(NOT VTKm_INSTALL_ONLY_LIBRARIES)
    set(hfiles ${ARGN})
    install(FILES ${hfiles}
      DESTINATION ${VTKm_INSTALL_INCLUDE_DIR}/${dir_prefix}
      )
  endif()
137 138 139 140 141 142
endfunction(vtkm_install_headers)


#-----------------------------------------------------------------------------
function(vtkm_declare_headers)
  vtkm_get_kit_name(name dir_prefix)
143
  vtkm_install_headers("${dir_prefix}" ${ARGN})
144 145 146 147 148 149 150 151 152 153 154 155 156 157
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)
158
  set(options STATIC SHARED)
159 160 161 162 163 164 165 166 167 168 169 170
  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})

171 172 173 174 175 176 177 178 179
  if(VTKm_LIB_STATIC)
    set(VTKm_LIB_type STATIC)
  else()
    if(VTKm_LIB_SHARED)
      set(VTKm_LIB_type SHARED)
    endif()
    #if cuda requires static libaries force
    #them no matter what
    if(TARGET vtkm::cuda)
180
      get_target_property(force_static vtkm::cuda INTERFACE_REQUIRES_STATIC_BUILDS)
181 182 183 184 185 186 187 188 189
      if(force_static)
        set(VTKm_LIB_type STATIC)
        message("Forcing ${lib_name} to be built statically as we are using CUDA 8.X, which doesn't support virtuals sufficiently in dynamic libraries.")
      endif()
    endif()

  endif()


190
  if(TARGET vtkm::cuda)
191
    set_source_files_properties(${VTKm_LIB_WRAP_FOR_CUDA} PROPERTIES LANGUAGE "CUDA")
192 193 194
  endif()

  add_library(${lib_name}
195
              ${VTKm_LIB_type}
196 197 198 199 200
              ${VTKm_LIB_SOURCES}
              ${VTKm_LIB_HEADERS}
              ${VTKm_LIB_TEMPLATE_SOURCES}
              ${VTKm_LIB_WRAP_FOR_CUDA}
              )
201

202 203 204 205 206 207
  #when building either static or shared we want pic code
  set_target_properties(${lib_name} PROPERTIES POSITION_INDEPENDENT_CODE ON)

  #specify when building with cuda we want separable compilation
  set_property(TARGET ${lib_name} PROPERTY CUDA_SEPARABLE_COMPILATION ON)

208
  #specify where to place the built library
209 210 211
  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})
212

213
  if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
214 215
    set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
    set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden")
216 217
  endif()

218 219 220 221 222
  # allow the static cuda runtime find the driver (libcuda.dyllib) at runtime.
  if(APPLE)
    set_property(TARGET ${lib_name} PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
  endif()

223
  # Setup the SOVERSION and VERSION information for this vtkm library
224
  set_property(TARGET ${lib_name} PROPERTY VERSION 1)
225
  set_property(TARGET ${lib_name} PROPERTY SOVERSION 1)
226

227 228 229 230 231 232 233 234 235 236
  # 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
237
  vtkm_generate_export_header(${lib_name})
238

239
  #install the headers
240
  vtkm_declare_headers(${VTKm_LIB_HEADERS}
241
                       ${VTKm_LIB_TEMPLATE_SOURCES})
242

243 244 245 246 247 248 249 250 251 252 253
  # When building libraries/tests that are part of the VTK-m repository inherit
  # the properties from vtkm_developer_flags. The flags are intended only for
  # VTK-m itself and are not needed by consumers. We will export
  # vtkm_developer_flags so consumer can use VTK-m's build flags if they so
  # desire
  if (VTKm_ENABLE_DEVELOPER_FLAGS)
    target_link_libraries(${lib_name} PUBLIC $<BUILD_INTERFACE:vtkm_developer_flags>)
  else()
    target_link_libraries(${lib_name} PRIVATE $<BUILD_INTERFACE:vtkm_developer_flags>)
  endif()

254
  #install the library itself
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
  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>
273
#   DEFINES <target_compile_definitions>
274
#   TEST_ARGS <argument_list>
275
#   MPI
276
#   ALL_BACKENDS
277
#   <options>
278
#   )
279 280 281 282 283 284 285 286 287 288
#
# [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
#
289 290
# [DEFINES]   : extra defines that need to be set for all unit test sources
#
291 292 293
# [TEST_ARGS] : arguments that should be passed on the command line to the
#               test executable
#
294 295
# [MPI]       : when specified, the tests should be run in parallel if
#               MPI is enabled.
296 297
# [ALL_BACKENDS] : when specified, the tests would test against all enabled
#                  backends. BACKEND argument would be ignored.
298
#
299
function(vtkm_unit_tests)
300 301 302 303
  if (NOT VTKm_ENABLE_TESTING)
    return()
  endif()

304
  set(options)
305
  set(global_options ${options} MPI ALL_BACKENDS)
306
  set(oneValueArgs BACKEND NAME)
307
  set(multiValueArgs SOURCES LIBRARIES DEFINES TEST_ARGS)
308
  cmake_parse_arguments(VTKm_UT
309
    "${global_options}" "${oneValueArgs}" "${multiValueArgs}"
310 311
    ${ARGN}
    )
312 313
  vtkm_parse_test_options(VTKm_UT_SOURCES "${options}" ${VTKm_UT_SOURCES})

314
  set(test_prog)
315
  set(backend ${VTKm_UT_BACKEND})
316

317
  set(enable_all_backends ${VTKm_UT_ALL_BACKENDS})
318
  set(all_backends Serial)
319
  if (VTKm_ENABLE_CUDA)
320
    list(APPEND all_backends Cuda)
321 322 323 324 325
  endif()
  if (VTKm_ENABLE_TBB)
    list(APPEND all_backends TBB)
  endif()
  if (VTKm_ENABLE_OPENMP)
326
    list(APPEND all_backends OpenMP)
327 328
  endif()

329
  if(VTKm_UT_NAME)
330 331 332 333 334
    set(test_prog "${VTKm_UT_NAME}")
  else()
    vtkm_get_kit_name(kit)
    set(test_prog "UnitTests_${kit}")
  endif()
335

336
  if(backend)
337
    set(test_prog "${test_prog}_${backend}")
338
    set(all_backends ${backend})
339
  elseif(NOT enable_all_backends)
340
    set (all_backends "NO_BACKEND")
341 342
  endif()

343 344
  if(VTKm_UT_MPI)
    # for MPI tests, suffix test name and add MPI_Init/MPI_Finalize calls.
345
    set(test_prog "${test_prog}_mpi")
346 347 348 349 350 351
    set(extraArgs EXTRA_INCLUDE "vtkm/cont/testing/Testing.h"
                  FUNCTION "vtkm::cont::testing::Environment env")
  else()
    set(extraArgs)
  endif()

352 353
  #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
354
  create_test_sourcelist(test_sources ${test_prog}.cxx ${VTKm_UT_SOURCES} ${extraArgs})
355
  #if all backends are enabled, we can use cuda compiler to handle all possible backends.
356 357
  if(TARGET vtkm::cuda AND (backend STREQUAL "Cuda" OR enable_all_backends))
    set_source_files_properties(${VTKm_UT_SOURCES} PROPERTIES LANGUAGE "CUDA")
358
  endif()
359

360
  add_executable(${test_prog} ${test_prog}.cxx ${VTKm_UT_SOURCES})
361 362
  set_property(TARGET ${test_prog} PROPERTY CUDA_SEPARABLE_COMPILATION ON)

363 364 365
  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})
366

367 368 369 370 371 372 373 374
  #Starting in CMake 3.13, cmake will properly drop duplicate libraries
  #from the link line so this workaround can be dropped
  if (CMAKE_VERSION VERSION_LESS 3.13 AND "vtkm_rendering" IN_LIST VTKm_UT_LIBRARIES)
    list(REMOVE_ITEM VTKm_UT_LIBRARIES "vtkm_cont")
    target_link_libraries(${test_prog} PRIVATE ${VTKm_UT_LIBRARIES})
  else()
    target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES})
  endif()
375

376 377
  target_compile_definitions(${test_prog} PRIVATE ${VTKm_UT_DEFINES})

378
  foreach(current_backend ${all_backends})
379
    set (device_command_line_argument --device=${current_backend})
380 381
    if (current_backend STREQUAL "NO_BACKEND")
      set (current_backend "")
382
      set(device_command_line_argument "")
383
    endif()
384
    string(TOUPPER "${current_backend}" upper_backend)
385 386 387
    foreach (test ${VTKm_UT_SOURCES})
      get_filename_component(tname ${test} NAME_WE)
      if(VTKm_UT_MPI AND VTKm_ENABLE_MPI)
388
        add_test(NAME ${tname}${upper_backend}
389
          COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS}
390
                  $<TARGET_FILE:${test_prog}> ${tname} ${device_command_line_argument} ${VTKm_UT_TEST_ARGS}
391 392 393
                  ${MPIEXEC_POSTFLAGS}
          )
      else()
394
        add_test(NAME ${tname}${upper_backend}
395
          COMMAND ${test_prog} ${tname} ${device_command_line_argument} ${VTKm_UT_TEST_ARGS}
396 397 398 399 400
          )
      endif()

      #determine the timeout for all the tests based on the backend. CUDA tests
      #generally require more time because of kernel generation.
401
      if (current_backend STREQUAL "Cuda")
402 403 404 405
        set(timeout 1500)
      else()
        set(timeout 180)
      endif()
406
      if(current_backend STREQUAL "OpenMP")
407 408 409 410 411 412 413 414 415
        #We need to have all OpenMP tests run serially as they
        #will uses all the system cores, and we will cause a N*N thread
        #explosion which causes the tests to run slower than when run
        #serially
        set(run_serial True)
      else()
        set(run_serial False)
      endif()

416
      set_tests_properties("${tname}${upper_backend}" PROPERTIES
417 418 419 420 421
        TIMEOUT ${timeout}
        RUN_SERIAL ${run_serial}
      )
    endforeach (test)
  endforeach(current_backend)
422 423 424

endfunction(vtkm_unit_tests)

425 426 427
# -----------------------------------------------------------------------------
# vtkm_parse_test_options(varname options)
#   INTERNAL: Parse options specified for individual tests.
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 455 456 457
#   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()