How to mix C++ and C correctly - c++

I am having some problems with this: I need to write a C wrapper for a C++ library. Say I have 3 files:
wrapper.h
typedef struct Foo Foo;
Foo* create_foo();
wrapper.cpp
extern "C" {
#include "wrapper.h"
}
#include "foo.h"
Foo* create_foo() {
return new Foo;
}
foo.h
class Foo {
public:
Foo();
};
This compiles fine:
clang++ -std=c++14 wrapper.cpp foo.h wrapper.h -shared -fPIC
clang++ -shared -o libbindings.so a.out
but when compiling the program that uses the C wrapper (it is compiler and linked by the programming language that uses the wrapper - Crystal), I get an undefined reference to create_foo() and a linker error collect2: error: ld returned 1 exit status. How can I debug this (and what am I doing wrong)?

Here is a working example:
wrapper.h (C & C++ aware)
#ifndef WRAPPER_H_
#define WRAPPER_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct CPPClass CPPClass;
CPPClass* CPPClass_new();
void CPPClass_do_something(CPPClass* cppclass);
int CPPClass_get_state(CPPClass* cppclass);
void CPPClass_delete(CPPClass* cppclass);
#ifdef __cplusplus
}
#endif
#endif /* WRAPPER_H_ */
wrapper.cpp (C++ only)
#include "wrapper.h"
class CPPClass
{
int state;
public:
CPPClass(): state(0) {}
void do_something() { ++state; }
int get_state() const { return state; }
};
extern "C" CPPClass* CPPClass_new()
{
return new CPPClass;
}
extern "C" void CPPClass_do_something(CPPClass* cppclass)
{
cppclass->do_something();
}
extern "C" int CPPClass_get_state(CPPClass* cppclass)
{
return cppclass->get_state();
}
extern "C" void CPPClass_delete(CPPClass* cppclass)
{
delete cppclass;
}
use-wrapper.c (C only)
#include <stdio.h>
#include "wrapper.h"
int main(void)
{
CPPClass* cppclass = CPPClass_new();
if(!cppclass)
{
printf("ERROR: failed to create CPPClass:\n");
return 1;
}
printf("state: %d\n", CPPClass_get_state(cppclass));
CPPClass_do_something(cppclass);
printf("state: %d\n", CPPClass_get_state(cppclass));
CPPClass_delete(cppclass);
}
Compile CPP
g++ -std=c++11 -shared -fPIC -o libwrapper.so wrapper.cpp
Compile C
gcc -o use-wrapper use-wrapper.c -L. -lwrapper -lstdc++
Output:
$ ./use-wrapper
state: 0
state: 1
Hope that helps.

You are creating a shared object named a.out, then another shared object named libbindings.so that ostensibly links to a.out but references nothing from it. Now if a set of input files doesn't have any undefined symbols, no libraries are searched or added to the output. So libbindings.so is essentially an empty library. Verify:
% nm a.out | grep create_foo
00000000000006bc T create_foo
% nm libbindings.so | grep create_foo
%
If you have several source files, you should build an object file from each source (use -c compilation flag), (then optionally combine the objects into a static library --- skip this step if you are not releasing static libraries) then build a shared object from previously built objects:
clang++ -c -fPIC foo.cpp
clang++ -c -fPIC bar.cpp
clang++ -shared -o libfoobar.so foo.o bar.o
If you only have one source, or very few source files you can easily compile together, you can build the shared library in one step:
clang++ -std=c++14 wrapper.cpp somethingelse.cpp -shared -fPIC -o libbindings.so
This is not recommended for large projects.

Related

Force alle functions in shared library to be defined

I want to write a shared library and I want to get a compiler/linker error if I forgot to implement some functions.
Consider the following case:
test.h
class Test {
public:
Test();
};
test.cpp
#include "test.h"
main.cpp
#include "test.h"
int main() {
new Test();
}
If I create a library with this command gcc -c -fpic test.cpp && g++ -shared -o libtest.so -Wl,--no-undefined -Wl,--no-allow-shlib-undefined test.o there is no error message, but the library is broken. Is there a way to force the creation of a not broken library?
Edit: adding additional flag, but doesn't change result
These codes have been modified:
test.h :
class Test {
public:
Test();
};
test.cpp :
#include "test.h"
Test::Test(){} // you must implement the constructor
You must have to implement the constructor, and if not, you get an error "undefined reference to `Test::Test()'".
main.cpp :
#include <iostream>
#include "test.h"
using namespace std;
int main(void)
{
Test* t = new Test(); // you must define a pointer
cout << "test* was created: " << t << endl;
delete t;
t = nullptr;
return 0;
}
Now all the code is OK. Then we create a shared-library with the following command:
g++ -shared -o test.so -fPIC test.cpp
Finally, we compile the main.cpp file at the same time as referring to the test.so shared-library and get the exe output, by the command below:
g++ -g main.cpp test.so -o test.exe

