Making C++ library without name mangling with MinGW - c++

I have several C++ classes which I decided to compile into separate library usable by other applications. Therefore I made a simple C-compatible envelope which wraps C++ classes. The function definitions in the header file are put in extern "C" block.
When I compile this using MinGW g++, I get shared library with decorated function names. Each function name has suffix #ars_size. To get rid of this names I passed -Wl,--kill-at argument to g++. Then I finally got undecorated names.
Then I made a simple C++/Qt application which serves as a tester of the new library. Unfortunately when I include the library's header file into my C++ application, I get linking errors:
release/mainwindow.o:mainwindow.cpp:(.text+0xd6f): undefined reference to `_imp__TdbGetLastErr#12'
release/mainwindow.o:mainwindow.cpp:(.text+0x1163): undefined reference to `_imp__TdbGetAsyncErr#12'
release/mainwindow.o:mainwindow.cpp:(.text+0x166f): undefined reference to `_imp__TdbStop#4'
release/mainwindow.o:mainwindow.cpp:(.text+0x1698): undefined reference to `_imp__TdbForceTrigger#0'
...
To get rid of these errors I have to exclude -Wl,--kill-at during compiling of the library. But then the library is not compatible with C applications. I believe the key is to make MinGW g++ to link undecorated functions. Please does anybody know, how to do this?
EDIT: Adding more details requested in comments.
When compiling the library, I include its header (with extern "C") from the
source code, so the compiler should be aware of extern "C".
The library is not so simple wrapper. Actually it creates several C++ objects
which are operated using handles from C applications. Also it catches
exceptions from C++ classes etc.
Klasyc

Related

C++ program using a mangled symbol from a C library causing an undefined symbol

