HOWTO Create and Deploy a Sample DLL using MinGW

  • strict warning: Non-static method Text_Wiki::singleton() should not be called statically in /var/www/drupal/6.x/sites/ on line 475.
  • strict warning: Non-static method Text_Wiki::factory() should not be called statically in /usr/share/php/Text/Wiki.php on line 448.
  • strict warning: Non-static method Text_Wiki::isError() should not be called statically in /usr/share/php/Text/Wiki.php on line 449.
  • strict warning: Declaration of Text_Wiki_Parse_Emphasis::process() should be compatible with Text_Wiki_Parse::process(&$matches) in /usr/share/php/Text/Wiki/Parse/Mediawiki/Emphasis.php on line 0.

A sample DLL

The DLL we will build will consist of a single source file "example_dll.cpp":

#include <stdio.h>
#include "example_dll.h"

__stdcall void hello(const char *s)
        printf("Hello %s\n", s);
int Double(int x)
        return 2 * x;
void CppFunc(void)
void MyClass::func(void)

The following header "example_dll.h" declares the interface of the DLL, and is used both when building the DLL and when building an executable that uses the DLL:


#ifdef __cplusplus
extern "C" {

#define EXAMPLE_DLL __declspec(dllexport)
#define EXAMPLE_DLL __declspec(dllimport)

void __stdcall EXAMPLE_DLL hello(const char *s);

int EXAMPLE_DLL Double(int x);

#ifdef __cplusplus

// NOTE: this function is not declared extern "C"
void EXAMPLE_DLL CppFunc(void);

// NOTE: this class must not be declared extern "C"
class EXAMPLE_DLL MyClass
        MyClass() {};
        virtual ~MyClass() {};
        void func(void);

#endif  // EXAMPLE_DLL_H

Note that the three functions defined by the DLL have been declared slightly differently (for illustration purposes).

Building the DLL

To build the DLL use the following commands:

g++ -c -DBUILDING_EXAMPLE_DLL example_dll.cpp
g++ -shared -o example_dll.dll example_dll.o -Wl,--out-implib,libexample_dll.a

The -DBUILDING_EXAMPLE_DLL compiler option causes the DLL's functions to be declared as "dllexport", meaning that they will be "exported" from the DLL and available to client applications. The "-shared" option tells the linker to create a DLL instead of an .exe, and the "--out-implib" linker option causes an import library to be created, which is used later on.


The import library created by the "--out-implib" linker option is required iff (==if and only if) the DLL shall be interfaced from some C/C++ compiler other than the MinGW toolchain. The MinGW toolchain is perfectly happy to directly link against the created DLL. More details can be found in the ld.exe info files that are part of the binutils package (which is a part of the toolchain).

Building a client executable

The following source code "example_exe.cpp" demonstrates calling the DLL's functions:

#include <stdio.h>
#include "example_dll.h"

int main(void)
        printf("%d\n", Double(333));

        MyClass a;

        return 0;

To build the above example program, use the following commands:

g++ -c example_exe.cpp
g++ -o example_exe.exe example_exe.o -L. -lexample_dll

The option -lexample_dll specifies that the executable be linked with the library libexample_dll.a. The option -L. instructs the linker to search for libraries in the current directory, which is necessary because "." is not in the default search path (this requirement can be avoided by placing libraries in the MinGW lib directory).

It is worth mentioning that the same executable may be built without an import library using the following command:

g++ -o example_exe.exe example_exe.o example_dll.dll

If this method works for your application then there is usually no need for an import library.

Building and using a DLL without the dllexport/dllimport attibutes

If you pass the -no-undefined and --enable-runtime-pseudo-reloc options to the linker, you don't have to add dllimport or dllexport attributes to the source code that the DLL is made with ; all functions are imported/exported automatically by default, just like in unices.

Is dllhelpers still a useful extra reference, or is it just too outdated? -- GregChicares?


There is an important thing to note with the above example functions:
Both hello(const char *) and Double(int) are surrounded by

#ifdef __cplusplus
extern "C" {

#ifdef __cplusplus

in the header file. This has the rather important consequence that their exported names use C-style name mangling (i.e. their names are "as is").

The function CppFunc( void ) is not inside an extern "C" {...} block and thus uses C++-style name mangling. This has the consequence that the exported name depends on the compiler used to generate the DLL. It is by design that such generated names are different from compiler to compiler.

The important and often overlooked consequence of this is that from the above DLL only the functions hello(const char *) and Double(int) are seamlessly callable from e.g. MS VC++ while CppFunc(void) is not (assuming the DLL is created by MinGW).

A similar statement goes for C++ classes exported in a DLL, i.e. for the class MyClass. For further reading search the Web for the keyword "ABI" and possible in conjunction with "C++". See also MixObjects.
Note: Someone else might want to provide more links here

A way to circumvent this problem is either using COM or create C-style wrapper functions to encapsulate the C++ ABI.

See Also

This page: DLL.

Site Status

Site maintenance completed May 25th, 2012 at 12:38 UTC