declspec - dllexport and dllimport

index
preamble examples MSDN extract minimal end
examples: CURL GLIB BOOST FLAC FLTK PNG FLU ALUT FREEGLUT FTGL GD GLEW GSHHS GTK ImageMagick LIBINTL SIGC LIBXML NSIS OPENRTI OSG PCRE PTHREADS XMLRPC

Preamble

This started out as a simple discussion on the use of __declspec(dllexport) and __declspec(dllimport) in multi-port  code, and I decided to take some sample of the main macro in some open source projects I have worked on...

Some extracts from MSDN help pages are included below, but in essence __declspec(dllexport) is used on functions and data EXPORTED by a Dynamic Link Library (DLL), and can be used with or in place of a DEF file. It adds an '_imp_' decoration, and causes the generation of the DLL LIB archive file to be used in a link.

Likewise __declspec(dllimport) is used to IMPORT functions and data into an executable (EXE), or another DLL. It again adds an '_imp_' decoration, and avoids the generation of a THUNK table page to do do address fix-ups when an executable is loaded for running, expressly informing the compiler and linker that this function/data is explicitly imported from a DLL.

As stated more can be read about this in the MSDN help extracts below, but to see the macro in use, below are extracts from various open source project. Now it is agreed that common usage alone is NOT always the best example of 'correct' usage, but does give an indication of what other think...

top


Examples

These were just culled from a search of my 'Project' folder for '__declspec'. The extracts were run though a c2htm.pl perl script, to render the color coded HTML, and in this process some errors may have crept into the code shown, but none the less they are a great set of examples of the use of __declspec(dllexport) and __declspec(dllimport) in the generally cross-platform code.

CURL - curl\include\curl\curl.h

/*
 * Decorate exportable functions for Win32 DLL linking.
 * This avoids using a .def file for building libcurl.dll.
 */
#if (defined(WIN32) || defined(_WIN32)) && !defined(CURL_STATICLIB)
#if defined(BUILDING_LIBCURL)
#define CURL_EXTERN  __declspec(dllexport)
#else
#define CURL_EXTERN  __declspec(dllimport)
#endif
#else
#ifdef CURL_HIDDEN_SYMBOLS
/*
 * This definition is used to make external definitions visibile in the
 * shared library when symbols are hidden by default.  It makes no
 * difference when compiling applications whether this is set or not,
 * only when compiling the library.
 */
#define CURL_EXTERN CURL_EXTERN_SYMBOL
#else
#define CURL_EXTERN
#endif
#endif

Then for prototypes - curl\include\curl\easy.h

CURL_EXTERN CURL *curl_easy_init(void);

top


GLIB - glib-2.24.2\glib\gtypes.h

/* We prefix variable declarations so they can
 * properly get exported in Windows DLLs.
 */
#ifndef GLIB_VAR
#  ifdef G_PLATFORM_WIN32
#    ifdef GLIB_STATIC_COMPILATION
#      define GLIB_VAR extern
#    else /* !GLIB_STATIC_COMPILATION */
#      ifdef GLIB_COMPILATION
#        ifdef DLL_EXPORT
#          define GLIB_VAR __declspec(dllexport)
#        else /* !DLL_EXPORT */
#          define GLIB_VAR extern
#        endif /* !DLL_EXPORT */
#      else /* !GLIB_COMPILATION */
#        define GLIB_VAR extern __declspec(dllimport)
#      endif /* !GLIB_COMPILATION */
#    endif /* !GLIB_STATIC_COMPILATION */
#  else /* !G_PLATFORM_WIN32 */
#    define GLIB_VAR extern
#  endif /* !G_PLATFORM_WIN32 */
#endif /* GLIB_VAR */

Then for prototypes - glib-2.24.2\glib\gmain.h

 GLIB_VAR GSourceFuncs g_timeout_funcs;

- glib-2.24.2\glib\gdebug.h

GLIB_VAR gboolean _g_debug_initialized;

GLIB - glib-2.0\gobject\gparamspecs.h

/* --- internal --- */
/* We prefix variable declarations so they can
 * properly get exported in windows dlls.
 */
#ifndef GOBJECT_VAR
#  ifdef G_PLATFORM_WIN32
#    ifdef GOBJECT_STATIC_COMPILATION
#      define GOBJECT_VAR extern
#    else /* !GOBJECT_STATIC_COMPILATION */
#      ifdef GOBJECT_COMPILATION
#        ifdef DLL_EXPORT
#          define GOBJECT_VAR __declspec(dllexport)
#        else /* !DLL_EXPORT */
#          define GOBJECT_VAR extern
#        endif /* !DLL_EXPORT */
#      else /* !GOBJECT_COMPILATION */
#        define GOBJECT_VAR extern __declspec(dllimport)
#      endif /* !GOBJECT_COMPILATION */
#    endif /* !GOBJECT_STATIC_COMPILATION */
#  else /* !G_PLATFORM_WIN32 */
#    define GOBJECT_VAR extern
#  endif /* !G_PLATFORM_WIN32 */
#endif /* GOBJECT_VAR */

BOOST -

