[SOLVED] How to call cpp library function in c code?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I have a problem. I would like to ask all the experts here.
We have a third party library which is written in c++. However, our application is all written using c language. I would like to call the function in the c++ library from my c code.
We have successfully compiled the library. When we get the library, there is 3 files in it.
mylibrary.pro
mylibrary.cpp
mylibrary.h
We perform 'qmake' to generate Makefile.
Then, we 'make' to generate mylibrary.o file and some share library files.
We wrote a simple cpp file to compile. Here is the code.
Code:
#include <iostream>
#include "mylibrary.h"
mylibrary *w;
int libInit( void )
{
w = new mylibrary;
return 0;
}
int libGetNumer( void )
{
return w->number();
}
void libClose( void )
{
delete w;
return;
}
int main( int argc, char *argv[] )
{
libInit();
printf("Hello %d\r\n", libGetNumer() );
printf("Hello %d\r\n", libGetNumer() );
libClose();
}
Then, we perform dynamic link to the library.
After that, we compile the code using following command:
gcc -Wall test.cpp /home/test/libmylibrary.so.1.0.0 -o test
It compile successfully and we are able to run the code.
Problem:
Although we successfully compiled the file, but we are running the code in cpp. The above example is calling from cpp library to cpp code. What we want is to call cpp library to c code.
Does anyone of you can give us an idea on how to do this?
One way is to create your own C++ wrapper code (as you have done above). Then place an 'extern "C" { }' around the wrapper declarations so that the C application code can call the wrapper functions to access the library.
The header for the wrapper will contain the C entry points.
The wrapper code can instantiate the library and have a function interface as you have done above:
wrapper.cpp
Code:
#include <iostream>
#include "mylibrary.h"
#include "wrapper.h"
mylibrary *w;
int libInit( void )
{
w = new mylibrary;
return 0;
}
int libGetNumer( void )
{
return w->number();
}
void libClose( void )
{
delete w;
return;
}
The wrapper code is compiled using 'g++ -c', and the rest of the code using 'gcc -c', and then everything can be linked.
Things get a bit trickier if you need to handle objects from the C++ library in your application, though this is possible too. There is a good article by Marshall Cline with a lot more detail.
Last edited by neonsignal; 11-26-2009 at 06:06 AM.
Anyway, some pointers (haha etc.) since neonsignal's suggestion is what you'd do in "real life", but I don't think it's what your assignment's after, so here's how to call C++ code from "raw" C...
When you compile the c++ program, the compiler will mangle the names - for example, the constructor for an Object class would get mangled to something like "_ZN6ObjectC1Ev". You can see all the names by running the 'nm' program on the object file - first use the --demangle option, then without. The raw names (e.g. _ZN6Object...) are what you want to call from your C code.
You want to call the constructor, which you should call with a pointer to a pointer which will hold a reference to the newly constructed object. This might as well be a void*, e.g.
Code:
void *obj;
_ZN...C1Ev(&obj):
When you call the function's method, your first argument needs to be the address of the pointer you got from construction. C++ compilers do this behind your back for you.
Also, you might need to pass -lstdc++ as an option to gcc, if the supplied library needs it. Probably not, though, but "give it a go" if things don't work.
That should be enough to get you started
Note: I edited this because I was being silly and said you needed to pass a pointer to an object's methods, but you don't - you need the *address* of the pointer, instead (including the constructor).
Last edited by JohnGraham; 11-26-2009 at 06:30 AM.
i've tried to instruction you suggested.
i compile the wrapper as: g++ -c -Wall -o wrapper wrapper.cpp
and compile the test.c file as: gcc -c -Wall -o test test.c
But there are no object file for wrapper and no executable file for my c code.
Is there anything missed in the compiling command ?
Certainly compile as C++ is a method, but our code in C has already been written, and it is a lot.
If we would like to change it, it takes really long time.
After I have compile successfully using the test code I provided above, I used the same method to compile another more complex program.
I tried several times and I am sure I perform all steps correctly.
However I get error.
These are the code in ProjectApplication.h:
Code:
#include <ProjectFunctionLayer.h>
#include <QLibrary>
class ProjectApplication{
public:
ProjectApplication();
~ProjectApplication();
int initializeAndCalibrate( void );
int returnHome( void );
unsigned int getStatus( void );
int doWork( unsigned int a, int b, bool c, unsigned int d );
int cleanWork( unsigned int number );
int homePosition[NUM];
protected:
bool fileExist( char* fileName );
ProjectFunctionLayer *proLayer;
};
I have another library folder with all the application codes in it. This includes ProjectFunctionLayer.h. In this header file, the NUM is defined.
I done a wrapper.cpp for this project.
Code:
#include <iostream>
#include "ProjectApplication.h"
#include "wrapper.h"
ProjectApplication *w;
int libInit ( void )
{
w = new ProjectApplication;
return 0;
}
int PROinitializeAndCalibrate ( void )
{
return w->initializeAndCalibrate();
}
int PROreturnHome ( void )
{
return w->returnHome();
}
unsigned int PROgetStatus ( void )
{
return w->getStatus();
}
int PROdoWork ( unsigned int PROa, int PROb, bool PROc, unsigned int PROd )
{
unsigned int PROa = a;
int PROb = b;
bool PROc = c;
unsigned int PROd = d;
return w->doWork( a, b, c, d );
}
int PROcleanWork( unsigned int PROnumber )
{
unsigned int PROnumber = number;
return w->cleanWork( unsigned int number );
}
void libClose ( void )
{
delete w;
return;
}
wrapper.h as follows
Code:
#ifdef __cplusplus
extern "C"
{
#endif
int libInit( void );
int PROinitializeAndCalibrate ( void );
int PROreturnHome ( void );
unsigned int PROgetStatus ( void );
int PROdoWork ( unsigned int PROa, int PROb, bool PROc, unsigned int PROd );
int PROcleanWork( unsigned int PROnumber );
void libClose( void );
#ifdef __cplusplus
}
#endif
I compile using g++ -Wall -c wrapper.cpp.
It returns me the following error.
Code:
In file included from wrapper.cpp:2:
ProjectApplication.h:16:30: error: ProjectFunctionLayer.h: No such file or directory
ProjectApplication.h:17:20: error: QLibrary: No such file or directory
In file included from wrapper.cpp:2:
ProjectApplication.h:62: error: ‘NUM’ was not declared in this scope
ProjectApplication.h:66: error: ISO C++ forbids declaration of ‘ProjectFunctionLayer’ with no type
ProjectApplication.h:66: error: expected ‘;’ before ‘*’ token
I searched on the net for solution of this and I could not get any.
Is there any expert that can help?
I ever wonder is it because of the protected part in ProjectApplication.h. I could not find any sample how to include this in the wrapper.cpp.
Also, the variable in public that is the "int homePosition[NUM];", I do not know how to put this in wrapper.cpp.
Always look at the first errors before you worry about the later ones. Since the include file ProjectFunctionLayer.h couldn't be found, you will get lots of errors simply because stuff from the header didn't get defined.
Normally you would use angle brackets when you are including library headers, and double quotes when you are including header files from your own project.
Also, if you have header files in other directories, you will need to add these directories to the search path when you do the compile, using the compiler flag '-I directory'.
Last edited by neonsignal; 11-30-2009 at 03:46 AM.
In file included from wrapper.cpp:2:
ProjectApplication.h:16:30: error: ProjectFunctionLayer.h: No such file or directory
ProjectApplication.h:17:20: error: QLibrary: No such file or directory
In file included from wrapper.cpp:2:
ProjectApplication.h:62: error: ‘NUM’ was not declared in this scope
ProjectApplication.h:66: error: ISO C++ forbids declaration of ‘ProjectFunctionLayer’ with no type
ProjectApplication.h:66: error: expected ‘;’ before ‘*’ token
Solve the first problem first, as that will generally make later problems go away.
The compiler cannot find the file ProjectFunctionLayer.h - where is this file? If it's in the current directory, use "Blah.h" instead of <Blah.h> (or pass -I. to g++).
As it happens, solving this won't make the second error go away. Try these:
1) Pass -I/usr/include/QtCore to gcc
2) If that doesn't work, run "locate QtCore" and pass whatever directory it's in as an -I option to gcc (as above)
3) If "locate QtCore" shows nothing, you need to use your package manager to install the Qt development package (e.g. libqt-dev (apt-style) or libpt-devel (yum-style)).
In file included from /home/eryn/Desktop/Project/Source/lib/include/ProjectFunctionLayer.h:2:
ProjectApplication.h:62: error: ‘NUM’ was not declared in this scope
So, here comes the first question.
The 'NUM' is defined in another directory than cmdapi directory. There is a directory named lib other than cmdapi. In the lib directory, there is a header file called memory.h. 'NUM' is defined as constant in it.
Code:
#define NUM 6
The include sequence of the header files are as follow:
Then, to proceed, I just close the statement that contains the NUM so that I can test on others.
I compile again using the above command. It returns no error this time as it did not meet NUM.
Then, I perform this error free also.
Code:
gcc -Wall -c arm.c
Then, I tried to link both.
Code:
g++ -o test test.o wrapper.o /home/eryn/Desktop/Project/Source/cmdapi/lib/libProjectApplication.so.1
It gives plenty of errors:
Code:
/usr/bin/ld: warning: libSupport.so.1, needed by /home/eryn/Desktop/Project/Source/cmdapi/lib/libProjectApplication.so.1.0.0, not found (try using -rpath or -rpath-link)
/home/eryn/Desktop/Project/Source/cmdapi/lib/libProjectApplicaton.so.1.0.0: undefined reference to `ProjectFunctionLayer::disconnect()'
/home/eryn/Desktop/Project/Source/cmdapi/lib/libProjectApplication.so.1.0.0: undefined reference to `ProjectFunctionLayer::Zero(int)'
/home/eryn/Desktop/Project/Source/cmdapi/lib/libProjectApplication.so.1.0.0: undefined reference to `ProjectFunctionLayer::setDesiredPos(int, int)'
.
.
.
collect2: ld returned 1 exit status
So, I gave it the link to the library libSupport.so.1
Code:
g++ -o test test.o wrapper.o /home/eryn/Desktop/Project/Source/cmdapi/lib/libProjectApplication.so.1.0.0 /home/eryn/Desktop/Project/Source/lib/lib/libSupport.so.1.0.0
It do compile. But when I run the .exe file.
The following error appear.
Code:
./test: error while loading shared libraries: libSupport.so.1: cannot open shared object file: No such file or directory
Your first error, not finding "NUM", might be because there is a header called "memory.h" in your /usr/include directory (at least, there is on my machine...) that the compiler finds before it sees yours. Are there any other things in your memory.h that the compiler finds OK (in the same compilation unit)? Renaming your memory.h would be the first thing I'd try.
Your last problem is because the dynamic linker needs to load /home/eryn/Desktop/Project/Source/lib/lib/libSupport.so.1 at run-time, but it can't find it.
There are two ways you tell ld-linux where to find libraries at run-time:
1) Put the directory of the library in /etc/ld.so.conf. Or, on most systems, in any file in /etc/ld.so.conf.d/ - a better solution, methinks, as you can have a file specifically for your project. Or
2) Include the directory in the environment variable LD_LIBRARY_PATH, i.e. the command:
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.