I'm using a C library in my C++ project, which uses Cmake. In that project, I'm building a plugin from that library. During the development of the project, I used to add files like this to my plugin library in cmake:
add_library(plugin SHARED
impl.cpp
Interface.h
${LIBBTC_REPO}/src/base58.c
${LIBBTC_REPO}/src/bip32.c
${LIBBTC_REPO}/src/block.c
${LIBBTC_REPO}/src/ripemd160.c
...
)
And everything was going fine. But after using the function ripemd160(), my shared library started giving an undefined symbol error:
plugin.so: undefined symbol: _Z9ripemd160PKhjPh
When studying the contents of the plugin with nm -g plugin.so | grep -i ripe, I got:
000000000002e1cb T ripemd160
U _Z9ripemd160PKhjPh
which shows that the original C function is not mangled and is not available, but C++ is expecting a mangled function name. That I don't understand.
What surprises me is that I also call other functions in other files. For example the function utils_hex_to_bin(), but I don't get that undefined symbol error there.
Why is C++ expecting this function to specifically be mangled, while all other C functions not? Is there a better way to do what I'm doing? Am I linking this incorrectly?
Btw, that file, ripemd160.c is the only file in the library that has the header file beside it, instead of being in the include directory. I don't know if that makes a difference.
I also tried creating another module for that library in CMake, but that doesn't help.
Please advise.
EDIT:
Just to be clear, I never decalred any of the functions in the library. I just include headers from that library and that takes care of declarations. That's why I never mentioned extern "C".
Solved: Wrapping the include with extern "C" solved the problem. Apparently the library dev forgot to do that.
Try to declare the ripemd160() function with extern "C". Or you can do this simply by
extern "C" { #include "ripemd160.h" }

Mixing C/C++ code yields "undefined symbol" with shared library

This problem has perplexed me for a week now so I thought it might finally be time to ask you guys for help. Here is the story in a nutshell:
We are developing an embedded server in-house using Qt/C++. It is a very simple server that processes client requests and loads the proper function through dlopen()/dlsym() calls to do something vendor specific. This means the vendor would simply provide us a .so file in C with their function (which is transparent to us) the way we define. This would be written in C because of a lot of low level things it would need to do, and our server is in Qt because we plan on eventually having a frontend for it.
Here is some pseudocode:
In our main.cpp file (this is written in C fashion but uses the g++ compiler as is defined in the Qt mkspec, compiled using -ldl and -rdynamic to export all symbols):
dlopen() vendor.so file (tried with both RTLD_NOW and RTLD_LAZY)
dlsym() vendor.so init() method (this will call the vendor's init method, which will set up the name/properties of this "vendor plugin" through setter methods inside our code, call this plugin_set_name(args...))
In the shared header file (shared.h) (both code bases would use this; ours would have complete definitions of the structs, vendors would simply have prototypes of setters/getters):
extern "C" int plugin_set_name(args...)
In the vendor main.c file (compiled using gcc, -fPIC, and -shared)
Implementation of init() function as mentioned above
So essentially, what is happening is that the C++ code will use the dl calls to load the init() function from the C .so library, and then the C .so library will call a function that is defined in the C++ code (in this case, plugin_set_name). Is this even possible? Neither is linked against each other since they are compiled independently of each other and with different compilers (gcc vs g++).
The error I am getting is on runtime: "undefined symbol: plugin_set_name" (so it finds and gets inside the library's init() method just fine). It works flawlessly when I use gcc and straight C code to do everything so I know it's not the code but something with mixing C/C++. I also understand the use of extern "C" to prevent name mangling and have used nm / readelf to determine that there is no mangling of any kind. Any ideas? What is the best way to go about this?
Somehow, this just magically works today. I can't explain it. I simply have extern "C" declarations around the shared header, so in shared.h:
#ifdef __cplusplus
extern "C" {
#endif
plugin_set_name(args...)
other_shared_functions
#ifdef __cplusplus
}
#endif
I've always had this however. In either case, it works now with vendor plugins being compiled in C and server being compiled in Qt and C++. I think the problem was a combination of where to place all the externs as well as g++ linking flags (where rdynamic is crucial). Thanks. Just putting this here in case anyone else runs into the same issue.

How do I connect a C program to a C++ library without needing stdc++ to link them?

I am trying to add some code to a larger C project that requires the use of a C++ library.
The C++ library provides a wrapper using functions marked extern "C" that provide access to the functionality of the library
//Some C++ library
//mywrapper.h
#ifdef __cplusplus
extern "C" {
#endif
void wrapperFunction1( int width );
void wrapperFunction1( int height);
#ifdef __cplusplus
} // extern "C"
#endif
This compiles with g++ without problem.
When making a C program and including mywrapper.h, I continually get linker errors referencing vtable and cxa_pure_virtual:
undefined reference to `vtable for __cxxabiv1::__class_type_info'
undefined reference to `__cxa_pure_virtual'
In testing, these errors go away and allow the program to compile when I add the stdc++ library, but this isn't a option for the larger C project. Is there a way to compile a C program to access a C++ library without these errors and without stdc++? And the deals of the errors are referring to modules that are deep inside of the C++ library and not referenced in mywrapper.h, so why is C program even trying to refer to them?
A C++ library depends on standard C++ library (libstdc++, -lstdc++ option to linker, defaulted if you run linker via g++). That's a fact. Nothing can be done about it. Get over it.
The wrapper header does not refer to those symbols, but the actual object files in the library do. So they need to be defined and the way to define them is to include the standard C++ library.
Note, that if the wrapped library itself is dynamic, it will know it's dependencies and you won't have to specify linking against libstdc++ dynamically.
It is the C++ library you've wrapped that requires stdc++, not your wrapper.
You've wrapped the C++ functions so that they are callable from C but they still use a library internally that depends on the C++ standard library. If you don't provide stdc++, the library you're using is missing part of its implementation. Unless you rewrite the C++ library, there is no way round that.
In general C++ code needs some level of run-time support to deal with specific C++ features. For example, there is a library function dealing with dynamic_cast<>(). Even if you don't use any of the standard C++ library you will need this language support libray. It is typically included in the standard C++ library but specifically for gcc this library is separately available. That is, you may get away with not including libstdc++ but you won't get away including this library. At the moment I can't find out how it is called though. I think it is -lcxxabi but I'm not sure.
It is perfectly valid not to include libstdc++ with some caveats. Depending on what you do in the C++ code (or in this case the library you're wrapping) it may expect the underlying runtime to provide certain functions:
Like you mention, RTTI info
__cxa_pure_virtual if you have unimplemented pure virtual functions (for example, in pure abstract classes)
Calls to constructors before main() and destructors after it
This happens not only when you don't include libstdc++ library, but also on stripped down custom versions of the library.
For example, Rowley Crossworks for ARM (toolchain for embedded systems) recommends that you write __cxa_pure_virtual error handler yourself.
Okay, I've done some more research and I stumbled over the answer, I had two problems, first was the error messages:
./lib.so: undefined reference to vtable for __cxxabiv1::__si_class_type_info'
./lib.so: undefined reference to `vtable for __cxxabiv1::__class_type_info'
These are related to C++'s Run-time type information, or rtti. Compiling the library with "-fno-rtti" eliminated these errors.
The second problem was:
./lib.so: undefined reference to __cxa_pure_virtual'
Which was cause be the C compiler's inability to handle a virtual function from C++. Creating an stub function with extern "C" eliminated the error and allowed the project to compile.
I'm still confirming if the library is working correctly, but those changes seem to have corrected the errors.
Thanks for the help everyone.

How do I resolve link errors that appear in Objective-C++ but not Objective-C?

I'm converting my App Delegate file from .m to .mm (Objective-C to Objective-C++) so that I can access a third-party library written in Objective-C++. In Objective-C, my app delegate builds and runs fine. But when I change the extension, the project builds and I get link errors, all of which are missing symbols from a static library written in C that I use. The errors are classic link errors with the following format:
"MyFunction(arguments)", referenced from:
-[MyAppDelegate myMethod] in MyAppDelegate.o
Symbol(s) not found
All of the problems are in the app delegate object. I know that I'm all set to compile Objective-C++ because my ViewController file is .mm. So my question has a few parts to it.
First, are these symbols truly not there in the sense that I can't use them? In other words, is it not possible to access plain old C functions from an Objective-C++ file? If this is true, that's pretty unfortunate. I thought that almost all Objective-C code, and certainly all Objective-C code that at least builds as .mm, was valid Objective-C++. Am I wrong?
If not, any idea how I can prevent these errors? Are there header rules that are different in Objective-C++ that I don't know about?
Thanks for any and all help.
Link errors with mixed C++/C or C++/Objective-C programs are usually due to C++ name mangling. Make sure you have extern "C" attached to all the appropriate declarations, and also that all of your code agrees on the linkage. That is, make sure that the function definition as well as the places where it is used can all see the extern "C" or extern "C++".
In your particular situation, it looks like MyFunction() is getting compiled with C++ linkage and having its name mangled, but that your myMethod Objective-C file is trying to link against the unmangled name.
Here is a link to the wikipedia article about name mangling.
Surround your header include with extern C.
This tells the linker that the function names in the library do not get C++ name mangling.
E.g.:
extern "C" {
#include "my-lib.h"
}

Using C/C++ static libraries from iPhone ObjectiveC Apps

Is it possible to have a C static library API, which uses C++ internally and hide this from users of the library?
I have writen a portable C++ library I wish to statically link to an iPhone application.
I have created an Xcode project using the Max OS X 'static library' template, and copied the source across, as well as writing a C wapper (to deal with exceptions) using (extern "C").
I am trying to use the generated library (.a file) in another Cocoa iPhone application.
Everything works well if the I use (.mm) extentions on the calling ObjectiveC file and (.cpp) on the implementation class in the library.
But I get unresolved symbols on linking when I try and change the wrapper file to a (.c) extention, even though all the wrapper function files are only C functions.
Just becuase C++ is used internally in a library, does it mean that externally it still must be treated as a C++ program. Is there not anyway to enforce this abstraction?
Edit: Thanks for the replies,
I had been using extern "C", I was just unsure about what configurations where needed in the calling project. ie. if the calling projected would require to know if it used C++ or could be ignorant and think its a purely C library.
It would seem I cannot, and I must use (.mm) files on my ObjectiveC classes.
It's too hard to do this in comments, so I'm just going to demonstrate for you quickly what the linking issues are that you're having. When Xcode encounters files, it uses build rules based on the suffix to decide which compiler to use. By default, gcc links the files to the standard C library, but does not link with the standard C++ library. Archive files (static libraries) have no linking resolution done at all. They are basically an archive of object files which need to be linked. Since you have no .mm or .cpp files in your project, g++ is never called and your files are never linked to the standard libraries. To correct this, just add the standard C++ libraries to your other linker flags in your Xcode project, or just simply add them to the pre-defined other flags option as -l (e.g., -lstdc++).
Here is a quick demonstration:
stw.h:
#ifdef __cplusplus
extern "C"
#endif
void show_the_world(void);
stw.cpp:
#include <iostream>
#include "stw.h"
using namespace std;
extern "C" void show_the_world() {
cout << "Hello, world!\n";
}
Build the library:
$ g++ -c stw.cpp -o stw.cpp -O0 -g
$ ar rcs stw.a stw.o
Using the library from a C application:
myapp.c:
#include "stw.h"
int main() {
show_the_world();
return 0;
}
Building the C application:
$ gcc -o myapp myapp.c stw.a -lstdc++ -g -O0
$ ./myapp
Hello, world!
$
If you try to compile without the -lstdc++ you will get all the unresolved issues because the C compiler has absolutely NO idea that it should link to the C++ runtime (and why would it, right!?!?) so you have to add this manually. The other option you have is to change the build rule for your project... instead of having Xcode use gcc to build .c and .m files, tell it to use g++ and your issues will be resolved.
You should declare the functions you want to be visible extern "C". Their signatures need to be C-compatible, but the contents do not (you may access C++ objects, for instance, but you cannot pass them directly; pointers are okay). The symbols will then be visible to any C-compatible environment.
EDIT: And compile it as a C++ source file, C doesn't have the notion of language linkage. There are a couple other gotchas with language linkage (like the fact that all extern "C" functions with the same name are the same function, regardless of namespace).
EDIT2: In the header, you can check for the macro __cplusplus, and use that to set for C++ and other languages, respectively (because C++ will require extern "C" declarations, and other languages will probably complain about them).
Basically when you compile the C functions with a C++ compiler it mangles the function names and uses the C++ ABI.
When you use the *.cpp or *.mm extension you are using the C++ compiler.
What you want to do is force the compiler to generate C functions with un-mangles names and using the C ABI.
You can do this by either:
Compile with the C compiler.
Compile with the C++ compiler but make sure that you prefix the function declarations with extern "C"
A favorite way to set up the header file, so that the same file can be included from both C and C++ source files is:
#ifndef HEADER_GUARD_1_H
#define HEADER_GUARD_1_H
#ifdef __cplusplus
extern "C" {
#endif
// Declare C function interface here.
int myFunc(int x,char*);
#ifdef __cplusplus
}
#endif
#endif
thanks, for such good discussion.
what I did is:
1) I created a static lib using cocaotouch static lib option. In that i have c/c++/obj-c all mix. however, my exports are only obj-c classes.
Infact i used objc- to c to C++.
2) then I creatd iphone app in X-code proj.
I added the otherlink flags my lib name ( -lxyz ) //my lib name is libxyz.a
I added lib search path, header search path
3) then I compiled. I got errors.
saying oeprator new, operator delete not found.
3) then apart my appdelegate, view controller, I added
dummy cpp(.h, .cpp)...
atestdummy.h atestdummy.cpp
4) then I build again...
thats it worked.
So - I whatever suggestions they gave earlier workedfor me.
basic reason, unless u r app sees a .cpp file .mm file with cpp code,
linked will not use g++.
Thanks all.
I have read the above and ssolved my problem.
u guys are good to share.