#ifdef BOOST_HAS_DECLSPEC // defined in config system
// we need to import/export our code only if the user has specifically
// asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost
// libraries to be dynamically linked, or BOOST_ARCHIVE_DYN_LINK
// if they want just this one to be dynamically linked:
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_ARCHIVE_DYN_LINK)
// export if this is our own source, otherwise import:
#ifdef BOOST_ARCHIVE_SOURCE
# define BOOST_ARCHIVE_DECL __declspec(dllexport)
#else
# define BOOST_ARCHIVE_DECL __declspec(dllimport)
#endif  // BOOST_ARCHIVE_SOURCE
#endif  // DYN_LINK
#endif  // BOOST_HAS_DECLSPEC
//
// if BOOST_ARCHIVE_DECL isn't defined yet define it now:
#ifndef BOOST_ARCHIVE_DECL
#define BOOST_ARCHIVE_DECL
#endif

top


FLAC - flac-1.2.1\include\FLAC\export.h

#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
#define FLAC_API
#else
#ifdef FLAC_API_EXPORTS
#define    FLAC_API    _declspec(dllexport)
#else
#define FLAC_API    _declspec(dllimport)
#endif

Then proto types like - flac-1.2.1\include\FLAC\format.h
extern FLAC_API const char *FLAC__VERSION_STRING; // data
 - flac-1.2.1\include\FLAC\metadata.h
FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo); // function

top


FLTK - fltk-1.1.10\FL\Fl_Export.H

/*
 * The following is only used when building DLLs under WIN32...
 */
#  if defined(FL_DLL) && (defined(_MSC_VER) || defined(__MWERKS__) || \
   defined(__BORLANDC__) || __GNUC__ >= 3)
#    ifdef FL_LIBRARY
#      define FL_EXPORT    __declspec(dllexport)
#    else
#      define FL_EXPORT    __declspec(dllimport)
#    endif /* FL_LIBRARY */
#  else
#    define FL_EXPORT
#  endif /* FL_DLL */

Then prototypes like - fltk-1.1.10\FL\filename.H
FL_EXPORT const char *fl_filename_name(const char *);

PNG - libpng from fltk-1.1.10\png\pngconf.h (actually from lpng155/pngconf.h)

/* Symbol export
 * =============
 * When building a shared library it is almost always necessary to tell
 * the compiler which symbols to export.  The png.h macro 'PNG_EXPORT'
 * is used to mark the symbols.  On some systems these symbols can be
 * extracted at link time and need no special processing by the compiler,
 * on other systems the symbols are flagged by the compiler and just
 * the declaration requires a special tag applied (unfortunately) in a
 * compiler dependent way.  Some systems can do either.
 *
 * A small number of older systems also require a symbol from a DLL to
 * be flagged to the program that calls it.  This is a problem because
 * we do not know in the header file included by application code that
 * the symbol will come from a shared library, as opposed to a statically
 * linked one.  For this reason the application must tell us by setting
 * the magic flag PNG_USE_DLL to turn on the special processing before
 * it includes png.h.
 *
 * Four additional macros are used to make this happen:
 *
 * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from
 *            the build or imported if PNG_USE_DLL is set - compiler
 *            and system specific.
 *
 * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to
 *                       'type', compiler specific.
 *
 * PNG_DLL_EXPORT Set to the magic to use during a libpng build to
 *                make a symbol exported from the DLL.  Not used in the
 *                public header files; see pngpriv.h for how it is used
 *                in the libpng build.
 *
 * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come
 *                from a DLL - used to define PNG_IMPEXP when
 *                PNG_USE_DLL is set.
 */
/* System specific discovery.
 * ==========================
 * This code is used at build time to find PNG_IMPEXP, the API settings
 * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL
 * import processing is possible.  On Windows/x86 systems it also sets
 * compiler-specific macros to the values required to change the calling
 * conventions of the various functions.
 */
#if ( defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\
      defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) ) && \
    ( defined(_X86_) || defined(_X64_) || defined(_M_IX86) ||\
      defined(_M_X64) || defined(_M_IA64) )
  /* Windows system (DOS doesn't support DLLs) running on x86/x64.  Includes
   * builds under Cygwin or MinGW.  Also includes Watcom builds but these need
   * special treatment because they are not compatible with GCC or Visual C
   * because of different calling conventions.
   */
#  if PNG_API_RULE == 2
    /* If this line results in an error, either because __watcall is not
     * understood or because of a redefine just below you cannot use *this*
     * build of the library with the compiler you are using.  *This* build was
     * build using Watcom and applications must also be built using Watcom!
     */
#    define PNGCAPI __watcall
#  endif
#  if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800))
#    define PNGCAPI __cdecl
#    if PNG_API_RULE == 1
#      define PNGAPI __stdcall
#    endif
#  else
    /* An older compiler, or one not detected (erroneously) above,
     * if necessary override on the command line to get the correct
     * variants for the compiler.
     */
#    ifndef PNGCAPI
#      define PNGCAPI _cdecl
#    endif
#    if PNG_API_RULE == 1 && !defined(PNGAPI)
#      define PNGAPI _stdcall
#    endif
#  endif /* compiler/api */
  /* NOTE: PNGCBAPI always defaults to PNGCAPI. */
#  if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
   ERROR: PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed
#  endif
#  if (defined(_MSC_VER) && _MSC_VER < 800) ||\
      (defined(__BORLANDC__) && __BORLANDC__ < 0x500)
    /* older Borland and MSC
     * compilers used '__export' and required this to be after
     * the type.
     */
