gmemon
gmemon

Reputation: 2731

Linking cuda object file

I have one .cu file that contains my cuda kernel, and a wrapper function that calls the kernel. I have a bunch of .c files as well, one of which contains the main function. One of these .c files calls the wrapper function from the .cu to invoke the kernel.

I compile these files as follows:

LIBS=-lcuda -lcudart
LIBDIR=-L/usr/local/cuda/lib64
CFLAGS = -g -c -Wall -Iinclude -Ioflib
NVCCFLAGS =-g -c -Iinclude -Ioflib
CFLAGSEXE =-g -O2 -Wall -Iinclude -Ioflib

CC=gcc
NVCC=nvcc
objects := $(patsubst oflib/%.c,oflib/%.o,$(wildcard oflib/*.c))

table-hash-gpu.o: table-hash.cu table-hash.h
        $(NVCC) $(NVCCFLAGS) table-hash.cu -o table-hash-gpu.o

main: main.c $(objects) table-hash-gpu.o
    $(CC) $(CFLAGSEXE) $(objects) table-hash-gpu.o -o udatapath udatapath.c $(LIBS) $(LIBDIR)

So far everything is fine. table-hash-gpu.cu calls a function from one of the .c files. When linking for main, I get the error that the function is not present. Can someone please tell me what is going on?

Upvotes: 1

Views: 2684

Answers (1)

talonmies
talonmies

Reputation: 72335

nvcc compiles both device and host code using the host C++ compiler, which implies name mangling. If you need to call a function compiled with a C compiler in C++, you must tell the C++ compiler that it uses C calling conventions. I presume that the errors you are seeing are analogous to this:

$ cat cfunc.c 

float adder(float a, float b, float c)
{
    return a + 2.f*b + 3.f*c;
}

$ cat cumain.cu 

#include <cstdio>
float adder(float, float, float);

int main(void)
{
    float result = adder(1.f, 2.f, 3.f);
    printf("%f\n", result);
    return 0;
}

$ gcc -m32 -c cfunc.c
$ nvcc -o app cumain.cu cfunc.o
Undefined symbols:
  "adder(float, float, float)", referenced from:
      _main in tmpxft_0000b928_00000000-13_cumain.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

Here we have code compiled with nvcc (so the host C++ compiler) trying to call a C function and getting a link error, because the C++ code expects a mangled name for adder in the supplied object file. If the main is changed like this:

$ cat cumain.cu 

#include <cstdio>
extern "C" float adder(float, float, float);

int main(void)
{
    float result = adder(1.f, 2.f, 3.f);
    printf("%f\n", result);
    return 0;
}
$ nvcc -o app cumain.cu cfunc.o
$ ./app
14.000000

It works. Using extern "C" to qualify the declaration of the function to the C++ compiler, it will not use C++ mangling and linkage rules when referencing adder and the resulting code links correctly.

Upvotes: 3

Related Questions