I'm building a Windows dynamic library using the MinGW toolchain.
To build this library I'm statically linking to other 2 which offer an API and I have a .def
file where I wrote the only symbol I want to be exported in my library.
The problem is that GCC is exporting all of the symbols including the ones from the libraries I'm linking to. Is there anyway to tell the linker just to export the symbols in the def
file?
I know there is the option --export-all-symbols
but there seems not to be the opposite to it.
Right now the last line of the build script has this structure:
g++ -shared CXXFLAGS DEFINES INCLUDES -o library.dll library.cpp DEF_FILE \
OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup
EDIT: In t开发者_运维知识库he docs about the linker it says that --export-all-symbols
is the default behavior and that it's disabled when you don't use that option explicitly if you provide a def
file, except when it doesn't; the symbols in 3rd party libs are being exported anyway.
EDIT: Adding the option --exclude-libs LIBS
or –exclude-symbols SYMBOLS
doesn't prevent the symbols from the libraries from being exported.
Not sure why there's no real answer to this, but here's what worked for me:
Compilation of your object files:
g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
Linking (
-Wl,--exclude-all-symbols
is important):g++ -Wl,--enable-auto-import -Wl,--out-implib,libsomelib.a -Wl,--exclude-all-symbols -shared dllmain.o -o somelib.dll
Then you choose which functions to export directly in source code of your DLL:
#include <windows.h>
__declspec(dllexport) void someExportedFunction() {
MessageBox(NULL, "msgbox", "msgbox", MB_OK);
}
void nonExportedFunction() {
MessageBox(NULL, "notexported", "notexported", MB_OK);
}
Verification:
C:\libtest>pedump -E somelib.dll
=== EXPORTS ===
# module "somelib.dll"
# flags=0x0 ts="2014-02-20 08:37:48" version=0.0 ord_base=1
# nFuncs=1 nNames=1
ORD ENTRY_VA NAME
1 1570 _Z20someExportedFunctionv
(pedump
= http://pedump.me)
You can use the option -Wl,--retain-symbols-file=file
and then list the symbols you want to keep (one per line) in file
. This will cause the linker to discard all other symbols, keeping just the ones you want.
This is a recurrent issue. Here are two related questions in SO:
- Removing exported symbols from a DLL and its associated import library (VS8)
- https://stackoverflow.com/questions/9586262/how-to-know-exported-symbols-for-windows-dll-from-linux-mingw/9600759#9600759 (DEAD)
and outside SO:
- http://boost.2283326.n4.nabble.com/unwanted-exported-symbols-in-a-DLL-which-statically-links-to-Boost-Library-td2590169.html
- http://sourceforge.net/p/mingw/bugs/1134/
i.e. global / local exporting on the Windows platform is not handled at the linker level but but the provision of a .def
file to complement the .dll
.
Lacking a good answer, I did a python script that takes care of removing stuff from the dll export table, you can find it here .
You can use dllwrap if your distribution of binutils (either native or cross compiling) provides it.
It can produce DLLs using the interface in a DEF file (under the hood it calls gcc, ld and dlltool to do so). The difference between using this and passing a DEF file to GCC directly is that the definitions in the file are treated differently.
For example, if you have a symbol rename in the export file:
_SomeFuntion = _SomeFunction@12
GCC will create 2 exports, one by the name of _SomeFunction
and the other one with the decorated name while dllwrap will only export _SomeFuntion
. So if you only add to the DEF file the symbols you want to be exported you will end up only with them in the library.
dllwrap by default uses the C compiler driver since it has no way of knowing otherwise. As you're linking C++ code, you have to use the option --driver-name c++
to set the driver. If you happen to have the MinGW executables with a prefix you have to include it too in the driver name (e.g. i686-mingw32-c++
instead of c++
) and you may need to use the option --dlltool-name
too.
Try using these two lines instead of the one you posted:
g++ -c CXXFLAGS DEFINES INCLUDES -o library.o library.cpp
dllwrap -o library.dll --driver-name c++ --def DEF_FILE OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup
The first one generates an object file from the code of library.cpp
and the second one assembles the dynamic library. The OBJECT_FILES
thing (which I assume to be other object files you generated previously) should have library.o
there too.
That said, I have to tell you dllwrap was already deprecated in 2006 and there is no documentation on it in the official binutils package; to get some info you may call it with --help
as usual. It can generate an import library in case you need it too.
Did you read this on the page you supplied alink to, regarding behaviour if --export-all-symbols is not used explicitly - auto export is disabled if:
Any symbol in any object file was marked with the __declspec(dllexport) attribute.
Have you tried explicitly exporting only the functions you are interested in? It's very easy to get names wrong in DEF file, because of mangling, so this method should be more reliable.
Disclaimer: I've only done this on Linux, but AFAIK it should work on Windows as well
You can use the -fvisibility=hidden
option; for more info see http://gcc.gnu.org/wiki/Visibility
精彩评论