#    ifndef PNG_EXPORT_TYPE
#      define PNG_EXPORT_TYPE(type) type PNG_IMPEXP
#    endif
#    define PNG_DLL_EXPORT __export
#  else /* newer compiler */
#    define PNG_DLL_EXPORT __declspec(dllexport)
#    ifndef PNG_DLL_IMPORT
#      define PNG_DLL_IMPORT __declspec(dllimport)
#    endif
#  endif /* compiler */
#else /* !Windows/x86 */
#  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
#    define PNGAPI _System
#  else /* !Windows/x86 && !OS/2 */
    /* Use the defaults, or define PNG*API on the command line (but
     * this will have to be done for every compile!)
     */
#  endif /* other system, !OS/2 */
#endif /* !Windows/x86 */

Then a prototype: This is perhaps the most 'complicated' of these 20 or so examples, and here the defines are extracted in more or less reverse order from pngconf.h, in an attempt to make its progressive definition clear.

First, the first example of the PNG library API - uint png_access_version_number();
/* Returns the version number of the library */
PNG_EXPORT(1, png_uint_32, png_access_version_number, (void));

Why this is then converted in PNG_EXPORTA is unclear, since the 5th argument is 'empty', but ok -
#define PNG_EMPTY /*empty list*/
#define PNG_EXPORT(ordinal, type, name, args)\
  PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY)

Now PNG_EXPORTA commences to convert it into a function prototype PNG_FUNCTION, and where the 'type' is another macro PNG_EXPORT_TYPE(type) -
#ifndef PNG_EXPORTA
# define PNG_EXPORTA(ordinal, type, name, args, attributes)\
  PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \
  extern attributes)
#endif

Remember above, the 5th argument was 'blank', but the above PNG_EXPORTA added 'extern'
#ifndef PNG_FUNCTION
# define PNG_FUNCTION(type, name, args, attributes) attributes type name args
#endif
so in simple term the function becomes 'extern type name args'.

Here the 'type' gets expanded, and reversed, to 'PNG_IMPEXP type'
#ifndef PNG_EXPORT_TYPE
# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type
#endif

In a Windows compile PNG_DLL_IMPORT will be declared as
#      define PNG_DLL_IMPORT __declspec(dllimport)
so now the decision as to whether PNG_USE_DLL has been defined, or not -
#ifndef PNG_IMPEXP
# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)
/* This forces use of a DLL, disallowing static linking */
# define PNG_IMPEXP PNG_DLL_IMPORT
# endif

And the 'default' if PNG_USE_DLL has NOT been defined - a static link
# ifndef PNG_IMPEXP
# define PNG_IMPEXP
# endif

SO, in the linking of a USER application, or DLL, to library PNG, it 'defaults' to a 'static' library function link. That is, if the user does NOT add /D "PNG_USE_DLL" to the compile, then they will get a link to the STATIC library function. Ipso facto, PNG_IMPEXP will be 'nothing'.

Now, if the user has and specifically wanted to link against the PNG DLL library, then they MUST remember to ADD /D "PNG_USE_DLL" as a compiler define, or as a define before including png.h, which then includes pngconf.h.

Likewise, if a user has the PNG source and wants to build the PNG DLL, then [s]he MUST again remember to defined /D "PNG_USE_DLL". Each of the PNG source files include a "pngpriv.h" private header, where, as you would expect it does -
# define PNG_IMPEXP PNG_DLL_EXPORT
to use __declspec(dllexport) from the above main macro set. This 'dllexport' not only adds the '__imp_' decoration to the function name, but also causes the linker to build an archive library for the user link process...
OR
Alternatively a Win32 DEF file can be used in the library source link. The PNG source provides such a sample DEF file in scripts/symbols.def.

THERE IS NO DOUBT THIS PNG EXAMPLE IS ONE OF THE HAIRIEST BEASTS AROUND ;=))

In this PNG case, the DEFAULT source build is the STATIC library, and the DEFAULT user link is with the STATIC library, and EXTRA steps need to be taken to (a) build a PNG DLL, and (b) use a PNG DLL.

While I have no doubt all the above 'MESS' works, lots seems very unnecessarily complicated. The GOOD part of it all is that defining 'nothing' will result in a DEFAULT STATIC LIBRARY situation ;=))

FLTK - fltk-1.1.10\zlib\zconf.h

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
#endif

top


FLU - FLU_2.8\FLU\flu_export.h

#ifdef FLU_DLL
#ifdef FLU_LIBRARY
  #define FLU_EXPORT __declspec(dllexport)
#else
  #define FLU_EXPORT __declspec(dllimport)
#endif
#else
#define FLU_EXPORT
#endif

Then prototypes like - FLU_2.8\FLU\Flu_Button.h - class
class FLU_EXPORT Flu_Button : public Fl_Button
 - FLU_2.8\FLU\Flu_File_Chooser.h - function
FLU_EXPORT const char* flu_file_chooser( const char *message, const char *pattern, const char *filename );
 - FLU_2.8\FLU\flu_file_chooser_pixmaps.h - data
FLU_EXPORT extern char* monalisa_xpm[];

top


ALUT - freealut-1.1.0\include\AL\alut.h

#if (defined(_WIN32)||defined(WIN32)) && !defined(_XBOX)
#ifndef ALUT_STATIC_LIB
#if defined (ALUT_BUILD_LIBRARY)
  #define ALUT_API __declspec(dllexport)
