CUDA和C++混合编程及CMakeLists.txt

1. 概要

首先认识一个问题,单从CMakeLists.txt的角度来看,无法同时使用两种编译器编译两种语言。不过直接编写Makefile是可以的,通过设置不同的任务,可以实现一个Makefile编译两个语言。但这不是这里要讨论的重点。

使用CUDA和C++进行混合编程的意思是:在cpp文件中调用CUDA函数,实现加速。

所以混合编程有两种方法:

1.1 直接编译

1.2 将CUDA工程编译成库,然后在我们的cpp工程中使用target_link_libraries()来链接到我们刚编译好的CUDA库。

2. 注意点

我们要做的事情是将CUDA工程编译成库,然后在我们的cpp工程中使用target_link_libraries()来链接到我们刚编译好的CUDA库。

有几个需要注意的地方,下面这些都是在cpp的CMakeLists.txt中:

  1. The project() command will initialize many CMake variables concerning your system and compiler. As such, it sets the languages that your CMake project will be using. Without specifying any language in the project() command, the defaults (C and CXX) are enabled:

    bash 复制代码
    # Initialize for C and C++ languages.
    project(cmake_and_cuda)

    啥意思?意思是说,CMakeLists.txt中的 project() 作用是根据你的系统和编译器初始化CMake变量,所以,projects()的作用是设置你CMake项目的语言,如果没有特别指出,默认使用C和CXX

  2. project() 应该紧跟在cmake_minimum_required()后面,这里因为我们需要引用cuda库,所以需要设置语言的时候加上cuda,有两种方式:

    bash 复制代码
    project(cmake_and_cuda CUDA CXX)
    # 或者如下:
    project(cmake_and_cuda CUDA CXX)
    enable_language(CUDA)
  3. 设置CUDA架构

    后面的数值需要根据显卡来确定,查阅 https://developer.nvidia.com/cuda-gpus,比如我的是8.6这里就设置86

    cpp 复制代码
    set(CMAKE_CUDA_ARCHITECTURES 86)
  4. 给cuda库进行编译,并且链接到cpp程序中去【直接编译的方法跳过】

    bash 复制代码
    add_subdirectory(kernels)
    target_link_libraries(main kernels)

3. 实现

main.cpp

cpp 复制代码
#include "kernels/test.cuh"

int main() {
  wrap_test_print();

  return 0;
}

版本一:

直接编译:

bash 复制代码
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)

project(cmake_and_cuda)
set(CMAKE_CUDA_ARCHITECTURES 86)
enable_language(CUDA)
# 把cu当成普通cpp来用
add_executable(main main.cpp kernels/test.cu)

版本二:

编译CUDA成库再链接方式的CMakeLists.txt

bash 复制代码
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)

project(cmake_and_cuda)

set(CMAKE_CUDA_ARCHITECTURES 86)
#set(CMAKE_CUDA_COMPILER /usr/local/cuda-11.1/bin/nvcc)
#set(CUDACXX /usr/local/cuda-11.1/bin/nvcc)

enable_language(CUDA)

add_executable(main main.cpp)
add_subdirectory(kernels)

# set_property(TARGET main 
#              PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_libraries(main kernels)

test.cuh:cuda的头文件

cpp 复制代码
#ifndef TEST_CUH__
#define TEST_CUH__

#include <stdio.h>

void wrap_test_print();

#endif

test.cu

cpp 复制代码
#include "test.cuh"
__global__ void test_print(){
  printf("Hello World!\n");
}

void wrap_test_print() {
  test_print<<<1, 1>>>();
  cudaDeviceSynchronize();
  return;
}

cuda的CMakeLists.txt【直接编译的方法不要这个CMakeLists.txt】

bash 复制代码
enable_language(CUDA)
add_library(kernels
test.cu
test.cuh
)
target_compile_features(kernels PUBLIC cxx_std_11)
set_target_properties(kernels
                       PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_link_libraries(kernels)

最终目录结构:

bash 复制代码
├── CMakeLists.txt
├── kernels
│   ├── CMakeLists.txt
│   ├── test.cu
│   └── test.cuh
└── main.cpp

编译运行,输出Hello World!

4. CLion注意点

如果你用的是clion来编写cpp和cuda的混合,很有可能你直接使用界面上的运行按钮会报错,找不到文件blabla...,比如fatal error: cuda_runtime.h: 没有那个文件或目录,但是其实你从终端里面cmake make是能通过也是正常执行的,只要你在终端编过一次,IDE中即使一堆报错波浪线也可以run,很莫名其妙。

解决办法,在CMakeLists中加上一句include_directories(/usr/local/cuda-11.1/targets/x86_64-linux/include),这里的路径可以通过在命令行执行locate cuda_runtime.h来获得,这样所有clion中所有和cuda相关的报红色波浪线的地方都可以加上#include <cuda_runtime.h>,这样就可以愉快的CLion来运行和调试代码啦!

相关推荐
黄雪超24 分钟前
JVM——函数式语法糖:如何使用Function、Stream来编写函数式程序?
java·开发语言·jvm
ThetaarSofVenice31 分钟前
对象的finalization机制Test
java·开发语言·jvm
水木兰亭37 分钟前
数据结构之——树及树的存储
数据结构·c++·学习·算法
思则变43 分钟前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
lijingguang1 小时前
在C#中根据URL下载文件并保存到本地,可以使用以下方法(推荐使用现代异步方式)
开发语言·c#
¥-oriented1 小时前
【C#中路径相关的概念】
开发语言·c#
CoderCodingNo2 小时前
【GESP】C++四级考试大纲知识点梳理, (7) 排序算法基本概念
开发语言·c++·排序算法
恋猫de小郭2 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
JosieBook2 小时前
【Java编程动手学】使用IDEA创建第一个HelloJava程序
java·开发语言·intellij-idea
Thomas_YXQ2 小时前
Unity3D DOTS场景流式加载技术
java·开发语言·unity