Compile C shared object with C++ files - c++

I have a C shared object (.so file) and i can only compile it using gcc because it uses C only functions like strcpy_s.
And i have a C++ code that contain some C++ only libraries.
Is that possible to compile the shared object with gcc and my code with g++ together ?

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

Why is __cplusplus defined within extern "C"

Within extern "C" { } the macro __cplusplus is still defined. When I want to include the C version of mpi.h in the header of my library which is dynamically load this will not work as mpi.h still finds __cplusplus and will still load like it was opened by C++.
#undef __cplusplus works with gcc. But I do not want to rely on this.
So how to write a C++ program that
- uses the C++ version of mpi and
- is linked against a C-library that uses the C-Version of mpi (where #include <mpi.h> appears already in the header?
Example code:
library.h:
#ifdef __cplusplus
extern "C" {
#endif
#include <mpi.h>
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
program.cpp:
#include <library.h>
#include <mpi.h>
int main() {
MPI::Init();
// do some mpi C++ calls...
library_do(MPI::COMM_WORLD);
MPI::Finalize();
}
In case somebody wants to play the example here the library.c:
#include <stdio.h>
#include "library.h"
void library_do(MPI_Comm comm)
{
int rank;
MPI_Comm_rank(comm, &rank);
printf("MPI Rank: %d", rank);
}
And to compile everything I try with
mpicc -shared library.c -o lib.so
mpicxx program.cpp -l lib.so
__cplusplus will always be defined by the compiler if the compiler is a C++ compiler. extern "C" {} only gives you C linkage so the code inside plays nice with a C compiler.
The point of using
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
is to prevent the name mangling that C++ does. We are basically saying dont use the name mangling like a traditional C++ function call instead leave it undecorated.
This link could be useful Name mangling
It is used to make C headers compatible with C++.
The flag __cplusplus is automatically defined in C++ compiler.
Because they are different things. extern "C" {} tells the compiler how to export symbols (see here), whereas __cplusplus tells you that you can use C++ code so your library can use different code paths inbetween #ifdefs.
The compiler outputs the following:
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:61:0,
from /usr/include/c++/4.8.2/bits/stl_tree.h:61,
from /usr/include/c++/4.8.2/map:60,
from /usr/include/openmpi-x86_64/openmpi/ompi/mpi/cxx/mpicxx.h:38,
from /usr/include/openmpi-x86_64/mpi.h:2674,
from x1.cpp:6:
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:72:3: error: template with C linkage
template<typename _Iterator, typename _Container>
^
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:85:3: error: template with C linkage
template<bool>
^
...
The mpi.h header detects that it's being compiled as C++ and so includes C++ specific features. However templates (among other things) don't work with C linkage (i.e. if the header is within an extern "C" block).
Move the include above extern "C":
#include <mpi.h>
#ifdef __cplusplus
extern "C" {
#endif
void library_do(MPI_Comm comm);
#ifdef __cplusplus
}
#endif
Of course it's defined. It's still a C++ compiler that compiled the code inside the extern "C" block. It doesn't stop treating the code as C++, only makes sure to use a C calling/naming convention.
If the header cannot be compiled by a C++ compiler, the only recourse is to create a C wrapper that exposes a C++ compatible API.
If you #include <mpi.h> from a C++ program, just don't put extern "C" around it. At least OpenMPI and Intel MPI do this for you in the header itself - if __cplusplus is defined.
You probably get into trouble because some MPI implementations still define the C++ interface in mpi.h that was deleted from the standard. This obviously breaks under extern "C". For instance with OpenMP you can skip this by setting OMPI_SKIP_MPICXX. Then the double extern "C" works, but I still wouldn't recommend it.
Update: In case you can't modify the library header, just #include <mpi.h> before #include <lib.h>.
That said, you should not use the C++ bindings for MPI. They were removed from the standard more than 6 years ago, after being for 3 years...

how does extern "C" allow C++ code in a C file?

In order to use C++ code in a C file, I read that we can just do extern "C" { (where the c++ code goes here)}, but when I try printing something out using cout, I keep getting an error because it does not recognize the library . I think I am just confused on how extern "C" allows you to use C++ code in C.
The opposite is true. You can use extern C to add code you want to compile as C code using a C++ compiler.
Unless I'm missing something you can't compile C++ code with a C compiler.
The extern "C" construct is a C++-specific syntax, no C compiler will understand it.
That's why you will almost always see it paired with some conditional compilation like
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
What extern "C" does is simply to inhibit name mangling meaning that symbols defined in a C++ source file can be used in a C program.
This allows you to have a project with mixed C and C++ sources, and the C source can call the C++ functions that have been defined as extern "C".
Very simple, and stupid, example just to show the point:
Lets say we have a C source file, compiled with a C compiler:
#include <stdio.h>
void foo(void); // Declare function prototype, so it can be called
int main(void)
{
printf("Calling foo...\n");
foo();
printf("Done\n");
return 0;
}
Then we have a C++ source file for the foo function:
#include <iostream>
extern "C" void foo()
{
std::cout << "Hello from foo\n";
}
The C source file is compiled with a C compiler, and the C++ source file is compiled with a C++ compiler. Then the two object files are linked together to form the executable program. Because foo was defined as extern "C" it's symbol name in the object file is not mangled, and the linker can resolve the reference from the object file created by the C compiler.
It works in the other direction as well. Because symbols in C are not mangled the C++ compiler needs to know that, and that is done by declaring the C symbols extern "C", usually in a header file using the conditional compilation as shown above. If extern "C" was not used, the C++ compiler would think that the symbols were C++ symbols, and mangle the names leading to linker problems when the linker can't find the mangled symbols.
Equally stupid example: First a C++ source file
#include <iostream>
extern "C" void bar(); // Declare function prototype as an unmangled symbol
int main()
{
std::cout << "Calling bar...\n";
bar();
}
Then the C source file
#include <stdio.h>
void bar(void)
{
printf("Inside bar\n");
}
extern "C" is a way of putting C code in C++ code. More specifically it tells the compiler to disable certain things like function overloading so that it can also turn off the name mangling. In C++ a simple function like:
int add(int a, int b) {
return a+b;
}
Will actually get some funky name in the library to denote the parameters so that if you define another function like:
double add(double a, double b) {
return a+b;
}
That it knows which one to call. You don't want that if you're trying to use a C library and that's what extern "C" is for. All of this being said, extern "C" does not allow C++ in a C program.
Exported C++ symbols, as generated my the compiler, are mangled to include additional type information about the symbol to the linker.
So the following overloaded functions would be distinguishable by the linker in C++, but not C:
int fn();
int fn(int);
int fn(char*);
int fn(char*) const;
int fn(const char*);
The extern "C" { ... } syntax allows symbols (or references to C symbols) to be defined in C++ code without using the mangling rules.
This allows such C++ code to be linked with C libraries.

Using Eigen in a C Project

I am working on a C project I got from the Internet, and I'm trying to add some functions to the project that involve linear algebra. In my previous works in C++, I usually rely on Eigen for linear algebra.
Is there a way to use Eigen for a C project? If yes, what should I do to make that work? (Simply adding Eigen header files is not enough since for example the standard C++ files do not get included automatically)
Eigen is a library which heavily uses C++ features which are not present in C. As such, it cannot be directly used from a C translation unit.
However, you can wrap the parts using Eigen in a separate shared library and expose a C interface. Here is a small example how one could write such a library.
Library interface
/* foo.h */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void foo(int arg);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
By default, C++ uses different mangling rules than C for names of exported functions. We use extern "C" to instruct the C++ compiler to use the C rules. Because the interface file will be seen by both the C++ and the C compiler, we wrap the extern declaration in #ifdefs which will only trigger for the C++ compiler.
Library implementation
/* foo.cpp */
#include "foo.h"
#include <iostream>
extern "C" {
void foo(int arg) {
std::cout << arg << std::endl;
}
} /* extern "C" */
We also need to define C linkage in the definition of the interface. Other than that, you can use any C++ features you like in the implementation (including Eigen).
C project
/* main.c */
#include "foo.h"
int main() {
foo(42);
return 0;
}
Include the interface header and use it like any other C library.
Building
$ g++ foo.cpp -shared -fPIC -o libfoo.so
$ gcc main.c -L. -lfoo -o main
Use a C++ compiler to build the shared library libfoo.so. Use a C compiler to build the main program, linking to the shared library. The exact build steps may vary for your compiler/platform.

C linkage and c++ headers

I want to use some c++ classes in shared library with C linkage. And i got following problems.
If
#include <iostream>
extern "C"
{
void f(){}
}
Compiles and links succesfully, but f() could not be found in resulting library.
If
extern "C"
{
#include <iostream>
void f(){}
}
I got many compiler errors (just dont know how to correctly translate them in english, something about template with C linkage) on every occurence of C++ keyword "template" in iostream and included headers.
What should be done?
The first variant is correct. Only stuff that even exists in C can be declared in a extern "C" block, and templates and classes certainly don't belong in that category. You only have to make sure, that your function is also declared as extern "C" in the header if you are using a C++-compiler. This is often achieved by writing
#ifdef __cplusplus
// C++ declarations (for example classes or functions that have C++ objects
// as parameters)
extern "C"
{
#endif
// C declarations (for example your function f)
#ifdef __cplusplus
}
#endif
in the header.
The first is correct; system headers (and most other headers as well)
can only be included at global scope, outside any namespaces, classes,
functions or linkage specification blocks. There are likely things in
<iostream> that wouldn't be legal in an extern "C", and even if
there weren't, the name mangling for extern "C" is almost certainly
different from that of C++, and the library itself was surely compiled
as extern "C++".
How did you define f? This could be a similar problem: if the source
file compiles it as an extern "C++" function, then the name will be
mangled differently than it was in the client files which compiled it as
an extern "C" function.
The general policy here is to handle the headers and the function
definitions/declarations in the same way you normally do, except that
you ensure that the header can be included in both C and C++ sources,
e.g.:
#if __cplusplus
extern "C" {
#endif
void f();
// Other `extern "C"` functions...
#if __cplusplus
}
#endif
Then include this header in all files where the function f() is used,
and in the file where it is defined.
Use __declspec to export functions, classes, etc...
Also: http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx
And this one is very good: http://www.flounder.com/ultimateheaderfile.htm

Including functions with extern C linkage in library

I have included some C functions with extern c linkage in c++ code. E.g.
// File Y.cpp:
extern C {
void fnA(void) { }
void fnB(void* a, void* b) { }
}
class test {
....
};
// end of file
File Y is under module Mod. While building library libMod-O.a for module Mod, I don't see the functions under extern block included, unless Y.h is included in some other file (Mod.cpp) and the class test is used. So unless I create an object of test class in Mod.cpp, I do not see the extern functions (fnA, fnB) in the libMod-O.a, even through Y.cpp is compiled during build of libMod-O.a. The result of this is that linker error happens as another module uses fnA, fnB.
I do not see the connection between the extern functions fnA and fnB being included and usage of class test in Mod.cpp. Is this expected or is there a better way to define this?
You mean extern "C" of course.
You need to have a clean separation between your C code and your C++ code.
In YourCCode.h:
#ifdef __cplusplus
extern "C" {
#endif
void fnA(void);
void fnB(void* a, void* b);
#ifdef __cplusplus
}
#endif
In YourCCode.c:
void fnA(void) {}
void fnB(void* a, void* b) {}
Make sure your compiler compiles YourCCode.c as C, not as C++.
In your C++ code
#include "YourCCode.h"
fnA();
// etc.
you might have a link order problem where the files that use fnA come after the link of libMod-O.a but where Mod.cpp with object test comes before libMod-O.a so the obj file is pulled in before fnA/fnB are needed later. the gnu linker is a single pass linker by default.