使用可见性属性(没有 __declspec(dllexport))时,Clang 可以生成导入库吗?

Posted

技术标签:

【中文标题】使用可见性属性(没有 __declspec(dllexport))时,Clang 可以生成导入库吗?【英文标题】:Can Clang generate an import library when using the visibility attribute (without __declspec(dllexport))? 【发布时间】:2019-11-17 23:24:34 【问题描述】:

使用 Microsoft 编译器时,要从库中导出类或函数,您可以使用类似于以下内容的代码:

class __declspec(dllexport) Foo ;

使用 Clang(和 GCC),您可以使用可见性属性来确保符号可见:

class __attribute__((visibility(default))) Foo ;

或者依赖于编译时设置的可见性。

当我在 Windows 上使用 Clang 编译时,如果一个类可见(即使具有显式属性),则不会导出该函数(不创建导入库)。

是否可以让 Clang 生成导入库而不使用 Clang 大部分但不完全支持的 Microsoft 扩展 __declspec(dllexport)

【问题讨论】:

您能否详细说明“Clang 主要但不完全支持的__declspec(dllexport)”,它不支持哪个方面? @mstorsjo 针对 LLVM 项目的__declspec(dllexport) 记录了几个错误;这是我最近提交的一个示例 - bugs.llvm.org/show_bug.cgi?id=44016 很公平,这种情况似乎确实偏离了 MSVC 的行为。 我很确定是 LLVM 端口激发了微软创建自己的分支。他们研究了一段时间,因为异常处理是更难破解的问题。它在 VS2017 左右变得稳定,并包含在 VS 安装程序中。 @HansPassant Microsoft fork 了什么? 【参考方案1】:

澄清一些事情;生成导入库的不是编译器 (Clang) 本身,而是链接器,而目标文件格式在此过程中起着重要作用。

调整通过__attribute__((visibility(default))) 导出的符号(当使用__attribute__((visibility(hidden))) 将其他符号标记为隐藏时,或使用-fvisibility=hidden 之类的设置默认值时,在构建ELF 目标文件时,GCC 和Clang 都适用。COFF 不'没有类似的每个符号可见性标志。

当使用 MS link.exe 或 LLVM 的 lld-link(模仿 link.exe 的行为)链接 DLL 时,只有标有 __declspec(dllexport) 或在传递给链接器的 def 文件中列出的符号是已导出。

在 MinGW 生态系统中(带来更多类似 unix 的行为),如果没有符号,默认是导出所有全局符号(使用一些逻辑来避免导出属于 mingw 基础库本身的东西)被明确选择导出。

如果使用 lld-link 而不是 MS link.exe 链接(如果直接调用链接器,则通过调用 lld-link 而不是链接,或者如果通过 clang-cl 前端调用链接器,则添加 -fuse-ld=lld),您可以通过添加特定于 lld 的选项 -lldmingw 来选择启用此行为,这会在 lld 中启用许多特定于 MinGW 的行为。

【讨论】:

谢谢。我希望 Clang 能够自动将符号标记为已导出,如果它们是可见的(基于属性或默认值),这将允许链接器生成导入库。【参考方案2】:

添加到@mstorsjo 的答案,这是一个将 def 文件传递​​给 clang 的示例。

clang -shared structs.c -o structs.dll -Wl"/DEF:structs.def"

我为此苦苦挣扎了一天,希望对某人有所帮助 (explaination)

【讨论】:

以上是关于使用可见性属性(没有 __declspec(dllexport))时,Clang 可以生成导入库吗?的主要内容,如果未能解决你的问题,请参考以下文章

pytorch源码解析-动态接口宏

__declspec(dllexport) 静态链接库到 dll

使用来自 C++ dll 的 __declspec(dllexport) 签名声明在 C# 中调用的问题

dll

__declspec(dllexport) 和 __declspec(dllimport)的区别

GetProcAddress与__declspec(dllimport)