Last updated: 31 May 2007
I recently had to remember how to build shared libraries across platforms and I didn't find any examples to jog my memory. I am publishing this tutorial and the accompanying source so I don't have to reconstruct it again the next time I need it.
The challenge is to build shared libraries from common source for three platforms: linux using gcc 4+; Windows XP using gcc 3+ and mingw (stuff you get from the Cygwin tools); and Windows XP using MSVC++.
The example I will use is a simple library consisting of two object files, each of which implements a single class:
Testclass.cpp
implements the Testclass
class. Testclass.hpp
defines the class and exposes
the "public" API of the library.Hiddenclass.cpp
implements a class on which the class
Testclass
depends, but which is not public.Testclass.so
for linux and
Testclass.dll
for windows are the shared
libraries that contain the objects compiled from
Testclass.cpp
and
Hiddenclass.cpp
.main.cpp
is the code for a program that uses the
interfaces of the class Testclass
as implemented in
the shared library.
The only platform-specific code in the two library source files is in
Testclass.cpp
:
#ifdef EXPAND_DLLEXPORT #define DLLEXPORT(x) __declspec(dllexport)x #else #define DLLEXPORT(x) x #endif . . . class DLLEXPORT(Testclass) { . . .
The __declspec(dllexport)
attribute is used in MSVC to
mark symbols that will be exported from a shared library.
It is not the only
way to do that, but the other methods depend on knowing the "decorated"
form of C++ symbols, and as a practical matter that's too much trouble.
A similar mechanism would be useful, but is not required for gnu. By
default, all symbols are exported from shared libraries built by g++.
The sample code includes a gnu makefile that builds for all three
platforms discussed above. It selects the correct methods by testing
the environment variable _TEST_PLATFORM_
. If this variable
is set to "msvc", the library and program are built using Microsoft Virtual
C++; if it is set to "mingw", they are built using g++ from the Cygwin
tools; otherwise they are built assuming a linux environment and g++.
Here is the output when the platform is set to "msvc" on windows. The makefile assumes that the MSVC++ binaries are in the PATH:
>set _TEST_PLATFORM_=msvc >make clean rm Testclass.obj Hiddenclass.obj Testclass.dll testprog.exe Testclass.lib >make cl /c Testclass.cpp -DEXPAND_DLLEXPORT Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. Testclass.cpp cl /c Hiddenclass.cpp -DEXPAND_DLLEXPORT Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. Hiddenclass.cpp cl /LD Testclass.obj Hiddenclass.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 8.00.50727.42 Copyright (C) Microsoft Corporation. All rights reserved. /out:Testclass.dll /dll /implib:Testclass.lib Testclass.obj Hiddenclass.obj Creating library Testclass.lib and object Testclass.exp cl /Fetestprog.exe main.cpp Testclass.lib Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. main.cpp Microsoft (R) Incremental Linker Version 8.00.50727.42 Copyright (C) Microsoft Corporation. All rights reserved. /out:testprog.exe main.obj Testclass.lib >
When the platform is set to "mingw" on Windows, this is the output:
>set _TEST_PLATFORM_=mingw >make clean rm Testclass.o Hiddenclass.o libTestclass.dll testprog.exe >make g++ -c Testclass.cpp g++ -c Hiddenclass.cpp g++ -shared -o libTestclass.dll Testclass.o Hiddenclass.o g++ -o testprog.exe main.cpp libTestclass.dll
Finally, on linux, after making sure that _TEST_PLATFORM_ is not set to anything, the output is.
$ make clean rm Testclass.o Hiddenclass.o libTestclass.so testprog $ make g++ -c Testclass.cpp g++ -c Hiddenclass.cpp g++ -shared -o libTestclass.so Testclass.o Hiddenclass.o; chcon -t texrel_shlib_t libTestclass.so g++ -o testprog main.cpp -L. -lTestclass $
The invocation of
chcon
may be necessary if you are running Secure Linux.
It's probably best to build without it first, then try to run the
executable. If the executable load fails with a message about not being
update to update relocatable address, run chcon
and try
again.
You can download a zipped archive of the source and the makefile: http://www.oocities.org/~bblair/dlldso.zip