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

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.

Related

Why can my my C++ program correctly linked when I replace libstdc++ with libgcc

Currently I read an article about name mangling on wikipeida(link). In that article, I learn that the common extern "C" idiom is used to protect those C code in C++ source file from being mangled, which make those source code incompatible to be linked against the original C lib.
So I make the following reasoning:
If I write code like this:
#include<stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
and compile this with command g++ test.cpp -o test, then it will successfully compile with no doubt. We don't have to enclose printf() with extern "C", even though printf() is a C function. That's because, there is an another printf() in libstdc++, which is different from that in libgcc.
So far, so good.
But I discover that that is not so true as I think.
I perform a few experiments:
I remove all the libstdc++ under /usr/lib , which include
/usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.a
/usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.so
/usr/lib/x86_64-linux-gnu/libstdc++.so.6
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
and then I make a copy of libgcc and place it under the place where libstdc++ has lived(otherwise the linker will complaint about libstdc++ not found)
$sudo cp ./gcc/x86_64-linux-gnu/4.8/libgcc.a ./gcc/x86_64-linux-gnu/4.8/libstdc++.a
However, the code above compile, without the extern "C" !!!
Why is that? shouldn't it throw out a Unresolved Reference or something similar because the printf(),which have been mangled by the C++ compiler, incompatible with the printf() in li libgcc ?
any one tell me why my question get downvoted ?
Your extern "C" is present, although it is hidden.
If you look in stdio.h, you will notice the line
__BEGIN_DECLS
(line 29 on my system*) which in turn expands to
# define __BEGIN_DECLS extern "C" {
(line 98 in sys/cdefs.h on my system) if you compile in C++ mode and to nothing otherwise. So the standard library header does the wrapping for you.
Removing your C++ standard libraries has no effect because those C functions live in the C standard library, and as all wrapping is done correctly, the linker can find and use them.
Now of course this is an implementation detail, in general, using <stdio.h> must work because the standard says so (currently, it's deprecated). How the compiler achieves that is not mandated.
*gcc6.1.1 packaged for Arch Linux
g++ will notice that you are compiling something with a .c extension and treat it as a C source file.
Make g++ compile C using gcc rules
Instead of deleting libraries from your system, which has a good chance of going wrong at some point, use GCC flags to print library search paths and see what's going on. You may also be interested in nm (which prints the real symbol names in use), c++filt (which demangles names), and ldd (which prints the libraries linked with).

g++ - Finding appopriate Windows libraries to link so as to compile FANN library

For various reasons I have been trying to compile the FANN library myself. I'm on Windows 10 with MinGW. To keep things simple I was going for something like this to start with:
g++ mushroom.c -o shroom.exe -lm -I src\ -I src\include\ src\doublefann.c
(mushroom.c includes <stdio.h> and "fann.h".)
Using the -I src\ -I src\include\ src\doublefann.c allowed me to get rid of various undefined reference errors resulting from header files not being found, but it now keeps throwing the following undefined reference:
doublefann.c:(.text+0x4ee9): undefined reference to GetTickCount()
FYI, this appears in fann.h (line 54):
/* COMPAT_TIME REPLACEMENT */
#ifndef _WIN32
#include <sys/time.h>
#else /* _WIN32 */
#if !defined(_MSC_EXTENSIONS) && !defined(_INC_WINDOWS)
extern unsigned long __stdcall GetTickCount(void);
In short, this seems to be an error with linking windows libraries, and I don't really know how to proceed so as to find the relevant ones to link.
Here is the full fann.h and the full doublefann.c
DISCLAIMERS AND NOTES
EDIT: Since going to bed last night, I refined my approach so you don't have to edit the actual FANN source files. (For the record, my original approach worked and you can look at the edit history to see what that was if you really care).
Firstly, for anyone else stumbling across this question, I should note that it's not really necessary to use FANN this way. The website provides cmake files as well as Visual Studio Solutions that both work fine.
WHATS WRONG
Looking back at the question, the problem is obvious and I hate myself for not seeing it before the first of way too many hours. You'll notice that all of the files in that command have the *.c extension. Forgive me for treating you like a novice, but I can't assume you know anything or I risk giving a bad answer. *.c is the canonical file extension for C source files. The gnu toolchain is a fairly flexible piece of software, and you can compile C code with g++ without errors most of the time. But you shouldn't, because you'll get this error. Since your source file, mushroom.c, is a C source file, it'll work for you to just compile the code as C (in this case with gcc, not g++). If, however, you're using things in your program like iostream or string or classes or any other C++ code, you're right to compile it as C++ (by convention you would change the extension then to *.cpp for clarification, but I'm not sure the GNU toolchain cares). In that case, whenever you want to include C code in your C++ program, be sure to wrap it in an extern "C"{}, so that the compiler knows the calling conventions and labels are C standard, which isn't always the same as C++ standard. This means that not only does calling C code from C++ without extern "C" risk passing arguments to functions in the wrong way (good way to cause a segfault), but the way variables and functions are renamed when compiled to assembly is different between the two languages, which is why you get Undefined Reference in the linking stage, but not the compiling stage. In this case, not only is doublefann.c a C source file (which by itself links fine), but so is the library that contains the function declaration of GetTickCount(). Specifically, you're linking to %SYSTEMROOT%\System32\kernel32.dll (normally, but I believe MinGW uses PATH_TO_MinGW\lib\lib32k.a), which defines how programs can interact with the Windows Operating System at the machine-code level. The __stdcall utility is defined here to call things like GetTickCount() from the OS, which are assembly functions, within C code. Because this is in a *.dll, the compiler cannot change __stdcall to suit C++ coventions. This is due to the fact that "dll" stands for "Dynamically Linked Library". Essentially this means that these files were already compiled into machine code when Windows (or MinGW) was installed. So editing it is nonsensical, because you'd need to have intimate working knowledge of the opcodes for every x86_64 processor ever made. Thus, calling in C will do everything in a way that __stdcall expects, but calling in C++ requires the extern "C", or it'll mangle the names of your function declaration and possibly cause runtime errors.
tl;dr
FANN is written in C, C=/=C++, so don't expect a C++ compiler to always compile C code perfectly.
Solution
There are two ways to go about solving this problem.
1
If you're using C++ features/libraries, change the name of your source code to mushroom.cpp (if you want) and change the line (wherever it occurs in your program)
#include "doublefann.c"
to be wrapped like so:
extern "C"{
#include "doublefann.c"
}
If you read through fann.h, you might have noticed the lines:
#ifdef __cplusplus //line 65
extern "C"
{
#ifndef __cplusplus
} /* to fool automatic indention engines */
#endif
#endif /* __cplusplus */
Don't worry, these don't appear to conflict. Frankly, I'm not sure what these lines are meant to accomplish, but I'm sure they know what they're doing.
2
If mushroom.c really is just pure C, just compile using:
gcc -o shroom.exe mushroom.c -lm -I src\ -I src\ -I src\include\ src\doublefann.c -Wall
and that should work. I added -Wall because I love being able to make my code absolutely perfect, feel free to leave that out it just prints every warning you could have.

