Noob Q: How to extern c function?

Hi. I have a simple problem that I can’t seem to figure out. I have two files: cuda.c and cudak.cu. The cu is the kernel, and the .c is a C program that calls the kernel. When I try to compile my program, I receive a linking error stating that runKernel in cuda.c is an unresolved external symbol.

Here is what is in the files:

//cuda.c

#include ...

#define ...

extern void runKernel(...);

int main(...){

    ...

    runKernel(...);

}
//cudak.cu

#include ...

#define ...

__global__ kernel(...){

    ....

}

extern void runKernel(...){

    .....

    kernel<<<x,y>>>(...);

};

This is just like the 'extern “C” ’ bit that I have seen and used in C++ programs with no problems, expect that I dropped the “C”. I have tried it with the “C” and with/without ‘extern’ in every possible combination, and it won’t work. What am I doing wrong? It is such a trivial thing, I am sure, but it is all that is holding me back right now.

I have split the program into two parts because I can’t get the cuda and mpi libs/headers to play nicely so I seperated the two. The mpi stuff is in cuda.c and the cuda stuff is in cudak.cu.

Using extern “C” in both of your files should work, i.e. extern “C” void runKernel().
Also make sure that linker is aware of .obj file created by nvcc.

When I try that it VS2005 tells me that there is a problem with having a string after “extern”. If I get rid of the “C” part it does not give me that error, but I get an unresolved symbol still. How do I make the linker aware of the .obj file? Is that the output field under custom build rules? I have that set…

That’s odd.

Can you give exact error message and number?

My main program is a C file, not C++. In C++ the 'extern"C" ’ bit works fine, but when I try 'extern “C” ’ in my C file it gives me this error:

Line (18) is the extern line which reads:

extern "C" void runKernel(const int argc, const char **argv,float*,float***,float*,float**,char**,int*,

       int,int,int,int,int,int,int,int,int,int);

Try this and let us know whether it works. In your cudak.cu file, split the definition and declaration of the function. So, you’ll end up with something like:

extern "C" void runKernel(...);

...

void runKernel(...)

{

    ...

}

And don’t forget to update the definition of the runKernel in the file that calls it.

Paulius

I’m attaching a small VS2005 project that has a kernel and kernel-launching function in a .cu file, the main in a .cpp file. Files are compiled into separate object files and then linked.

Note that the project assumes that CUDA library and include file directories are set in the VS environment. You can either add those to your environment, or modify the compilation rule for the .cu file (right-click, properties, custom-build step, general).

Paulius
obj_integ.zip (4.05 KB)

I had tried that before posting here, and I tried it again to make sure, and it still does not work. I’ve used the extern “C” before with no problems, but that was in a .cpp file. This is a .c file, so it is written in C, not C++, and C does not seem to allow a string after ‘extern’.

In the project you gave me, try changing the main.cpp to main.c and then you will see the problem (I think), after adding the argc,argv stuff. I cannot compile your project because of the “cuda_runtime.h” include file. What is this file? I have been using cutil.h, is this correct? I have written a test program that does some basic multiplication on my GPU, and it works great (using cutil.h), so I know that cutil.h can be used.

So does anyone have any ideas? There has to be a way to do this…

Well it seems to work now. Strange. I didn’t change anything - I just restarted my computer a few times. Thanks for everyone’s help.

SOLUTION FOUND!!!

In the .c file I have to do “extern void runKernel(…);” and in the .cu file I have to do “extern “C” void runKernel(…);”. It is strange that I have to mix them like that, but it seems to work now.

cutil.h only gives you CUDA utility macros and a few functions that come with the SDK. It’s important to understand, that cutil stuff is not part of CUDA, it’s an optional add-on.

You don’t need to include cuda headers in .cu files that get processed by nvcc. However, if you’re using CUDA types or calls in files processed by a C/C++ compiler (without going through nvcc first) you must include some CUDA headers. cuda_runtime.h has the definitions of the host run-time functions. You also get the vector types through it. All of the CUDA toolkit includes are in the “include” directory inside the directory where CUDA toolkit is installed (C:\CUDA\include in default Win installations).

Paulius

Ah… Ok, that makes sense. Thanks.

For others coming across this problem+solution, I might recommend sticking the declaration in a C header, such as; in ‘example.h’:

[codebox]

void runKernel(…); // functions declared like this are implicitly ‘extern’

[/codebox]

then in the C high level file:

[codebox]

include <example.h>

[/codebox]

and in the cuda file:

[codebox]

extern “C”

{

include <example.h>

}

[/codebox]

I think the problem is down to the fact there is no common declaration - despite the “extern void runKernel(…);”, which would be considered a C++ function declaration when compiled in a .cu file by nvcc.

Having said that, I think it’s also cleaner to have runKernel(…) defined in the C file, and leave only the kernels in the ‘.cu’ file.

Cheers,

Derek

Hi Derek

I got the same problem that trwebb1 had with extern.

The main function is in C file (main.c)
The call kernal function in cu file (CallKernel.cu)

I have did the following:

(1) in the main function I added…> extern void CallKernel(,);
(2) in the call kernal function I added…> extern “C” void CallKernel(,);

But doesnt work…Any recomend?

Thanks Hussam

I make following and it works fine:

Thanks Deus for your reply;

My main function in c not cpp (i.e main.c)

and it compile as: Compile as C Code (/TC)

The issue is, according to my application I can not make the main.c to be compiled as CPP code (/TP).

If you change your main.cpp configuration properties…>c/c++…>advanced from Compiled as CPP code (/TP) to Compile as C Code (/TC)

I think you will have the same sort of error that I got.

I have tried to add a ccp file for example (link.cpp) to link main.c to CallKernal.cu but it didnt work as below

[codebox]//----------------------

//–main.c

//----------------------

main()

{

CallKernelCPP(…)

}[/codebox]

[codebox]//--------------------

//–link.cpp

//--------------------

#include link.h

extern “C” void CallKernalCPP(…)

{

CallKernal(…)

}[/codebox]

[codebox]//link.h

extern “C”

void CallKernelCPP(…);[/codebox]

Thanks Deus for your reply;

My main function in c not cpp (i.e main.c)

and it compile as: Compile as C Code (/TC)

The issue is, according to my application I can not make the main.c to be compiled as CPP code (/TP).

If you change your main.cpp configuration properties…>c/c++…>advanced from Compiled as CPP code (/TP) to Compile as C Code (/TC)

I think you will have the same sort of error that I got.

I have tried to add a ccp file for example (link.cpp) to link main.c to CallKernal.cu but it didnt work as below

[codebox]//----------------------

//–main.c

//----------------------

main()

{

CallKernelCPP(…)

}[/codebox]

[codebox]//--------------------

//–link.cpp

//--------------------

#include link.h

extern “C” void CallKernalCPP(…)

{

CallKernal(…)

}[/codebox]

[codebox]//link.h

extern “C”

void CallKernelCPP(…);[/codebox]

Check calling conventionals, like __cdelc, stdacall, fastcall.

Check calling conventionals, like __cdelc, stdacall, fastcall.