Calling C code from C++ with using extern "C"

I have 3 files with me, one c++ file, main.cpp, one c file, test.c and one header file, test.h
I wanted to try and use C code into C++ file. For the same reason, I have declared an function in test.h and defined that in test.c and using that in main.cpp
main_temp.c is just for explanation.
test.h
void test(int);
test.c
#include <stdio.h>
void test(int a) {
printf("%d", a);
main_temp.cpp
#include "test.h"
int main() {
foo(5);
}
Here, I understand why this would not work. C symbol would be simple 'foo' but since C++ does more things while creating symbols, it might be 'void#test(int)' and to solve this name mangling problem, I have to treat C++ symbol as a C symbol. So, I would use extern "C" and my main.cpp becomes as like:
main.cpp
extern "C" {
#include "test.h"
}
int main() {
foo(5);
}
I could not understand as to why this would not work! I get :
main.cpp:(.text+0xa): undefined reference to `test`
Can somebody share the insights?
I trust you compile or link them together? Else that would be the cause. On gcc it would be something like:
g++ -c -o main.o main.cpp
gcc -c -o test.o test.c
g++ -o a.out main.o test.o
Assuming you have no bugs with compiling/linking, compile both main.cpp and test.c into object files and run nm on both. It will show what symbol main.o wants and what symbol test.o exports. It should become clear then why linker cannot do its job.

How to compile a cpp and then link it to a shared library

I want to have the functions which are defined in another .cpp file become available in another simulation tool.
I found the following code in this question: -finstrument-functions doesn't work with dynamically loaded g++ shared objects (.so)
Trace.cpp
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
void __cyg_profile_func_enter(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
}
#endif
void __cyg_profile_func_enter(void* this_fn, void* call_site)
{
printf("entering %p\n", (int*)this_fn);
}
void __cyg_profile_func_exit(void* this_fn, void* call_site)
{
printf("exiting %p\n", (int*)this_fn);
}
Trace.cpp is compiled by doing:
g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic MyLib.cpp MyLibStub.cpp Trace.cpp -o libMyLib.so.0.0
ln -s libMyLib.so.0.0 libMyLib.so.0
ln -s libMyLib.so.0.0 libMyLib.so
g++ MainStatic.cpp -g -Wall -lMyLib -L./ -o MainStatic
g++ MainDynamic.cpp -g -Wall -ldl -o MainDynamic
Note that I don't need: MyLib.cpp and MyLibStub.cpp.
Instead compiled Trace.cpp doing:
g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic Trace.cpp -o libMyLib.so.0.0
What I've tried:
The shared object where I want to have Trace.cpp is obtained by:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
I added -L and -l:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -L /home/user/Desktop/test/ -lMyLib -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
and got:
/usr/bin/ld: cannot find -lMyLib
I also tried:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins /home/user/Desktop/test/libMyLib.so.0.0 -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
which compiled successfully but the application crashed:
Error during startup: Cannot load library
'../../src//libveins.so': libMyLib.so.0: cannot open shared object
file: No such file or directory.
Question:
How to compile Trace.cpp correctly?
How to link it with the rest of the shared library?
As you might notice I am not very experienced with compiling, linking and similar. So, any extra explanation is very welcome!
As #Flexo restates what #EmployedRussian said in the linked question, the main point is to get your implementation of __cyg_profile_func_*** before the one provided by libc.so.6.
One method to do this, is to use the LD_PRELOAD environment variable. Here you can read what LD_PRELOAD does and how it works.
To use the LD_PRELOAD trick you will need to compile your implementation of the above-mentioned functions as a shared library.
You can do this by doing:
g++ -shared -fPIC myImp.cc -o myImp.so -ldl
Once you get the .so file, navigate to the directory where your executable is located and do:
LD_PRELOAD=<path/to/myImp.so>- ./<myExecutable>
For shared libraries, dynamic linking is used. Meaning:
resolving of some undefined symbols (is postponed) until a program is run.
By using LD_PRELOAD you resolve the symbols of your interest before letting the linked do that.
Here you have an implementation of myImp.cc, which I took from: https://groups.google.com/forum/#!topic/gnu.gcc.help/a-hvguqe10I
The current version lacks proper implementation for __cyg_profile_func_exit, and I have not been able to demangle the function names.
#ifdef __cplusplus
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
void __cyg_profile_func_enter(void *this_fn, void *call_site)__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)__attribute__((no_instrument_function));
}
#endif
static FILE *fp;
int call_level=0;
void * last_fn;
void __cyg_profile_func_enter(void *this_fn, void *call_site)
{
Dl_info di;
if (fp == NULL) fp = fopen( "trace.txt", "w" );
if (fp == NULL) exit(-1);
if ( this_fn!=last_fn) ++call_level;
for (int i=0;i<=call_level;i++)
{
fprintf(fp,"\t");
}
//fprintf(fp, "entering %p\n", (int *)this_fn);
fprintf(fp, "entering %p", (int *)this_fn);
if (dladdr(this_fn, &di)) {
fprintf(fp, " %s (%s)", di.dli_sname ? di.dli_sname : "<unknown>", di.dli_fname);
}
fputs("\n", fp);
(void)call_site;
last_fn = this_fn;
}
void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
--call_level;
for (int i=0;i<=call_level;i++) fprintf(fp,"\t");
fprintf(fp, "exiting %p\n", (int *)this_fn);
(void)call_site;
}
Another option for function tracing which uses LD_PRELOAD is used by LTTng, in the section Function Tracing, but I have never used it...

