views:

403

answers:

3

Over the months I've written some nice generic enough functionality that I want to build as a library and link dynamically against rather than importing 50-odd header/source files.

The project is maintained in Xcode and Dev-C++ (I do understand that I might have to go command line to do what I want) and have to link against OpenGL and SDL (dynamically in SDL's case). Target platforms are Windows and OS X.

What am I looking at at all?

  • What will be the entry point of my library if it needs one?
  • What do I have to change in my code? (calling conventions?)
  • How do I release it? My understanding is that headers and the compiled library (.dll, .dylib(, .framework), whatever it'll be) need to be available for the project - especially as template functionality can not be included in the library by nature.
  • What else I need to be aware of?
+2  A: 

It can be problematic to export a C++ class library from a dynamic library, but it is possible.
You need to mark each function to be exported from the DLL (syntax depends on the compiler). I'm poking around to see if I can find how to do this from xcode. In VC it's __declspec(dllexport) and in CodeWarrior it's #pragma export on/#pragma export off.

This is perfectly reasonable if you are only using your binary in-house. However, one issue is that C++ methods are named differently by different compilers. This means that nobody who uses a different compiler will be able to use your DLL, unless you are only exporting C functions.

Also, you need to make sure the calling conventions match in the DLL and the DLL's client. This either means you should have the same default calling convention flag passed to the compiler for both the DLL or the client, or better, explicitly set the calling convention on each exported function in the DLL, so that it won't matter what the default is for the client.

This article explains the naming issue: http://en.wikipedia.org/wiki/Name_decoration

Drew Hoskins
it appears that xcode uses #pragma GCC visibility push(hidden) and #pragma GCC visibility push(default) to control symbol visibility, while Dev-C++ uses VC's(?) syntax.
iCE-9
+10  A: 

I'd recommend building as a statc library rather than a DLL. A lot of the issues of exporting C++ functions and classes go away if you do this, provided you only intend to link with code produced by the same compiler you built the library with.

Building a static library is very easy as it is just an collection of .o/.obj files - a bit like a ZIP file but without compression. There is no need to export anything - just include the library in the list of files that your application links with. To access specific functions or classes, just include the relevant header file. Note you can't get rid of header files - the C++ compilation model, particularly for templates, depends on them.

anon
+1  A: 

The C++ standard doesn't define a standard ABI, and that's bad news for people trying to build C++ libraries. This means that you get different behavior from your compiled code depending on which flags were used to compile it, and that can lead to mysterious bugs in code that compiles and links just fine.

This extends beyond just different calling conventions - C++ code can be compiled to support or not support RTTI, exception handling, and with various optimizations that can affect the the memory layout of class instances, which C++ code relies on.

So, what can you do? I would build C++ libraries inside my source tree, and make sure that they're built as part of my project's build, and that all the libraries and the code that links to them use the same compiler flags.

Note that name mangling, which was supposed to at least prevent you from linking object files that were compiled with different compilers/compiler flags only mostly works, and there are certain things you can do, especially with GCC, that will result in code that links just fine and fails at runtime.

You have to be extra careful with vendor supplied dynamic C++ libraries (QT on most Linux distributions, for example.) I've seen instances of vendor supplied libraries that were compiled in ways that prevented certain things from working properly. For example, some Redhat Linux releases (maybe all of them) disabled exceptions in QT, which made it impossible to catch exceptions in main() if the exceptions were thrown in a QT callback. Fun.

Ori Pessach
Of course the same is true of all other computer languages - I'm not aware of any standardised language that standardises the ABI.
anon
There's always Java, but that would only be a de-facto standard so I won't mention it here.
Ori Pessach
No, java may be gpod counter-example to my blanket statement. I'm not sure it can be said to have an ABI though.
anon
The JVM spec is the ABI, in essence. There are at least a couple of standardized ways to link native code with code running under the JVM, and I think that counts as well. Also, The dead simple calling conventions in C at least made it possible to reliably link C code with other C code and with code written in languages that took care to support them. I don't think the C ABI is officially standardized, though.
Ori Pessach