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

时间:2011-03-14 06:36:25

标签: linker cuda

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

如果此头文件包含在2个或更多.cu文件中,则在链接期间出现LNK2005错误:

  

FooDevice.cu.obj:错误LNK2005:“int   __cdecl getCurThreadIdx(void)“(?getCurThreadIdx @@ YAHXZ)已定义   在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;
}

Main.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;
}

2 个答案:

答案 0 :(得分:7)

为什么会导致此错误?

因为你已经在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);

这将阻止它被多次声明。

  

功能模板是免除的   一个定义规则,可能更多   而不是他们中的一个定义   不同的翻译单位。充分   功能模板专业化是   不是模板,而是普通的   功能,所以你需要使用内联   关键字如果需要,不要违反ODR   将它们放在包含的头文件中   进入几个翻译单位。

取自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()内联的声明违反了一个定义规则。

答案 1 :(得分:0)

应该内联。您可以尝试添加inline关键字。

也许您可以删除不必要的代码并创建一个简单的文本示例供我们查看?通常问题在于细节......