How do you compile C++ source code that includes C source file?

I'm attempting to use SQLite in a c++ program. My knowledge of C/C++ is limited as I've mostly used Java to this point. I had some classes in college but its been a while and we never covered anything like this. SQLite is written in C. When compiling the program how would you do this? (I have MinGW installed on my windows platform so gcc and g++ are what i use to compile.)
You protect the C headers in your C++ code by
extern "C" {
// your includes here
}
and that should be all---g++ should happily link code from both gcc and g++. The extern "C" ... trick is also used in C++ system headers and many libraries, just look at the headers that came with your g++ installation or some suitable Open Source projects. Here is a Boost example:
edd#max:~$ grep 'extern "C"' /usr/include/boost/date_time/*
/usr/include/boost/date_time/filetime_functions.hpp: extern "C" {
/usr/include/boost/date_time/filetime_functions.hpp: } // extern "C"
edd#max:~$
Edit: Thanks to delnan for an attentive comment---this is from the sqlite3.h header itself:
/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif
so this is of course already taken care of.
C++ achieves compatibility with C through the use of extern "C" declarations. There are some good explanations of what extern "C" means and why it is needed at this SO question: Why do we need extern ā€œCā€{ #include } in C++?. Virtually all C-based libraries, including sqlite, provide for automatic C++ compatibility by including extern "C" in their header files.
Therefore, SQLite will work without any special handling on your part (other than including the header and the library as you normally would for a C or a C++ library)...
/* my_sqlite_program.cpp */
#include <sqlite3.h>
int main()
{
...call sqlite functions...
}
compile with
g++ -Wall -Werror my_sqlite_program.cpp -lsqlite3 -o my_sqlite_program
For SQLite in specific, there's nothing really complicated about it.
If you're using a dynamic or static library, you just include their headers and link against the proper lib files.
If you're including SQLite fully inside your app, you'll need to include all the source files in your project and build them as well, and include the headers as needed (using it as a static/dynamic library might be nicer though).
If you need to use C code in files compiled as C++, Dirk's answer is correct, but that's not needed for SQLite.
How can you call C programs from C++ source code?
By using a facility called as linkage specification provided by the compilers. The specification tells the compiler how to link the source code.
Linkage specification is of the format
extern "Language_Type"
{
}
In your case you can wrap your SQLlite C functions like
extern "C"
{
//SQLite function declarations
}
This should enable you to get it working but Since you are trying to call SQlite c functions from C++, SQLite already provides some wrappers for achieving what you are trying to achieve. Check more details on SQLite website. Also, some open source projects also provide what you want. Check CppSQLite
Hope this helps!

Trouble compiling dll that accesses another dll

So, I have an interesting issue. I am working with a proprietary set of dlls that I ,obviously, don't have the source for. The goal is to write an intermediate dll that groups together a large series of funnction calls from the proprietary dlls. The problem I am having, when compiling with g++, is that I get errors for the original dlls along the lines of:
cannot export libname_NULL_THUNK_DATA. Symbol not found.
If I add a main and just compile to an executable everything works as expected. I'm using mingw for compilation. Thanks for any help.
In response to the first reply: Either I'm confused about what you're saying or I didn't word my question very well. I'm not explicitly trying to export anything from my wrapper I am just calling functions from their dlls. The problem is that I get errors that it can't export these specific symbols from the dll to my wrapper. The issue is that I'm not even entirely sure what these _NULL_THUNK_DATA symbols are for. I did a search and read somewhere that they shouldn't be exported because they're internal symbols that windows uses. I have tried using the --exclude-symbols directive to the linker but it didn't seem to do anything. I apologize if I'm completely misunderstanding what you're trying to say.
So, I think my issue was related to this. When just compiling a standard executable that uses a dll I was able to include the headers and directly call the functions for example:
#include :3rdparty.h
int main(){
dostuff(); // a function in the 3rdparty.dll
}
this would compile and run fine. I just needed to link the libraries in the g++ command.
When linking with the -shared flag I would get these errors (with main removed of course). I think it has something to do with the fact that by default g++ attempts to import all symbols from the dll. What I didn't understand is why this happens in the dll vs in an executable. I will try doing it using GetProcAddress(). Thank you!
it should be as easy as you think it should be.
eg:
your dll code needs:
void doStuff()
{
3rdparty.login();
3rdparty.dostuff();
3rdparty.logoff();
};
so far - so good, you've included the right headers .... (if you have them, if you don't then you need to import the library using LoadLibrary(), then create a function pointer to each exported dll entrypoint using GetProcAddress() and then call that function pointer)
You then link with the 3rd party lib and that's it. Occasionally you will have to wrap the definitions with 'extern "C"' in order to get the linkage name mangling correct.
As you say you're using g++, you can't be getting confused with __declspec(dllimport) which is a MS VC extension.
"Compiling" tells me that you're approaching this from the wrong end. Your DLL should not export its own wrapper functions, but directly refer to exports from other DLLs.
E.g. in a Windows Kernel32.DEF file, the following forward exists:
EXPORTS
...
HeapAlloc = NTDLL.RtlAllocHeap
There's no code for the HeapAlloc function.

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.