5

By Plugin.
We mean a library that is loaded vi dlopen() and its symbols resolved via dlsym() (not a standard shard library that is dynamically loaded by the runtime system).

Referring to http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/. The document was last updated in 2006. It recommends the use of extern "C" to prevent mangling of function names, so that dlsym can find its functions with relative ease.

Is this still relevant for dynamic libraries? In my particular case, I am trying to create a dynamic library on OSX using libtool. Perhaps using __attribute__ ((constructor)) is more hip and modern, I have had little success discovering the recommended practice.

Martin York
  • 257,169
  • 86
  • 333
  • 562
Roger Halliburton
  • 1,965
  • 3
  • 14
  • 18

2 Answers2

5

I'm pretty sure extern "C" is still the best way to export unmangled functions from C++ code. Using it across several platforms without issues.

James M
  • 18,506
  • 3
  • 48
  • 56
  • You build on one platform and use on other platforms? I doubt that would work even for C. – Martin York Jan 20 '12 at 17:39
  • 1
    I think he's saying that the code he compiles with it runs on myriad platforms; but the binaries are built on their target platform. – Rob Marrowstone Jan 20 '12 at 17:48
  • @Hoons: In that case a C++ mangeled name will work just as well. The difference will be when you **manually** use dlsym() to resolve the symbol name. – Martin York Jan 20 '12 at 18:00
  • 1
    @Loki I see what you're saying, but to me I've always found that using `extern "C"` for exactly this reason has been worth it; I don't have to look at the symbols in the binaries so I can look them up at runtime, and if I have say configuration files which refer to these names I don't have to worry about them changing if we change compilers. – Rob Marrowstone Jan 20 '12 at 18:11
  • @Hoons: Absolutely agree. But the question was not about runtime plugins (I will change that in a second) nor is the answer for plugins. A normal user could think this advice applies to normal shard libraries (aka dynamically loaded libraries) which in my opinion is not the case. If the compiler/runtime is resolving the names then exposing a C++ interface from a shared library is the preferred way to go, otherwise all the C++ benefits are lost (without some extra work in wrapping the interface). – Martin York Jan 20 '12 at 18:25
  • Well, if you're writing a library in C++ and you want it to be usable from C, that's another reason to use `extern "C"` (even in a normal shared library). – James M Jan 20 '12 at 18:35
  • @LokiAstari The question was always about runtime (plugin) libraries, why else would I be using dlopen? – Roger Halliburton Jan 20 '12 at 19:11
  • @RogerHalliburton: Yes we get that now (from your comments below). But I don't see that in the original question. – Martin York Jan 20 '12 at 19:27
1

A runtime plugin

If you plan to load a library manually dlopen() and use dlsym() to retrieve and resolve functions/objects then using a extern "C" name becomes much easier. It is a pain for mangled names.

Thus if you want easier portability/usabilty then use an C (extern "C") interface.

But you should consider the cons to exposing a C (extern "C") interface.
This means you can not expose any of your C++ objects directly via the interface. Thus you are loosing a lot of functionality like RAII initially. You should compensate for this by writing extra wrapper calls to wrap the calls to your C interface

Normal shared libraries

Edit: Original answer:

The original question was about shared libraries (only via comments did we find it was about plugin shared libraries).

So the names are unmanageable.
This is not a problem if the compiler/runtime are resolving the symbols.

Do you plan on using multiple compilers? as this is the only reason I can see for exporting a C interface (as different C++ compiler often use different ABI).

If you are using the same compiler then why not use the C++ interface.
Personally on any given platform I only use one compiler and I only use the shared objects on that platform. If the compiler is upgraded something bigger has happened I am re-build all my libraries anyway.

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • I am using the dlopen API, which is the recommended practice for creating a module/plug-in dynamic library on OSX. dlopen is a C API. – Roger Halliburton Jan 20 '12 at 17:43
  • Let's assume I want a dynamically loaded lib and not the "standard runtime". :) – Roger Halliburton Jan 20 '12 at 17:46
  • dlopen() will accept mangeled names and resolve them fine. But note the mangeled name may be different on different platorms/compilers. – Martin York Jan 20 '12 at 17:55
  • `extern "C"` has no bearing on RAII. It simply tells the compiler to emit an unmangled name, 's all. – n. m. could be an AI Jan 20 '12 at 18:28
  • @n.m. Using `extern "C"` does more than that. It means use the C ABI (not mangling the names is a side affect as C names are not mangeled). This means you can only expose C functions/objects. Because you can't expose any C++ objects via the C interface, thus RAII can't be used (you can only expose C object through a C interface). So yes absolutely it does have a baring on RAII. – Martin York Jan 20 '12 at 18:30
  • The easiest way to export class objects is to use the same technique COM uses: pure virtual interfaces. – mcmcc Jan 20 '12 at 18:42
  • @mcmcc: Yes COM is something we should copy But your basic idea holds. Basically you can retrieve objects via pointers over the C interface on the dll and cast them to the correct interface type. But the objects must be released by calling the C interface on the dll to release the object (assuming it was dynamically allocated and not a pointer to a static object). My point holds there is extra work using C++ objects over a C interface. – Martin York Jan 20 '12 at 18:43
  • @Loki You can expose C++ objects via `extern "C"` functions. Try it. Sure the standard does not guarantee it works, but it does not prohibit it either (the standard doesn't guarantee that `dlopen` will work, too). It does work in practice. You cannot call such functions from C, but that's a problem of C, not of C++. – n. m. could be an AI Jan 20 '12 at 18:47
  • @n.m. You are relying particularities in your C++ compiler that the C and C++ ABI for functions calling are the same. As you say it might work. But if we are making that kind of assumption then why bother even declaring the interface as extern "C" you may as well use a C++ interface at that point. At least it will break noticeably (as the symbols will not resolve) when you compiler stops working rather than break invisibly (calling a function with parameters in register rather than the stack). – Martin York Jan 20 '12 at 19:10
  • @Loki No, I absolutely do not rely on such things. Both the caller and the callee use the "C" calling convention. "C++" calling convention doesn't ever come into play, be it identical to "C" or different. – n. m. could be an AI Jan 20 '12 at 21:34
  • @Loki I have created [a question](http://stackoverflow.com/q/8948443/775806) about this. – n. m. could be an AI Jan 20 '12 at 22:24
  • @n.m.: Of course it does. You are depending on the calling convention of C/C++ to be identical. You may be lucky. That is all. What I am saying is if you are going to do this there is no point trying to portable (you have just thrown portability out of the window so there is no point in using extern "C" anyway). So why not just expose the C++ interface in the first place (you are relying on it anyway). The difference is yours will break silently. – Martin York Jan 20 '12 at 22:51
  • @Loki Please read my question that I have linked, and answer it, if you know the answer. The comments are not the right place for such discussion. – n. m. could be an AI Jan 20 '12 at 23:31