c++ - 尝试与从 CUDA 对象构建的共享库链接时未定义的符号
问题描述
我正在尝试从几个 .cu 源文件和一个非常简单的 C++ 主程序构建一个简单的应用程序,它从一个 .cu 文件调用一个函数。我正在从已编译的 .cu 文件中创建一个共享库(.so 文件)。我发现一切都可以毫无问题地构建,但是当我尝试运行应用程序时,我收到一个链接器未定义符号错误,其中包含我从 main() 调用的 .cu 函数的错误名称。如果我构建一个静态库,我的应用程序运行得很好。这是我设置的makefile:
.PHONY: clean
NVCCFLAGS = -std=c++11 --compiler-options '-fPIC'
CXXFLAGS = -std=c++11
HLIB = libhello.a
SHLIB = libhello.so
CUDA_OBJECTS = bridge.o add.o
all: driver
%.o :: %.cu
nvcc -o $@ $(NVCCFLAGS) -c -I. $<
%.o :: %.cpp
c++ $(CXXFLAGS) -o $@ -c -I. $<
$(HLIB): $(CUDA_OBJECTS)
ar rcs $@ $^
$(SHLIB): $(CUDA_OBJECTS)
nvcc $(NVCCFLAGS) --shared -o $@ $^
#driver : driver.o $(HLIB)
# c++ -std=c++11 -fPIC -o $@ driver.o -L. -lhello -L/usr/local/cuda-10.1/targets/x86_64-linux/lib -lcudart
driver : driver.o $(SHLIB)
c++ -std=c++11 -fPIC -o $@ driver.o -L. -lhello
clean:
-rm -f driver *.o *.so *.a
以下是 makefile 用作素材的各种源文件。添加.cu:
__global__ void add(int n, int* a, int* b, int* c) {
int index = threadIdx.x;
int stride = blockDim.x;
for (int ii = index; ii < n; ii += stride) {
c[ii] = a[ii] + b[ii];
}
}
添加.h:
extern __global__ void add(int n, int* a, int* b, int* c);
桥接.cu:
#include <iostream>
#include "add.h"
void bridge() {
int N = 1 << 16;
int blockSize = 256;
int numBlocks = (N + blockSize - 1)/blockSize;
int* a;
int* b;
int* c;
cudaMallocManaged(&a, N*sizeof(int));
cudaMallocManaged(&b, N*sizeof(int));
cudaMallocManaged(&c, N*sizeof(int));
for (int ii = 0; ii < N; ii++) {
a[ii] = ii;
b[ii] = 2*ii;
}
add<<<numBlocks, blockSize>>>(N, a, b, c);
cudaDeviceSynchronize();
for (int ii = 0; ii < N; ii++) {
std::cout << a[ii] << " + " << b[ii] << " = " << c[ii] << std::endl;
}
cudaFree(a);
cudaFree(b);
cudaFree(c);
}
桥.h:
extern void bridge();
驱动程序.cpp:
#include "bridge.h"
int main() {
bridge();
return 0;
}
我对 cuda 很陌生,所以我希望这就是我做错了什么。我玩过一些使用 extern "C" 声明,但这似乎只是将“未定义符号”错误从运行时移动到构建时。
我熟悉最终得到未定义符号的各种方式,并且我提到了我已经执行的各种实验(静态链接、外部“C”声明),这些实验让我认为这个问题没有得到解决通过提出的重复问题。
我未解决的符号是_Z6bridgev
在我看来,链接器应该能够解析符号。如果我可以在 driver.o 上运行,我会看到:
0000000000000000 T main
U _Z6bridgev
如果我在 libhello.so 上运行 nm,我会看到:
0000000000006e56 T _Z6bridgev
解决方案
当 Robert Crovella 能够让我的示例在他的机器上运行,而我无法让他的示例在我的机器上运行时,我开始意识到我的问题与 cuda 或 nvcc 无关。事实上,对于共享库,加载器必须在运行时解析符号,而我的共享库不在“众所周知的位置”。刚才建了一个简单的测试用例,纯粹用c++源码,重复了我的失败。一旦我复制libhello.so
到/usr/local/lib
,我就能够driver
成功运行。所以,如果这是人民的意愿,我可以结束我最初的问题。
推荐阅读
- jointjs - 如何使jointJs矩形文本响应以使文本保持在矩形内?
- tensorflow - 如何创建我自己的手写数据集,如 IAM 数据集
- angular - 无法匹配任何路由。URL 段:同时使用多个路由器出口
- python - 在它的身体上移动箭头
- dynamics-crm - 在 Dynamics 365(版本 9.0)中修改业务流程的“LocalizedName”
- java - swing 组件无法在 javafx 应用程序中完全运行
- c# - C# 线性函数,带有 null 的小数数组
- email - 无法在谷歌应用程序脚本中将内联图像添加到电子邮件
- javascript - 使用计数器从函数中获取变量
- django - Django-Oscar form fork - 错误未知字段(但字段在模型中)