У меня есть простой код cuda, который я компилирую в библиотеку stati c с использованием nvcc
, и некоторый пользовательский код, который я компилирую с g++
и связываю с ранее скомпилированной библиотекой stati c. При попытке установить ссылку я получаю ошибки компоновщика для таких вещей, как cudaMalloc
, даже если я использую параметр -cudart static
в командной строке nvcc
компиляции.
Вот мой код:
//kern.hpp
#include <cstddef>
class Kern
{
private:
float* d_data;
size_t size;
public:
Kern(size_t s);
~Kern();
void set_data(float *d);
};
//kern.cu
#include <iostream>
#include <kern.hpp>
__global__ void kern(float* data, size_t size)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if(idx < size)
{
data[idx] = 0;
}
}
Kern::Kern(size_t s) : size(s)
{
cudaMalloc((void**)&d_data, size*sizeof(float));
}
Kern::~Kern()
{
cudaFree(d_data);
}
void Kern::set_data(float* d)
{
size_t grid_size = size;
std::cout << "Starting kernel with grid size " << grid_size << " and block size " << 1 <<
std::endl;
kern<<<grid_size, 1>>>(d_data, size);
cudaError_t err = cudaGetLastError();
if(err != cudaSuccess)
std::cout << "ERROR: " << cudaGetErrorString(err) << std::endl;
cudaDeviceSynchronize();
cudaMemcpy((void*)d, (void*)d_data, size*sizeof(float), cudaMemcpyDeviceToHost);
cudaDeviceSynchronize();
}
//main.cpp
#include <iostream>
#include <kern.hpp>
int main(int argc, char** argv)
{
std::cout << "starting" << std::endl;
Kern k(256);
float arr[256];
k.set_data(arr);
bool ok = true;
for(int i = 0; i < 256; ++i) ok &= arr[i] == 0;
std::cout << (ok ? "done" : "wrong") << std::endl;
}
Я компилирую керн с помощью nvcc
следующим образом:
nvcc -I ./ -lib --compiler-options '-fPIC' -o libkern.a kern.cu -cudart static
И затем main с g++
следующим образом:
g++ -o main main.cpp -I ./ -L. -L/opt/cuda/lib64 -lkern
Что дает ошибки:
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `Kern::Kern(unsigned long)':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x4d): undefined reference to `cudaMalloc'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `Kern::~Kern()':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x6b): undefined reference to `cudaFree'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `Kern::set_data(float*)':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x152): undefined reference to `__cudaPushCallConfiguration'
/usr/bin/ld: tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x175): undefined reference to `cudaGetLastError'
/usr/bin/ld: tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x1a1): undefined reference to `cudaGetErrorString'
/usr/bin/ld: tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x1c6): undefined reference to `cudaDeviceSynchronize'
/usr/bin/ld: tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x1ee): undefined reference to `cudaMemcpy'
/usr/bin/ld: tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x1f3): undefined reference to `cudaDeviceSynchronize'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `__cudaUnregisterBinaryUtil()':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x24e): undefined reference to `__cudaUnregisterFatBinary'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `__nv_init_managed_rt_with_module(void**)':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x269): undefined reference to `__cudaInitModule'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `__device_stub__Z4kernPfm(float*, unsigned long)':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x305): undefined reference to `__cudaPopCallConfiguration'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `__nv_cudaEntityRegisterCallback(void**)':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x430): undefined reference to `__cudaRegisterFunction'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `__sti____cudaRegisterAll()':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x44b): undefined reference to `__cudaRegisterFatBinary'
/usr/bin/ld: tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x47c): undefined reference to `__cudaRegisterFatBinaryEnd'
/usr/bin/ld: ./libkern.a(tmpxft_00001d30_00000000-8_kern.o): in function `cudaError cudaLaunchKernel<char>(char const*, dim3, dim3, void**, unsigned long, CUstream_st*)':
tmpxft_00001d30_00000000-5_kern.cudafe1.cpp:(.text+0x4d9): undefined reference to `cudaLaunchKernel'
collect2: error: ld returned 1 exit status
Но если я сделаю следующее:
g++ -o main main.cpp -I ./ -L. -L/opt/cuda/lib64 -lkern -lcudart
все работает. Мой вопрос в том, что, поскольку у меня есть -cudart static
в скомпилированной строке nvcc
, не должны ли libkern.a
уже иметь символы для среды выполнения cuda? Почему -lcudart
по-прежнему необходим в строке g++
?
Кроме того, если я изменю libkern.a
на общий объект, не будет работать связь со средой выполнения cuda в строке g++
. То есть работает следующее:
nvcc -I ./ -shared --compiler-options '-fPIC' -o libkern.so kern.cu -cudart static
g++ -o main main.cpp -I ./ -L. -L/opt/cuda/lib64 -lkern
Почему версия библиотеки stati c не работает, а версия общего объекта работает?
Обратите внимание, что я пробовал описанный выше сценарий ios после замены -cudart static
на -lcudart_static
в строке nvcc
, и после этой замены не произошло никаких изменений в поведении. Этого и следовало ожидать, поскольку два варианта по сути делают одно и то же, правильно?
Я на linux.
nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Wed_Oct_23_19:24:38_PDT_2019
Cuda compilation tools, release 10.2, V10.2.89
g++ --version
g++ (GCC) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Любая помощь и / или разъяснения приветствуются .