I have a C library that I need to use in a C++ code, so I need to wrap the whole lib with an extern "C"
block. The problem is that the library seems to include a C++ compiled code, so wrapping the whole lib would also wrap that C++ header.
Inside lib.h
I only include all the internal headers I want to expose, something like this:
#ifndef LIB_H
#define LIB_H
#include "lib_foo.h"
#include "lib_bar.h"
#include "lib_baz.h"
#endif
So the client will only need to include lib.h
to use the lib.
In my first attempt I've done this:
#ifndef LIB_H
#define LIB_H
extern "C" {
#include "lib_foo.h"
#include "lib_bar.h"
#include "lib_baz.h"
}
#endif
But then I get a symbol lookup error when I execute any function inside already_compiled_c++.h
.
How can I avoid from applying extern "C"
in the already_compiled_c++.h
header file?
Edit:
Solved. This was not a problem using extern "C"
, it was a problem linking the compiled c++ library with gyp correctly: Using shared library in Gyp in node-sqlite3
Note that extern C
isn't legal C, so it must only be included hen compiling as C++.
The already_compiled_c++.h header probably contains a guard against multiple includes, so just include it first:
#ifndef LIB_H
#define LIB_H
# This include added so that it won't get marked extern "C" when included by lob_foo.h.
#include <already_compiled_c++.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "lib_foo.h"
#include "lib_bar.h"
#include "lib_baz.h"
#ifdef __cplusplus
}
#endif
#endif
Note: You need to check if already_compiled_c++.h
is conditionally included and add the corresponding conditionals.
You cannot call C++ from a file compiled in plain C.
If lib_foo.h is plain C, it cannot directly use the functions in already_compiled_c++.h. You will most likely need to create a C wrapper for it.
This answer may help you further: Elegantly call C++ from C
If your diagram is accurate, then lib_foo.h
should not be including already_compiled_c++.h
. Edit it to stop including that.
If the functions declared in already_compiled_c++.h
had their implementation compiled to use the C++ ABI, there is no way that your C program could link against them. (short of extremely ugly hacking).
To avoid snarls like this in the future, explicitly put #ifdef __cplusplus
extern "C" {
guards in every header file which will have a C implementation, but might be used in a C++ program, and vice versa.
A workaround for your current situation would be to make a .cpp
file that has thunks for the functions you need. Publish your thunks under extern "C"
, and implement them by calling the functions in already_compiled_c++.h
.
Rethink your design. You can't include C++ headers from C, only the reverse. A few suggestions:
1) Although the original idea behind 'extern "C"' was to wrap includes of C headers from C++ files, if you have headers that should be C-accessible but are implemented in C++, the common approach is to wrap the declarations in it and not the includes. (With the requisite #ifdef __cplusplus so the C code, which always treats headers as being C, doesn't choke on the unneeded C++-ism 'extern "C"')
2) Don't expose C++ as the public API of a library. C++ in general does not provide a binary stable ABI. If you add a method and it's not at the end, or if you add an instance variable to a class, or if you change something in a templated class, all clients would have to be recompiled (with static libraries that usually happens anyway, but this is a big problem for dylibs/DLLs/frameworks). So in general the best idea is to keep C++ as an implementation detail and only expose C features from your library.
3) If you need to expose C++ from your library, use the Pimpl (private implementation) pattern and no templates, and put it in a separate header that isn't included by the master C header, so C clients can just not include it. Such a separate header is also useful for #2 because your library's modules' implementation files (which are in C++) can include it and thus use the classes in it.
4) To C++, a pointer to a struct Foo and a pointer to a class Foo are the same thing. So if you need to return a C++ class from a C-only API implemented behind the scenes in C++, what you can do is just always use struct Foo* in the headers (which C understands correctly), and provide C wrapper functions for the class's methods like:
extern "C" int FooGetCount( struct Foo* thisFoo )
{
return thisFoo->GetCount();
}
That way they can keep around pointers to C++ objects and access their properties, but don't need to actually use C++. Of course you also need to provide similar wrappers for creating/deleting the object, as C doesn't have the new/delete operators.