がべーじこれくしょん

技術系とかいろいろ

CUDA_STANDARD is set to invalid value '17'と言われた時

tl;dr CUDA関連はターゲットを分けろ(初心者)

何が起きていたか

CUDAは現状C++11にしか対応していないことは周知の事実とします。

以下のようなCMakeLists.txtを作って作業をしてました。

cmake_minimum_required(VERSION 3.10)

if(NOT DEFINED CMAKE_CUDA_COMPILER)
    set(CMAKE_CUDA_COMPILER /usr/local/cuda/bin/nvcc)
endif()

project(sample LANGUAGES CXX CUDA)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CUDA_STANDARD 11)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${sample_SOURCE_DIR}/bin)

cmake_policy(SET CMP0079 NEW)

find_package(CUDA REQUIRED)
include_directories("${CUDA_INCLUDE_DIRS}")

if(NOT DEFINED CMAKE_CUDA_STANDARD)
    set(CMAKE_CUDA_STANDARD 11)
    set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()

add_executable(sample main.cpp)
target_sources(sample
    PRIVATE
        cuda.hpp
        gpu_functions.h
        gpu_functions.cpp)

target_link_libraries(sample ${CUDA_LIBRARIES})

gpu_functions.h

#pragma once

#include "cuda.hpp"

__global__ void kernel(void);

void proxy(void);

gpu_functions.cu

#include <cstdio>
#include "gpu_functions.h"

__global__ void kernel(void) {
  printf("Hello from CUDA kernel.\n");
}

void proxy(void) {
  kernel<<<1,1>>>();
}

cuda.hppというのは、以下記事に転がっていた有益なコードを拝借してます。が、今回は特にGPUメモリへデータを転送するということはしていないのであくまでcuda_runtime_api.hproc-cpuinfo.fixstars.com

さてビルドをしてみると以下のエラーが。

CUDA_STANDARD is set to invalid value '17'

このメッセージでググっても記事が出てきません。冷静に考えてみると、いくらCMakeにCUDAが統合されたからとはいえ、どれがCUDAのソースかはCMakeにはわかりません。

当然分けないといけないわけなんですが、上記のCMakeLists.txtは通常のC++ソースファイル類と同じターゲットに加えてしまっていました。これではCUDAのソースもg++へ投げられてしまいます。 (CUDA_STANDARDの値が17になっていた原因がさっぱりですが、CXX_STANDARDが17になっていたため、CUDA_STANDARDも17にセットされてしまっていたのでしょうか…わかりません)

解決

ちゃんとターゲットを分けてリンクしましょう。

cmake_minimum_required(VERSION 3.10)

if(NOT DEFINED CMAKE_CUDA_COMPILER)
    set(CMAKE_CUDA_COMPILER /usr/local/cuda/bin/nvcc)
endif()

project(sample LANGUAGES CXX CUDA)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CUDA_STANDARD 11)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${sample_SOURCE_DIR}/bin)

cmake_policy(SET CMP0079 NEW)

find_package(CUDA REQUIRED)
include_directories("${CUDA_INCLUDE_DIRS}")

if(NOT DEFINED CMAKE_CUDA_STANDARD)
    set(CMAKE_CUDA_STANDARD 11)
    set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()

add_executable(sample main.cpp)

add_library(cudalib
        cuda.hpp
        gpu_functions.h
        gpu_functions.cu)
set_target_properties(cudalib PROPERTIES
        CUDA_SEPERABLE_COMPILATION ON)

target_link_libraries(sample cudalib)

target_link_libraries(sample ${CUDA_LIBRARIES})

参考

https://cliutils.gitlab.io/modern-cmake/chapters/packages/CUDA.html