我正在使用MinGW工具链构建Windows动态库。
要构建这个库,我静态链接到提供API的其他2,我有一个.def
文件,我写了我想要在我的库中导出的唯一符号。
问题是GCC正在导出所有符号,包括我链接到的库中的符号。无论如何要告诉链接器只是导出def
文件中的符号吗?
我知道有--export-all-symbols
选项,但似乎没有相反的选择。
现在,构建脚本的最后一行具有以下结构:
g++ -shared CXXFLAGS DEFINES INCLUDES -o library.dll library.cpp DEF_FILE \
OBJECT_FILES LIBS -Wl,--enable-stdcall-fixup
编辑:在关于链接器的docs中,它表示--export-all-symbols
是默认行为,并且如果您提供def
文件时未明确使用该选项,则会禁用它,除非没有;无论如何,第三方库中的符号正在导出。
编辑:添加选项--exclude-libs LIBS
或–exclude-symbols SYMBOLS
并不会阻止导出库中的符号。
答案 0 :(得分:3)
不确定为什么没有真正的答案,但这对我有用:
编译目标文件:
g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
链接(-Wl,--exclude-all-symbols
很重要):
g++ -Wl,--enable-auto-import -Wl,--out-implib,libsomelib.a -Wl,--exclude-all-symbols -shared dllmain.o -o somelib.dll
然后,您可以选择直接在DLL的源代码中导出哪些函数:
#include <windows.h>
__declspec(dllexport) void someExportedFunction() {
MessageBox(NULL, "msgbox", "msgbox", MB_OK);
}
void nonExportedFunction() {
MessageBox(NULL, "notexported", "notexported", MB_OK);
}
验证
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)
答案 1 :(得分:2)
这是一个经常出现的问题。以下是SO中的两个相关问题:
和SO之外:
即。 Windows平台上的全局/本地导出不是在链接器级别处理,而是提供.def
文件以补充.dll
。
缺乏一个好的答案,我做了一个python脚本,负责从dll导出表中删除东西,你可以找到它here。
答案 2 :(得分:1)
您是否在您提供的页面上阅读了此内容,如果未明确使用--export-all-symbols,则会显示行为 - 如果出现以下情况,则禁用自动导出:
任何目标文件中的任何符号都是 标有__declspec(dllexport) 属性。
您是否尝试仅显式导出您感兴趣的功能?在DEF文件中输入名称很容易,因为修改了,所以这种方法应该更可靠。
答案 3 :(得分:1)
如果您的binutils(本机或交叉编译)的分发提供它,您可以使用dllwrap。
它可以使用DEF文件中的接口生成DLL(它会调用gcc,ld和dlltool来实现)。使用它和直接将DEF文件传递给GCC之间的区别在于文件中的定义被区别对待。
例如,如果导出文件中有符号重命名:
_SomeFuntion = _SomeFunction@12
GCC将创建2个导出,一个名称为_SomeFunction
,另一个名称为装饰名称,而dllwrap只导出_SomeFuntion
。因此,如果您只将DEF文件添加到要导出的符号中,则最终只能将它们添加到库中。
dllwrap使用C编译器驱动程序,因为它无法另知。在链接C ++代码时,必须使用选项--driver-name c++
来设置驱动程序。如果碰巧有带前缀的MinGW可执行文件,则必须在驱动程序名称中包含它(例如i686-mingw32-c++
而不是c++
),您可能也需要使用选项--dlltool-name
尝试使用这两行而不是您发布的那一行:
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
第一个从代码library.cpp
生成一个目标文件,第二个文件组装动态库。 OBJECT_FILES
事物(我假设是您之前生成的其他目标文件)也应该有library.o
。
那就是说,我必须在2006年告诉你dllwrap已经deprecated了,官方的binutils包里没有关于它的文档;要获得一些信息,您可以像往常一样使用--help
进行调用。它可以在您需要时生成导入库。
答案 4 :(得分:1)
您可以使用-Wl,--retain-symbols-file=file
选项,然后在file
中列出您要保留的符号(每行一个)。这将导致链接器丢弃所有其他符号,只保留您想要的符号。
答案 5 :(得分:0)
免责声明:我只在Linux上完成此操作,但AFAIK也适用于Windows
您可以使用-fvisibility=hidden
选项;有关详细信息,请参阅http://gcc.gnu.org/wiki/Visibility