How to Use Shared Library Created in C++ in a C Program

Can I use shared library created in C++ in a C program?

You want something more like this (and here I will use a slightly more meaningful example):

C/C++ header - animal.h

#ifndef ANIMAL_H
#define ANIMAL_H

#ifdef __cplusplus
class Animal {
public:
Animal() : age(0), height(0) {}
Animal(int age, float height) : age(age), height(height) {}
virtual ~Animal() {}

int getAge();
void setAge(int new_age);

float getHeight();
void setHeight(float new_height);

private:
int age;
float height; // in metres!
};
#endif /* __cplusplus */

#ifdef __cplusplus
extern "C" {
#endif
struct animal; // a nice opaque type

struct animal *animal_create();
struct animal *animal_create_init(int age, float height);
void animal_destroy(struct animal *a);

void animal_setage(struct animal *a, int new_age);
void animal_setheight(struct animal *a, float new_height);
int animal_getage(struct animal *a);
float animal_getheight(struct animal *a);
#ifdef __cplusplus
}
#endif

#endif /* ANIMAL_H */

C++ animal implementation file - animal.cpp

#include "animal.h"
#define TO_CPP(a) (reinterpret_cast<Animal*>(a))
#define TO_C(a) (reinterpret_cast<animal*>(a))

void Animal::setAge(int new_age) { this->age = new_age; }
int Animal::getAge() { return this->age; }
void Animal::setHeight(float new_height) { this->height = new_height; }
float Animal::getHeight() { return this->height; }

animal *animal_create() {
animal *a = TO_C(new Animal);
return a;
}

animal *animal_create_init(int age, float height) {
animal *a = TO_C(new Animal(age, height));
return a;
}

void animal_destroy(animal *a) {
delete TO_CPP(a);
}

void animal_setage(animal *a, int new_age) {
TO_CPP(a)->setAge(new_age);
}

void animal_setheight(animal *a, float new_height) {
TO_CPP(a)->setHeight(new_height);
}

int animal_getage(animal *a) {
TO_CPP(a)->getAge();
}

float animal_getheight(animal *a) {
TO_CPP(a)->getHeight();
}

C client code - main.c

#include "animal.h"
#include <stdio.h>

int main()
{
// 6'0" 25yo (perhaps a human? :P)
struct animal *a = animal_create(25, 1.83);

animal_setage(a, 26); // birthday
printf("Age: %d\nHeight: %f", animal_getage(a), animal_getheight(a));

animal_destroy(a);
return 0;
}

C++ client code - main.cpp

#include "animal.h"
#include <iostream>

int main()
{
// 6'0" 25yo (perhaps a human? :P)
Animal* a = new Animal(25, 1.83);
a->setAge(26); // birthday
std::cout << "Age: " << a->getAge() << std::endl;
std::cout << "Height: " << a->getHeight();

delete a;
return 0;
}

So when you compile the library, you compile animal.cpp with a C++ compiler. You can then link to it with C code, and use the animal_xxx functions.

Note the use of struct animal and Animal. Animal is a normal C++ type. It's exactly what it looks like. struct animal, on the other hand, is an "opaque" type. That means that your C program can see it's there, and can have one, but it doesn't know what is inside it. All it knows is that it has a function that takes a struct animal*.

In a real library you will want to have customisation points for memory allocation. So assuming this is the library libjungle, you probably want at least jungle_setmalloc and jungle_setfree with sensible defaults. You can then set up the global new and delete in libjungle's C++ code to use these user-defined functions.

Compile a C program in Linux using shared library

You need to place -l options on the end of linker invocation command line:

gcc -o program -L. mymain.o -lmyclib

Use C shared library in C++ program

extern "C"
{
#include "Label.h"
}

Like this.

Using C++ shared library from C

That's because of name mangling, the function names get mangled in c++ to provide function overloading, if you need to use these functions in c, the declare the functions with extern "C" so the compiler wont mangle the names of the functions.

So adding this prototype for function void function() {}

extern "C" void function();

would do it. And I assume you can figure out how to fix other functions.

Is it possible to include C++ libraries in C programs?

No, it is not possible. One thing that is certanly going to miss are exception handling functions. You have to compile the main using c++ compiler.

If you really want to develop in c, and use a c++ library, you can develop a c library, and compile main with g++.


Even if compiling succeeds, linking will fail at the end. See :
Why can't I link a mixed C/C++ static library that has a C interface using gcc?

And it is not only exception functionality missing. There are lots of other things, which can be easily solved by using g++ to link everything.

As I said above, the solution is to call some function from main and link it with g++ :

#include "my_c_main.h"

int main(int argc, char* argv[])
{
return run_my_c_main( argc, argv );
}

How do I share my C/C++ project and hide some of the source code?

Suppose you have the following source file:

mylib.c:

#include <stdio.h>

void my_print(int i)
{
printf("i=%d\n", i);
}

The public header for this would be:

mylib.h:

#ifndef MYLIB_H
#define MYLIB_H

void my_print(int i);

#endif

You could then build the library like this:

gcc -g -Wall -Wextra -c mylib.c
gcc -g -Wall -Wextra -shared -fPIC -o libmylib.so mylib.o

Then you can distribute libmylib.so and mylib.h to users. Then can then use it in their code like this:

user_prog.c:

#include "mylib.h"

int main()
{
my_print(5);
return 0;
}

They would then put libmylib.so into someplace like /usr/lib or /usr/local/lib, and compile like this:

gcc -g -Wall -Wextra -o user_prog user_prog.c -l mylib

For your particular case, assuming head1.h contains the public interface and source1.cpp source2.cpp source3.cpp the library, you would compile like this:

g++ -g -Wall -Wextra -c source1.cpp
g++ -g -Wall -Wextra -c source2.cpp
g++ -g -Wall -Wextra -c source3.cpp
g++ -g -Wall -Wextra -shared -fPIC -o libmylib.so source1.o source2.o source3.o

How can a shared library (.so) call a function that is implemented in its loader code?

You'll need make a register function in your .so so that the executable can give a function pointer to your .so for it's later used.

Like this:

void in_main_func () {
// this is the function that need to be called from a .so
}

void (*register_function)(void(*)());
void *handle = dlopen("libmylib.so");

register_function = dlsym(handle, "register_function");

register_function(in_main_func);

the register_function needs to store the function pointer in a variable in the .so where the other function in the .so can find it.

Your mylib.c would the need to look something like this:

void (*callback)() = NULL;

void register_function( void (*in_main_func)())
{
callback = in_main_func;
}

void function_needing_callback()
{
callback();
}

Compile C shared object with C++ files

Sure, you can link your C++ program with your shared C library. Just make sure that you tell the C++ compiler that the functions in that library have C linkage by adding extern "C" { ... } around the functions in your C library's header file:

shared_c_lib.h

#ifdef __cplusplus
extern "C" {
#endif

// all your C functions declarations/prototypes

#ifdef __cplusplus
} // extern "C"
#endif


Related Topics



Leave a reply



Submit