linker - CUDA:头文件中使用的 __device__ 函数上的 LNK2005 错误

标签 linker cuda

我有一个 设备 在头文件中定义的函数。它在头文件中的原因是因为它被 使用。全局内核,它需要在头文件中,因为它是模板内核。

当此头文件包含在 2 个或更多 .cu 文件中时,我在链接期间收到 LNK2005 错误:

FooDevice.cu.obj : error LNK2005: "int __cdecl getCurThreadIdx(void)" (?getCurThreadIdx@@YAHXZ) already defined in Main.cu.obj



为什么会导致这个错误?如何解决?

这是产生上述错误的示例代码:

FooDevice.h:
#ifndef FOO_DEVICE_H
#define FOO_DEVICE_H

__device__ int getCurThreadIdx()
{
    return ( ( blockIdx.x * blockDim.x ) + threadIdx.x );
}

template< typename T >
__global__ void fooKernel( const T* inArr, int num, T* outArr )
{
    const int threadNum = ( gridDim.x * blockDim.x );

    for ( int idx = getCurThreadIdx(); idx < num; idx += threadNum )
        outArr[ idx ] = inArr[ idx ];

    return;
}

__global__ void fooKernel2( const int* inArr, int num, int* outArr );

#endif // FOO_DEVICE_H

FooDevice.cu:
#include "FooDevice.h"

// One other kernel that uses getCurThreadIdx()
__global__ void fooKernel2( const int* inArr, int num, int* outArr )
{
    const int threadNum = ( gridDim.x * blockDim.x );

    for ( int idx = getCurThreadIdx(); idx < num; idx += threadNum )
        outArr[ idx ] = inArr[ idx ];

    return;
}

主.cu:
#include "FooDevice.h"

int main()
{
    int num             = 10;
    int* dInArr         = NULL;
    int* dOutArr        = NULL;
    const int arrSize   = num * sizeof( *dInArr );

    cudaMalloc( &dInArr, arrSize );
    cudaMalloc( &dOutArr, arrSize );

    // Using template kernel
    fooKernel<<< 10, 10 >>>( dInArr, num, dOutArr );

    return 0;
}

最佳答案

为什么会导致这个错误?

因为你已经在 FooDevice.cu 和 Main.cu 中包含了你的头文件,所以你现在有两个相同函数的副本,链接器会检测到这一点。

如何解决?

如果您在 foo.h 中定义了以下内容

template<typename T> __device__ T foo(T x)
{
    return x;
}

还有两个 .cu 文件,它们都包含 foo.h 并包含对它的调用,例如
int x = foo<int>(1);

然后你可以强制 foo() 内联:
template<typename T>
inline __device__ T foo(T x)
{
    return x;
}

并调用:
int x = foo<int>(1);

这将阻止它被多次声明。

Function templates are an exempt of One Defintion Rule and may be more than one definition of them in different translation unit's. Full function template specialization is not a template, rather an ordinary function, so you need to use inline keyword not to violate ODR if you want to put them in a header file included into several translation unit's.



取自 http://www.velocityreviews.com/forums/t447911-why-does-explicit-specialization-of-function-templates-cause-generation-of-code.html

另见:http://en.wikipedia.org/wiki/One_Definition_Rule

我像这样改变了你的代码:
inline __device__ int getCurThreadIdx()
{
    return ( ( blockIdx.x * blockDim.x ) + threadIdx.x );
}

template< typename T >
__global__ void fooKernel( const T* inArr, int num, T* outArr )
{
    const int threadNum = ( gridDim.x * blockDim.x );

    for ( int idx = getCurThreadIdx(); idx < num; idx += threadNum )
        outArr[ idx ] = inArr[ idx ];

    return;
}

现在可以编译了。您没有内联 getCurThreadIdx() 的声明违反了一个定义规则。

关于linker - CUDA:头文件中使用的 __device__ 函数上的 LNK2005 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5295503/

相关文章:

cuda - 是否可以在 AMD GPU 上运行 CUDA?

c++ - 如何检查为什么链接需要某些符号?

c++ - Lapack 链接错误,使用 -fPIC 重新编译

c++ - 将文件 (.a) 链接到共享对象 (.so)

c++ - 元组上的推力排序非常慢

c++ - CUDA:二维数组索引给出意想不到的结果

algorithm - CUDA:线程中的更大问题

CUDA 地址越界

c++ - 将静态链接库变成动态链接库

c# - Type.GetProperties 什么都不返回