【问题标题】:nvlink error : Undefined reference to * in 'Debug/*.cu.obj' (CUDA Separate Compilation, Visual Studio 2013)nvlink 错误:“Debug/*.cu.obj”中对 * 的未定义引用(CUDA 单独编译,Visual Studio 2013)
【发布时间】:2019-06-19 20:19:21
【问题描述】:

我有一个非常简单的字符串类,分别在 StringT.cu 和 StringT.cpp 中声明和定义。

StringT.cu

#ifndef STRING_T_CU
#define STRING_T_CU

#include "cuda_runtime.h"

class StringT
{
public:
   static const int MAX_LEN = 15;

   __host__ __device__ StringT(char const * s);
   __host__ __device__ ~StringT();
   __host__ __device__ char* Get();

private:
   char* str;
};

#endif

StringT.cpp

#include "StringT.cu"

#include <stdlib.h>
#include <malloc.h>

StringT::StringT(char const * s)
{
   str = (char*)malloc(MAX_LEN + 1);
   int k;
   for (k = 0; *s != NULL; ++s, ++k) {
      if (k > MAX_LEN) {
         break;
      }
      str[k] = *s;
   }
   str[k] = '\0';
}

StringT::~StringT()
{
   free(str);
}

char* StringT::Get()
{
   return str;
}

我想简单地调用 kernel.cu 中的类。

kernel.cu

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

#include "StringT.cu"
#include "CudaUtil.h"

__global__ void kernel()
{
   StringT s("aa");
   printf("%s", s.Get());
}

int main()
{
   kernel <<< 1, 1 >>> ();
   checkCudaErrors(cudaDeviceSynchronize());
   checkCudaErrors(cudaGetLastError());

   return 0;
}

但是这段代码编译失败,出现如下错误:

1>CUDALINK:nvlink 错误:“Debug/kernel.cu.obj”中对“_ZN7StringTC1EPKc”的未定义引用

1>CUDALINK:nvlink 错误:“Debug/kernel.cu.obj”中对“_ZN7StringT3GetEv”的未定义引用

1>CUDALINK:nvlink 错误:在“Debug/kernel.cu.obj”中未定义对“_ZN7StringTD1Ev”的引用

如您所见,所有方法都已定义。我还尝试按照this 帖子的指示更改运行时库。我应该补充一点,当我计划使用动态并行时,我启用了可重定位设备代码。同时,我确实遇到了this 文档,并在“在 CUDA 中使用单独编译”部分找到了一些说明。但是,我在这个项目中使用了 Visual Studio,并且不确定如何更改编译器设置。我尝试将各种东西添加到

C/C++ -> 命令行 -> 附加选项

CUDA C/C++ -> 命令行 -> 附加选项

链接器 -> 命令行 -> 附加选项

CUDA 链接器 -> 命令行 -> 附加选项

但仍然没有得到它的工作。有人知道吗?

已编辑 我重命名了包含字符串类的声明和定义的文件:

StringT.cuh

#ifndef STRING_T_CUH
#define STRING_T_CUH

#include "cuda_runtime.h"

class StringT
{
public:
   static const int MAX_LEN = 15;

   __host__ __device__ StringT(char const * s);
   __host__ __device__ ~StringT();
   __host__ __device__ char* Get();

private:
   char* str;
};

#endif

StringT.cu

#include "StringT.cuh"

#include <stdlib.h>
#include <malloc.h>

__host__ __device__ StringT::StringT(char const * s)
{
   str = (char*)malloc(MAX_LEN + 1);
   int k;
   for (k = 0; *s != NULL; ++s, ++k) {
      if (k > MAX_LEN) {
         break;
      }
      str[k] = *s;
   }
   str[k] = '\0';
}

__host__ __device__ StringT::~StringT()
{
   free(str);
}

__host__ __device__ char* StringT::Get()
{
   return str;
}

我使用 CUDA 8.0 安装中的 vs 集成选项附带的模板创建了项目,将可重定位代码更改为 true 并将 arch 更改为 sm_61、compute_61(我有 GTX 1080 Ti)。

在我将输出详细程度更改为详细信息后,错误消息是:

1>CUDALINK:nvlink 错误:“Debug/kernel.cu.obj”中对“_ZN7StringTC1EPKc”的未定义引用

1>CUDALINK:nvlink 错误:“Debug/kernel.cu.obj”中对“_ZN7StringT3GetEv”的未定义引用

1>CUDALINK:nvlink 错误:在“Debug/kernel.cu.obj”中未定义对“_ZN7StringTD1Ev”的引用

另一方面,我确实设法通过扩展一个示例项目“simpleSeparateCompilation”来编译和运行代码。但是,我看不到任何额外的命令行选项。现在这对我有用,但当然我还没有解决原来的问题。

【问题讨论】:

  • 您不能在 .cpp 文件中包含类成员函数的定义。如果这样做,将永远不会为 GPU 编译任何代码
  • 感谢您的回复。如果我将 .cpp 文件重命名为“StringTDef.cu”,我会收到如下错误:命令“nvcc ....”与代码 255 一起存在。但是相同的代码在没有 host 的情况下也可以编译b>device 限定符,但 ofc 没有生成设备代码。我想将声明和定义分开,因为我需要将标头包含在不同的文件中并避免多重定义错误。我该怎么做?
  • 您引用的错误只是表明编译失败。您能否将更新的代码和实际错误编辑到您的问题中。一般来说,您必须在 .cu 文件中添加注释 __device__ __host__,否则它将不起作用。您可以将声明和定义分开,这没问题。无论您遇到什么其他错误,都与我建议的更改无关
  • 谢谢。我已经更新了这个问题。至于 kernel.cu 文件,我更新了代码以包含“StringT.cuh”。
  • 如果您打算在不同的 .cu 文件中定义的内核中使用类中的设备函数,则需要使用单独的编译和设备链接

标签: visual-studio visual-studio-2013 cuda


【解决方案1】:

如果使用 Visual Studio,将 .cpp 重命名为 .cu 和/或将 .h 重命名为 .cuh 会/不起作用。

为了生成设备代码,除了启用“C++ File”和“Header File”之外,还必须添加“CUDA C/C++ File”或“CUDA C/C++ Header”

  1. 可重定位设备代码(属性 -> 配置属性 -> CUDA C/C++ -> 通用 -> 生成可重定位设备代码)
  2. 设备链接(属性 -> 配置属性 -> CUDA 链接器 -> 通用 -> 执行设备链接)

【讨论】:

    猜你喜欢
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    相关资源
    最近更新 更多