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

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.

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)

If you are changing the project properties from dynamic to static linkage as specified in the openjpeg.h you have to specify preprocessor that can use the static linkage..so in addition to changing the property from dynamic to static, add the preprocessor OPJ_STATIC...
For example:
#if defined(_WIN32)
#if defined(OPJ_STATIC)
# define OPJ_CALLCONV __stdcall
#el if defined(libjpeg_EXPORTS)
#define JPEG_EXPORT __declspec(dllexport)
#else
#define JPEG_EXPORT __declspec(dllimport)
#endif
#else
#define JPEG_EXPORT
#endif

Related

PGDLLIMPORT and PostgreSQL C hooks

I've been using PostgreSQL hooks for some time now, and yesterday I wanted to try to add my own hook to test something(and for fun).
So I looked up ExecutorStart_hook to see what are the things I would need to do in order to get my own hook into PostgreSQL.
In execMain.c it is pretty straight forward, first define the hook
ExecutorStart_hook_type ExecutorStart_hook = NULL;
then use it in ExecutorStart(...);.
In executor.h we define the hook type first, and then we import the hook variable.
typedef void (*ExecutorStart_hook_type) (QueryDesc *queryDesc, int eflags);
extern PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook;
Where are importing this hook variable from? I don't see it anywhere else except in execMain.c, and I don't see a PGDLLEXPORT there.
On non-windows platforms, that does nothing.
On windows, PGDLLIMPORT's meaning changes based on whether the PostgreSQL server is being compiled, or an extension. The headers are written from the perspective of an extension, which is why it says PGDLLIMPORT.
If you look at the definition of PGDLLIMPORT in src/include/port/win32.h:
#ifdef BUILDING_DLL
#define PGDLLIMPORT __declspec (dllexport)
#else /* not BUILDING_DLL */
#define PGDLLIMPORT __declspec (dllimport)
#endif
... you'll see that if BUILDING_DLL is set, we expand it to __declspec(ddlexport). So it exports the symbol from the server binary. We only set BUILDING_DLL when compiling postgres.exe; its name a bit unfortunate. It's like that because on Windows you're usually exporting symbols from DLLs for use in applications, not vice versa like in postgres.
If BUILDING_DLL is not set, we define PGDLLIMPORT to __declspec(dllimport), importing the symbol from the server binary into whatever's linking to it.
So ... when postgres includes executor.h it exports the symbol. When you include executor.h in your extension DLL project, it imports the symbol.
All this is necessary because of how DLL linkage works on win32/PE. On ELF platforms (Linux, BSD, etc) and Mach-O (Mac OS X), none of it is necessary.

LNK2019 (unresolved external symbol) when linking against built dynamic library in QT

