跨文件引用代码的完整指南
在CUDA编程中,当你有多个.cu文件时,可以通过头文件(.h或.cuh)来实现代码的共享和引用。下面是详细的实现方法。
1. 基本项目结构
project/
├── helper.cu # 包含需要共享的CUDA函数
├── helper.cuh # 声明helper.cu中的函数
├── main.cu # 主程序文件
└── Makefile # 编译脚本
2. 实现步骤
2.1. 创建头文件(.cuh)
helper.cuh - 声明需要共享的函数和内核:
#ifndef HELPER_CUH
#define HELPER_CUH
#include <cuda_runtime.h>
// 声明设备函数(如果需要在多个文件中使用)
__device__ float device_helper_function(float x);
// 声明全局函数(内核)
__global__ void shared_kernel(float* input, float* output, int n);
// 声明主机辅助函数
void host_helper_function(float* data, int size);
// 声明CUDA内存管理函数
cudaError_t allocate_memory(float** ptr, size_t size);
cudaError_t free_memory(float* ptr);
#endif // HELPER_CUH
2.2. 实现源文件(.cu)
helper.cu - 实现头文件中声明的函数:
#include "helper.cuh"
#include <stdio.h>
// 实现设备函数
__device__ float device_helper_function(float x) {
return x * x + 2.0f * x + 1.0f;
}
// 实现全局函数(内核)
__global__ void shared_kernel(float* input, float* output, int n) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < n) {
output[idx] = device_helper_function(input[idx]);
}
}
// 实现主机辅助函数
void host_helper_function(float* data, int size) {
printf("Processing %d elements in helper function\n", size);
// 这里可以添加更多的处理逻辑
}
// 实现内存分配函数
cudaError_t allocate_memory(float** ptr, size_t size) {
return cudaMalloc(ptr, size);
}
cudaError_t free_memory(float* ptr) {
return cudaFree(ptr);
}
2.3. 主程序文件(.cu)
main.cu - 引用并使用另一个文件中的代码:
#include "helper.cuh" // 包含共享的头文件
#include <iostream>
#include <cuda_runtime.h>
// 错误检查宏
#define CHECK_CUDA_ERROR(call) \
{ \
cudaError_t err = call; \
if (err != cudaSuccess) { \
std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__ \
<< " - " << cudaGetErrorString(err) << std::endl; \
exit(1); \
} \
}
int main() {
const int n = 1000;
size_t size = n * sizeof(float);
// 使用helper.cu中的函数分配内存
float *d_input, *d_output;
CHECK_CUDA_ERROR(allocate_memory(&d_input, size));
CHECK_CUDA_ERROR(allocate_memory(&d_output, size));
// 使用helper.cu中的主机函数
host_helper_function(nullptr, n);
// 配置内核启动参数
int blockSize = 256;
int gridSize = (n + blockSize - 1) / blockSize;
// 调用helper.cu中定义的内核
shared_kernel<<<gridSize, blockSize>>>(d_input, d_output, n);
// 检查内核执行错误
CHECK_CUDA_ERROR(cudaGetLastError());
CHECK_CUDA_ERROR(cudaDeviceSynchronize());
std::cout << "Kernel executed successfully!" << std::endl;
// 清理
CHECK_CUDA_ERROR(free_memory(d_input));
CHECK_CUDA_ERROR(free_memory(d_output));
return 0;
}
3. 编译方法
3.1. 使用NVCC直接编译
# 【方法一】编译所有.cu文件并链接
nvcc -o my_program main.cu helper.cu
# 【方法二】分步编译
nvcc -c helper.cu -o helper.o
nvcc -c main.cu -o main.o
nvcc main.o helper.o -o my_program
3.2. 使用Makefile
Makefile:
# 编译器设置
NVCC = nvcc
NVCC_FLAGS = -O3
TARGET = my_program
# 源文件
SOURCES = main.cu helper.cu
OBJECTS = $(SOURCES:.cu=.o)
# 默认目标
all: $(TARGET)
# 链接目标文件
$(TARGET): $(OBJECTS)
$(NVCC) $(NVCC_FLAGS) $(OBJECTS) -o $(TARGET)
# 编译.cu文件到.o文件
%.o: %.cu
$(NVCC) $(NVCC_FLAGS) -c $< -o $@
# 清理
clean:
rm -f $(TARGET) $(OBJECTS)
# 重新编译
rebuild: clean all
编译和运行:
# 编译项目
make
# 运行程序
./my_program
Processing 1000 elements in helper function
Kernel executed successfully!
3.3. 使用CMake编译
# 设置CMake最低版本要求
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
# 设置项目名称和版本
project(my_program
VERSION 1.0
DESCRIPTION "A simple CUDA project with CMake"
LANGUAGES CXX CUDA) # 注意:这里必须包含CUDA语言
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置CUDA架构(根据你的GPU调整)
set(CUDA_ARCH "80" CACHE STRING "CUDA architecture")
set(CMAKE_CUDA_ARCHITECTURES ${CUDA_ARCH})
# 打印配置信息
message(STATUS "Building for CUDA architecture: ${CUDA_ARCH}")
# 添加包含目录
include_directories(./)
# 查找CUDA工具包(现代CMake版本通常不需要显式调用,但为了兼容性保留)
find_package(CUDAToolkit REQUIRED)
# 添加可执行文件
add_executable(${PROJECT_NAME}
main.cu
helper.cu
)
# 设置CUDA编译选项
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<COMPILE_LANGUAGE:CUDA>:
-Xcompiler=-Wall
-Xcompiler=-Wextra
--default-stream per-thread
>
)
# 设置目标属性
set_target_properties(${PROJECT_NAME} PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
CUDA_RESOLVE_DEVICE_SYMBOLS ON
)
# 链接CUDA运行时库(现代CMake会自动处理,但显式声明更清晰)
target_link_libraries(${PROJECT_NAME} PRIVATE
CUDA::cudart
)
# 安装规则(可选)
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin
)
# 添加测试(可选)
enable_testing()
add_test(NAME run_cuda_example
COMMAND ${PROJECT_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)