I've got a class with nested classes mixing both C++, CUDA and Thrust. I want to split member definitions across a number of files.
// In cls.h:
#include <thrust/device_vector.h>
class cls {
class foo { // define in foo.cu (include "cls.h")
kernelWrapper();
}
class bar { // define in bar.cu (include "cls.h")
thrust::device_vector A;
thrustStuff();
}
thrust::device_vector B;
pureCPP(); // define in cls.cpp (include "cls.h")
moreThrust(); // define in cls.cu (include "cls.h")
}
In each definition file I simply #include "cls.h"
. However, I am currently getting an assortment of compiler errors no matter what I try, like pureCPP was referenced but not defined
.
I've read Thrust can only be used with .cu
files. Because my parent class cls
declares Thrust-type variables like B
(and hence #include
s thrust/device_vector.h
), does that force all files that #include
cls.h
to be made into .cu
files?
Where do I use extern "C"
in this case? I suppose cls.cpp
would require all functions in .cu
files to be wrapped in extern "C"
, but what about .cu
to .cu
calls, like moreThrust()
calling bar::thrustStuff()
I've also been made aware members of classes don't work with extern "C"
, so do I have to write an extern "C"
wrapper function for each member function?
I'm utterly confused as to how to make this all work - what cocktail of #include
s and extern "C"
s do I need for each file?
Taking your small example, this compiled and ran fine for me
/*
Inside File cls.h
*/
#pragma once
#include <thrust/device_vector.h>
#include <stdio.h>
class cls {
public:
class foo { // define in foo.cu (include "cls.h")
public:
void kernelWrapper();
};
class bar { // define in bar.cu (include "cls.h")
thrust::device_vector<int> A;
public:
void thrustStuff();
};
public:
void pureCPP(); // define in cls.cpp (include "cls.h")
void moreThrust(); // define in cls.cu (include "cls.h")
private:
thrust::device_vector<int> B;
};
/*
Inside File foo.cu
*/
#include "cls.h"
void cls::foo::kernelWrapper()
{
printf("kernelWrapper\n");
}
/*
Inside File bar.cu
*/
#include "cls.h"
void cls::bar::thrustStuff()
{
printf("Thrust Stuff\n");
}
/*
Inside File cls.cpp
*/
#include "cls.h"
void cls::pureCPP()
{
printf("pureCPP\n");
}
/*
Inside File cls.cu
*/
#include "cls.h"
void cls::moreThrust()
{
printf("moreThrust\n");
}
/*
Inside File main.cpp
*/
#include "cls.h"
int main()
{
cls a_class;
a_class.pureCPP();
a_class.moreThrust();
cls::bar a_class_bar;
a_class_bar.thrustStuff();
cls::foo a_class_foo;
a_class_foo.kernelWrapper();
}
Running this prints
pureCPP
moreThrust
Thrust Stuff
KernelWrapper
If anything, I'd bet that you're using an IDE and it's not compilling all of your files, so while you have your class member declaration in your header file, but it'll never find the corresponding definition. Your exact compilation commands will be different, but for me (on Linux) I used
nvcc -G -g -O0 -gencode arch=compute_20,code=sm_21 -odir "src" -M -o "src/bar.d" "../src/bar.cu"
nvcc --device-c -G -O0 -g -gencode arch=compute_20,code=sm_21 -x cu -o "src/bar.o" "../src/bar.cu"
nvcc -G -g -O0 -gencode arch=compute_20,code=sm_21 -odir "src" -M -o "src/cls.d" "../src/cls.cu"
nvcc --device-c -G -O0 -g -gencode arch=compute_20,code=sm_21 -x cu -o "src/cls.o" "../src/cls.cu"
nvcc -G -g -O0 -gencode arch=compute_20,code=sm_21 -odir "src" -M -o "src/foo.d" "../src/foo.cu"
nvcc --device-c -G -O0 -g -gencode arch=compute_20,code=sm_21 -x cu -o "src/foo.o" "../src/foo.cu"
nvcc -G -g -O0 -gencode arch=compute_20,code=sm_21 -odir "src" -M -o "src/main.d" "../src/main.cpp"
nvcc -G -g -O0 --compile -x c++ -o "src/main.o" "../src/main.cpp"
nvcc -G -g -O0 -gencode arch=compute_20,code=sm_21 -odir "src" -M -o "src/clscpp.d" "../src/cls.cpp"
nvcc -G -g -O0 --compile -x c++ -o "src/clscpp.o" "../src/cls.cpp"
nvcc --relocatable-device-code=true -gencode arch=compute_20,code=sm_21 -link -o "split_compilation" ./src/bar.o ./src/cls.o ./src/foo.o ./src/clscpp.o ./src/main.o
The idea is just to compile all of your source files and link them together. For example, if I didn't compile and link the cls.cpp file, I'd get a linker error on any calls to pureCPP
.
Also, note that if you're using actual device code, you'll have to have specify __device__
and/or __host__
for your member functions. See this other SO question