【问题标题】:Does "-Wl,-soname" work on MinGW or is there an equivalent?“-Wl,-soname”是否适用于 MinGW 或是否有等效的?
【发布时间】:2021-01-08 02:17:57
【问题描述】:

我正在尝试使用 MINGW 在 Windows 上构建 DLL。

可以在以下位置找到一个非常好的摘要(在我看来): https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/

甚至还有一个基本项目可用于本次讨论: https://github.com/TransmissionZero/MinGW-DLL-Example/releases/tag/rel%2Fv1.1

请注意,此项目中存在一个外观错误,这将导致它无法立即使用:Makefile 没有创建“obj”目录 - 调整 Makefile 或手动创建它。

所以这是真正的问题。 如何更改 Windows DLL 名称,使其与实际的 DLL 文件名不同?? 本质上,我试图在 Windows 上实现,这里在 Linux 上很好地描述了效果: https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html

最初我尝试更改用于创建 DLL 的资源文件中的“InternalName”和“”OriginalFilename”,但这不起作用。

在第二步中,我尝试在执行最终链接的命令上添加“-Wl,-soname,SoName.dll”,以更改 Windows DLL 名称。

但是,这似乎没有达到预期的效果(我使用的是 MingW 7.3.0,x86_64-posix-seh-rev0)。 有两件事让我这么说:

1/ 测试可执行文件仍然有效(我预计它会失败,因为它试图定位 SoName.dll 但找不到它)。

2/ "pexports.exe AddLib.dll" 产生以下输出,其中库名称未更改:

LIBRARY "AddLib.dll"
EXPORTS
Add
bar DATA
foo DATA

我做错了什么吗?也许我的期望错了?

感谢您的帮助! 大卫

