BuildingWinDLL

From KitwarePublic
Jump to navigationJump to search

How to build a Windows DLL (for the NON-Windows Developer). A Short introduction.

Those folks coming from an environment like Linux, OS X or even MinGW may have some initial issues when trying to create a DLL on windows. Usually the problems involve the library symbols NOT getting exported. This article will try to walk you through what needs to be done in order for you to bring your code to an MS compiler successfully.

This short explanation was taken from a recent post to the cmake mailing list and generally sums up the problem.
Visual Studio generates 2 files: one import library (.lib) and one - dynamic library (.dll). GCC (and mingw family) exports all symbols by default, VS doesn't export anything by default. And if your dll doesn't export anything, VS simply doesn't generate the import library (for example, if you generate resource-only dll). The only thing cmake knows is when you using VS generator, library extension to link with -- is .lib. And when you use __declspec( dllexport ), cl.exe puts special marks in objects indicating that this symbol should be exported or imported. Also, VS can tell linker to add some library, as boost does with #pragma's.


So with all this information, how does all this work with CMake? There are a few pieces of code that you will need to add to your project.

  • Let us first consider the CMake code. In your CMakeLists.txt file you will have something along the lines of:
# Allow the developer to select if Dynamic or Static libraries are built
OPTION (BUILD_SHARED_LIBS "Build Shared Libraries" OFF)
# Set the LIB_TYPE variable to STATIC
SET (LIB_TYPE STATIC)
IF (BUILD_SHARED_LIBS)
  # User wants to build Dynamic Libraries, so change the LIB_TYPE variable to CMake keyword 'SHARED'
  SET (LIB_TYPE SHARED)
ENDIF (BUILD_SHARED_LIBS)

# Create a target for the library
ADD_LIBRARY(MyLibrary ${LIB_TYPE} MyLibrary.cpp)

On MSVC platforms and when building a DLL, CMake will add the following preprocessor definition for you:
MyLibrary_EXPORTS. This is generated by concatenating the name of the target 'MyLibrary' with '_EXPORTS'.

Now we have to exploit that definition in our code so we need to add some c code into a header that will get included by every class or file in the project. A Good name for this might be DLLDefines.h. Notice I did NOT call it Win32Exports.h as GCC 4.x series has some of these types of definitions that can be used and we should keep all this in a single file (see GCC Visibility ). So, what is the contents of "DLLDefines.h" you might ask?

// Contents of DLLDefines.h
#ifndef _MyLibrary_DLLDEFINES_H_
#define _MyLibrary_DLLDEFINES_H_

/* Cmake will define MyLibrary_EXPORTS on Windows when it
configures to build a shared library. If you are going to use
another build system on windows or create the visual studio
projects by hand you need to define MyLibrary_EXPORTS when
building a DLL on windows.
*/
// We are using the Visual Studio Compiler and building Shared libraries

#if defined (_WIN32) 
  #if defined(MyLibrary_EXPORTS)
    #define  MYLIB_EXPORT __declspec(dllexport)
  #else
    #define  MYLIB_EXPORT __declspec(dllimport)
  #endif /* MyLibrary_EXPORTS */
#else /* defined (_WIN32) */
 #define MYLIB_EXPORT
#endif

#endif /* _MyLibrary_DLLDEFINES_H_ */

Ok. Now that we have that code, what do we do with it?

For every class or function that you want to be exported from your library you need to declare like the following:

class MYLIB_EXPORT SomeLibrary
{
 // All your normal code here.
};

If you have some static functions then you will need something like the following:

class MyStaticFunctionClass
{
  public:
    static MYLIB_EXPORT void MyExportedFunction(int i);
};

After all this code is put in place then when you compile your library as a dll, Visual Studio should create the proper set of libraries.


But wait! I have an existing project that I am bringing to cmake and it already has this type of code in place but the definition that the project uses is different than what CMake produces, now what do I do?

 Say that project uses ""COMPILING_DLL"" as its definition, then you can do the following in CMake: 
SET_TARGET_PROPERTIES (MyLibrary ROPERTIES DEFINE_SYMBOL  "COMPILING_DLL" )

I hope this helps explain what needs to be done when porting a linux, OS X or MinGW shared library to Windows.