簡體   English   中英

將庫的主機端和 CUDA 設備端版本分開

[英]Separate the host-side and CUDA-device-side versions of library

我有一個帶有__host__ __device__函數的庫。 我還有一個#ifdef __CUDACC__小工具,它確保常規 C++ 編譯器看不到__host__ __device__並因此可以編譯這些函數。

現在,我想在一個普通的 C++ 靜態庫文件(Linux 上的.a )中使用我的庫函數的編譯主機端版本 - 我什至希望在 CUDA 不可用時可以編譯該庫; 我希望在單獨的靜態庫中編譯設備端版本。

我快到了(我想),但是遇到了鏈接錯誤。 這里是這樣一個庫的玩具源、一個測試程序(它調用一個函數的設備端和主機端版本)和我使用的構建命令。

我怎么了?


  • my_lib.hpp (庫頭文件):
#ifdef __CUDACC__
__host__ __device__
#endif
void foo(int*x, int* y);
int bar();
  • my_lib.cu (庫源):
#include "my_lib.hpp"

#ifdef __CUDACC__
__host__ __device__
#endif
void foo(int*x, int* y)  { *x = *y; }

int bar() { return 5; }
  • main.cu (測試程序):
#include "my_lib.hpp"

__global__ void my_kernel() {
  int z { 78 };
  int w { 90 };
  foo(&z,&w);
}

int main() {
  int z { 123 };
  int w { 456 };
  foo(&z,&w);
  my_kernel<<<1,1>>>();
  cudaDeviceSynchronize();
  cudaDeviceReset();
}

我的構建命令:

c++ -c -x c++ -o my_lib-noncuda.o my_lib.cu
ar qc my_lib-noncuda.a my_lib-noncuda.o
ranlib my_lib-noncuda.a
nvcc -dc -o my_lib-cuda.o my_lib.cu
ar qc my_lib-cuda.a my_lib-cuda.o
ranlib my_lib-cuda.a
nvcc -dc -o main.rdc.o main.cu
nvcc -dlink -o main.o main.rdc.o my_lib-cuda.a
c++ -o main main.o my_lib-noncuda.a -lcudart

我得到的錯誤 - 在最后一個鏈接命令上:

/usr/bin/ld: main.o: in function `__cudaRegisterLinkedBinary_39_tmpxft_00003f88_00000000_6_main_cpp1_ii_e7ab3416':
link.stub:(.text+0x5a): undefined reference to `__fatbinwrap_39_tmpxft_00003f88_00000000_6_main_cpp1_ii_e7ab3416'
/usr/bin/ld: main.o: in function `__cudaRegisterLinkedBinary_41_tmpxft_00003f69_00000000_6_my_lib_cpp1_ii_ab44b3f6':
link.stub:(.text+0xaa): undefined reference to `__fatbinwrap_41_tmpxft_00003f69_00000000_6_my_lib_cpp1_ii_ab44b3f6'
collect2: error: ld returned 1 exit status

筆記:

  • 我在 Devuan GNU/Linux 上使用 CUDA 10.1 和 g++ 9.2.1。
  • 這是對已刪除問題的“跟進”; @talonmies 評論說我最好准確地展示我所做的; 這在某種程度上改變了問題。
  • 有點相關的問題: 這個

讓我們將您的示例修改為我認為您的實際使用案例。 修改將main()放入一個.cpp文件中,由g++編譯,並將 CUDA 代碼放入一個單獨的.cu文件中,由nvcc編譯。 這對於使您的兩個庫設置工作很重要; 並且是有道理的,因為“主要包含需要單獨編譯和鏈接的 CUDA 內核”是nvcc編譯模型的特殊情況。

重組后的代碼:

main.cu :

include "my_lib.hpp"

__global__ void my_kernel() {
  int z { 78 };
  int w { 90 };
  foo(&z,&w);
}

int cudamain()
{
  my_kernel<<<1,1>>>();
  return 0;
}

main.cpp :

#include <cuda_runtime_api.h>
#include "my_lib.hpp"

extern int cudamain();

int main() {
  int z { 123 };
  int w { 456 };
  foo(&z,&w);
  cudamain();
  cudaDeviceSynchronize();
  cudaDeviceReset();
}

所有其他文件保持在問題中。

構建程序所需的命令現在是:

c++ -c -x c++ -o my_lib-noncuda.o my_lib.cu
ar qc my_lib-noncuda.a my_lib-noncuda.o
ranlib my_lib-noncuda.a

nvcc -std=c++11 -dc -o my_lib-cuda.rdc.o my_lib.cu
ar qc my_lib-cuda.a my_lib-cuda.rdc.o
ranlib my_lib-cuda.a

# Until this line - identical to what you have tried in your question

nvcc -std=c++11 -c -rdc=true main.cu -o main.cu.o 
nvcc -dlink -o main.o main.cu.o my_lib-cuda.a

c++ -std=c++11 -o main main.cpp main.o main.cu.o -I/path/to/cuda/include \
    -L/path/to/cuda/lib64 my_lib-cuda.a my_lib-noncuda.a -lcudart -lcudadevrt

要記住的重要一點是,主機端組件需要在構建中進行。 因此,您必須將 CUDA 主機代碼的nvcc輸出傳遞給主鏈接,並且還必須將您的 CUDA 側庫添加到主鏈接。 否則將缺少對代碼的主機端運行時 API 支持。 另請注意,您必須鏈接設備運行時庫才能使其正常工作。

以下是創建兩個庫的方法,一個僅包含 CUDA 設備功能,另一個僅包含主機功能。 您可以省略“復雜的” #if#ifndef保護。 但是,您的庫my_lib-cuda.a也會有“非 CUDA 代碼”。

對於其他問題,請參閱 @talonmies 社區 wiki 答案或參考我已在評論中發布的鏈接: https ://devblogs.nvidia.com/separate-compilation-linking-cuda-device-code/ - “高級用法”部分:使用不同的鏈接器”。

my_lib.cu

#include "my_lib.hpp"

#ifdef __CUDA_ARCH__
__device__
#endif
#if (defined __CUDA_ARCH__) || (not defined __CUDACC__)
void foo(int*x, int* y)  { *x = *y; }
#endif

#ifndef __CUDACC__
int bar() { return 5; }
#endif

庫的構建過程保持不變:(僅將ar qc更改為ar rc以替換現有文件,因此在不事先刪除庫的情況下重建時不會出現錯誤)

c++ -c -x c++ -o my_lib-noncuda.o my_lib.cu
ar rc my_lib-noncuda.a my_lib-noncuda.o
ranlib my_lib-noncuda.a
nvcc -dc -o my_lib-cuda.o my_lib.cu
ar rc my_lib-cuda.a my_lib-cuda.o 
ranlib my_lib-cuda.a 

構建 CUDA 程序:(通過僅使用nvcc而不是c++簡化,或者查看@talonmies 社區 wiki 答案)

nvcc -dc main.cu -o main.o
nvcc main.o my_lib-cuda.a my_lib-noncuda.a -o main

如果您還如上所述省略my_lib.cu#if#ifndef ,則可以省略指向my_lib-noncuda.a的鏈接。

構建一個C ++程序:(假設有#ifdef __CUDACC__圍繞在CUDA代碼衛士main.cu

c++ -x c++ -c main.cu -o main.o
c++ main.o my_lib-noncuda.a -o main

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM