【问题标题】:Compiling part of a C++ program for GPU为 GPU 编译 C++ 程序的一部分
【发布时间】:2014-07-11 13:18:43
【问题描述】:

是否可以使用 nvcc 将 GPU 的 (C++) 代码编译成共享对象(.so 文件)并从 C++ 程序动态加载它(在这种情况下,Cern 的 ROOT,本质上是 @987654322 @ ("CINT"))。

我想运行的一个简单示例是:

extern "C"
void TestCompiled() {
  printf("test\n");
  exit(0); 
}

这段代码是用nvcc --compiler-options '-fPIC' -o TestCompiled_C.so --shared TestCompiled.cu 编译的。将共享对象加载到 ROOT 中:

{ // Test.C program
  int error, check;
  check = gROOT->LoadMacro("TestCompiled_C.so", &error);
  cout << "check " << check << " " << " error: " << error << endl;
  TestCompiled();  // run macro
  exit(0); 
}

加载库正常,但没有找到TestCompiled()

$ root -b -l Test.C
root [0] 
Processing Test.C...
check 0  error: 0
Error: Function Hello() is not defined in current scope  Test.C:11:
*** Interpreter error recovered ***

通过使用 ROOT 编译第一个测试脚本(没有 extern 行,使用 root TestCompiled.C++ 编译)来做同样的事情......我可以尝试什么来让 C++ 程序在 nvcc 进行编译时找到测试函数?

【问题讨论】:

  • 如果c++程序找不到test函数,说明库路径有问题。我不使用 nvcc,但通常您要么必须导出库路径,要么包含 -Wl,-rpath=/path/to/your/lib 以便找到 lib 和函数。运行ldd -v execuatablename,看看c++ 可执行文件查看库是否有任何问题。我确定您正在使用它,但 Cuda Toolkit 有详尽的文档。
  • @DavidC.Rankin 谢谢,但是库 is 找到(已加载),只是它没有找到其中的函数(可能是它被破坏了不同的方式?)...我的学生会看看你提供的链接。
  • 包含函数定义的头文件包含在你用nvcc编译的c++源文件中?
  • 没有包含头文件。我们会试试这个。但是请注意,如果 ROOT 自己编译第一个 (TestCompile) 程序,则一切正常:它不需要任何头文件来加载编译文件并运行其 TestCompiled() 函数。

标签: c++ dynamic-linking nvcc


【解决方案1】:

我假设正在输出的共享对象文件与任何其他共享库一样,例如使用 GCC 使用 shared 选项创建的共享库。在这种情况下,要动态加载对象,您需要使用dlopen 函数来获取共享对象的句柄。然后,您可以使用dlsym 函数在文件中查找符号。

void *object_handle = dlopen("TestCompiled_C.so", RTLD_NOW);
if (object_handle == NULL)
{
  printf("%s\n", dlerror());
  // Exit or return error code
}
void *test_compiled_ptr = dlsym(object_handle, "TestCompiled");
if (!test_compiled)
{
  printf("%s\n", dlerror());
  // Exit or return error code
}

void (*test_compiled)() = (void (*)()) test_compiled_ptr;
test_compiled();

编译时需要包含dlfcn.h 并与-ldl 链接。

这与您现在所做的不同之处在于您正在加载库静态而不是动态。尽管共享对象是“动态链接库”,因为它们在 Windows 世界中被调用,但按照您现在的方式进行操作是在程序启动时加载对象中的所有符号。要在运行时动态加载某些符号,您需要这样做。

【讨论】:

    【解决方案2】:

    我正在复制解决问题的answer from the RootTalk forum 的要点以供参考:

    一个关键点是ROOT(CINT)的C解释器需要一个“CINT字典”用于外部编译的函数。 (通过ROOT编译没有问题,因为ACLiC在预编译宏[root TestCompiled.C++]时会创建这个字典)。

    所以,必须创建一个接口TestCompiled.h++

    #ifdef __cplusplus
    extern "C" {
    #endif
    
      void TestCompiled(void);
    
    #ifdef __cplusplus
    } /* end of extern "C" */
    #endif
    

    接口必须与共享对象一起加载到 ROOT 中:

    { // Test.C ROOT/CINT unnamed macro (interpreted)
      Int_t check, error;
      check = gROOT->LoadMacro("TestCompiled_C.so", &error);
      std::cout << "_C.so check " << check << " error " << error << std::endl;
      check = gROOT->LoadMacro("TestCompiled.h++", &error);
      std::cout << "_h.so check " << check << " error " << error << std::endl;
      TestCompiled(); // execute the compiled function
    }
    

    ROOT 现在可以使用外部编译的程序:root -b -l -n -q Test.C 有效。

    这可以在以下TestCompiled.C 上使用例如 g++ 进行测试:

    #include <cstdio>
    extern "C" void TestCompiled(void) { printf("test\n"); }
    

    编译

    g++ -fPIC -shared -o TestCompiled_C.so TestCompiled.C
    

    【讨论】:

      猜你喜欢
      • 2013-05-16
      • 2014-12-05
      • 2012-09-17
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-16
      相关资源
      最近更新 更多