nvcc 编译 .cu 源代码的基本用法

编译命令

nvcc 是 NVIDIA 提供的 CUDA C/C++ 的编译器。编译一个简单的 vectorAdd.cu 源代码的命令是:

bash 
nvcc vectorAdd.cu -o vectorAdd

这将使用默认参数编译 vectorAdd.cu,并输出一个叫 vectorAdd 的可执行文件。

一些常用的 nvcc 编译参数包括:

  • -arch=sm_XX 指定 GPU 计算能力
  • -std=c++11 指定 C++ 标准
  • -g 添加调试信息
  • -lineinfo 添加行信息
  • -O2 高级优化
  • -w 抑制 warning
  • -c 只编译不链接链接参数:- -lcuda -lcudart 链接 CUDA runtime 库
  • -lcublas -lcudnn 链接 CUDA 库
  • -L/path 指定库搜索路径一个常见的完整编译命令可能像:
bash 
nvcc -arch=sm_61 -std=c++11 -O2 -lineinfo vectorAdd.cu -o vectorAdd -lcudart -L/cuda/lib64

指定了 GPU 计算能力、C++11 标准、优化等选项,并链接了 CUDA runtime 库。

太复杂了,整个简单的

nvcc 可以直接编译 CUDA 源代码生成可执行文件,同时具有编译和链接的功能,所以不需要额外添加 -c 参数。直接使用:

​nvcc matrixMultiply.cu -o exe

nvcc 会进行以下步骤:

1. 用相应的 CUDA 编译器编译 .cu 源文件,生成目标代码

2. 链接目标代码和默认包含的 CUDA 运行时库,生成最终可执行文件所以一个简单的 nvcc 命令就可以完成编译链接,生成可执行文件。

而如果需要分步编译,则需要使用 -c 参数生成独立的目标文件:

​nvcc -c matrixMultiply.cu -o matrixMultiply.o

然后再链接目标文件:

nvcc matrixMultiply.o -o exe -lcudart -lcublas

总结一下:

- nvcc 文件 -o exe: 编译+链接,直接生成可执行文件
- nvcc -c 文件 -o obj: 仅编译,生成目标文件
- nvcc obj -o exe lib: 链接目标文件生成可执行文件

 nvcc 链接 CUDA 库

1. 必须链接cudart运行时库:

bash 
nvcc demo.cu -o demo -lcudart​

2. 使用cublas库做矩阵运算:

bash 
nvcc demo.cu -o demo -lcublas -lcudart

注意链接顺序,先放CUDA库。

3. 指定自定义的库搜索路径:

​bash 
nvcc demo.cu -o demo -L/path/to/cuda/lib -lcublas -lcudart

4. 链接指定版本的库:

​bash 
nvcc demo.cu -o demo -L/cuda-10.1/lib64 -lcublas -lcudart

5. 动态链接库:

bash
nvcc demo.cu -o demo

然后运行时:

bash
LD_LIBRARY_PATH=/cuda/lib ./demo

6. 使用cuDNN库(需要LICENSE):

bash 
nvcc demo.cu -o demo -lcudnn -lcublas -lcudart
两种源文件:

对于CUDA程序,我们通常有:

  1.  .cu文件:包含CUDA C/C++代码,包括主程序代码和CUDA kernels。需要nvcc编译。
  2. .cpp/.c文件:只包含主程序代码,不含CUDA kernels。可以用gcc/g++编译。

编译CUDA程序的一般步骤是:

  1. 用nvcc编译.cu文件,生成.o文件
  2. 用g++编译.cpp文件,也生成.o文件
  3. 再用g++/nvcc链接所有.o文件生成最终可执行文件
​nvcc -c demo.cu -o demo.o 
g++ -c main.cpp -o main.o 
nvcc demo.o main.o -o demo -lcudart

即分别编译.cu和.cpp文件,然后链接生成可执行文件。

使用shell脚本编译
bash
#!/bin/bash

# 1. #! - Shebang的开始标识,告诉系统这是一个可执行脚本。
# 2. /bin/bash - 指定脚本需要使用的解释器路径,在这里是bash shell。
# 3. 将脚本作为参数传递给指定的解释器来执行。
# 也就是说,#!/bin/bash 这一行告诉系统当运行这个脚本时,使用 /bin/bash 这个bash解释器来执行。
# Shebang非常重要,它可以使脚本具备可执行性,并调用正确的解释器。
# 除了`#!/bin/bash`指定bash外,还可以根据需要指定其他解释器,例如:
# - #!/bin/sh - 运行sh shell
# - #!/usr/bin/python - 指定python解释器
# - #!/usr/bin/perl - 指定perl解释器


