I'm learning to program C++ in Linux, and I have the following problem:
I have 4 files: main.cpp, model.cpp, view.cpp and controller.cpp, each (except main) with their own header files. main.cpp includes model.h, view.h and controller.h, and view.h includes other libraries that are only relevant to it (necessary to run the graphic library). Those libraries are in different folders and have other dependencies on their own (that's why I don't want to move them). So, my makefile looks as follows:
model: model.cpp model.h
g++ -c model.cpp
view: view.cpp view.h
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c view.cpp
controller: controller.cpp
g++ -c controller.cpp
main: main.cpp
g++ -c main.cpp
and also a line to link all the files together (I didn't added it because I'm writing this on my Mac and copying it from the screen of my Raspberry Pi).
My problem is that when I try to compile them, all of them work, except for main, it tells me the following:
In file included from main.cpp:6:0:
view.h:4:23: fatal error: VG/openvg.h: No such file or directory
compilation terminated.
make: *** [main] Error 1
From what I can understand, when I compile view with "make view", it can find the files included without problem, because it has the paths in which it must look, but since "make main" doesn't have those paths, it doesn't know where to look for openvg.h. The problem is that if I add the paths to main, it tells me that there's multiple definitions for what's inside the library... Any help?
The #include VG/openvg.h is in /opt/vc/include and is included from view.h
When you make view you are including it from view.cpp which is compiled with -I/opt/vc/include
When you make main you are including it from main.cpp which is compiled without flags so it can't find the file.
You need to add the flags
main: main.cpp
g++ -c -I/opt/vc/include main.cpp
You may need the other flags as well, depending on what view.h includes.
The multiple definitions are caused by $(OPENVGLIBDIR)/fontinfo.h
which contains
Fontinfo SansTypeface, SerifTypeface, MonoTypeface;
so if you include that file in more than one object file and link them (main.o and view.o in this case) you will get multiple definitions.
Change it to
extern Fontinfo SansTypeface, SerifTypeface, MonoTypeface;
I then got Background etc undefined as libshapes is a C library. To get round this I changed
#include "fontinfo.h"
#include "shapes.h"
in view.h to
extern "C" {
#include "fontinfo.h"
#include "shapes.h"
}
and it builds for me (with references to model and controller removed).
In your makefile, the view/model/controller/main targets are making the .o files so they should be .o too. When you make test when no .o exists, it is looking for the .o target. If there isn't one in your makefile it will use the default which is a straight g++ -c.
Your make file should be like this:
test: model.o view.o controller.o main.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)/oglinit.o
g++ -o test view.o main.o model.o controller.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)oglinit.o -L/opt/vc/lib -L/opt/vc/include -lGLES -ljpeg
view.o: view.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c view.cpp
main.o: main.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c main.cpp view.cpp
model.o: model.cpp
g++ -c model.cpp
controller.o: controller.cpp
g++ -c controller.cpp
here are my files, the code seems to run fine if in main.cpp I include view.cpp instead of view.h, but I don't think that's what I'm supposed to be doing:
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include "model.h"
#include "view.h"
#include "controller.h"
using namespace std;
int main() {
int n;
View view;
view.initialize();
view.drawBackground();
view.show();
std::cin >> n;
}
view.h:
#ifndef VIEW_H
#define VIEW_H
#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
class View{
private:
int width, height;
public:
View();
int getWidth();
int getHeight();
void drawBackground();
void initialize();
void show();
};
#endif
view.cpp
#include "view.h"
View::View(){
int width, height;
VGfloat w2, h2, w;
}
int View::getWidth(){
return width;
}
int View::getHeight(){
return height;
}
void View::drawBackground(){
Background(0,0,0);
Stroke(255,255,255,1);
Fill(255,0,0,1.0);
Circle(width/2, height/2, 100);
}
void View::initialize(){
init(&width, &height);
Start(width, height);
}
void View::show(){
End();
}
Thanks A LOT for your help man! I've been fighting with this for the last couple of days (that's what I get for getting used to automatic compiling/linking). It's somewhat based on that example. I can make it run if I make each object by itself and then link them all together like this:
test: model.o view.o controller.o main.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)/oglinit.o
g++ -o test view.o main.o model.o controller.o $(OPENVGLIBDIR)/libshapes.o $(OPENVGLIBDIR)oglinit.o -L/opt/vc/lib -L/opt/vc/include -lGLES -ljpeg
view: view.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c view.cpp
main: main.cpp
g++ -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I.. -c main.cpp view.cpp
model: model.cpp
g++ -c model.cpp
controller: controller.cpp
g++ -c controller.cpp
if I do "make view" "make main" and then "make test" everything goes fine, but if I try "make test" without any object created prior to that I get fatal error: VG/openvg.h: No such file or directory when it's trying to compile view.cpp
Related
I created my Makefile for a simple program but it returns undefined reference for class functions constantly:
g++ -c src/main.cpp -o lib/main.o
g++ -c src/functions.cpp -o lib/functions.o
g++ -c src/Circular.cpp -o lib/Circular.o
g++ lib/main.o -o bin/app.exe
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: lib/main.o:main.cpp:(.text+0x20): undefined reference to `Circular::Circular()'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [app.exe] Error 1
Here is my Makefile:
app.exe: lib/main.o lib/Circular.o lib/functions.o
g++ lib/main.o -o bin/app.exe
lib/functions.o: src/functions.cpp
g++ -c src/functions.cpp -o lib/functions.o
lib/Circular.o: src/Circular.cpp
g++ -c src/Circular.cpp -o lib/Circular.o
lib/main.o: src/main.cpp
g++ -c src/main.cpp -o lib/main.o
Here is a short snippet of main.cpp:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
#include "../include/Circular.h"
#include "../include/functions.h"
using namespace std;
int main(int argc, const char * argv[]) {
Circular item;
return 0;
}
Circular.h:
#include "node.h"
class Circular
{
public:
Circular();
node *start;
node *last;
int counter;
}
Circular.cpp:
#include "../include/Circular.h"
#include <iostream>
using namespace std;
Circular::Circular()
{
start = NULL;
last = NULL;
}
and node.h:
struct node
{
int data;
struct node *next;
struct node *prev;
};
I know the problem is about linker and with Makefile but even though I tried different possible solutions, somehow it doesn't work. Therefore, maybe someone can see the mistake I am making. Thanks!
I managed to create a Makefile from this source .
The Makefile looks like this:
CXX = g++
CXXFLAGS = -std=c++17 -Wall
LXXFLAGS = -std=c++17
OBJECTS = main.o Circular.o functions.o
TARGET = main
$(TARGET): $(OBJECTS)
$(CXX) $(LXXFLAG) $(OBJECTS) -o $(TARGET)
main.o: main.cpp Circular.cpp Circular.h functions.cpp functions.h
$(CXX) $(CXXFLAGS) -c main.cpp
Circular.o: Circular.cpp
$(CXX) $(CXXFLAGS) -c Circular.cpp
functions.o: functions.cpp
$(CXX) $(CXXFLAGS) -c functions.cpp
clean:
rm -f $(TARGET) $(OBJECTS)
And also added cout to you Circular constructor to check the execution as below:
#include "Circular.h"
#include <iostream>
using namespace std;
Circular::Circular()
{
start = NULL;
last = NULL;
cout << "Yes!" << endl;
}
Here's the result:
Output
Don't forget to put a semicolon for your Circular class in your Circular.h.
NOTE: If you aren't able to use make in cmd,use choco install make.
The Makefile should be structured to build the dependencies, then the final assembly into a .exe. Each path should be specified exactly as it is, not approximated:
app.exe: lib/main.o lib/Circular.o lib/functions.o
g++ lib/main.o lib/Circular.o lib/functions.o -o app.exe
lib/main.o: src/main.cpp
g++ -c src/main.cpp -o lib/main.o
lib/functions.o: src/functions.cpp
g++ -c src/functions.cpp -o lib/functions.o
lib/Circular.o: src/Circular.cpp
g++ -c src/Circular.cpp -o lib/Circular.o
The key here is be consistent and that includes things like the order of things specified in this file. Whatever order you pick, stick to it. This makes tracking down problems way easier.
If this project gets more complex you probably want to pivot to using a dependency tracking Makefile template instead of this homebrew one. Note how in those you don't need to specify a rule for each file, but instead a rule for each type of file, as in .cpp -> .o, and the rest happens automatically.
I try to include my self built .so library in the test.cpp file.
When I try to make the test.cpp file I get this exception:
root#airdrop:/home/pi/naza-interface/examples# make
g++ -c test.cpp
test.cpp:31:35: fatal error: naza_interface_manual.h: No such file or
directory
#include "naza_interface_manual.h"
^
compilation terminated.
Makefile:5: recipe for target 'test.o' failed
make: *** [test.o] Error 1
The Makefile for test.cpp looks like that:
output: test.o
g++ -L. -lnazainterface -o test test.o
test.o:
g++ -c test.cpp
clean:
rm -f *.o
test.cpp just includes the library.
#include "naza_interface_manual.h"
The library contains two files, naza_interface_manual.h and naza_interface_manual.cpp. The library's makefile looks like that:
libso: naza_interface_manual.o pca9685.o
g++ -fPIC -L/usr/local/lib -shared naza_interface_manual.o
pca9685.o -lbcm2835 -o libnazainterface.so
naza_interface_manual.o: src/naza_interface_manual.cpp src/naza_interface_manual.h
g++ -fPIC -c -Wall src/naza_interface_manual.cpp
pca9685.o: src/PCA9685/pca9685.cpp src/PCA9685/pca9685.h
g++ -c src/PCA9685/pca9685.cpp
install: naza_interface_manual.o pca9685.o
g++ -L/usr/local/lib naza_interface_manual.o pca9685.o -lbcm2835 -
shared -o /usr/local/libnazainterface.so
clean:
rm *.o output
naza_interface_manual.h:
#ifndef NAZA_INTERFACE_MANUAL_H_
#define NAZA_INTERFACE_MANUAL_H_
class naza_interface_manual_c{
public:
naza_interface_manual_c();
// A: For roll control (left/right)
// E: For pitch control (front/back)
// T: For throttle control
// R: For rudder control
// U: For Control Model Switch
void configure_pins(int A, int E, int T, int R, int U);
void fly_forward(int speed);
void fly_backward(int speed);
void fly_up(int speed);
void fly_down(int speed);
void fly_left(int speed);
void fly_right(int speed);
};
#endif
naza_interface_manual.cpp:
#include <iostream>
#include <wiringPi.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "naza_interface_manual.h"
#include "PCA9685/pca9685.h"
naza_interface_manual_c::naza_interface_manual_c(){
std::cout << "Starting Naza Interface";
}
void naza_interface_manual_c::configure_pins(int A, int E, int T, int R, int U){
PCA9685 pca9685;
pca9685.SetFrequency(100);
pca9685.Write(CHANNEL(0), VALUE(350));
}
void naza_interface_manual_c::fly_forward(int speed){
}
void naza_interface_manual_c::fly_backward(int speed){
}
void naza_interface_manual_c::fly_up(int speed){
}
void naza_interface_manual_c::fly_down(int speed){
}
void naza_interface_manual_c::fly_left(int speed){
}
void naza_interface_manual_c::fly_right(int speed){
}
Your Makefile doesn't install the header file. In fact, it also installs the shared object in a non-standard location: /usr/local. You want the library to go into /usr/local/lib and you need the header file installed in /usr/local/include.
Your Makefile is not consistent with conventional rules: You have no all rule, you are creating the library directly in the installation directory, instead of calling /usr/bin/install... I suggest you look into "proper" Makefile layout, if you want to distribute this. Users expect a lot of things from the Makefiles you give them; there are de-facto standards to follow.
If you want to use the library without having installed it, you need to provide the compiler the relevant include directive in your test.o: target; something like -Ipath/to/your/header.
Your compilation doesn't give the compiler the include path to find the header.
Instead, specify a base location and add the path to the compile. Otherwise if you can change the naza interface library, its install target should install the headers to a system (or $PREFIX/include) location.
test.o:
g++ -I$(NAZA_INTERFACE_LIB)/src/ -c test.cpp
I need to access a C++ function from C but I get some error like :-
/tmp/ccUqcSZT.o: In function `main':
main.c:(.text+0x5): undefined reference to `load_alert_to_db'
collect2: error: ld returned 1 exit status
My main.c code is:-
#include <stdio.h>
extern void load_alert_to_db(void);
int main(void){
/* Create empty queue */
load_alert_to_db();
return 0;
}
C++ code implementation db_manager.cpp is:-
#include <sstream>
#include <iostream>
#include <sstream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <algorithm>
#include <time.h>
#include <cstring>
#include <fstream>
//using namespace oracle::occi;
#include <iostream>
using namespace std;
extern "C" void load_alert_to_db(void)
{
cout<<"db occi"<<endl;
}
makefile is:-
CC= g++
all:
$(CC) -c -Wall -Werror -fPIC db_manager.cpp
$(CC) -shared -o libdb_manager.so db_manager.o
gcc -L/home/oracle/Desktop/storage/ -Wall main.c -o data -ldb_manager
gcc -o data main.c
clean:
rm -f *.o data
so please help me which one is my problem. I am also include
export LD_LIBRARY_PATH=/home/oracle/Desktop/storage/:$LD_LIBRARY_PATH
environmental variable in .bash_profile
gcc -o data main.c
Not sure why you have this line in your makefile since it will compile main.c without reference to the previously created library and hence cause an undefined-symbol error such as the one you're seeing.
This is especially so, since you appear to have done it the right way on the preceding line:
gcc -L/home/oracle/Desktop/storage/ -Wall main.c -o data -ldb_manager
However, the entire point of using makefiles is so that it figures out the minimum necessary commands for you, based on dependencies. Lumping a large swathe of commands into a single rule tends to defeat that purpose. You would be better off making your rules a little more targeted, such as (untested but should be close):
all: data
data: main.o libdb_manager.so
gcc -o data main.o -ldb_manager
main.o: main.c
gcc -o main.o main.c
libdb_manager.so: db_manager.cpp
g++ -c -Wall -Werror -fPIC -o db_manager.o db_manager.cpp
g++ -shared -o libdb_manager.so db_manager.o
That way, if you make a small change to one part (like main.c), it doesn't have to go and compile/link everything in your build tree.
Your makefile seems to be completely broken and random, and you're not even linking the required object files. You can simplify this:
all:
$(CC) -c -Wall -Werror -fPIC db_manager.cpp
$(CC) -shared -o libdb_manager.so db_manager.o
gcc -L/home/oracle/Desktop/storage/ -Wall main.c -o data -ldb_manager
gcc -o data main.c
to just this:
all:
gcc -Wall -c main.c
g++ -Wall -c db_manager.cpp
g++ main.o db_manager.o -o data
this is what I needed to do:
Supposing the C++ function is called Debug::Write(str)
Then in your hpp file do the following:
#ifdef __cplusplus
extern "C" void DebugTmp(char *str);
#endif
Then in the corresponding cpp file do this:
void DebugTmp(char *str)
{
Debug::Write(str);
}
Then in your C file where you call DebugTmp define the prototype:
void DebugTmp(char *str);
then call it as below:
static void MyFunction( void )
{
DebugTmp("This is debug trace\n");
}
I just started using makefiles and came across a problem. (C++ project)
I'm trying to make a dependency chain:
main.cpp depends on class a. And class a depends on class b.
The main idea is to recompile class a using the allready compiled class b, while class a doesn't have the main() function. (When class a is modified)
Here is my makefile:
makefile
all: main.o
main.o: main.cpp classa.o
g++ main.cpp classa.o -o main.o
classa.o: classa.h classa.cpp classb.o
g++ -c classa.cpp classb.o -o classa.o
classb.o: classb.h classb.cpp
g++ -c classb.cpp -o classb.o
And the code:
main.cpp
#include "classa.h"
int main() {
ClassA a;
return 0;
}
classa.h
#ifndef CLASSA_H
#define CLASSA_H
#include "classb.h"
class ClassA {
private:
ClassB b;
public:
ClassA();
};
#endif // CLASSA_H
classa.cpp
#include "classa.h"
ClassA::ClassA() {
}
classb.h
#ifndef CLASSB_H
#define CLASSB_H
class ClassB {
public:
ClassB();
};
#endif // CLASSB_H
classb.cpp
#include "classb.h"
ClassB::ClassB() {
}
The Problem:
When i use make -f makefile i get the following error:
g++ -c classb.cpp -o classb.o
g++ -c classa.cpp classb.o -o classa.o
g++: warning: classb.o: linker input file unused because linking not done
g++ main.cpp classa.o -o main.o
classa.o: In function `ClassA::ClassA()':
classa.cpp:(.text+0x18): undefined reference to `ClassB::ClassB()'
collect2: error: ld returned 1 exit status
makefile:4: recipe for target 'main.o' failed
make: *** [main.o] Error 1
I believe that it starts on reusing classb.o with the parameter -c.
To me -c is a magical "use when i compile code without the main() function" parameter.
I would be happy if you could enlighten me where i did go wrong, and wether what i'm trying to do is possible.
Regards, chocolateftw
Your makefile should look more like this:
all: main
main: main.cpp classa.o classb.o
g++ main.cpp classa.o classb.o -o main
classa.o: classa.h classa.cpp
g++ -c classa.cpp -o classa.o
classb.o: classb.h classb.cpp
g++ -c classb.cpp -o classb.o
You build .o files from .cpp files and then link .o files into the final output (also built from a .cpp file).
You need to list all relevant object files when linking and do not need to list them when only compiling (which is what happens when you use the -c flag which tells gcc to skip the linking step).
The key here is that classa.o does not depend on classb.o or classb.cpp (it probably does depend on classb.h though in which case you might want to add that to the requirements). The fully linked binary depends on both of them and they then depend on each other as needed.
That said you can dramatically simplify the above makefile by not specifying your own rules and simply using the built-in rules. The following makefile should do what you want.
all: main
main: classa.o classb.o
classa.o: classa.h
classb.o: classb.h
If you need custom compiler/linker flags later you can use the default variables to have them used on the appropriat lines. See 10.3 Variables Used by Implicit Rules and 10.2 Catalogue of Built-In Rules for the variables and what rules use them.
I have an existing application that uses a C++ class, a C++ wrapper, and FORTRAN code for the computationally intensive parts of the application. I would like to implement parts of the FORTRAN in CUDA to take advantage of parallelization, but I would still like to access some of the subroutines, so I need to link CUDA, C++, and FORTRAN code.
I have three questions:
1. How do I correctly link all of the object files with the Linux Terminal and with the Makefile (included below)?
2. What is the proper way to reference the CUDA function in the class header without confusing the compiler's recognition of device and host code?
3. Is passing a class to CUDA just like passing a class to any other external C code?
Note: I have not included full code (some of it is quite long) except for the Makefile. If I need to include more, please let me know.
.h file
#ifndef _DGCPM_H_
#define _DGCPM_H_
extern "C"{
#include <string.h>
#include <zlib.h>
#include <math.h>
}
/* Prototypes of Fortran subroutines */
extern "C" {
void initialize_(float *2Darray);
void advance_(float *2Darray);
//Want "advance" to be implemented in CUDA
}
/* Proper prototype of CUDA call? */
//extern "C" void cudaadvance(float *2Darray);
class DGCPM{
public:
DGCPM(); /* Initialized with defaults setup */
~DGCPM(); /* Free memory */
void advance(float dT); /* Advance model dT seconds */
private:
float **2Darray;
void initialize(float **2Darray);
};
#endif
.C wrapper
#include "../include/DGCPM.h"
DGCPM::DGCPM(){
initialize();
}
void DGCPM::advance(float dT){
advance_(2Darray[0]);
}
main.C file
#include <stdlib.h>
#include <stdio.h>
#include <zlib.h>
#include "../include/DGCPM.h"
int main(){
class DGCPM *model;
model=new class DGCPM();
//Write data to class from a file, then
for(int i=0;i<200;i++){
printf("%d\n",i);
model->advance(3600);
//write model state to file;
}
//Close file
return 0;
}
Makefile (Note: "pbo" is the FORTRAN code)
INSTALLDIR=../../lib/
FLAGS=-Wall -g -I ../../amj/include
CFLAGS=$(FLAGS)
CPPFLAGS=$(FLAGS)
FFLAGS=$(FLAGS)
CPP=g++
CC=gcc
FC=g77
PBO_PATH=../ober/for/
VPATH=$(PBO_PATH)
DGCPM_OBJ=DGCPM.o pbo.o
TESTDGCPM_OBJ=testDGCPM.o DGCPM.o pbo.o
ALL_OBJ=$(TESTDGCPM_OBJ)
install: all
mkdir -p $(INSTALLDIR)
cp libDGCPM.a $(INSTALLDIR)
all: libDGCPM.a testDGCPM
libDGCPM.a: $(DGCPM_OBJ)
ar rc $# $^
testDGCPM: $(TESTDGCPM_OBJ)
$(CPP) -o $# $^ -L ../../amj/lib -lamjMemory -lg2c -lz
clean:
- rm $(ALL_OBJ)
- rm $(INSTALLDIR)/libDGCPM.a
You currently don't have any CUDA code, so I may can't give enough details.
For your Qs:
Linking object files including CUDA code requires nvcc compiler driver. You could first compile your code files with individual compilers, i.e. gcc for .c, g++ for .cpp, g77 for .f and nvcc for .cu. Then you can use nvcc to link all the object files .o;
host and device code are explicitly declared in .cu file with __host__ and __device__. It's your responsibility not to invoke device code from other host code;
Why are your passing a class to CUDA? If you want to replace your fortran code with CUDA, you only need to invoke CUDA functions in your C++ wrapper class, and invoking CUDA API functions uses the the same grammar as invoking c++ functions.
Here is an example from my project. The executable is built with 1 .cu, 1 .cpp, a few extern .a as well as some .so. For .cpp I use Intel's compiler icpc other than the default g++. Please note my main() is in the .cu file.
# Compile : bin.cu/b-rbm-gpu.cu
nvcc -ftz true -ccbin icpc -Xcompiler "-Wall -Wno-long-long -ansi -pedantic -ansi-alias -parallel -fopenmp -openmp-link=static -static-intel -wd10237" -O3 -Xcompiler "-O3" -gencode arch=compute_20,code=sm_20 -Ilib -c -o bin.cu/b-rbm-gpu.o bin.cu/b-rbm-gpu.cu
# Compile : lib/KTiming.cpp
icpc -Wall -Wno-long-long -ansi -pedantic -ansi-alias -parallel -fopenmp -openmp-link=static -static-intel -wd10237 -O3 -MMD -Ilib -c -o lib/KTiming.o lib/KTiming.cpp
# Link : bin.cu/b-rbm-gpu
nvcc -ftz true -ccbin icpc -Xcompiler "-Wall -Wno-long-long -ansi -pedantic -ansi-alias -parallel -fopenmp -openmp-link=static -static-intel -wd10237" -O3 -Xcompiler "-O3" -Ilib -Llib bin.cu/b-rbm-gpu.o lib/KTiming.o -lpthread -lm /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_intel_lp64.a /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_intel_thread.a /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_core.a /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_core.a -lcublas -lcurand -lcusparse -o bin.cu/b-rbm-gpu
Here is the solution. To use the CUDA code, I reference it with, for example,
extern "C" void myfunction_(void)
In the header file, I add
void myfunction_(void);
in the extern "C" prototypes. In the public functions of the class I added
void mycudafunction(void);
In the C++ wrapper, I add
void DGCPM::mycudafunction(){
myfunction_();
}
I can now call "myfunction" from the main program with this type of syntax
model = new class DGCPM();
model->mycudafunction();
I modified my Makefile by adding myfunction.o to all of my objects and adding
-L /usr/local/cuda/lib -lcuda -lcudart
to all of my linking instructions.
To compile, create the CUDA object file (myfunction.o), and link, I type this in the terminal:
nvcc -c myfunction.cu
make
Here is the modified code:
.h file
#ifndef _DGCPM_H_
#define _DGCPM_H_
extern "C"{
#include <string.h>
#include <zlib.h>
#include <math.h>
}
/* Prototypes of Fortran subroutines */
extern "C" {
void initialize_(float *2Darray);
void advance_(float *2Darray);
/*CUDA prototype, can be changed to "cudaadvance" or the like*/
void myfunction_(void);
}
class DGCPM{
public:
DGCPM(); /* Initialized with defaults setup */
~DGCPM(); /* Free memory */
void advance(float dT); /* Advance model dT seconds */
void mycudafunction(void);
private:
float **2Darray;
void initialize(float **2Darray);
};
#endif
.C Wrapper
#include "../include/DGCPM.h"
DGCPM::DGCPM(){
initialize();
}
void DGCPM::advance(float dT){
advance_(2Darray[0]);
}
void DGCPM::mycudafunction(){
myfunction_();
}
main.C file
#include <stdlib.h>
#include <stdio.h>
#include <zlib.h>
#include "../include/DGCPM.h"
int main(){
class DGCPM *model;
model=new class DGCPM();
//Write data to class from a file, then
for(int i=0;i<200;i++){
printf("%d\n",i);
model->mycudafunction();
model->advance(3600);
//write model state to file;
}
//Close file
return 0;
}
Makefile
INSTALLDIR=../../lib/
FLAGS=-Wall -g -I ../../amj/include
CFLAGS=$(FLAGS)
CPPFLAGS=$(FLAGS)
FFLAGS=$(FLAGS)
CPP=g++
CC=gcc
FC=g77
PBO_PATH=../ober/for/
VPATH=$(PBO_PATH)
DGCPM_OBJ=DGCPM.o pbo.o myfunction.o
TESTDGCPM_OBJ=testDGCPM.o DGCPM.o pbo.o myfunction.o
ALL_OBJ=$(TESTDGCPM_OBJ)
install: all
mkdir -p $(INSTALLDIR)
cp libDGCPM.a $(INSTALLDIR)
all: libDGCPM.a testDGCPM
libDGCPM.a: $(DGCPM_OBJ)
ar rc $# $^
testDGCPM: $(TESTDGCPM_OBJ)
$(CPP) -o $# $^ -L ../../amj/lib -lamjMemory -lg2c -lz -L /usr/local/cuda/lib -lcuda -lcudart
clean:
- rm $(ALL_OBJ)
- rm $(INSTALLDIR)/libDGCPM.a
Here's the simple CUDA program I used to test.
#include <stdio.h>
__global__ void kernel( void ) {
}
extern "C" void myfunction_(void) {
kernel<<<1,1>>>();
printf( "Hello, World!\n" );
return;
}