如何告诉MinGW链接器不要导出所有符号?

时间:2010-05-11 11:11:44

标签: c++ windows dll gcc g++

我正在使用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并不会阻止导出库中的符号。

6 个答案:

答案 0 :(得分:3)

不确定为什么没有真正的答案,但这对我有用:

  1. 编译目标文件:

    g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
    
  2. 链接(-Wl,--exclude-all-symbols很重要):

    g++ -Wl,--enable-auto-import -Wl,--out-implib,libsomelib.a -Wl,--exclude-all-symbols -shared dllmain.o -o somelib.dll
    
  3. 然后,您可以选择直接在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