#else
  #define ALUT_API __declspec(dllimport)
#endif
#else /* ALUT_STATIC_LIB */
  #define ALUT_API extern
#endif /* ALUT_STATIC_LIB n/y */
#else
#if defined(ALUT_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY)
  #define ALUT_API __attribute__((visibility("default")))
#else
  #define ALUT_API extern
#endif
#endif

prototype like - freealut-1.1.0\include\AL\alut.h
ALUT_API ALboolean ALUT_APIENTRY alutInit (int *argcp, char **argv);

top


FREEGLUT - freeglut\include\GL\freeglut_std.h

/* Windows static library */
#   ifdef FREEGLUT_STATIC
#       define FGAPI
#       define FGAPIENTRY
        /* Link with Win32 static freeglut lib */
#       if FREEGLUT_LIB_PRAGMAS
#           pragma comment (lib,"freeglut_static.lib")
#       endif /* Windows shared library (DLL) */
#   else
#       define FGAPIENTRY __stdcall
#       if defined(FREEGLUT_EXPORTS)
#           define FGAPI __declspec(dllexport)
#       else
#           define FGAPI __declspec(dllimport)
            /* Link with Win32 shared freeglut lib */
#           if FREEGLUT_LIB_PRAGMAS
#               pragma comment (lib, "freeglut.lib")
#           endif
#       endif
#   endif

prototypes like - freeglut\include\GL\freeglut_std.h
FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv );

top


FTGL - ftgl-2.1.3\src\FTGL\ftgl.h

// Compiler-specific conditional compilation
#ifdef _MSC_VER // MS Visual C++
    // Disable various warning.
    // 4786: template name too long
    #pragma warning(disable : 4251)
    #pragma warning(disable : 4275)
    #pragma warning(disable : 4786)
    // The following definitions control how symbols are exported.
    // If the target is a static library ensure that FTGL_LIBRARY_STATIC
    // is defined. If building a dynamic library (ie DLL) ensure the
    // FTGL_LIBRARY macro is defined, as it will mark symbols for
    // export. If compiling a project to _use_ the _dynamic_ library
    // version of the library, no definition is required.
    #ifdef FTGL_LIBRARY_STATIC // static lib - no special export required
    #  define FTGL_EXPORT
    #elif FTGL_LIBRARY         
    // dynamic lib - must export/import symbols appropriately.
    #  define FTGL_EXPORT   __declspec(dllexport)
    #else
    #  define FTGL_EXPORT   __declspec(dllimport)
    #endif
#else
    // Compiler that is not MS Visual C++.
    // Ensure that the export symbol is defined (and blank)
    #define FTGL_EXPORT
#endif

top


GD - gd\src\gd.h

#if defined(GD_STATIC) || (!defined(WIN32) && !defined(_WIN32_WCE))
#define NONDLL 1
#endif /* WIN32 */
#ifdef NONDLL
#define BGD_DECLARE(rt) extern rt
#else
#ifdef BGDWIN32
#define BGD_DECLARE(rt) __declspec(dllexport) rt __stdcall
#else
#define BGD_DECLARE(rt) __declspec(dllimport) rt _stdcall
#endif /* BGDWIN32 */
#endif /* NONDLL */
/* 2.0.20: for actual storage of exported data, functions don't need this,
  currently needed only for font pointers */
#ifdef NONDLL
/* 2.0.25: bring back extern */
#define BGD_EXPORT_DATA_PROT extern
#define BGD_EXPORT_DATA_IMPL
#else
#ifdef BGDWIN32
#define BGD_EXPORT_DATA_PROT __declspec(dllexport) extern
#define BGD_EXPORT_DATA_IMPL __declspec(dllexport)
#else
#define BGD_EXPORT_DATA_PROT __declspec(dllimport) extern
#define BGD_EXPORT_DATA_IMPL __declspec(dllimport)
#endif /* BGDWIN32 */
#endif /* NONDLL */

top


GLEW - glew-1.7.0\auto\src\glew_head.h

/*
 * GLEW_STATIC is defined for static library.
 * GLEW_BUILD  is defined for building the DLL library.
 */
#ifdef GLEW_STATIC
#  define GLEWAPI extern
#else
#  ifdef GLEW_BUILD
#    define GLEWAPI extern __declspec(dllexport)
#  else
#    define GLEWAPI extern __declspec(dllimport)
#  endif
#endif

top


GSHHS - gshhs\GMT\src\gmt.h

/* Declaration modifiers for DLL support (MSC et al) */
#if defined(DLL_GMT)    /* define when library is a DLL */
#if defined(DLL_EXPORT) /* define when building the library */
#define MSC_EXTRA_GMT __declspec(dllexport)
#else
#define MSC_EXTRA_GMT __declspec(dllimport)
#endif
#else
#define MSC_EXTRA_GMT
#endif /* defined(DLL_GMT) */

top


GTK - multiple libraries

 - gtk+-2.22.0\gdk\gdktypes.h

#ifdef G_OS_WIN32
#  ifdef GDK_COMPILATION
#    define GDKVAR __declspec(dllexport)
#  else
#    define GDKVAR extern __declspec(dllimport)
#  endif
#else
#  define GDKVAR extern
#endif

gtk+-2.22.0\gtk\gtkmain.h

