You are on page 1of 6

10/22/2017 Exporting C++ from dlls

fun4jimmy.blog
Hello airplanes? Yeah it's blimps, you win. home | links | tags

30/12/2012 c++ | dlls | windows

Exporting C++ from dlls


This post will cover how to export functions from a windows dynamic-link library starting with the
basics and then covering some more advanced examples. The first part of this explanation is
very similar to this msdn article, so if you already know that you may want to skip ahead to the
Advanced Exporting section.

Basic Exporting
So let’s start with the basics, to export a function from a dll you need to inform the compiler
which functions and classes you want to be accessible from the library. This can be done in
multiple ways but the simplest is to use __declspec(dllexport) to markup the functions or
classes when declaring and __declspec(dllimport) when using them.

// function declaration in library header


//
__declspec(dllexport) void function();

// function declaration in executable source


//
__declspec(dllimport) void function();

Having to declare everything twice, once for use within the library and once for use external to
the library, is not really something we want to have to do even for just one function so the
common practice is to use a macro like so:

#if defined(DYNAMICLIB_EXPORTS)
# define DL_API __declspec(dllexport)
# else
# define DL_API __declspec(dllimport)
#endif

DL_API void function();


{}

https://www.fun4jimmy.com/2012/12/30/exporting-c-from-dlls.html 1/6
10/22/2017 Exporting C++ from dlls

When building the library DYNAMICLIB_EXPORTS is defined so the macro will be


__declspec(dllexport) and when including the library the macro will be __declspec(dllimport)
which is exactly what we want.

Exporting classes is pretty similar, we can export individual class methods or more commonly
the class as a whole:

#if defined(DYNAMICLIB_EXPORTS)
# define DL_API __declspec(dllexport)
# else
# define DL_API __declspec(dllimport)
#endif

class SingleMethodExported
{
public:
DL_API void Method();
};

class DL_API WholeClassExported


{
};

This is all basic stuff that has been covered many times before so we won’t cover any more
simple examples, time to move on to some more complex stuff.

Advanced Exporting
Now we’ve done that we can try doing something a bit more challenging, trying to export some
code defined in a lib from a dll that links it. This is useful if our dynamic library links a third party
static library that will be used in both our library and any executable that links our library. We
may need to ensure that the version of the third party our dynamic library uses is the same as
the one used by the executable. There are a couple of ways to do this, one uses #pragma s and
one uses .def files and we’re going to cover both.

First let’s start with some simple example code, we’ll have a static library called staticlib, a
dynamic library called dynamiclib and an executable that needs to use both called application.

In our staticlib we have some functions declared like this:

#ifndef SL_API
# define SL_API
#endif

extern "C"
https://www.fun4jimmy.com/2012/12/30/exporting-c-from-dlls.html 2/6
10/22/2017 Exporting C++ from dlls

{
SL_API void slFunction();
};

namespace sl
{
SL_API void slFunctionInNamespace();
} // namespace sl

Note that we have a macro SL_API that is defined as nothing. This is useful if we ever want to
switch the library from being static to dynamic but is not necessary for either of the techniques
covered here.

In our dynamiclib we have some functions declared like this:

#if defined(DYNAMICLIB_EXPORTS)
# define DL_API __declspec(dllexport)
#else
# define DL_API __declspec(dllimport)
#endif

extern "C"
{
DL_API void dlFunction();
};

namespace dl
{
DL_API void dlFunctionInNamespace();
} // namespace dl

Declaring a function within an extern "C" section means that the compiler won’t do any name
mangling. We’re going to look at the differences between a name mangled function and a plain
C function and see why it’s much easier to try and export plain C functions.

This example code is very simple and there is no harm in application directly linking with
staticlib but for the purposes of this example we’ll pretend we still need to export everything
from dynamiclib. If staticlib contained functions that allocated and deallocated objects and
these functions were called from the dynamiclib and the application then there is a chance for
a mismatched new / delete or malloc / free . By exporting staticlib functionality from
dynamiclib we prevent any chance of a mismatch as all definitions will come from dynamiclib.

It would be nice if defining the SL_API macro as __declspec(dllexport) when compiling


dynamiclib and defining it as __declspec(dllimport) when using dynamiclib was enough to
export the staticlib functions. Something like this:

https://www.fun4jimmy.com/2012/12/30/exporting-c-from-dlls.html 3/6
10/22/2017 Exporting C++ from dlls

#if defined(DYNAMICLIB_EXPORTS)
# define SL_API __declspec(dllexport)
#else
# define SL_API __declspec(dllimport)
#endif

#include <sl/slFunction.h>

Unfortunately it’s not, if we try and compile our application like this we get some LNK2019:
unresolved external symbol linker errors. When compiling in Visual Studio 2012 with no
optimisation and generating a program database for edit and continue these errors will look
something like this:

error LNK2019: unresolved external symbol _slFunction referenced in function _main


