我正在使用GNU binutils在Windows上使用程序集构建一个dll.
我知道可以在加载可执行文件时或在运行时加载dll(使用LoadLibrary api调用).
对于加载时加载,我似乎只需要dll文件:不需要.a,.lib或.def文件.我想知道这些文件格式代表什么,它们的用途是什么.
我所知道的和一些具体问题:
.a是Unix上通常用于静态库的扩展..a文件是使用GNU ld 的--out-implib选项生成的.它被认为是一个"进口图书馆",足够公平.问题是"如果我在链接时不需要它,那对我来说有什么用?"
.lib是Windows上用于静态库的扩展,根据维基百科,在windows下也被用作"导入库",所以我强烈怀疑它们只是binutils调用.a文件的另一个名称.真假 ?
我可以找到的所有页面都指出.def文件列出了dll的导出符号.这与"导入库"应该做的有点类似吗?
另外,我在这里读到使用.def文件是在源文件中手动指定导出的替代方法(我做过).但我还记得读取(找不到引用).def文件为导出的符号提供索引(序号),允许更快的运行时加载.是这样吗 ?
使用模块定义文件(MyDLL.def)创建基本C++ DLL和导出的名称.编译后我检查导出的函数名称,dumpbin.exe
我希望看到:
SomeFunction
Run Code Online (Sandbox Code Playgroud)
但我看到了这一点:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
Run Code Online (Sandbox Code Playgroud)
为什么?
导出的函数显示为未修饰(特别是与不使用Module Def文件相比),但其他内容是什么?
如果我使用dumpbin.exe来自任何商业应用程序的DLL,你会得到干净的:
SomeFunction
Run Code Online (Sandbox Code Playgroud)
没有别的......
我还尝试删除模块定义并使用"C"导出方式导出名称,即:
extern "C" void __declspec(dllexport) SomeFunction();
Run Code Online (Sandbox Code Playgroud)
(简单地使用"extern"C"没有创建导出函数)
但是,这仍然会产生相同的输出,即:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
Run Code Online (Sandbox Code Playgroud)
我也尝试了这个#define dllexport __declspec(dllexport)选项并创建了一个没有问题的LIB.但是,我不想在他们的C#应用程序中向使用DLL的人提供LIB文件.
它是一个普通的C++ DLL(非托管代码),用C++编译,只是一个简单的头和代码.没有Module Def我得到了错误的导出函数(我可以创建一个静态库并使用LIB没问题.我试图避免这种情况).如果我使用extern "C" __declspec(dllexport) OR模块定义我得到的似乎是一个未修饰的函数名...唯一的问题是它后跟一个"=",看起来像是函数的装饰版本.我想摆脱"="之后的东西 - 或者至少理解它为什么存在.
既然这样,我敢肯定,我可以使用P调用从C#中的函数/调用...我只是想避免垃圾在"="号结束.
我对如何更改项目/编译器设置的建议持开放态度,但我只使用了标准的Visual Studio DLL模板 - 没什么特别的.
我正在使用Visual Studio 2008 SP1(专业版,适用于32位和64位版本).我正在寻找一种解决方法,我认为这是Visual Studio中一个非常无益的" 限制 ".
我觉得很奇怪,在Visual Studio连接器和编译器不以DLL文件的创建时间这一权利,自动扫描所有导出的符号所有指定的静态库中所示的相同的方式构建一个导入库和导出文件,并在一StackOverflow评论.我确认仅仅在组成静态库的文件中应用__declspec(dllexport)和__declspec(dllimport)属性类,函数和数据声明是不够的
.
链接器不扫描导出符号的所有静态库,因此不会将它们拉入DLL文件(符号必须由.objDLL链接命令行上的文件或我在下面显示的其他方式引用).如果没有对每个导出符号的显式引用,仍可能会创建DLL文件,但不会创建其关联的导入库文件.
根据我的收集,Microsoft建议使用LIB.EXE 来创建DEF文件,但不幸的是,LIB.EXE页面应用了一个约束:
请注意,如果您在创建导入库之前创建导入库,则在构建导入库时,必须在构建导入库时
.dll传递相同的目标文件集.dll.
鉴于我在新的构建环境中也使用了CMake,这是一个不幸的约束.CMake隐藏了实际传递给链接器的细节(我认为这在99%的时间里都是好事),但在这种情况下我需要在CMake执行时访问一些信息,而不是然后使用手工制作的脚本或其他脆弱的skulduggery.
如何强制DLL链接器解析构成DLL文件的所有静态库中的所有导出符号,这不会导致脆弱性和额外的构建逻辑维护工作?在这里考虑全自动化,并记住我需要多次为多个不同的DLL执行此操作.
我的问题是:
如何仅使用CMake语法获取最终DLL链接命令行上使用的目标文件和静态库集?
有没有更好的方法来解决这个问题,在调用最终链接之前不需要调用单独的实用程序,例如LIB.EXE ?我担心LIB.EXE链接本身之外的额外构建开销会再次重新扫描所有静态库 ,即使它只是在单独的执行中写出来.
以下是我现在无法考虑的解决方案:
在原始文件.h或.cpp文件之外的任何地方手动指定未引用的符号,因为每次开发人员忘记更新列出(很可能是名称错位的)符号名称的文件时,这样做会中断.并且它将打破关于未解析符号的非用户友好链接器错误,这对于开发人员来说将是昂贵的调试.这个非答案包括以下方法:
明确地将.obj文件添加到DLL链接命令行中(其中的变体包括添加"假" .obj文件,这些文件具有对未引用但导出的符号的虚拟引用(并注意这是我的旧构建环境今天所做的,并且它很臭) ),和,
手工制作DEF文件以包含未引用但导出的符号,以及 …
是否通过不透明指针将 C++ 库包装到 C 提供了稳定的 ABI 接口?我很清楚 ABI 接口以及为什么 c++ 没有稳定的接口。这与名称修改和许多其他事情有关。我知道 C 在这部分非常稳定。与 C++ 相比,将 C 库包装成各种其他语言也很容易。这两个是为我的库制作 ac API 的驱动力。
将 C++ 库包装为 C 时,底层代码仍然是 C++。我的情况是 C++,带有 boost 共享 ptr 和其他依赖项。
那么既然底层代码是C++,那么ABI的稳定性是如何实现的。或者换句话说,共享库(.so、.dll 等)中仍然编译了 C++ 的东西。
我想知道它是如何工作的。也许有人可以为我提供一个很好地解释这些东西的例子。