gcc - 如何在结构定义中结合 __attribute__((dllexport)) 和 [[nodiscard]]?
Posted
技术标签:
【中文标题】gcc - 如何在结构定义中结合 __attribute__((dllexport)) 和 [[nodiscard]]?【英文标题】:gcc - How to combine __attribute__((dllexport)) and [[nodiscard]] in a struct definition? 【发布时间】:2019-09-18 13:22:54 【问题描述】:我有一个标有 C++17 的 [[nodiscard]]
属性的结构。它是这样定义的:
struct [[nodiscard]] MyObject final
explicit MyObject(int id);
~MyObject();
MyObject(const MyObject&) = delete;
MyObject& operator=(const MyObject&) = delete;
int id;
;
现在我想从我的动态库中导出它。
在 MSVC 上,语法 struct __declspec(dllexport) [[nodiscard]] MyObject final
按预期工作。
但是 GCC 无法同时编译 struct __attribute__((dllexport)) [[nodiscard]] MyObject final
和 struct [[nodiscard]] __attribute__((dllexport)) MyObject final
:编译器无法处理这样的语法。
语法__attribute__((dllexport)) struct [[nodiscard]] MyObject final
编译但似乎没有做我想要的,因为它会产生以下警告:
:1:49: 警告: 'struct 声明中忽略的属性 MyObject' [-Wattributes]
1 | __attribute__((dllexport)) struct [[nodiscard]] MyObject final | ^~~~~~~~
:1:49: 注意:'struct MyObject' 的属性必须遵循 “结构”关键字
那么,如何从 GCC 上的动态库中导出 [[nodiscard]]
结构?
【问题讨论】:
考虑到 Clang handles 是struct __attribute__((dllexport)) [[nodiscard]] MyObject
版本,它可能是 GCC 中的一个错误(或者更确切地说是缺少某个功能)。另请注意,Windows 上的 GCC handles __declspec(dllexport)
。
@andrey 您提供的链接向我显示了带有__attribute__((visibility("default")))
而不是__attribute__((dllexport))
的代码。如果我用__attribute__((dllexport))
替换它,我会收到以下警告:unknown attribute 'dllexport' ignored [-Wunknown-attributes]
。
那是因为带有 Clang 的 Compiler Explorer 节点正在运行 Linux。 dllexport
用于 DLL,它们是 Windows 共享库。 Linux(也可能是 MacOS)上共享库的等效属性是visibility("default")
,在命令行上是-fvisibility=hidden
。在为 Linux 构建时,编译器自然无法识别 dllexport
属性(它是如何编写的),但重要的是该属性被正确解析(即使它随后被忽略)。
@andrey 是的,我在 Linux 上测试了该代码,但我对在 Linux 上创建共享库知之甚少,所以我认为 Linux 编译器也能够以某种方式识别 dllexport
.好的,所以我应该改用__attribute__((visibility("default")))
。这很清楚。那么,事实上,它很可能是一个(又一个)GCC 错误。如果您将其写为答案,我会将其标记为已接受。
【参考方案1】:
所有这些都适用于dllexport
和dllimport
。
这似乎是 GCC 解析器中的一个错误。
Clang manages to parse struct __attribute__((dllexport)) [[nodiscard]] MyObject ...
版本。
正如@Artyer 所述,GCC(和 Clang)支持 dllexport
- [[gnu::dllexport]]
的 C++ 语法。
还应该注意的是,Windows 上的 GCC (MinGW) 支持 __declspec(dllexport)
以与 Visual C++ 兼容,并且实际上可以正确解析 class __declspec(dllexport) [[nodiscard]] Test ...
(使用 GCC 8.1.0 测试)。
以上所有内容都假设您正在为 Windows 编译,dllexport
实际上意味着什么。在其他平台上,编译器会简单地忽略它(通常会发出警告)。
在 Linux 上,应该使用 -fvisibility=hidden
隐藏所有符号,除了由属性 visibility("default")
选择的符号之外。没有“导入”替代方案 - 在构建和使用库时都使用 "default"
。在 Linux 上导出类时,您不想导出的任何内容都可以标记为 visibility("hidden")
以覆盖类的属性。
GCC 和 Clang 支持 visibility
的两种语法:__attribute__((visibility("default")))
和 [[gnu::visibility("default")]]
。
更多关于 GCC 可见性的信息可以在HERE找到。
我不确定从共享库中导出符号在 MacOS 上的工作方式(可能与在 Linux 上相同?)。
【讨论】:
很好的答案,谢谢。我还想补充一点,__attribute__((visibility("default")))
和 [[gnu::visibility("default")]]
不能完全互换。 __attribute((visibility("default"))) int foo();
和 int __attribute((visibility("default"))) foo();
都有效,但 C++ 的标准属性语法更严格:[[gnu::visibility("default")]] int foo();
可以正常工作,而 int [[gnu::visibility("default")]] foo();
不能正常工作:(【参考方案2】:
尝试使用 C++ 属性而不是使用__attribute__
:
struct [[gnu::dllexport]] [[nodiscard]] MyObject final
也可以使用定义来处理 MSVC
【讨论】:
我认为这行不通。我认为[[gnu::dllexport]]
可能存在,并且在在*** 上提出这个问题之前专门搜索了它。但那时我什么也没发现。现在,当我尝试编译您的代码时,我收到警告 'gnu::dllexport' scoped attribute directive ignored
,这意味着 [[gnu::dllexport]]
是 GCC 的未知属性。
@Taras 我用 GCC 8.1.0 尝试了 MinGW,它识别了 [[gnu::dllexport]]
和 [[gnu::dllimport]]
(并且该符号实际上已导出)。也许您不在 Windows 上?
@Taras 或者您使用的是不支持 [[gnu::dllexport]]
的旧版 GCC?
@andrey 在上面的 cmets 中回复了你。
@Taras 有。这是[[gnu::visibility("default")]]
:)【参考方案3】:
截至 2022 年,这仍然是 gcc 中的一个问题。用于此的 gcc bugzilla 条目是 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69585
【讨论】:
以上是关于gcc - 如何在结构定义中结合 __attribute__((dllexport)) 和 [[nodiscard]]?的主要内容,如果未能解决你的问题,请参考以下文章