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

Jam*_* R. 13 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
Run Code Online (Sandbox Code Playgroud)

编辑:在关于链接器的文档中,它表示这--export-all-symbols是默认行为,并且如果您提供def文件时未明确使用该选项则禁用它,除非它没有; 无论如何,第三方库中的符号正在导出.

编辑:添加选项--exclude-libs LIBS–exclude-symbols SYMBOLS不阻止导出库中的符号.

ant*_*one 8

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

  1. 编译目标文件:

    g++ -O0 -gdwarf-4 dll\dllmain.cpp -c -o dllmain.o
    
    Run Code Online (Sandbox Code Playgroud)
  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
    
    Run Code Online (Sandbox Code Playgroud)

然后您选择直接在 DLL 的源代码中导出哪些函数:

#include <windows.h>

__declspec(dllexport) void someExportedFunction() {
    MessageBox(NULL, "msgbox", "msgbox", MB_OK);
}

void nonExportedFunction() {
    MessageBox(NULL, "notexported", "notexported", MB_OK);
}
Run Code Online (Sandbox Code Playgroud)

确认:

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
Run Code Online (Sandbox Code Playgroud)

( pedump= http://pedump.me )


Xan*_*ndy 2

如果您的 binutils 发行版(本机或交叉编译)提供了 dllwrap,则可以使用 dllwrap。

它可以使用 DEF 文件中的接口生成 DLL(在幕后它调用 gcc、ld 和 dlltool 来执行此操作)。使用此方法与直接将 DEF 文件传递​​给 GCC 的区别在于文件中的定义的处理方式不同。

例如,如果导出文件中有符号重命名:

_SomeFuntion = _SomeFunction@12
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

第一个从代码生成目标文件library.cpp,第二个编译动态库。这个OBJECT_FILES东西(我假设是您之前生成的其他目标文件)library.o也应该在那里。

也就是说,我必须告诉您 dllwrap 已在 2006 年被弃用,并且官方 binutils 软件包中没有关于它的文档;要获取一些信息,您可以像往常一样调用它--help。它可以生成一个导入库,以防您也需要。