# 指定编译器
nvcc=nvcc
g++=g++

# 编译参数
cflags="-O2"
cuda_libs="-lcudart -lcublas"

# 源文件
main_file="main.cpp"
kernel_file="kernel.cu" 

# 生成的文件
main_o="main.o"
kernel_o="kernel.o"
exe="demo"

# 编译主程序
$g++ $cflags -c $main_file -o $main_o

# 编译CUDA kernel
$nvcc $cflags -c $kernel_file -o $kernel_o

# 链接可执行文件
$g++ $main_o $kernel_o -o $exe $cuda_libs

# 清理
clean(){
  rm -f $main_o $kernel_o $exe
}

要运行这个shell脚本,主要有以下几个步骤:

1. 将脚本保存为一个文件,比如取名为 compile.sh

2. 打开终端,切换到脚本所在目录

3. 为脚本添加可执行权限:

chmod +x compile.sh

4. 执行脚本:

./compile.sh

这样就可以运行这个编译CUDA程序的shell脚本了。

5. 清理编译结果运行时加上clean选项可以清理生成的文件:

./compile.sh clean

6. 增加执行权限对编译生成的可执行文件也可以添加执行权限:

chmod +x demo

另外,还可以:

- 通过bash执行: bash compile.sh

- 直接作为可执行文件运行: ./compile.sh

- 参数执行: ./compile.sh clean (执行脚本的clean函数)

所以主要记住以下步骤:

1. 保存为脚本文件
2.  additions 权限
3. 在终端通过 ./脚本名 执行
4. 可以加参数执行脚本内特定函数

如果脚本文件不在当前目录,也可以通过完整路径EXECUTEPATH/compile.sh来运行。

自用
nvcc=nvcc
g++=g++ 

cflags="-O2"
cuda_libs="-lcudart -lcublas"

kernel_files="matrixMultiple.cu a.cu b.cu"
cpp_files="A.cpp B.cpp C.cpp"

kernel_o="matrixMultiple.o a.o b.o" 
cpp_o="A.o B.o C.o"

exe=hmw

$g++ $cflags -c $cpp_files -o $cpp_o
$nvcc $cflags -c $kernel_files -o $kernel_o
$nvcc $cflags -o $exe $cpp_o $kernel_o $cuda_libs
#nvcc链接的参数顺序不是非常严格,只要包含了所有必要的选项即可。
#$nvcc $cflags $cpp_o $kernel_o -o $exe $cuda_libs
#所以上面这个也可

简化 

bash
#!/bin/bash
set -x

# 设置CPATH指向cudnn头文件目录
OLD_PATH=$CPATH
CPATH=/usr/local/cuda-11.8/include
export CPATH

# 编译参数
cflags="-O2"
cuda_libs="-lcudart -lcublas -lcudnn" 

# 源代码目录
#cpp_src_dir=" "
#cuda_src_dir=" "

# 获取源文件列表
#cpp_files=($cpp_src_dir/*.cpp) 
#cu_files=($cuda_src_dir/*.cu)

# 源文件数组
cpp_files=(A.cpp B.cpp C.cpp)
cu_files=(matrixMultiply.cu a.cu b.cu)

# 生成对象文件名数组
cpp_objs=${cpp_files[@]/%.cpp/.o}
cu_objs=${cu_files[@]/%.cu/.o}

# 生成可执行文件名字
exe="exec"

# 编译cpp源文件
echo "Compiling C++ source files..."
for f in ${cpp_files[@]}; do
    g++ $cflags -c $f -o ${f/%.cpp/.o}
    if [ $? -ne 0 ]; then
        echo "C++ compile failed. Exiting..."
        exit 1
    fi
done

# 编译cuda源文件
echo "Compiling CUDA source files..."
for f in ${cu_files[@]}; do
    nvcc $cflags -c $f -o ${f/%.cu/.o}
    if [ $? -ne 0 ]; then
        echo "CUDA compiling failed. Exiting..."
        exit 1
    fi 
done

# 链接可执行文件
echo "Linking final executable..."
nvcc ${cpp_objs[@]} ${cu_objs[@]} -o $exe $cuda_libs

echo "Compile and link success!"

# 恢复原有CPATH
CPATH=$OLD_CPATH
export CPATH

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值