Jack
Jack

Reputation: 361

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):

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):

In the vendor main.c file (compiled using gcc, -fPIC, and -shared)

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?

Upvotes: 1

Views: 787

Answers (1)

Jack
Jack

Reputation: 361

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.

Upvotes: 2

Related Questions