【问题标题】:Multi-config/multi-platform build for CUDA using CMake使用 CMake 为 CUDA 构建多配置/多平台
【发布时间】:2018-07-23 15:12:53
【问题描述】:

我最近与 CMake 发生了一些争执,试图让它在涉及 Cuda 的不同平台上为调试和发布目标生成项目文件。我在 Windows 和 Linux 上使用的 Cuda 版本是 9.1。 CMake 版本在 Windows 上为 3.9,在 Linux 上为 3.10。

问题实际上很简单,因为如果 nvcc 正确传递了"-DEBUG" 标志,我可以在 Windows 上生成构建。但是,我似乎无法通过配置自动正确传递标志。我尝试使用CMAKE_NVCC_FLAGS_CONFIGCMAKE_CXX_FLAGS_CONFIG 并将CUDA_PROPAGATE_HOST_FLAGS 设置为ON/OFF,将CUDA_HOST_COMPILATION_CPP 切换为ON/OFF 也没有帮助。使用表达式生成器设置标志以使用set_directory_property 设置目录属性,或者作为cuda_add_executable 的选项也不起作用。

这是我的 cmake 脚本的要点:

# CMake entry point
cmake_minimum_required (VERSION 3.9.1)

set( APP_NAME example-CUDA )

find_package(XYZ)
find_package(CUDA)  # not required according to 1st-class status in CMake3 .8+

enable_language(CUDA)
set(CUDA_VERBOSE_BUILD ON)

set(SRC_EXAMPLE "main.cpp" "gj.cu"  "gj.cuh")
SOURCE_GROUP(Example FILES ${SRC_EXAMPLE})

set(SRC_BUILD_FILES ${SRC_EXAMPLE})

# note: similar stuff for linux ommitted..
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /sdl- -Zm256")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MD")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /we4146 /we4308 /we4532 /we4533 /we4700 /we4703 /we4789 /we4995 /we4996")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /INCREMENTAL")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MP")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /we4146 /we4308 /we4532 /we4533 /we4700 /we4703 /we4789 /we4995 /we4996")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 /WX /sdl- -Zm256")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zi")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG" CACHE STRING "compile flags debug" FORCE)
endif()

# cuda 9 flags for max compatibility ( note: no more sm 20!)
set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    "-arch=sm_30 -gencode=arch=compute_30,code=sm_30 -gencode=arch=compute_50,code=sm_50 -gencode=arch=compute_52,code=sm_52 -gencode=arch=compute_60,code=sm_60 -gencode=arch=compute_61,code=sm_61 -gencode=arch=compute_62,code=sm_62 -gencode=arch=compute_70,code=sm_70 -gencode=arch=compute_70,code=compute_70")

include_directories(SYSTEM  ${CUDA_TOOLKIT_INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR})

#set(CUDA_HOST_COMPILATION_CPP ON) 
#set(CUDA_PROPAGATE_HOST_FLAGS ON)

#set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}   " -D_DEBUG ")             # works, but hadcoded config :(

set(CUDA_NVCC_FLAGS_DEBUG   ${CUDA_NVCC_FLAGS_DEBUG}    " -D_DEBUG ") # fails, not picked up..

#cuda_add_executable (${APP_NAME} ${SRC_EXAMPLE} OPTIONS $<$<CONFIG:Debug>:"-DEBUG">) #fails, generator not run

cuda_add_executable (${APP_NAME} ${SRC_EXAMPLE})
target_link_libraries (${APP_NAME} PUBLIC CUDA XYZ)

我在 VS2015(我也在使用 2017)中遇到的错误是典型的 _ITERATOR_DEBUG_LEVEL 不正确,这意味着其中一个编译单元未正确传递 -DEBUG 标志,并且链接器看到混合了重新调试和发布模块.由 nvcc.exe 构建的模块在内部传递给 cl.exe 用于非 cuda 代码位的编译,除了缺少所有 _DEBUG 配置标志。我通读了 FindCUDA.cmake 以找到一些有趣的东西,但几乎不可能分辨出什么是有效的,什么是无效的。