/* Gtk version.
 */
#ifdef G_PLATFORM_WIN32
#ifdef GTK_COMPILATION
#define GTKMAIN_C_VAR __declspec(dllexport)
#else
#define GTKMAIN_C_VAR extern __declspec(dllimport)
#endif
#else
#define GTKMAIN_C_VAR extern
#endif

prototypes like
GTKMAIN_C_VAR const guint gtk_major_version;

 - gtk+-2.22.0\gtk\gtktexttypes.h

#ifdef G_OS_WIN32
#ifdef GTK_COMPILATION
#define VARIABLE __declspec(dllexport)
#else
#define VARIABLE extern __declspec(dllimport)
#endif
#else
#define VARIABLE extern
#endif

top


ImageMagick - ImageMagick-6.4.2\bzlib\bzlib.h 

#if defined(WIN32)
# include <windows.h>
# if defined(_DLL) && !defined(_LIB)
#   if !defined(BZ_EXPORT)
#     pragma message( "BZIP compiling as DLL import" )
#     define BZ_API(func) func
#     define BZ_EXTERN __declspec(dllimport)
#   else
#     pragma message( "BZIP compiling as DLL export" )
#     define BZ_API(func) func
#     define BZ_EXTERN extern __declspec(dllexport)
#   endif
# else
#   pragma message( "BZIP compiling as library" )
#   define BZ_API(func) func
#   define BZ_EXTERN extern
# endif
#else
#   define BZ_API(func) func
#   define BZ_EXTERN extern
#endif

top


LIBINTL - libintl-0.14.4\include\libintl.h

#ifdef LIBINTL_STATIC
#define LIBINTL_DLL_EXPORTED
#else /* LIBINTL_STATIC */
#ifdef BUILDING_LIBINTL
#define LIBINTL_DLL_EXPORTED __declspec(dllexport)
#else
#define LIBINTL_DLL_EXPORTED __declspec(dllimport)
#endif
#endif /* LIBINTL_STATIC */

top


SIGC - libsigc\libsigc++-2.2.8\msvc\sigc++config.h

#ifdef SIGC_DLL
# if defined(SIGC_BUILD) && defined(_WINDLL)
#  define SIGC_API __declspec(dllexport)
# elif !defined(SIGC_BUILD)
#  define SIGC_API __declspec(dllimport)
# else
#  define SIGC_API
# endif
#else /* !SIGC_DLL */
# define SIGC_API
#endif /* !SIGC_DLL */

top


LIBXML - libxml2\include\libxml\xmlexports.h

/* Windows platform with MS compiler */
#if defined(_WIN32) && defined(_MSC_VER)
  #undef XMLPUBFUN
  #undef XMLPUBVAR
  #undef XMLCALL
  #undef XMLCDECL
  #if defined(IN_LIBXML) && !defined(LIBXML_STATIC)
    #define XMLPUBFUN __declspec(dllexport)
    #define XMLPUBVAR __declspec(dllexport)
  #else
    #define XMLPUBFUN
    #if !defined(LIBXML_STATIC)
      #define XMLPUBVAR __declspec(dllimport) extern
    #else
      #define XMLPUBVAR extern
    #endif
  #endif
  #if defined(LIBXML_FASTCALL)
    #define XMLCALL __fastcall
  #else
    #define XMLCALL __cdecl
  #endif
  #define XMLCDECL __cdecl
  #if !defined _REENTRANT
    #define _REENTRANT
  #endif
#endif

LIBXML - libxml2\include\libxml\xmlwin32version.h

/**
 * LIBXML_DLL_IMPORT:
 *
 * Used on Windows (MS C compiler only) to declare a variable as
 * imported from the library. This macro should be empty when compiling
 * libxml itself. It should expand to __declspec(dllimport)
 * when the client code includes this header, and that only if the client
 * links dynamically against libxml.
 * For this to work, we need three macros. One tells us which compiler is
 * being used and luckily the compiler defines such a thing: _MSC_VER. The
 * second macro tells us if we are compiling libxml or the client code and
 * we define the macro IN_LIBXML on the compiler's command line for this
 * purpose. The third macro, LIBXML_STATIC, must be defined by any client
 * code which links against libxml statically.
 */
#ifndef LIBXML_DLL_IMPORT
#if defined(_MSC_VER) && !defined(IN_LIBXML) && !defined(LIBXML_STATIC)
#define LIBXML_DLL_IMPORT __declspec(dllimport)
#else
#define LIBXML_DLL_IMPORT
#endif
#endif

top


NSIS - nsis\cvs\Contrib\System\Source\System.h

// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the SYSTEM_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// SYSTEM_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef SYSTEM_EXPORTS
#define SYSTEM_API __declspec(dllexport)
#else
#define SYSTEM_API __declspec(dllimport)
#endif

top


OPENRTI - openrti\include\RTI13\RTI.hh

#if defined(_WIN32)
# if defined(RTI_EXPORTS)
#  define RTI_EXPORT __declspec(dllexport)
# else
#  define RTI_EXPORT __declspec(dllimport)
# endif
# if defined(FedTime_EXPORTS)
#  define FEDTIME_EXPORT __declspec(dllexport)
# else
#  define FEDTIME_EXPORT __declspec(dllimport)
# endif
#else
# define RTI_EXPORT
# define FEDTIME_EXPORT
#endif

