簡體   English   中英

使用 CMake 為 CUDA 構建多配置/多平台

[英]Multi-config/multi-platform build for CUDA using CMake

我最近與 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 標志,並且鏈接器看到 rebug 和 release 模塊混合。 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()

我沒有CUDA / NVCC的知識,但看的文檔FindCUDA ,這里有一對夫婦的事情,你可以嘗試:

  • 通過通行證調試標志CMAKE_C_FLAGS_DEBUG ,因為文檔CUDA_HOST_COMPILER指出,在默認情況下, CMAKE_C_COMPILER使用,不CMAKE_CXX_COMPILER
  • 通過cuda_add_executable()傳遞調試標志:文檔表明它調用cuda_wrap_srcs() ,您可以在其中使用OPTIONS DEBUG ...傳遞特定標志OPTIONS DEBUG ...

希望這可以幫助。

有幾件事共同造成了這個問題,最大的一個是對 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 Find_Package 調用 CUDA,你可以繼續設置一個 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 上工作而不會有太多麻煩,請發表評論!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM