Ссылка на общую библиотеку cuda: неопределенная ссылка на cudaRegisterLinkedBinary
Цель:
- создайте разделяемую библиотеку, содержащую мои ядра CUDA, которая имеет CUDA-свободный упаковщик / заголовок.
- создать
test
исполняемый файл для общей библиотеки.
проблема
- общая библиотека
MYLIB.so
похоже компилируется нормально. (нет проблем). - Ошибка в связывании:
./libMYLIB.so: undefined reference to __cudaRegisterLinkedBinary_39_tmpxft_000018cf_00000000_6_MYLIB_cpp1_ii_74c599a1
упрощенный make-файл:
libMYlib.so : MYLIB.o
g++ -shared -Wl,-soname,libMYLIB.so -o libMYLIB.so MYLIB.o -L/the/cuda/lib/dir -lcudart
MYLIB.o : MYLIB.cu MYLIB.h
nvcc -m64 -arch=sm_20 -dc -Xcompiler '-fPIC' MYLIB.cu -o MYLIB.o -L/the/cuda/lib/dir -lcudart
test : test.cpp libMYlib.so
g++ test.cpp -o test -L. -ldl -Wl,-rpath,. -lMYLIB -L/the/cuda/lib/dir -lcudart
в самом деле
nm libMYLIB.so
показывает, что все функции API CUDA являются "неопределенными символами":
U __cudaRegisterFunction
U __cudaRegisterLinkedBinary_39_tmpxft_0000598c_00000000_6_CUPA_cpp1_ii_74c599a1
U cudaEventRecord
U cudaFree
U cudaGetDevice
U cudaGetDeviceProperties
U cudaGetErrorString
U cudaLaunch
U cudaMalloc
U cudaMemcpy
Так что CUDA как-то не связалось с общей библиотекой MYLIB.so Что мне не хватает?
CUDA даже не связывался с объектным файлом как-то:
nm MYLIB.o
U __cudaRegisterFunction
U __cudaRegisterLinkedBinary_39_tmpxft_0000598c_00000000_6_CUPA_cpp1_ii_74c599a1
U cudaEventRecord
U cudaFree
U cudaGetDevice
U cudaGetDeviceProperties
U cudaGetErrorString
U cudaLaunch
U cudaMalloc
U cudaMemcpy
(так же, как и выше)
3 ответа
Вот пример создания общего объекта linux по указанным вами направлениям:
- создайте разделяемую библиотеку, содержащую мои ядра CUDA, которая имеет CUDA-свободный упаковщик / заголовок.
- создать тестовый исполняемый файл для общей библиотеки.
Сначала общая библиотека. Команды сборки для этого следующие:
nvcc -arch=sm_20 -Xcompiler '-fPIC' -dc test1.cu test2.cu
nvcc -arch=sm_20 -Xcompiler '-fPIC' -dlink test1.o test2.o -o link.o
g++ -shared -o test.so test1.o test2.o link.o -L/usr/local/cuda/lib64 -lcudart
Возможно, вы пропустили второй шаг выше в вашем make-файле, но я не проанализировал, есть ли другие проблемы с вашим make-файлом.
Теперь для тестового исполняемого файла команды сборки выглядят следующим образом:
g++ -c main.cpp
g++ -o testmain main.o test.so
Чтобы запустить его, просто выполните testmain
исполняемый, но не забудьте test.so
библиотека на вашем LD_LIBRARY_PATH
,
Это файлы, которые я использовал для тестирования:
test1.h:
int my_test_func1();
test1.cu:
#include <stdio.h>
#include "test1.h"
#define DSIZE 1024
#define DVAL 10
#define nTPB 256
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
__global__ void my_kernel1(int *data){
int idx = threadIdx.x + (blockDim.x *blockIdx.x);
if (idx < DSIZE) data[idx] =+ DVAL;
}
int my_test_func1(){
int *d_data, *h_data;
h_data = (int *) malloc(DSIZE * sizeof(int));
if (h_data == 0) {printf("malloc fail\n"); exit(1);}
cudaMalloc((void **)&d_data, DSIZE * sizeof(int));
cudaCheckErrors("cudaMalloc fail");
for (int i = 0; i < DSIZE; i++) h_data[i] = 0;
cudaMemcpy(d_data, h_data, DSIZE * sizeof(int), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy fail");
my_kernel1<<<((DSIZE+nTPB-1)/nTPB), nTPB>>>(d_data);
cudaDeviceSynchronize();
cudaCheckErrors("kernel");
cudaMemcpy(h_data, d_data, DSIZE * sizeof(int), cudaMemcpyDeviceToHost);
cudaCheckErrors("cudaMemcpy 2");
for (int i = 0; i < DSIZE; i++)
if (h_data[i] != DVAL) {printf("Results check failed at offset %d, data was: %d, should be %d\n", i, h_data[i], DVAL); exit(1);}
printf("Results check 1 passed!\n");
return 0;
}
test2.h:
int my_test_func2();
test2.cu:
#include <stdio.h>
#include "test2.h"
#define DSIZE 1024
#define DVAL 20
#define nTPB 256
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
__global__ void my_kernel2(int *data){
int idx = threadIdx.x + (blockDim.x *blockIdx.x);
if (idx < DSIZE) data[idx] =+ DVAL;
}
int my_test_func2(){
int *d_data, *h_data;
h_data = (int *) malloc(DSIZE * sizeof(int));
if (h_data == 0) {printf("malloc fail\n"); exit(1);}
cudaMalloc((void **)&d_data, DSIZE * sizeof(int));
cudaCheckErrors("cudaMalloc fail");
for (int i = 0; i < DSIZE; i++) h_data[i] = 0;
cudaMemcpy(d_data, h_data, DSIZE * sizeof(int), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy fail");
my_kernel2<<<((DSIZE+nTPB-1)/nTPB), nTPB>>>(d_data);
cudaDeviceSynchronize();
cudaCheckErrors("kernel");
cudaMemcpy(h_data, d_data, DSIZE * sizeof(int), cudaMemcpyDeviceToHost);
cudaCheckErrors("cudaMemcpy 2");
for (int i = 0; i < DSIZE; i++)
if (h_data[i] != DVAL) {printf("Results check failed at offset %d, data was: %d, should be %d\n", i, h_data[i], DVAL); exit(1);}
printf("Results check 2 passed!\n");
return 0;
}
main.cpp:
#include <stdio.h>
#include "test1.h"
#include "test2.h"
int main(){
my_test_func1();
my_test_func2();
return 0;
}
Когда я компилирую в соответствии с данными командами и запускаю ./testmain
Я получил:
$ ./testmain
Results check 1 passed!
Results check 2 passed!
Обратите внимание, что если вы предпочитаете, вы можете сгенерировать libtest.so
вместо test.so
, а затем вы можете использовать измененную последовательность сборки для тестового исполняемого файла:
g++ -c main.cpp
g++ -o testmain main.o -L. -ltest
Я не верю, что это имеет какое-то значение, но это может быть более знакомый синтаксис.
Я уверен, что есть несколько способов сделать это. Это всего лишь пример. Вы можете также просмотреть соответствующий раздел руководства nvcc, а также просмотреть примеры.
РЕДАКТИРОВАТЬ: я проверил это под CUDA 5.5 RC, и последний шаг ссылки на приложение жаловался на то, что не найти CUDART Lib (warning: libcudart.so.5.5., needed by ./libtest.so, not found
). Однако следующая относительно простая модификация (пример Makefile) должна работать под cuda 5.0 или cuda 5.5.
Makefile:
testmain : main.cpp libtest.so
g++ -c main.cpp
g++ -o testmain -L. -ldl -Wl,-rpath,. -ltest -L/usr/local/cuda/lib64 -lcudart main.o
libtest.so : link.o
g++ -shared -Wl,-soname,libtest.so -o libtest.so test1.o test2.o link.o -L/usr/local/cuda/lib64 -lcudart
link.o : test1.cu test2.cu test1.h test2.h
nvcc -m64 -arch=sm_20 -dc -Xcompiler '-fPIC' test1.cu test2.cu
nvcc -m64 -arch=sm_20 -Xcompiler '-fPIC' -dlink test1.o test2.o -o link.o
clean :
rm -f testmain test1.o test2.o link.o libtest.so main.o
Другие ответы не работали для меня (возможно, потому что я использую cuda 10). Решение, которое работало для меня, заключалось в компиляции файлов cuda:
nvcc -dc -o cuda_file.o cuda_file.cu
Чем компилировать файл C++ как:
g++ -c -o cpp_file.o cpp_file.cpp
И, наконец, связать все, используя nvcc:
nvcc -o my_prog cpp_file.o cuda_file.o -lcudart -lcuda -L<other stuff>
Не воспринимайте этот код буквально. Но ядром решения этой ошибки было использование nvcc вместо g ++ на последнем этапе компоновки.
Вы пытались явно отключить код перемещаемого устройства? т.е. -rdc=false
? Я получил это undefined reference to __cudaRegisterLinkedBinaryWhatever
с -rdc=true
и он ушел, когда я его убрал. Хотя мне не хватает специалиста, чтобы объяснить, что именно происходит с этим.