LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 11-26-2009, 04:16 AM   #1
eryn
Member
 
Registered: Jul 2009
Posts: 43

Rep: Reputation: 15
How to call cpp library function in c code?


Hi,

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?

Thank you very much.
 
Old 11-26-2009, 05:54 AM   #2
neonsignal
Senior Member
 
Registered: Jan 2005
Location: Melbourne, Australia
Distribution: Debian Wheezy (Fluxbox WM)
Posts: 1,363
Blog Entries: 52

Rep: Reputation: 353Reputation: 353Reputation: 353Reputation: 353
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.

wrapper.h
Code:
#ifdef __cplusplus
extern "C"
{
#endif
int libInit( void );
int libGetNumer( void );
void libClose( void );
#ifdef __cplusplus
}
#endif
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.
 
1 members found this post helpful.
Old 11-26-2009, 06:07 AM   #3
JohnGraham
Member
 
Registered: Oct 2009
Posts: 467

Rep: Reputation: 138Reputation: 138
When you post homework, it's:

1) Polite to *say* that it's homework, and

2) Obvious



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.
 
Old 11-26-2009, 10:48 AM   #4
eryn
Member
 
Registered: Jul 2009
Posts: 43

Original Poster
Rep: Reputation: 15
hello expert neonsignal

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 ?

Thank you and Have a nice day
 
Old 11-26-2009, 11:21 AM   #5
cola
Senior Member
 
Registered: Sep 2007
Location: Dhaka,Bangladesh
Distribution: Debian
Posts: 1,019

Rep: Reputation: 63
Code:
g++ test.cpp -o test
./test
 
Old 11-26-2009, 12:54 PM   #6
eryn
Member
 
Registered: Jul 2009
Posts: 43

Original Poster
Rep: Reputation: 15
To cola,

We need the library function to be called in c code. Therefore, our calling code has to be .c file and not .cpp file.
 
Old 11-26-2009, 01:18 PM   #7
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: FreeBSD, Debian, Mint, Puppy
Posts: 3,287

Rep: Reputation: 173Reputation: 173
why don't you just compile it as C++ ?

C can compile as C++ quite easily. surely the file extension isn't that
much of an emotional bond
 
Old 11-26-2009, 04:39 PM   #8
neonsignal
Senior Member
 
Registered: Jan 2005
Location: Melbourne, Australia
Distribution: Debian Wheezy (Fluxbox WM)
Posts: 1,363
Blog Entries: 52

Rep: Reputation: 353Reputation: 353Reputation: 353Reputation: 353
Quote:
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
You do it in two stages. Compile to object files first:
Code:
g++ -Wall -c wrapper.cpp
gcc -Wall -c test.c
Then link the object files (you may need to use g++ for this, as it links in different libraries):
Code:
g++ -o test test.o wrapper.o /home/test/libmylibrary.so.1.0.0

Last edited by neonsignal; 11-26-2009 at 05:02 PM.
 
1 members found this post helpful.
Old 11-26-2009, 07:22 PM   #9
eryn
Member
 
Registered: Jul 2009
Posts: 43

Original Poster
Rep: Reputation: 15
To bigearsbilly,

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.
 
Old 11-26-2009, 08:55 PM   #10
eryn
Member
 
Registered: Jul 2009
Posts: 43

Original Poster
Rep: Reputation: 15
To neonsignal,

It works with your method. Thank you.
 
Old 11-30-2009, 01:15 AM   #11
eryn
Member
 
Registered: Jul 2009
Posts: 43

Original Poster
Rep: Reputation: 15
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.

I hope anyone out there can help.

Thank you.
 
Old 11-30-2009, 03:43 AM   #12
neonsignal
Senior Member
 
Registered: Jan 2005
Location: Melbourne, Australia
Distribution: Debian Wheezy (Fluxbox WM)
Posts: 1,363
Blog Entries: 52

Rep: Reputation: 353Reputation: 353Reputation: 353Reputation: 353
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.
 
Old 11-30-2009, 03:46 AM   #13
JohnGraham
Member
 
Registered: Oct 2009
Posts: 467

Rep: Reputation: 138Reputation: 138
Quote:
Originally Posted by eryn View Post
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
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)).

John G
 
Old 12-01-2009, 03:29 AM   #14
eryn
Member
 
Registered: Jul 2009
Posts: 43

Original Poster
Rep: Reputation: 15
This seems to be an include path problem.

I tried to debug using the following command.
Code:
 g++ -Wall -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtNetwork -I/usr/include/qt4/QtNetwork -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I../cmdapi -I../lib/include -I.moc -I. -c  wrapper.cpp
The errors reduced to
Code:
 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:

ProjectApplication.h -> ProjectFunctionLayer.h -> memory.h

I do not know how to eliminate this error.

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
I really do not know what is going wrong.

Thank you and really appreciate any help.

Last edited by eryn; 12-01-2009 at 03:47 AM.
 
Old 12-01-2009, 04:20 AM   #15
JohnGraham
Member
 
Registered: Oct 2009
Posts: 467

Rep: Reputation: 138Reputation: 138
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:

Code:
LD_LIBRARY_PATH=/home/eryn/Desktop/Project/Source/lib/lib:$LD_LIBRARY_PATH ./test
Should work.

John G
 
1 members found this post helpful.
  


Reply

Tags
c++, call, function, interface, link


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
How to call PGPLOT function in FORTRAN code? lengyue Linux - Software 26 12-09-2009 05:36 AM
call a function from library EnTe Programming 4 02-22-2008 06:15 AM
Function for getting the language code in standard library jaepi Programming 1 12-10-2007 01:33 PM
function call in kernel code vishalbutte Programming 1 02-15-2006 01:32 PM


All times are GMT -5. The time now is 05:51 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration