FreddyKay FreddyKay - 11 months ago 39
C++ Question

CUDA mutliple definition error during linking

I am starting to use CUDA and thrust for a project of mine, so I am still new to some of it aspects. I ran into the following problem.

I have to separate .cu files which I want to use with a common header file which has a struct that both of them shall be able to use. It is something like this:

#ifndef global_h
#define global_h
struct globalParam
uint64_t spaceToUse;
globalParams() : spaceToUse(1024*1024*1024) {}

globalParam glParam;

The First .cu file looks like this:

#ifndef firstcufile_cu
#define firstcufile_cu
#include "Global.h"

template<typename T>
QVector<T> GPUcalculateNormSq(const QVector<T>& real, const QVector<T>& imag)
QVector<T> result (real.size());
uint64_t maxSpace = glParam.spaceToUse;

//Some Code to use thrust and using tops maxSpace bytes.

return result;

template QVector<float> GPUcalculateNormSq(const QVector<float>& real, const QVector<float>& imag);
template QVector<double> GPUcalculateNormSq(const QVector<double>& real, const QVector<double>& imag);


The second .cu file looks like this:

#ifndef secondcufile_cu
#define secondcufile_cu
#include "Global.h"

template<typename T>
double getMean(const T& vec)
uint64_t spaceNeededOnGPU = vec.size() * sizeof (T);
uint64_t maxSpace = glParam.spaceToUse;

//Some code to make sure tops maxSpace bytes on GPU
double sum = thrust::reduce(std::begin(vec), std::end(vec));
return sum / vec.size();

template double getMean(const QVector<float>& vec);

Now the error I get is:

secondcufilecuda_d.o:(.bss+0x18): multiple definition of `glParam'
firstcufilecuda_d.o:(.bss+0x18): first defined here

The functions above seem similar, but thats becauseI tried to make them as simple as possible. It would be possible to write everything into a single .cu file, but I would like to split it up if possible.

What am I doing wrong with the linker? I am compiling and linking from within a Qt Creator project. Let me know if you need my lines from the .pro file to know how I use the nvcc compiler.

Answer Source

It's due to the fact that Global.h is included multiple times and each time it is included it provides: globalParam glParam;. That is not a forward declaration (i.e. not just a type signature) but amounts to an actual instantiation of a globalParam struct. This then, causes there to be two variables both named glParam (each corresponding to a separate #include of Global.h) and that gives you multiple definition errors.

Quick fix: try using extern if you wish to share your global variable (then the linker knows that it's just a reference to, well, a 'external' symbol).

Better fix: consider refactoring your code to pass in the global parameter via reference or pointer as argument to your functions. That way you won't even have to declare the glParam variable in the header, side stepping the entire issue and making your code more easy to understand/reason about into the bargain.