我显然遗漏了一些东西,但是什么?有什么解决方法吗?

更新 1:我还在 CMakeLists.txt 层次结构中设置了以下方式:

project (MyLittleBigProject)

# Set default build type
set(PROJECT_CONFIGURATIONS      Debug Release               CACHE TYPE INTERNAL FORCE)
if(DEFINED CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Build configs: ${PROJECT_CONFIGURATIONS}")
else()
    set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build configs: ${PROJECT_CONFIGURATIONS}")
endif()

【问题讨论】:

  • 是否有可能使用 C 编译器而不是 C++ 编译器编译某些代码,在这种情况下,您还需要调整 CMAKE_C_FLAGS_DEBUG 吗?另外,您是否设置了CMAKE_BUILD_TYPE 并在某个时候调用了project()
  • 感谢@piwi 的快速回复。是的,'project()' 在 CMakeLists.txt 文件的层次结构中被调用。此外,这个特定示例与许多 cpp 示例之一一起使用,所有构建都很好,我从未设置任何特定的 C 标志。我也设置了'CMAKE_BUILD_TYPE',我用上面的信息更新了我的答案。感谢您查看此内容。

标签: c++ linux visual-studio cuda


【解决方案1】:

我不了解 CUDA/NVCC,但是查看FindCUDA 的文档,您可以尝试以下几件事:

  • 通过CMAKE_C_FLAGS_DEBUG 传递调试标志,因为CUDA_HOST_COMPILER 的文档指出默认情况下使用CMAKE_C_COMPILER,而不是CMAKE_CXX_COMPILER
  • 通过cuda_add_executable() 传递调试标志:文档表明它调用cuda_wrap_srcs(),您可以在其中使用OPTIONS DEBUG ... 传递特定标志

希望这会有所帮助。

【讨论】:

  • 我已经尝试了第二个选项,并且对于第一个想法,我尝试使用 CMAKE_C_FLAGS_DEBUG,它应该在调试模式下为 C 编译器设置标志。我会尽快回复您,改用 CMAKE_C_COMPILER_DEBUG..
  • @StarShine CMAKE_C_COMPILER_DEBUG 是我的错误对不起,我的意思是CMAKE_C_FLAGS_DEBUG(我编辑了我的答案)。
  • 好的,至于第二个选项,使用 cuda_wrap_srcs() 意味着您自己设置每个设置。这是基于 FindCUDA.cmake 的,它已被弃用,有利于在 CMake 中使用现在提升的 CUDA 语言的一等公民身份,但不幸的是,它似乎不适用于不同的配置。
  • @StarShine 对不起,我不能帮你解决你的问题 :-( 但是,你可以做的是查看 CMakeFiles 目录中的文件,因为通常调用的命令存储在这些目录,以及CMakeOutput.log 文件。也许你会发现发生了什么的线索......
  • 是的,我可以尝试一下,谢谢。希望@ComicSansMS 或其他 CMake 大师之一能有所启发..
【解决方案2】:

有几件事共同造成了这个问题,最大的一个是根本不存在对 VS2017 的支持。

也就是说,通过构建我自己的 Cmake 虚拟目标来包装所有 CUDA 库依赖项和构建设置,我仍然可以让它正确地为其他编译器工作。我从我能找到的 CUDA 的现有 Find_XXX CMake 脚本开始,并在宏之后添加了以下部分(我在几乎所有依赖项中都使用了这个技巧)。这部分实际上并不是绝对必要的,因为 CMake 显然在幕后为您做了同样的事情,但它也适用于该自动魔法出现问题的情况,并且您可以完全控制正在发生的事情。

set(API "CUDA")
if(NOT TARGET "${API}")     
    if (CUDA_cudart_static_LIBRARY)     # we assume at least cuda 5.5+
        add_custom_target("Generate${API}" DEPENDS  "${CUDA_cudart_static_LIBRARY}" )        
        add_library(            "${API}"            STATIC          IMPORTED                                GLOBAL )      
        set_property(TARGET     "${API}"            PROPERTY        IMPORTED_LOCATION                       "${CUDA_cudart_static_LIBRARY}")
        set_property(TARGET     "${API}"            PROPERTY        INTERFACE_LINK_LIBRARIES                "${CUDA_LIBRARIES}")        

        set_property(TARGET     "${API}"            PROPERTY        INTERFACE_INCLUDE_DIRECTORIES           "${CUDA_INCLUDE_DIRS}"   )
        set_property(TARGET     "${API}"            PROPERTY        FOLDER                                  "APIGenerators"     )
        set_property(TARGET     "Generate${API}"    PROPERTY        FOLDER                                  "APIGenerators"     )
        add_dependencies(       "${API}"            "Generate${API}")
    else()
        add_library(            "${API}"            INTERFACE       IMPORTED                                GLOBAL )
    endif() 
endif()

现在您已经为 CUDA 准备好您自己的 CUDA Find_Package 调用,您可以继续设置一个 cmake 来创建您的项目,只需调用 find_package(CUDA)。 CMake 会“自动”识别 CUDA,因此链接实际上是隐式的。下面是我为在后台调用的 NVCC 编译步骤设置一些变量的方法:

enable_language(CUDA)
set(CUDA_VERBOSE_BUILD ON)

set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    "-I=${GLM_INCLUDE_DIR} ")
set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    "-I=${GLEW_INCLUDE_PATH} ")
set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    "-I=${YOUR_INCLUDE_DIRS} ")
# cuda 9 flags for max compatibility ( no more sm 20!)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
    #set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}   "-arch=sm_30 -gencode=arch=compute_30,code=sm_30 -gencode=arch=compute_50,code=sm_50 -gencode=arch=compute_52,code=sm_52 -gencode=arch=compute_60,code=sm_60 -gencode=arch=compute_61,code=sm_61 -gencode=arch=compute_62,code=sm_62 -gencode=arch=compute_70,code=sm_70 -gencode=arch=compute_70,code=compute_70")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    "-arch=sm_30")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_30,code=sm_30")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_50,code=sm_50")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_52,code=sm_52")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_60,code=sm_60")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_61,code=sm_61")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_62,code=sm_62")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_70,code=sm_70")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_70,code=compute_70")