top


OSG - Multiple Libraries, each with it own macro

OSG\OSG-3.0.1\include\OpenThreads\Exports

#ifndef WIN32
    #define OPENTHREAD_EXPORT_DIRECTIVE
#else
    #if defined( OT_LIBRARY_STATIC )
        #define OPENTHREAD_EXPORT_DIRECTIVE
    #elif defined( OPENTHREADS_EXPORTS )
        #define OPENTHREAD_EXPORT_DIRECTIVE __declspec(dllexport)
    #else
        #define OPENTHREAD_EXPORT_DIRECTIVE __declspec(dllimport)
    #endif
#endif
#endif

OSG\OSG-3.0.1\include\osgAnimation\Export

#if defined(_MSC_VER) || \
       defined(__CYGWIN__) || defined(__MINGW32__) || \
       defined( __BCPLUSPLUS__) || defined( __MWERKS__)
#  if defined( OSG_LIBRARY_STATIC )
#    define OSGANIMATION_EXPORT
#  elif defined( OSGANIMATION_LIBRARY )
#    define OSGANIMATION_EXPORT   __declspec(dllexport)
#  else
#    define OSGANIMATION_EXPORT   __declspec(dllimport)
#endif
#else
#define OSGANIMATION_EXPORT 
#endif 

OSG\OSG-3.0.1\include\osgDB\Export

#if defined(_MSC_VER) || \
       defined(__CYGWIN__) || defined(__MINGW32__) || \
       defined( __BCPLUSPLUS__) || defined( __MWERKS__)
    #  if defined( OSG_LIBRARY_STATIC )
    #    define OSGDB_EXPORT
    #  elif defined( OSGDB_LIBRARY )
    #    define OSGDB_EXPORT   __declspec(dllexport)
    #  else
    #    define OSGDB_EXPORT   __declspec(dllimport)
    #  endif
#else
    #  define OSGDB_EXPORT
#endif

OSG\OSG-3.0.1\include\osgFX\Export

#if defined(_MSC_VER) || \
       defined(__CYGWIN__) || defined(__MINGW32__) || \
       defined( __BCPLUSPLUS__)  || defined( __MWERKS__)
    #  if defined( OSG_LIBRARY_STATIC )
    #    define OSGFX_EXPORT
    #  elif defined( OSGFX_LIBRARY )
    #    define OSGFX_EXPORT   __declspec(dllexport)
    #  else
    #    define OSGFX_EXPORT   __declspec(dllimport)
    #  endif
#else
    #  define OSGFX_EXPORT
#endif

OSG - OSG\OSG-3.0.1\include\osg\Export

#if defined(_MSC_VER) || \
    defined(__CYGWIN__) || defined(__MINGW32__) || \
    defined(__BCPLUSPLUS__)  || defined( __MWERKS__)
    #  if defined( OSG_LIBRARY_STATIC )
    #    define OSG_EXPORT
    #  elif defined( OSG_LIBRARY )
    #    define OSG_EXPORT   __declspec(dllexport)
    #  else
    #    define OSG_EXPORT   __declspec(dllimport)
    #  endif
#else
    #  define OSG_EXPORT
#endif

top


PCRE - pcre\pcre.h

/* Win32 uses DLL by default; it needs special stuff for exported functions
   when building PCRE. */
#ifdef _WIN32
#  ifdef PCRE_DEFINITION
#    ifdef DLL_EXPORT
#      define PCRE_DATA_SCOPE __declspec(dllexport)
#    endif
#  else
#    ifndef PCRE_STATIC
#      define PCRE_DATA_SCOPE extern __declspec(dllimport)
#    endif
#  endif
#endif

prototypes like
PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);

top


PTHREADS - pthreads\pthread.h

/*
 * When building the library, you should define PTW32_BUILD so that
 * the variables/functions are exported correctly. When using the library,
 * do NOT define PTW32_BUILD, and then the variables/functions will
 * be imported correctly.
 */
#if !defined(PTW32_STATIC_LIB)
#  ifdef PTW32_BUILD
#    define PTW32_DLLPORT __declspec (dllexport)
#  else
#    define PTW32_DLLPORT __declspec (dllimport)
#  endif
#else
#  define PTW32_DLLPORT
#endif

prototypes like - pthreads\pthread.h
PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr);

top


MSDN HELP

To explore Microsoft HELP (MSDN), to see what its says -
From http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx and others found -

<quote>
The dllexport and dllimport storage-class attributes are Microsoft-specific extensions to the C and C++ languages. They enable you to export and import functions, data, and objects to and from a DLL. These attributes explicitly define the DLL's interface to its client, which can be the executable file or another DLL. Declaring functions as dllexport eliminates the need for a module-definition (.DEF) file, at least with respect to the specification of exported functions.

The 32-bit edition of Visual C++ (effectively from Visual Studio 6.0 - 1998 - MSVC6), uses __declspec(dllimport) and __declspec(dllexport) to replace the __export keyword previously used in 16-bit versions of Visual C++.

You do not need to use __declspec(dllimport) for your code to compile correctly, but doing so allows the compiler to generate better code. The compiler is able to generate better code because it knows for sure whether a function exists in a DLL or not, so the compiler can produce code that skips a level of indirection that would normally be present in a function call that crossed a DLL boundary. However, you must use __declspec(dllimport) in order to import variables used in a DLL.

