Var*_*gaD 12 c++ gcc visibility symbols
我正在Linux和gcc上尝试C++符号可见性.似乎首选的方法是使用-fvisibility = hidden,并根据Visibility gcc wiki页面(http://gcc.gnu.org/wiki/Visibility)逐个导出使用过的符号.我的问题是很多库都没有很好地处理这个问题,他们忘了明确导出符号,这是一个严重的问题.经过几次修复后,甚至某些部分的升压仍可能受到影响.当然,这些错误应该是固定的,但在此之前我想用一种"安全"的方式尽可能地隐藏符号.
我提出了一个解决方案:我将所有符号放在命名空间中,然后使用符号隐藏属性并导出公共接口,这样只会影响我的符号.
问题是,当我针对每个未导出的类编译针对该库的内容时,我收到了警告消息,并且我在应用程序中将其用作类字段.
namespace MyDSO __attribute__ ((visibility ("hidden"))) {
struct Foo {
void bar() __attribute__ ((visibility ("default"))) {}
};
}
struct Bar {
MyDSO::Foo foo;
};
int main() {}
Run Code Online (Sandbox Code Playgroud)
警告消息可以在这个小例子中重现,但当然命名空间应该在应用程序中的另一个类的库中.
$ gcc-4.7.1 namespace.cpp -o namespace
namespace.cpp:7:8: warning: ‘Bar’ declared with greater visibility than the type of its field ‘Bar::foo’ [-Wattributes]
Run Code Online (Sandbox Code Playgroud)
由于我理解符号可见性,隐藏命名空间应该与使用-fvisibility = hidden具有非常相似的效果,但我从未使用后者获得类似的警告.我看到当我将-fvisibility = hidden传递给应用程序时,应用程序中的类也将被隐藏,所以我不会收到警告.但是当我没有通过选项时,标题中的符号似乎都不会被编译器隐藏,所以我不会再收到警告.
这条警告信息的建议是什么?这是一个严重的问题吗?在哪种情况下会导致任何问题?如何隐藏命名空间与fvisibility = hidden不同?
Nia*_*las 20
在回答您的具体问题之前,我应该提及其他人阅读每个命名空间应用符号可见性属性是GCC特定的功能.MSVC仅支持类,函数和变量上的dllexport,如果您希望代码可移植,则必须在那里匹配MSVC.正如我原来的GCC符号可见性指南(您在GCC网站上链接的那个)指出,MSVC的基于宏的dllexport机器可以很容易地重复使用以实现类似GCC的类似功能,因此移植到MSVC将为您提供符号可视性处理"免费" ".
关于您的具体问题,GCC警告您是正确的.如果外部用户试图使用公共类型Bar,他们几乎肯定需要使用Bar内的所有内容,包括Bar :: foo.出于同样的原因,所有私有成员函数,尽管是私有的,都需要是可见的.很多人都在这个奇怪,理由是私有成员函数符号被定义无法访问任何人,但他们忘了,只是因为程序员不能访问并不意味着编译器并不需要访问.换句话说,私有成员函数对您来说是私有的,而不是编译器.如果它们出现在头文件中,这通常意味着编译器需要访问,即使在匿名命名空间(对于程序员而言只是匿名的,而不是对于倾向于使用内容的哈希作为"真实"命名空间名称的编译器).
隐藏命名空间对-fvisibility = hidden具有非常不同的效果.这是因为GCC会针对特定类型(例如vtable,type_info等)喷出许多符号.-fvisibility =隐藏隐藏任何编译器指示方式无法隐藏的东西,并且它对于加载两个二进制文件是绝对必要的与碰撞符号相同的过程,例如使用不同版本的Boost构建的两个共享对象.
我很感激您尝试解决由于ELF中符号可见性损坏而导致的问题,以及对破坏的C++二进制文件的影响以及程序员生产力的损失.但是你无法修复它们 - 它们是ELF本身的错误,它是为C而不是C++设计的.如果有任何安慰,我几个月前在这个主题上写了一篇内部黑莓白皮书,因为ELF符号可见性问题对我们来说在BB10中同样重要,因为它们适用于任何拥有重要C++代码库的大公司.所以,也许你可能会看到一些为C++ 17提出的解决方案,特别是如果Doug Gregor的C++模块实现取得了很好的进展.