error LNK2019: unresolved external symbol "void __cdecl sl::slFunctionInNamespace(void)" (?slF

#pragma exporting
The first method we’re going to cover is using #pragma s to export. Using
#pragma comment(linker, "") we can hard code linker options inside an object file, specifically
the /export option.

So to export these unresolved external symbols from dynamiclib we need to add another
source file with some #pragma statements in. For our simple C function void slFunction() this
is simple as the symbol name is the same as the function name with an underscore prepended.
For our C++ function namespace sl { void slFunctionInNamespace(); } it’s a bit more complicated
as the symbol name has been mangled by the compiler. There are several ways of finding out
the symbol name of a mangled function but in this case we’re going to use linker error message
which handily also included the symbol name it was looking for.

Looking again at the error messages we can see for the name mangled function the symbol was
reported with part of it in quotes "void __cdecl sl::slFunctionInNamespace(void)" and a second
part in brackets (?slFunctionInNamespace@sl@@YAXXZ) , we’re interested in the part in brackets as
this is the name after it has been mangled.

Now we have both symbol names we can fill in our source file to export these functions:

#pragma comment(linker, "/export:_slFunction")


#if (_MSC_VER == 1700)
# if _DEBUG
# pragma comment(linker, "/export:?slFunctionInNamespace@sl@@YAXXZ")
# endif
#endif

https://www.fun4jimmy.com/2012/12/30/exporting-c-from-dlls.html 4/6
10/22/2017 Exporting C++ from dlls

Just to be safe there are some extra guards around the #pragma for the name mangled function.
Name mangling is dependent on compiler options and versions of the compiler so this specific
match will only work with Visual Studio 2012 builds that generated debug symbols.

Now, as long as it is compiled with the correct compiler version and options, our application will
successfully link and use the versions of the staticlib functions exported from dynamiclib.

.def file exporting


A slightly less intrusive way of doing the same thing is to use a .def file, less intrusive as it only
requires an additional .def file when linking dynamiclib. The .def file contains a list of symbols
names to export so we can simply add the staticlib symbol names we need:

LIBRARY dynamiclib
EXPORTS
slFunction @1
?slFunctionInNamespace@sl@@YAXXZ @2

Again this is relying on the mangled symbol name for the C++ function so we would need a
different def file for every configuration of dynamiclib we decide to build. Assuming the .def file
is called dynamiclib.def when linking dynamiclib we need to add the linker option
/DEF dynamiclib.def and application will now successfully link.

Finding mangled symbol names


At the moment the only way we have of finding mangled symbol names is to rely on linker error
messages which, although fine in this example, is a pretty slow method if we were exporting an
entire third party library.

One alternative is to use the command dumpbin included with visual studio. Using the
command line dumpbin /linkermember:1 staticlib.lib , the generated output contains a public
symbols section that looks something like this:

4 public symbols

24A ??_C@_0CD@MJKDCNBD@called?5slFunction?5from?5staticlib@
24A ??_C@_0DC@JOPHPFLM@called?5sl?3?3slFunctionInNamespace@
24A ?slFunctionInNamespace@sl@@YAXXZ
24A _slFunction

Using a script to parse the output of this file looking for the pattern ?function@namespace a .def
file or file containing the necessary #pragma s could be auto generated as a pre build step saving
the tedious process of manually generating them from linker errors.

https://www.fun4jimmy.com/2012/12/30/exporting-c-from-dlls.html 5/6
10/22/2017 Exporting C++ from dlls

Another potential method would be to parse a generated pdb file using something like pdbparser
to pull out the symbol names and auto generate the required files this way.

Combining either of these methods with a C++ parser you could generate the necessary files
given a set of input header files. A C++ command line application using clang and the
pdbparser or a script that uses clang‘s python bindings and dumpbin would be ideal but
writing them is not a trivial process.

Summary
So after a quick gloss over the basics of dll exporting we have learnt the more complex process
of exporting static library code from a dynamic library. If the static library only deals with plain C
functions the process is relatively simple and really only requires the names of all the functions
that should be exported. If the static library has C++ functions or classes, we didn’t cover those
but they require a name mangled function for every class method to be exported, then it is a lot
harder due to the name mangling done by the compiler. This process could be automated given
a list of input names and using dumpbin or parsing a .pdb but we’ve not covered that and it is
non trivial. If this is ever needed in the real world then hope the third party library only uses C
functions and there is no need to generate symbols for every configuration.

For a working example of the techniques discussed in this post there is a repository on github
https://github.com/fun4jimmy/dllexport-snippet. The repository only contains project files for
Visual Studio 2012 though there is a Premake4 script to generate projects for other Visual
Studio versions. Other version of Visual Studio will require different mangled names so the .def
file and the .cpp file containing the #pragma s will need modifying.

fun4jimmy.blog
fun4jimmy
fun4jimmy

https://www.fun4jimmy.com/2012/12/30/exporting-c-from-dlls.html 6/6

You might also like