acm*_*acm 7 c++ dll visibility shared-libraries
在构建C++ DLL或共享库时,__attribute__((__visibility__("default")))或__declspec(dllexport)经常通过宏附加到应该为库的使用者提供的具体符号(类,函数等)时,其他符号默认为具有内部可见性.
但是应该如何处理内联函数或模板?
似乎对于内联函数,答案应该是不需要注释.如果定义内联函数的标题的使用者实际内联函数,则不需要符号.如果消费者发出了一个外线定义,那仍然可以.唯一的缺点是DLL内部和每个消费库内部的内联函数的定义可能不同.所以,如果你期望可靠地比较内联函数的地址,你可能会遇到麻烦,但无论如何这看起来都很粗略.
鉴于该论点,似乎因为模板主体通常对于消费TU完全可见,所以应用相同的逻辑.
我觉得这里可能存在一些关于'extern模板'和显式实例化的细微之处.
有没有人对可见性属性如何遵循内联函数和模板有具体的指导?
内联函数在外部不可见(没有链接,IIRC),因此它们不能从 DLL 导出。如果它们是公开的,那么它们将完全写入您的库的头文件中,并且每个用户都会重新编译它。
正如您在问题中所说,由于内联代码在使用该库的每个模块中都会重新编译,因此对于该库的未来版本可能会出现问题。
我对共享库中的内联函数的建议是,它们应该仅用于非常琐碎的任务或绝对通用的函数。请注意,将公共内联函数转换为非内联函数是一项 ABI 重大更改。
例如:
memcpy。排队!bswap函数。排队!实际上,内联函数可以有多个不同的地址这一事实并不重要。
关于extern 模板和显式实例化,只要稍加小心,它们就可以用于从库中导出模板。如果模板实例化仅限于一组特定的情况,您甚至可以避免将模板代码复制到头文件中。
注意 1:在下面的示例中,我将使用一个简单的函数模板,但类模板的工作方式完全相同。注 2:我使用的是 GCC 语法。MSC 代码是相似的,我想你已经知道差异了(而且我没有 MSC 编译器来测试)。
template<int N> int foo(int x); //no-instantiable template
Run Code Online (Sandbox Code Playgroud)
#include "public_foo.h"
//Instantiate and export
template __attribute__ ((visibility("default")))
int foo<1>(int x);
template __attribute__ ((visibility("default")))
int foo<2>(int x);
Run Code Online (Sandbox Code Playgroud)
#include "public_foo.h"
int main()
{
foo<1>(42); //ok!
foo<2>(42); //ok!
foo<3>(42); //Linker error! this is not exported and not instantiable
}
Run Code Online (Sandbox Code Playgroud)
相反,如果您的模板应该可以自由实例化,但您希望它以特定方式频繁使用,则可以从库中导出这些模板。想一想std::basic_string:它最有可能被用作std::basic_string<char>and std::basic_string<wchar_t>,但不太可能被用作std::basic_string<float>。
template<int N> int foo(int x)
{
return N*x;
}
//Do not instantiate these ones: they are exported from the library
extern template int foo<1>(int x);
extern template int foo<2>(int x);
Run Code Online (Sandbox Code Playgroud)
#include "public_foo.h"
//Instantiate and export
template __attribute__ ((visibility("default")))
int foo<1>(int x);
template __attribute__ ((visibility("default")))
int foo<2>(int x);
Run Code Online (Sandbox Code Playgroud)
#include "public_foo.h"
int main()
{
foo<1>(42); //ok, from library
foo<2>(42); //ok, from library
foo<3>(42); //ok, just instantiated
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1266 次 |
| 最近记录: |