我正在阅读Dear ImGui API,我想知道在这样的函数声明之前添加预处理器变量(在这里是[[IMGUI_API)是什么意思:
#ifndef IMGUI_API
#define IMGUI_API
#endif
...
namespace ImGui
{
...
IMGUI_API float GetWindowWidth();
...
};
提前感谢!
动态共享库(和Windows中的DLL)的主要属性之一是库的内部符号不向用户公开。在GCC中,这是通过在构建库时在命令行上将默认符号可见性指定为“隐藏”来完成的。但是,这会使所有符号(包括您希望用户调用的符号)都隐藏起来,从而产生不希望的效果,从而使您的库实际上无效。
GCC提供了一种手动控制可见性的方法-__attribute__((visibility("default")))
。这会将功能标记为具有默认可见性,这意味着它将由DSO公开。此属性在函数声明之前指定。
这会产生一个新问题-库用户在包含头文件时不需要/不希望在库函数中指定此属性。当用户包含标题时,应删除这些定义,仅保留裸函数声明。
有两种解决方法-拥有标头的两个副本,或者在编译前使用预处理程序更改代码。大多数(几乎所有)库程序员都选择后者,因为很难同步同一文件的两个副本。
ImGui的作者实现后一种方法的方式非常优雅-而不是像这样定义内联的API标记:
#ifdef IMGUI_API_BUILD
#define IMGUI_API __attribute__((visibility("default")))
#else
#define IMGUI_API
#endif
他们的定义如下:
#ifndef IMGUI_API #define IMGUI_API #endif
如果未覆盖该符号,则将符号定义为默认值。这的天才实际上是在编译过程中-通过在命令行上指定
IMGUI_API
的定义,他们可以更改代码的行为,而无需将其构建过程的元素暴露给世人。他们所要做的就是将
-D IMGUI_API=__attribute((visibility("default")))
添加到编译器命令行,并且头文件神奇地将每个API函数标记为从共享库中导出。实际上,他们可以将定义更改为所需的任何值,而无需在其他程序员以这种方式使用的头文件中公开该细节。调试信息,其他功能选项,指定热/冷路径信息...所有这些都可以在命令行上指定,而无需将该信息放入头文件中。
编辑:
现在看他们的代码,似乎他们还没有意识到这一点,并且为Linux创建了一个非常强大的共享库解决方案,毫无意义。尽管如此,以上所有内容仍然有效-其他库也可以执行相同的操作。