views:

1075

answers:

2

I have a CUDA program that works fine, but that is currently all written in one file. I'd like to split this big file into several smaller ones, in order to make it easier to maintain and navigate.

The new structure is :

foo.cuh
foo.cu
bar.cuh
bar.cu
main.cu

The .cuh header files contain structs and function prototypes, and the .cu files contain the function definitions (as usual). The main file includes bar.cuh, and bar.cu includes foo.cuh. All the .cu files include cutil_inline.h, in order to be able to use the CUDA functions.

Hence :

// main.cu
#include "bar.cuh"
#include <cutil_inline.h>

int main() [...]

// bar.cu
#include "bar.cuh"
#include "foo.cuh"
#include <cutil_inline.h>

[...]

// foo.cu
#include "foo.cuh"
#include <cutil_inline.h>

[...]

The problem is that when I compile my Visual Studio 2008 project with this new structure, I get tons of link errors :

error LNK2005: "void __cdecl __cutilBankChecker(unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,char *,int,char *,int)" (?__cutilBankChecker@@YAXIIIIIIPADH0H@Z) already defined in cuda_generated_foo.cu.obj cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cutilCondition(int,char *,int)" (?__cutilCondition@@YAXHPADH@Z) already defined in cuda_generated_foo.cu.obj cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cutilExit(int,char * *)" (?__cutilExit@@YAXHPAPAD@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "int __cdecl cutGetMaxGflopsDeviceId(void)" (?cutGetMaxGflopsDeviceId@@YAHXZ) already defined in cuda_generated_foo.cu.obj   cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cudaSafeCallNoSync(enum cudaError,char const *,int)" (?__cudaSafeCallNoSync@@YAXW4cudaError@@PBDH@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cudaSafeCall(enum cudaError,char const *,int)" (?__cudaSafeCall@@YAXW4cudaError@@PBDH@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cudaSafeThreadSync(char const *,int)" (?__cudaSafeThreadSync@@YAXPBDH@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cufftSafeCall(enum cufftResult_t,char const *,int)" (?__cufftSafeCall@@YAXW4cufftResult_t@@PBDH@Z) already defined in cuda_generated_foo.cu.obj  cuda_generated_bar.cu.obj

I understand what they mean (all those symbols already defined are part of cutil_inline.h) but I have to include this header in all files, otherwise it does not compile. What am I doing wrong ?

UPDATE: To clarify the situation : * with all code in one big file, it compiles, links and runs fine * with the new structure (several smaller files) and including cutil_inline.h in all .cu files, it compiles correctly but fails during linking * with the new structure and including cutil_inline.h only in the main file, it fails during compilation, saying that the cutil function are unknown in the files where cutil_inline.h was not included (as expected, but I had to try everything) - List item

A: 

Do you need to link with the cutil library (i.e. cutil32D.lib for 32-bit debug etc.)?

For some reason you have multiple definitions. Are you using the NVIDIA Cuda.rules file to enable Visual Studio to compile your .cu files to .obj files? It looks like you have modified the rules to link with cutil, whereas you should use the NVIDIA Cuda.rules to tell VS how to compile .cu to .obj, then modify the standard linker properties to pull in the cutil library.

Tom
Yes, I link with cutil32.lib. Why ?
Wookai
Because the symbols you are seeing errors on are provided by cutil32.lib, I misread and thought they were missing rather than duplicated. I've updated my answer.
Tom
I am actually using Cmake 2.8 to generate the VS2008 solution for my project. By looking at it, I'd say that the build rule is fairly similar to the nVidia CUDA rules distributed with the SDK.
Wookai
Can you post the command line used to compile each of the .cu files?
Tom
A: 

Somehow, the functions in cutil_inline.h aren't flagged as "inline" when they are compiled.

If you got this error in a normal non-Cuda C++ project, the answer would simply be that you have function definitions (not just declarations) in the header file and the "inline" keyword in missing.

You might have to generate the corresponding .i files (pre-processor) output to really see what's going on after all macro expansion.

EDIT 1/2/2009

If you can't figure out what's wrong just by reading the .h files, because of some macro expansion obfuscation, here's how you generate the .i file:

  1. In the Visual Studio "Solution Explorer" window, right-click on the source file and choose "Properties".

  2. In the properties tree, select "C/C++", "Preprocessor".

  3. Change the "Generate Preprocessed File" from "No" to one of the other options.

  4. Then compile the file. The compiler will write the preprocessor output to a file and then stop without actually compiling. You can see in the .i file produced what the final result of all macro expansions is.

  5. You will have to go back and reset that property back to "No" in order to get the project to compiler to work properly again.

Die in Sente
How can I do that ?
Wookai
Add --keep to the nvcc command lines to keep a whole load of intermediate files.
Tom