dllimport /dllexport and static libraries compilation under visual c++

Marco Antonio picture Marco Antonio · Jan 30, 2011 · Viewed 7.9k times · Source

I desperatly need your help.

Im trying to compile statically the poppler library (specially for qt4) on windows with the visual c++ 2008 compiler. To achieve this task I needed to compile a bunch of other libraries as dependencies for poppler statically too. When I finally generate the static version of poppler I got a linking error when building my app:

error LNK2019: unresolved external symbol "__declspec(dllimport)...

I already added the new include path and linked the poppler-qt4.lib but i get the error anyways. Searching for a solution I found this discussion here in stackoverflow

How to link a static library in Visual C++ 2008?

whit this information I looked on the include files of the libraries (dependencies of poppler like zlib, libpng, cairo, ...) and I found, in various cases, that they don't have a preprocessor directive to especify the static version of the lib. Example static directive (openjpeg.h):

#if defined(OPJ_STATIC) || !(defined(_WIN32) || defined(WIN32) || defined(__WIN32__))
# define OPJ_API
# define OPJ_CALLCONV
#else
# define OPJ_CALLCONV __stdcall
# ifdef OPJ_EXPORTS
#  define OPJ_API __declspec(dllexport)
# else
#  define OPJ_API __declspec(dllimport)
# endif /* OPJ_EXPORTS */
#endif /* !OPJ_STATIC || !WIN32 */

Example without static directive (jconfig.h from jpeg lib):

#if defined(_WIN32)
    #if defined(libjpeg_EXPORTS)
        #define JPEG_EXPORT __declspec(dllexport)
    #else
        #define JPEG_EXPORT __declspec(dllimport)
    #endif
#else
    #define JPEG_EXPORT 
#endif

My question is: Is not enough to change the properties of the project from dynamic to static so I have to change this headers too?, and if this is true, where can I define this new directives for making a difference between static or dynamic compilation?

Thanks in advance.

Answer

Yttrill picture Yttrill · Sep 12, 2015

First please note Windows does not have any dynamic linkage at all. Surprise! Instead, it uses thunks. So what happens is: if you make a symbol dllexport, it has its actual name, the same name as if it were not dllexport. However it is marked in the object file for exporting.

If you say dllimport, on the other hand, the name is changed, in C roughly by prepending __imp_ to the name, more nasty in C++.

Now, when you link a DLL, you get a DLL (of course) but you also get a LIB file. That is a static link library. Which is the only kind the linker can handle. For each symbol exported from the DLL there is a dllimport symbol in that LIB file, in particular with __imp_ prefix or whatever for C++.

So now in a program or DLL you want to link to that DLL you made you link instead against the import LIB. The import LIB routines are thunks that patch up to the actual load time addresses from the DLL.

So now, if you try to do ordinary static linkage against a LIB file made by LIB.EXE by simply combining OBJ files which contained some dllexport, it will fail if the reference is a dllimport. Because you're refering to __imp_function() when the library actually contains plain function().

So with static linkage, you have to drop the dllimport. AFAIK dllexport is irrelevant. Note that this applies to the client of the library, not the library itself.

What does that mean? Well it is perfectly fine to statically link to a library which in turn dynamically links to another library. In fact by default static links on Windows dynamically link to the C runtime and OS DLLs. So the rule is: the client must chose the method of linking to a library, the provider should provide both versions. But take care they have different names!! (Otherwise the LINK making the DLL will make fred.LIB and the LIB will also make fred.LIB)