Using __declspec(dllimport) for Function Calls

In the following code example, assume func1 is a function that resides in a DLL separate from the .EXE file that contains the main function.

Without __declspec(dllimport), given this code:
  void main(void)   {  func1();  }
the compiler generates code that looks like this:
   call func1
and the linker translates the call into something like this:
   call 0x4000000         ; The address of 'func1'.

If func1 exists in another DLL, the linker can't resolve this directly because it has no way of knowing what the address of func1 is. In 32-bit environments, the linker generates a thunk of which it does know the address. The thunk looks like:

  0x40000000:    jmp DWORD PTR __imp_func1

Here __imp_func1 is the address for func1's slot in the import address table of the .EXE file. All the addresses are thus known to the linker. The loader only has to update the .EXE file's import address table at load time for everything to work correctly.

Therefore, using __declspec(dllimport) is better because if the linker does not generate a thunk if it is not required. Thunks make the code larger (on RISC systems, it can be several instructions) and can degrade your cache performance. If you tell the compiler the function is in a DLL, it can generate an indirect call for you.

So now this code:
  __declspec(dllimport) void func1(void);
  void main(void) {  func1();  }
generates this instruction:
  call DWORD PTR __imp_func1
There is no thunk and no jmp instruction, so the code is smaller and faster.

On the other hand, for function calls inside a DLL, you don't want to have to use an indirect call. You already know a function's address. Time and space is required to load and store the address of the function before an indirect call, so a direct call is always faster and smaller. You only want to  use __declspec(dllimport) when calling DLL functions from the outside the DLL itself. Don't use __declspec(dllimport) on functions inside a DLL when building that DLL.

Using _declspec(dllexport)

Microsoft introduced __export in the 16-bit compiler version of Visual C++ to allow the compiler to generate the export names automatically and place them in a .LIB file. This .LIB file could then be used just like a static .LIB to link with a DLL.

Microsoft added __declspec(dllexport) to continue this convenience. Its purpose is to add the export directive to the object file so you don't need a .DEF file.

This convenience is most apparent when trying to export decorated C++ function names. There is no standard specification for name decoration, so the name of an exported function may change between compiler versions. If you use __declspec(dllexport), recompiling the DLL and dependent .EXE files is necessary only to account for any naming convention changes.

Many export directives, such as ordinals, NONAME, and PRIVATE, can be made only in a .DEF file, and there is no way to specify these attributes without a .DEF file. However, using __declspec(dllexport) in addition to using a .DEF file does not cause build errors.

Using __declspec(dllexport) and __declspec(dllimport) on Data

In the case of data, using __declspec(dllimport) is a convenience item that removes a layer of indirection. When you import data from a DLL, you still have to go through the import address table. In the Win32 days before __declspec(dllimport), this meant you had to remember to do an extra level of indirection when accessing data exported from the DLL:

  // project.h
  #ifdef _DLL     // If accessing the data from inside the DLL
     ULONG ulDataInDll;
  #else            // If accessing the data from outside the DLL
     ULONG *ulDataInDll;
  #endif

You would then export the data in your .DEF file:
  // project.def
  LIBRARY project
  EXPORTS
      ulDataInDll   CONSTANT
and access it outside the DLL:

  if (*ulDataInDll == 0L) {
     // Do stuff here
  }

When you mark the data as __declspec(dllimport), the compiler automatically generates the indirection code for you. You no longer have to worry about the steps above. As stated previously, do not use __declspec(dllimport) declaration on the data when building the DLL. Functions within the DLL will not use the import address table to access the data object; therefore, you will not have the extra level of indirection present.

To export the data automatically from the DLL, use this declaration:

  __declspec(dllexport) ULONG ulDataInDLL;

Using a .DEF File

If you choose to use __declspec(dllimport) along with a .DEF file, you should change the .DEF file to use DATA in place of CONSTANT to reduce the likelihood that incorrect coding will cause a problem:

  // project.def
  LIBRARY project
  EXPORTS
      ulDataInDll   DATA

The following table shows why:

Keyword         Emits in the import library   Exports
CONSTANT  _imp_ulDataInDll                 _ulDataInDll   
                      _ulDataInDll
DATA            _imp_ulDataInDll                  _ulDataInDll

Using __declspec(dllimport) and CONSTANT lists both the __imp_ version and the undecorated name in the .LIB DLL import library that is created to allow explicit linking. Using __declspec(dllimport) and DATA lists just the __imp_ version of the name.

If you use CONSTANT, either of the following code constructs could be used to access the ulDataInDll:

   __declspec(dllimport) ULONG ulDataInDll; /*prototype*/
      if (ulDataInDll == 0L)   /*sample code fragment*/

   -or-

  ULONG *ulDataInDll;      /*prototype*/
     if (*ulDataInDll == 0L)  /*sample code fragment*/

However, if you use DATA in your .DEF file, only code compiled with the following definition can access the variable ulDataInDll:

 __declspec(dllimport) ULONG ulDataInDll;
   if (ulDataInDll == 0L)   /*sample code fragment*/

Using CONSTANT is more risky because if you forget to use the extra level of indirection, you could potentially access the import address table's pointer to the variable — not the variable itself. This type of problem can often manifest as an access violation because the import address table is currently made read-only by the Microsoft compiler and linkers.

