从零写一个自己的完整c++ cuda项目
所以,你想从零开始写一个完整的C++ CUDA项目?别急,兄弟,咱们先来聊聊这事儿的“先决条件”。首先,你得有个好工具,比如CLion,编辑器界的“瑞士军刀”。接着,cudatoolkit、cudnn、pytorch这些玩意儿都得装好,不然你的代码就像没了引擎的跑车,光有壳子跑不动。别忘了设置环境变量和动态链接库,不然系统找不着它们,你的项目就只能“卡壳”了。
然后,咱们得聊聊CMakeLists.txt,这玩意儿就像项目的“施工图纸”。你得告诉CMake,项目叫啥,用啥语言(CUDA和C++都得写上,别漏了),还得找到pytorch的配置文件。这里有个坑,如果你不小心导入了libpytorch的cmake文件夹,那就等着报错吧,你会看到“Could NOT find Torch”这种让人崩溃的提示。
最后,别忘了把pytorch的头文件和库文件加进来,不然你的代码就像缺零件的机器,根本转不起来。总之,搞CUDA项目就像搭乐高,每一步都得小心翼翼,不然最后拼出来的可能是个“四不像”哦!
pytorch关于c++的所有文档集合
Welcome to PyTorch Tutorials — PyTorch Tutorials 2.0.0+cu117 documentation
前置条件
使用编辑器clion,安装好cudatoolkit,cudnn,pytorch环境,编译工具gcc等等。
记得要设置好cudatoolkit的环境变量和动态链接库,这样到时候才能找到cudatoolkit和cudnn
安装教程可看
https://mp.csdn.net/mp_blog/creation/editor/new/129111146
注意我们如果要使用pytorch 的c语言版,是不需要安装额外的libpytorch的,因为pytorch下载的时候就自动整合了这些。
官方教程
CUDA projects | CLion Documentation
Installing C++ Distributions of PyTorch — PyTorch master documentation
通过clion创建cuda可执行项目
参照Installing C++ Distributions of PyTorch — PyTorch master documentation
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(untitled LANGUAGES CUDA CXX)
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")add_executable(untitled main.cu test1.cu pointops_api.cpp)
set(CMAKE_CUDA_STANDARD 17)set_target_properties(untitled PROPERTIESCUDA_SEPARABLE_COMPILATION ON)include_directories(SYSTEM ${TORCH_INCLUDE_DIRS})
target_link_libraries(untitled CUDA "${TORCH_LIBRARIES}")
cmake_minimum_required(VERSION 3.10)
要求使用的最低cmake版本,cmake低于这个版本不能编译该项目,可以自己设定
project(untitled LANGUAGES CUDA CXX)
untitled 为项目名,LANGUAGES CUDA CXX这个非常重要,就是我们的代码里的cu代码,和cpp,cc等代码能被正常编译,也就是同时启用CUDA代码和cxx代码的编译,
如果不加上CXX,就会报错
cmake-build-debug Unknown extension ".cc" for file
因为比如cpp文件cuda的编译器nvcc是可以编译的,但.cc文件也就是c++的源代码文件他无法编译,此时需要启用c++编译,也就是加上CXX。
find_package(Torch REQUIRED)
找到pytorch的c++文件,将pytorch导入进来。
这里是会先找pytorch的config文件,叫做 TorchConfig.cmake或torch-config.cmake,这个是pytorch关于cmake的配置文件,比如包含了去哪找pytorch的头文件,以及动态库等等,否则编译时是找不到对应的头文件的。
为了找到TorchConfig.cmake,我们需要设置一个缓存变量CMAKE_PREFIX_PATH,让他能够找到pytorch的TorchConfig.cmake的位置。
CMAKE_PREFIX_PATH=/home/zxy/mambaforge/envs/sphere/lib/python3.7/site-packages/torch/share/cmake
该路径可以由torch.utils.cmake_prefix_path查询到
CMAKE_PREFIX_PATH作用:
用于FIND_XXX()搜索的路径,并添加适当的后缀。
指定一个将被FIND_XXX()命令使用的路径。它包含了 "基础 "目录,FIND_XXX()命令将适当的子目录附加到基础目录中。因此,FIND_PROGRAM()在路径中的每个目录中添加/bin,FIND_LIBRARY()在每个目录中添加/lib,FIND_PATH()和FIND_FILE()添加/include。默认情况下,它是空的,它的目的是由项目来设置。参见CMAKE_SYSTEM_PREFIX_PATH, CMAKE_INCLUDE_PATH, CMAKE_LIBRARY_PATH, CMAKE_PROGRAM_PATH。
FIND_PROGRAM中变为torch.utils.cmake_prefix_path/bin
FIND_PATH中变为torch.utils.cmake_prefix_path/include
找torch包变为torch.utils.cmake_prefix_path/torch 这个正是我们需要的,此时就能正确找到torch了
cmake最终写为如下,用于添加缓存变量
cmake -D CMAKE_PREFIX_PATH=/home/zxy/mambaforge/envs/sphere/lib/python3.7/site-packages/torch/share/cmake
注意:如果下载了libpytorch(也就是单独的c++ pytorch库,不要将他的cmake文件夹导入进来,否则会报
Libtorch C++ build ‘Could NOT find Torch (missing: TORCH_LIBRARY)’
)
add_executable(untitled main.cu test1.cu pointops_api.cpp)
所有要进行编译的代码都在这声明。
include_directories(SYSTEM ${TORCH_INCLUDE_DIRS})
target_link_libraries(untitled CUDA "${TORCH_LIBRARIES}")
将pytorch头文件加入到头文件查找路径,将pytorch库文件添加到链接查找路径
cmake缓存变量
cmake缓存变量(Cache Variabl),相当于一个全局变量。在同一个CMake工程中任何地方都可以使用。
如何指定缓存变量?
- 法1 在调用cmake的时候加-D,后面的就是缓存变量
cmake -DCMAKE_PREFIX_PATH=/your/path
cmake -D CMAKE_PREFIX_PATH=/your/path
这两种都可以
- 法2 在clion中修改,这两个位置是同步的,修改其中的一个框就行,其实和法1是同一种方式
- 法3 使用set 命令
set(<variable> <value>... CACHE <type> <docstring> [FORCE]) |
- variable:变量名称
- value:变量值列表
- CACHE:cache变量的标志
- type:变量类型,取决于变量的值。类型分为:BOOL、FILEPATH、PATH、STRING、INTERNAL
- docstring:必须是字符串,作为变量概要说明
- FORCE:强制选项,强制修改变量值
-
代码结构
- learn_cmake:为根目录
- build:为CMake配置输出目录(在此例中即生成sln解决方案的地方)
- cmake_config.bat:执行CMake配置过程的脚本(双击直接运行)
- CMakeLists.txt:CMake脚本
-
示例代码(CMakeLists.txt文件内容)
cmake_minimum_required(VERSION 3.18)# 设置工程名称set(PROJECT_NAME KAIZEN)# 设置工程版本号set(PROJECT_VERSION "1.0.0.10" CACHE STRING "默认版本号")# 工程定义project(${PROJECT_NAME}LANGUAGES CXX CVERSION ${PROJECT_VERSION})# 打印开始日志message(STATUS "\\n# BEGIN_TEST_CACHE_VARIABLE") 定义缓存变量# 定义一个STRIING类型缓存变量(不加FORCE选项)set(MY_GLOBAL_VAR_STRING_NOFORCE "abcdef" CACHE STRING "定义一个STRING缓存变量")message("MY_GLOBAL_VAR_STRING_NOFORCE: ${MY_GLOBAL_VAR_STRING_NOFORCE}")# 定义一个STRIING类型缓存变量(加FORCE选项)set(MY_GLOBAL_VAR_STRING "abc" CACHE STRING "定义一个STRING缓存变量" FORCE)message("MY_GLOBAL_VAR_STRING: ${MY_GLOBAL_VAR_STRING}")
- 法4 在CMakeCache.txt中进行修改,注意这种的优先级比较低,就是使用命令行定义的变量会覆盖CMakeCache.txt的同名变量,可以说是命令行定义会覆盖CMakeCache.txt的值,每次运行cmake,比如命令行传入了CMAKE_PREFIX_PATH为aaa,那么会先修改CMakeCache.txt的CMAKE_PREFIX_PATH为aaa,再读入CMakeCache.txt的总体缓存数据。覆盖说明我在CMakeCache.txt定义的值,如果在命令行定义过了比如aaa,无论再怎么在CMakeCache.txt里修改都没有用,修改成bbb,ccc,运行一次cmake直接被改写成aaa。
当 CMake 首次在一个空的构建树中运行时,它会创建一个 CMakeCache.txt
文件并使用项目的可自定义设置填充它。此选项可用于指定优先于项目默认值的设置。可以根据需要为尽可能多的CACHE
条目重复该选项。
CMakeCache.txt文件示例
//Path to a program.
CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy//Path to a program.
CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump//No help, variable specified on the command line.
CMAKE_PREFIX_PATH:UNINITIALIZED=/home/zxy/mambaforge/envs/sphere/lib/python3.7/site-packages/torch/share/cmake//Value Computed by CMake
CMAKE_PROJECT_DESCRIPTION:STATIC=//Value Computed by CMake
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
可以通过一下的形式查看变量,就写在txt文件中
message("================${CMAKE_CXX_FLAGS}====