【问题讨论】:

    标签: gcc dll mingw mingw-w64 dllexport


    【解决方案1】:

    首先,我想说的是使用 .def 文件指定导出的符号或使用 __declspec(dllexport) / __declspec(dllimport) 很重要,但切勿混合使用这两种方法。还有另一种方法使用-Wl,--export-all-symbols 链接器标志,但我认为这很丑陋,只有在你想要快速和肮脏时才应该使用。

    可以告诉 MinGW 使用与库名称不匹配的 DLL 文件名。在链接步骤中使用-o指定DLL,使用-Wl,--out-implib,指定库文件。

    让我通过展示如何将chebyshev 构建为静态库和共享库来进行说明。它的源代码仅包含 2 个文件:chebyshev.hchebyshev.c

    1. 编译
    gcc -c -o chebyshev.o chebyshev.c -I. -O3
    
    1. 创建静态库
    ar cr libchebyshev.a chebyshev.o
    
    1. 创建一个.def 文件(因为它没有提供并且__declspec(dllexport) / __declspec(dllimport) 也没有使用)。请注意,此文件不包含带有 LIBRARY 的行,允许链接器稍后指定 DLL 文件名。 如果项目没有提供 .def 文件,有几种方法可以做到这一点:

    3.1。从.h 文件中获取符号。这可能很难,因为有时您需要区分类型定义(如 typedefenumstruct)和需要导出的实际函数和变量;

    echo "EXPORTS" > chebyshev.def
    sed -n -e "s/^.* \**\(chebyshev_.*\) *(.*$/\1/p" chebyshev.h >> chebyshev.def
    

    3.2。使用nm列出库文件中的符号,过滤掉你需要的符号类型。

    echo "EXPORTS" > chebyshev.def
    nm -f posix --defined-only -p libchebyshev.a | sed -n -e "s/^_*\([^ ]*\) T .*$/\1/p" >> chebyshev.def
    
    1. 将静态库链接到共享库。
    gcc -shared -s -mwindows -def chebyshev.def -o chebyshev-0.dll -Wl,--out-implib,libchebyshev.dll.a libchebyshev.a
    

    如果您有一个使用 __declspec(dllexport) / __declspec(dllimport) 的项目,事情就容易多了。您甚至可以让链接步骤使用-Wl,--output-def, 链接器标志生成.def 文件,如下所示:

    gcc -shared -s -mwindows -o myproject.dll -Wl,--out-implib,myproject.dll.a -Wl,--output-def,myproject.def myproject.o
    

    此答案基于我使用 C 的经验。对于 C++,您确实应该使用 __declspec(dllexport) / __declspec(dllimport)

    【讨论】:

    • 非常感谢您提供所有详细信息并分享您的经验;-) 我能够复制您指出的所有步骤而没有任何麻烦。通过您的方法,我可以看到两个关键点: 1/ DEF 文件不包含带有 LIBRARY 2 的行/ -Wl,--out-imlib 选项允许我拥有一个不同于DLL 名称。但是我特别想达到的效果有点不同 - 请参阅:man7.org/conf/lca2006/shared_libraries/slide4b.html 为糟糕的格式道歉 - 我仍然不明白如何做我想做的事
    • 不确定我是否完全理解您的需求,但请注意,与 Unix/Linux 世界中的 .so 文件不同(LD_LIBRARY_PATH 有助于定位共享库),Windows 上的 .dll 文件需要与.exe 位于同一位置或在PATH 环境变量中列出的文件夹中。
    • 更具体地说:您的方法几乎符合我的要求:dlltool -I libchebyshev.dll.a 产生 chebyshev-0.dll,这是工作的一半(与导入库链接时)。然而,我很想了解的是如何将 DLL 内部名称设置为不同于 DLL 文件名的名称。你的方法并没有解决这一半的工作。 pexports.exe chebyshev-0.dll 仍然产生 LIBRARY "chebyshev-0.dll"
    • @DaveC 内部名称必须与 .dll 名称匹配。它也是以 PE 格式存储的名称(不带 .dll 扩展名),用于 .dll 和 .exe 文件,以指定它们所依赖的共享库。我不明白这些会有什么不同,或者你为什么想要这个。有了我上面的提示,你已经可以选择任何你想要的名字了。
    【解决方案2】:

    我相信我已经找到了一种在 Windows 上实现的机制,https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html 中描述的 Linux 效果

    这涉及到dll_tool

    example Makefile中原来有这行:

    gcc -o AddLib.dll obj/add.o obj/resource.o -shared -s -Wl,--subsystem,windows,--out-implib,libaddlib.a
    

    我只是将其替换为下面的 2 行:

    dlltool -e obj/exports.o --dllname soname.dll -l libAddLib.a obj/resource.o obj/add.o
    gcc -o AddLib.dll obj/resource.o obj/add.o obj/exports.o -shared -s -Wl,--subsystem,windows
    

    真的,关键似乎是使用 dlltool 结合 dllname 创建导出文件。该导出文件与构成 DLL 主体的目标文件链接,并处理 DLL 与外部世界之间的接口。请注意,dlltool 也会同时创建“导入库”

    现在我得到了预期的效果,我可以看到“内部 DLL 名称”(不确定正确的术语是什么)发生了变化:

    第一个证据:

    >> dlltool.exe -I libAddLib.a
    soname.dll
    

    第二个证据:

    >> pexports.exe AddLib.dll
    LIBRARY "soname.dll"
    EXPORTS
    Add
    bar DATA
    foo DATA
    

    第三个证据:

    >> AddTest.exe
    Error: the code execution cannot proceed because soname.dll was not found.
    

    虽然达到了预期的效果,但这似乎仍然是某种变通方法。我的理解(但我很可能错了)是 gcc 选项“-Wl,-soname”应该实现完全相同的效果。至少它在 Linux 上是这样,但是这在 Windows 上可能会坏吗??

    【讨论】:

    • 您正在创建一个文件 libAddLib.a - 它应该真正被称为 libAddLib.dll.a,因为它是共享库的导入库 - 它指的是 soname.dll 而您的二进制文件实际上被称为 @987654335 @。这没有任何意义,因此您的 AddTest.exe 找不到正确的库是正常的。我不知道你为什么要做这样的事情。
    • 我完全理解你为什么会感到困惑......我对我的 AddTest.exe 没有找到正确的库并不感到惊讶 - 这正是我所期望的行为,当 DLL 文件名称(“AddLib.dll”)与 PE 结构中的 DLL 名称(“soname.dll”)不匹配。我在原始帖子中提出的观点是,当我使用“-Wl,-soname,SoName.dll”来构建我的 DLL 时,我希望 AddTest.exe 以同样的方式失败。然而它仍然有效....因此本次讨论的标题是:“-Wl,-soname”在 MinGW 上工作吗?
    • 为什么构建一个“文件名”与 PE 结构中的“内部名称”(即“soname”)不匹配的 DLL 会很有用。有一个很好的讨论here 和大量的信息there。这些链接描述了传统上在 linux 上使用但在 Windows 上不使用的机制。尽管如此,“soname”的概念存在于 Windows 上,因此我希望“-Wl,-soname”可以在 MinGW 上工作,但似乎没有。
    • 最后,“-Wl,-soname”可能对 Windows 没有影响(或者我的期望可能是错误的),但我上面提出的解决方案表明可以实现相同的效果使用 dlltool 和 dllname 的效果。 AddTest.exe 没有找到正确的库这一事实表明“soname”被有效地设置在 DLL 的 PE 结构中。
    • 我一直认为 -Wl,-soname,libname.dll 在 MinGW 上不起作用。我也相信当你从源代码构建时,你应该尽可能避免dlltool。我的建议是只使用dlltool 为您没有来源的.dll 文件制作.dll.a 文件。我基于这些原则构建了我所有的winlibs.com 版本(除了所有内容都是从源代码构建的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    相关资源
    最近更新 更多