The Current Visual C++ linker issues a warning if it sees CONSTANT in the .DEF file to account for this case. The only real reason to use CONSTANT is if you can't recompile some object file where the header file didn't list __declspec(dllimport) on the prototype.

</quote>

Minimal Approach

While this is not particularly recommended it does seem you can get away with a very minimal (lazy) approach. That is just using the __declspec(dllexport). This WORKS, but has some 'bad' side effects. (a) As defined above, a THUNK jump table would probably be created, but with today's faster CPU and abundant memory this seems a quite minimal problem, and (b) the linker generates the same type of LIB (archive) for the EXE as it does when building a DLL, but this is just more confusing than a problem. A useless archive library file...

XMLRPC - include\xmlrpc-c\c_util.h

/* XMLRPC_DLLEXPORT is an attribute of an external symbols that says it
   is to be exported from a library that contains it.
*/
#if defined(_DLL) &&  defined(_MSC_VER)
#define XMLRPC_DLLEXPORT __declspec(dllexport)
#else
#define XMLRPC_DLLEXPORT
#endif

XMLRPC prototypes like - include\xmlrpc-c\base.h
XMLRPC_DLLEXPORT void xmlrpc_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP);

But since this 'lazy' macro STILL requires the MAIN effort of adding this XMLRPC_DLLEXPORT to each function, (data or class) exported as part of the API, one can only wonder why the macro is not filled out like the above TWENTY(20) or so cases, by adding say an XMLRPC_BUILDLIB, to be defined when building a library (DLL), so that when this is NOT defined the __declspec(dllimport) is used. Then the linker is clearly instructed that a THUNK table is not required, and NO archive library need be generated when build either an EXE or DLL that uses the XMLPRC library.

The other thing XMLRPC does wrong is the use of #if defined(_DLL) to determine if the __declspec() macro is created. Here it confuses the Micorsoft(MS) RUNTIME choices (/MD or /MT), with user DLL creation, /D _USRDLL. MS have two RUNTIME configurations - well there are more than 2, but the 2 important ones today are - Multithreaded DLL (/MD), to link with MSVCRT.lib, and just Multithreaded (/MT), to link with LIBCMT.lib. It is the /MD compiler option which defines _DLL, and this has NOTHING to do with whether you are building a DLL, LIB  or an EXE.

In fact when building a DLL it does NOT matter if you choose /MD or /MT runtime, since it is an independent 'library', run in separate address space. But if you are building an EXE that links with a static LIB (3rdparty) library, as opposed to a DLL, then it is very necessary to EXACTLY match the EXE and LIB with the SAME runtime. Just like it is important to match the Debug or Release configuration of the EXE and a LIB, otherwise you get LINK ERRORS.

The error reported advises certain imported 'system' type functions are 'duplicated', and suggest that one or the other library should be excluded from the link. However, I have almost NEVER found this 'exclusion' suggestion to work. Anyway, the error magically goes away if you exactly MATCH the EXE and LIB runtimes (and configuration) ;=))

Typical link error when the EXE is compiled with /MT, and the static library is compiled with /MD :-
MSVCRT.lib(MSVCR100.dll) : error LNK2005: _isdigit already defined in LIBCMT.lib(_ctype.obj)
LINK : warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; use /NODEFAULTLIB:library
This was using MSVC10 (2010).

Further, while /MD is the 'default' for MSVC, the MSVCRT.lib causes a version dependent DLL linkage, like to the MSVCR80.DLL, MSVCR90.DLL, MSVCR100.DLL, or other versions of this 'system' DLL, so without user intervention, such an EXE with /MD DLL linkage will only run in systems with that specific version of the 'system' DLL installed.

Using /MT on the other hand avoids all this DLL 'version' mess, since the LIBCMT.lib is a 'static' runtime version, so /MT is generally the better choice, or at least the more portable across various 'Windows' systems.

So again it is suggested the macro NOT use _DLL switch, and include another item like XMLPRC_STATIC so the user can decide to link with the DLL-specific version, or the 'static' version of the XMLRPC libraries, and this is kept quite apart from which MS RUNTIME is chosen. i.e. whether or not _DLL is defined.

So all in all, I would suggest the XMLRPC project, as it presently stands, is a quite BAD example of the use of the __declspec() macro ;=(( It is much better you follow some of the choices made by the other 20 or so examples!

Thus the FULL macro suggested for the XMLRPC project would be something like :-

/* In Windows,
   define XMLRPC_STATIC if you want to BUILD, or LINK an EXE
   or DLL to, the XMLRPC static libraries.
   Otherwise define XMLRPC_BUILDLIB when building an XMLRPC
   DLL, and not if building an EXE or DLL that links with 
   an XMLRPC DLL.
   This is regardless whether choosing /MD or /MD runtimes.
*/
#if (defined(WIN32) || defined(WIN64)) && !defined(XMLRPC_STATIC)
# if defined (XMLRPC_BUILDLIB)
#  define XMLRPC_DLLEXPORT __declspec(dllexport)
# else
#  define XMLRPC_DLLEXPORT __declspec(dllimport)
# endif
#else
#define XMLRPC_DLLEXPORT
#endif

This would bring it into full conformance by only changing one macro.

top


EOF - delspec.htm - 2012-02-22

checked by tidy  Valid HTML 4.01 Transitional

index