问题描述
我正在尝试使用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
我做错什么了吗?我的期望也许不对吗?
感谢您的帮助! 大卫
解决方法
首先,我想说重要的是使用.def文件指定导出的符号,或使用__declspec(dllexport)
/ __declspec(dllimport)
,但切勿混用这两种方法。还有一种使用-Wl,--export-all-symbols
链接器标志的方法,但是我认为这很丑陋,只有在您想要快速而肮脏的情况下才应使用。
可以告诉MinGW使用与库名不匹配的DLL文件名。在链接步骤中,使用-o
指定DLL,并使用-Wl,--out-implib,
指定库文件。
让我通过展示如何将chebyshev构建为静态库和共享库来进行说明。其来源仅包含2个文件:chebyshev.h
和chebyshev.c
。
- 编译
gcc -c -o chebyshev.o chebyshev.c -I. -O3
- 创建静态库
ar cr libchebyshev.a chebyshev.o
- 创建一个
.def
文件(因为没有提供文件,也没有使用__declspec(dllexport)
/__declspec(dllimport)
)。请注意,此文件不包含带有LIBRARY
的行,允许链接程序稍后指定DLL文件名。 如果项目未提供.def
文件,有几种方法可以做到这一点:
3.1。从.h
文件中获取符号。这可能很难,因为有时您需要区分类型定义(例如typedef
,enum
,struct
)与需要导出的实际函数和变量之间的区别;
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
- 将静态库链接到共享库。
gcc -shared -s -mwindows -def chebyshev.def -o chebyshev-0.dll -Wl,libchebyshev.dll.a libchebyshev.a
如果您有一个使用__declspec(dllexport)
/ __declspec(dllimport)
的项目,事情会容易得多。您甚至可以使链接步骤使用.def
链接器标记生成-Wl,--output-def,
文件,如下所示:
gcc -shared -s -mwindows -o myproject.dll -Wl,myproject.dll.a -Wl,myproject.def myproject.o
此答案基于我对C的经验。对于C ++,您确实应该使用__declspec(dllexport)
/ __declspec(dllimport)
。
我相信我已经找到一种在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,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,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上可能会被破坏吗?