我正在使用MinGW工具链构建一个Windows动态库。
为了构建这个库,我静态链接到其他2个提供API的库,并且我有一个.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
不会阻止导出库中的符号。
7条答案
按热度按时间jjhzyzn01#
不知道为什么没有真实的的答案,但这里是什么对我有效:
1.编译目标文件:
1.链接(
-Wl,--exclude-all-symbols
很重要):然后选择要在DLL的源代码中直接导出的函数:
验证:
(x一米一米一x = x一e0一米一x)
wsewodh22#
你可以使用选项
-Wl,--retain-symbols-file=file
,然后在file
中列出你想要保留的符号(每行一个),这将导致链接器丢弃所有其他符号,只保留你想要的符号。7ajki6be3#
这是一个反复出现的问题。以下是《战略目标》中两个相关的问题:
和外部SO:
即,Windows平台上的全局/本地导出不在链接器级别处理,而是提供
.def
文件以补充.dll
。由于缺乏一个好的答案,我做了一个python脚本,负责从dll导出表中删除内容,您可以找到它here。
tktrz96b4#
如果您的binutils发行版(本机或交叉编译)提供了dllwrap,则可以使用它。
它可以使用DEF文件中的接口生成DLL(在底层它调用gcc、ld和dlltool来完成此操作),使用此接口与直接将DEF文件传递给GCC之间的区别在于文件中的定义被区别对待。
例如,如果导出文件中有一个重命名符号:
GCC会创建两个导出,一个名为
_SomeFunction
,另一个名为修饰名,而dllwrap只会导出_SomeFuntion
。因此,如果你只向DEF文件添加你想要导出的符号,你最终只会在库中找到它们。默认情况下,dllwrap使用C编译器驱动程序,因为它无法知道其他情况。当你链接C++代码时,你必须使用选项
--driver-name c++
来设置驱动程序。如果你碰巧有带前缀的MinGW可执行文件,你也必须在驱动程序名称中包含它(例如i686-mingw32-c++
而不是c++
),你可能也需要使用选项--dlltool-name
。请尝试使用以下两行代码,而不是您发布的代码:
第一个程序从
library.cpp
的代码生成一个目标文件,第二个程序汇编动态库,OBJECT_FILES
的东西(我假设它是您之前生成的其他目标文件)也应该有library.o
。也就是说,我必须告诉您,dllwrap在2006年就已经是deprecated了,并且在官方的binutils包中没有关于它的文档;要获得一些信息,你可以像往常一样用
--help
调用它。它可以生成一个导入库,以防你也需要它。o2gm4chl5#
您是否在提供了链接的页面上阅读了以下内容,关于未显式使用--export-all-symbols时的行为-在以下情况下禁用自动导出:
任何对象文件中的任何符号都标记有__declspec(dllexport)属性。
你有没有试过只导出你感兴趣的函数?在DEF文件中很容易出现名字错误,这是因为mangling,所以这个方法应该更可靠。
hpxqektj6#
免责声明:我只在Linux上做过这个,但AFAIK它应该也能在Windows上工作
您可以使用
-fvisibility=hidden
选项;有关详细信息,请参见http://gcc.gnu.org/wiki/Visibilitywtlkbnrh7#
您可以在GNU LD中使用version script来创建导出符号的允许列表。
假设在
library.cpp
中有一个library_somefunc
函数,而您只想导出该符号,您可以准备一个名为version-script.txt
的纯文本文件:通过将
library_somefunc
指定为global,您可以指示该符号应该在动态链接库中导出。我们将*
指定为local,以便不导出其他符号。然后,使用以下命令生成dll:
可以使用Dependencies检查DLL文件是否正确导出符号。