else()      
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    "-arch=sm_30")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_30,code=sm_30")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_50,code=sm_50")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -gencode=arch=compute_52,code=sm_52")
    set(CUDA_NVCC_FLAGS   ${CUDA_NVCC_FLAGS}    " -std=c++11")
endif()

现在您可以关闭包含主机标志的 CUDA 标志,因为您自己设置了它们,并指定了一些在我的案例中需要的相关编译定义。

set(CUDA_HOST_COMPILATION_CPP OFF)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
target_compile_definitions(${APP_NAME} PRIVATE $<$<CONFIG:Debug>:"_DEBUG ">)
target_compile_definitions(${APP_NAME} PRIVATE "_MWAITXINTRIN_H_INCLUDED")
target_compile_definitions(${APP_NAME} PRIVATE "_FORCE_INLINES")
target_compile_definitions(${APP_NAME} PRIVATE "__STRICT_ANSI__")

set_target_properties(${APP_NAME} PROPERTIES COMPILE_FLAGS "-std=c++11")    

最后但并非最不重要的一点是,切换到 C++11 编译,否则你的编译器可能会被所有类似 模板的自动类型构造弄糊涂。

set_target_properties(${APP_NAME} PROPERTIES COMPILE_FLAGS "-std=c++11")

希望这对你们中的一些人有所帮助。如果您知道如何在 VS2017 上轻松运行,请发表评论!

【讨论】:

    猜你喜欢
    • 2022-07-12
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2017-05-25
    • 2021-08-17
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    相关资源
    最近更新 更多