I am using QT 5.5.0 within QtCreator to build a C++ application (referenced to as "the application" from now on) which I am trying to link against dynamic link C library ("the library"). All methods which originate from this library cannot be found by the linker when building the application, example output for one method:
error: LNK2019: unresolved external symbol "__declspec(dllimport) int __cdecl rlwe_FFT_CTX_init(struct fft_ctx *)" (__imp_?rlwe_FFT_CTX_init##YAHPAUfft_ctx###Z) referenced in function [...]
The library is imported by the following statement in the .pro file:
LIBS += "-L$$_PRO_FILE_PWD_/../../Libraries/rlwekex/Build/rlwekex/Release/Win32/" -lrlwekex
I expect this to work, since qmake is running fine and the linker will output another error if I change this to a non-existent library name. Both the application and the library are 32 bit.
The .lib and .dll files for the library have been built by myself using Visual Studio 2013. The same header files are used for building the library and as includes inside the application. A compile switch will mark methods as __declspec(dllexport) or __declspec(dllimport) using the following code:
# ifdef RLWEKEX_DLL_EXPORT
# define RLWEKEX_EXPORT __declspec(dllexport)
# else
# define RLWEKEX_EXPORT __declspec(dllimport)
# endif
The macros are correctly evaluated in both the library (export) as well as the application (import). The signature of the example method would be as follows:
RLWEKEX_EXPORT int rlwe_FFT_CTX_init(FFT_CTX *ctx);
Using dumpbin I can verify that the method is actually exported to the .lib - corresponding /HEADERS entry:
Version : 0
Machine : 14C (x86)
TimeDateStamp: 563B4D17 Thu Nov 05 13:35:35 2015
SizeOfData : 0000001F
DLL name : rlwekex.dll
Symbol name : _rlwe_FFT_CTX_init
Type : code
Name type : no prefix
Hint : 2
Name : rlwe_FFT_CTX_init
I have another Visual Studio 2013 project which is a test suite (written in C) for this particular library, which is linking against it just fine! QtCreator and Visual Studio 2013 are running on the same machine and are both using the same compiler toolkit (msvc).
Now of course my question: What could be the reason that I can link against the library in the VS2013 test suite, but not in the QT project? Any help would be appreciated!
C++ mangles names of functions while C does not.
The header file for the library needs to contain, near the beginning of the file, something like:
#ifdef __cplusplus
extern "C" {
#endif
and near the end of the header file
#ifdef __cplusplus
}
#endif
Note: the above lines are between the 'include guards', not to replace them
.

Which import directive will import a symbol from a DLL and not add a prefix? (Visual Studio)

The short question is: Which directive adds no prefix to an imported symbol?
I have a library that is 100% C (no C++ and not C compiled with a C++ compiler) It's C top to bottom. (I have to mention that because sometimes folks confuse how Visual Studio works when compiling C using the C++ compiler with C using a C compiler.)
The library was compiled with CMAKE and it outputted a DLL with a symbol table that looks like this:
dumpbin.exe /exports mydll.dll
...stuff...
1 0 00001087 mylib_get_x
..etc..
There's a static lib file too.
dumpbin.exe /exports mydll.lib
...stuff...
mylib_get_x
Notice how there are no weird prefixes? (i.e. no imp on the symbols) This makes the DLL extremely useful when trying to import the functions into things like the FFI in LuaJIT and other compilers/environments.
And I have an app that uses "mylib_get_x()"
/* myfile.c */
... stuff ...
int x;
x = mylib_get_x();
The result is: unresolved external symbol _mylib_get_x referenced in function ...
If I prefix the mylib_get_x() with any of these:
__declspec(dllimport)
__cdecl
__stdcall
_cdecl
extern
extern "C" __declspec(dllimport)
<nothing>
It doesn't matter. It won't work. They add prefixes. Which one adds nothing?
When it was compiled, it had __declspec(dllexport) on it, but it's a 3rd party library, so somehow they got it to avoid the extra prefixes.
I can link in the supplied .lib file that was generated. Same result. (see the dumpbin above that shows the symbol table from the .lib file without prefixes) I can create a manual .def file, generate a lib file from it and link to that. Same result.
I would love it if someone could explain what prefixes go with what directive.
Which directive adds no prefix to the symbol?

What are the exact steps for creating and then linking against a Win32 DLL on the command line?

Here's my library Lib.c file:
#include <stdio.h>
int helloworld(){
printf("Hello World DLL");
}
Here's my exe Main.c file:
int helloworld();
int main(int argc, char** argv){
helloworld();
}
I would like to create Lib.dll, and Main.exe, where Lib.dll comes from Lib.c and Main.exe links against Lib.dll.
What are the specific steps to achieve this?
See this related question on how to build the DLL.
Your library code as it stands does not export any symbols and your executable does not import the symbols from your library. Two typical patterns for doing that are shown below but you might want to read up on that first.
The first method uses __declspec() to declare in the code what functions (or other items) are exported from your DLL and imported by other executables. You use a header file to declare the exported items and have a preprocessor flag used to control whether the symbols are exports or imports:
mylib.h:
#ifndef MYLIB_H
#define MYLIB_H
#if defined(BUILDING_MYLIB)
#define MYLIB_API __declspec(dllexport) __stdcall
#else
#define MYLIB_API __declspec(dllimport) __stdcall
#endif
#ifdef __cplusplus
extern "C" {
#endif
int MYLIB_API helloworld(void);
#ifdef __cplusplus
}
#endif
#endif
I have also specifically set the calling convention to __stdcall as are most DLL functions (I could have used WINAPI instead of __stdcall if I had included windows.h) and have declared the functions as extern "C" so their names do not get mangled when compiled as C++. Not such a problem here as it's all C, but if you were to build the DLL from C source and then try to use it from a C++ executable then the imported names would be incorrect.
The code could then look like this:
mylib.c
#include "mylib.h"
#include <stdio.h>
int MYLIB_API helloworld(void)
{
printf("Hello World DLL");
return 42;
}
You'd build your DLL using the following command line. As well as creating the DLL it will create the import library (.lib) required to use your DLL from another executable (as well as the export file, but that is only required in certain circumstances):
cl /DBUILDING_MYLIB mylib.c /LD
The /DBUILDING_MYLIB argument defines the preprocessor symbol used to control whether the functions in the DLL are exports (if it is defined) or imports (not defined). So you'd define it when building the DLL but not when building your application.
The /LD parameter tells cl to produce a DLL.
The second method is to use module definition files as mentioned in the comments. You can use the code you already have but you also need to create the module definition file. At it's simplest it looks like this:
LIBRARY mylib
EXPORTS
helloworld
In this case to build the DLL you require the following command line:
cl /LD mylib.c /link /DEF:mylib.def
You could then code your application so that it used your library header with the imported version of your DLL function:
main.c
/* No need to include this if you went the module definition
* route, but you will need to add the function prototype.
*/
#include "mylib.h"
int main(void)
{
helloworld();
return (0);
}
Which you could then compile with the following command line (assuming the import library from the DLL creation is in the same directory as your main.c). This step is the same whether you used declspec or module definition files:
cl main.c /link mylib.lib
Arguments passed after the /link argument are passed onto the linker command line as they appear, so as just a filename it is used as extra input to link into the executable. In this case we specify the import library generated when we built the DLL.
The command lines I've shown here are pretty much the absolute minimum you'd need but it'll allow you to create a DLL and link an application to it.
I have assumed the calling convention is correct in all of the above and I have not experimented much to see whether I got it wrong at any point.

Unable to resolve symbol when using lib... any ideas?

Written in C (into a C++ project):
I have two projects in VS08 under the same solution. One is a DLL file and the other ("runner") is the a console application for using/testing the DLL file. The header file has a header file with all the functions (__declspec(dllexport)). When I use functions without any arguments, by the runner console application, they run OK. When I try to call a function with arguments I get unable to resolve symbol... error. The strange thing is that VS08 recognizes the function and I can open it from the runner main() with the right-click menu, however it can't find it.
Worth mentioning that I am including the header file and not importing the DLL with function pointers... My feeling is that the functions get renamed somehow in the compiling process and the linker can't find the functions with the arguments. If I would be able to to see the list of new names (inside the object file?) maybe I could include them in the header file to fix this?
Thanks.
Written in C (into a C++ project):
That's possibly a pretty good lead. A C program cannot consume functions that were written in C++. When you use __declspec(dllexport), the function gets exported with its C++ name. Which is decorated by the compiler, a trick to allow overloaded functions to link properly. A C compiler doesn't apply the same kind of decoration, the linker will complain that it can't find the function.
To make this work, you have to declare the function with the extern "C" declarator. Make the .h file look like this:
#ifdef __cplusplus
extern "C" {
#endif
#undef DLLEXPORT
#ifdef BUILDING_MYDLL
# define DLLEXPORT __declspec(dllexport)
#else
# define DLLEXPORT __declspec(dllimport)
#endif
DLLEXPORT void Foo(int arg);
// etc..
#ifdef __cplusplus
}
#endif
In your DLL project, use Project + Properties, C/C++, Preprocessor and add BUILDING_MYDLL to the Preprocessor Definitions settings.
A short explanation for this macro madness: the #ifdef __cplusplus ensures that all the DLL declarations are declared extern "C" when they are compiled by the C++ compiler so that they'll match the C compiler symbols. The DLLEXPORT macro ensures that the functions are exported when you build the DLL, imported when you link the DLL import library in another project.
You can get additional troubleshooting from the dumpbin.exe utility by running it with the /exports option on your DLL. It shows the exact names of exported functions. Run it from the Visual Studio command prompt. A mismatch between the names you see in the output verses the linker error messages is a sure sign of trouble.
First off: Intellisense finding it ('open for the rightclick menu' eeeeck?) is no proof; it proves you put the declaration in a header file;
You are probably right about the name mangling thing: If you have C externals you need to declare them inside an extern "C" {} block:
extern "C" {
void dostuff(int param1, char* param2);
}
instead of
extern void dostuff(int param1, char* param2);
The most flexible approach is probably to include the extern "C" around the complete C header file conditionally:
// Sample.h
#if defined(__cplusplus)
extern "C"
{
#endif
// Function declarations
#if defined(__cplusplus)
}
#endif
See MSDN for more info

Resources