undefined reference to function in gcc

I am trying to use a C static library but getting the following error while compiling/linking in gcc. The main file test.c needs to call a function from the static library libtest.a
Header file : testcplusplus.h
void print_cplusplus(int b);
testcplusplus.c :
#include <stdio.h>
#include "testcplusplus.h"
void print_cplusplus(int b) {
printf ("Value of b is %d \n",b);
}
Main C file : test.c
#include <stdio.h>
#include "testcplusplus.h"
int main() {
int a = 2 ;
print_cplusplus(a);
}
Commands Used :
g++ -c -o testcplusplus.o testcplusplus.c
ar rvs libtest.a testcplusplus.o
gcc -o test test.c -L. -ltest **// Error comes here**
Error:
In function `main':
test.c:(.text+0x15): undefined reference to `print_cplusplus'
collect2: ld returned 1 exit status
You only specify function parameter types when you declare/define the function, not when you call it. The function call should look like
print_cplusplus(a);
You also need to include testcplusplus.h from test.c so that the declaration is available when you call it. The return type of main needs to be int; and print_cplusplus should either have void return type, or should return a value.
Finally, you'll need to declare the function extern "C" for it to be callable from a C program - but only when compiling C++.
// testcplusplus.h
#ifdef __cplusplus
extern "C" {
#endif
void print_cplusplus(int b);
#ifdef __cplusplus
}
#endif
You don't rewrite a variables type when you use it, it's only used in declarations:
print_cplusplus(a);

C++ Undefined Reference (Even with Include)

I cannot get this simple piece of code to compile without including the TestClass.cpp file explicitly in my main.cpp file. What am I doing wrong? Thanks in advance!
Here is the code:
TestClass.h
#ifndef TESTCLASS_H_
#define TESTCLASS_H_
class TestClass
{
public:
static int foo();
};
#endif
TestClass.cpp
#include "TestClass.h"
int TestClass::foo() { return 42; }
main.cpp
#include <iostream>
#include "TestClass.h"
using namespace std;
int main()
{
cout << TestClass::foo() << endl;
return 0;
}
Here is the error:
g++ main.cpp -o main.app
/tmp/ccCjOhpy.o: In function `main':
main.cpp:(.text+0x18e): undefined reference to `TestClass::foo()'
collect2: ld returned 1 exit status
Include TestClass.cpp into the commandline, so the linker can find the function definition:
g++ main.cpp TestClass.cpp -o main.app
Alternatively, compile each to their own object file, then tell the compiler to link them together (it will forward them to the linker)
g++ -c main.cpp -o main.o
g++ -c TestClass.cpp -o TestClass.o
g++ main.o TestClass.o -o main.app
You're not compiling and linking against TestClass.cpp (where the implementation of foo() is). The compiler is thus complaining that your trying to use an undefined function.