符号可见性和命名空间(Symbol visibility and namespace)

2019-07-22 12:34发布

我在Linux和gcc C ++符号可见性试验。 看来,优选的方法是使用-fvisibility =隐藏的,并且出口中使用的符号根据能见度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() {}

警告消息可以在这个小例子转载,但当然,命名空间应该在图书馆中的应用其他类。

$ 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]

据我所知符号可见,隐藏的命名空间应该有相当类似的效果,使用-fvisibility =隐藏,但我从来没有使用后者类似的警告。 我看到,当我通过-fvisibility =隐藏到应用程序中应用程序的类也将被隐藏,所以我不会得到一个警告。 但是,当我没有通过选项没有符号的标题会显得隐藏的编译器,所以我不会再得到一个警告。

什么是提出这个警告信息? 它是一个严重的问题? 在哪些情况下可以在此产生任何问题? 如何隐藏命名空间是fvisibility不同=隐藏?

Answer 1:

在我回答你的具体问题,我应该提到别人读取每个命名空间将符号可见属性是特定GCC-功能。 MSVC只在类,函数和变量支持DLLEXPORT,如果你想你的代码移植必须有匹配MSVC。 由于我原来的GCC符号可见指南(你链接到GCC网站上的一个)指出,MSVC的基于宏观DLLEXPORT机器可以很容易地重复使用,以实现对GCC类似的东西,所以移植到MSVC将让你的符号可见处理“免费”。

关于你提到的具体问题,GCC是正确的警告你。 如果外部用户尝试使用公共型酒吧,他们几乎肯定需要使用内部酒吧的一切,包括酒吧:: foo中。 对于完全相同的原因,所有私有成员函数,尽管是私人的,必须是可见的。 很多人都在这个奇怪,理由是私有成员函数符号被定义无法访问任何人,但他们忘了,只是因为程序员不能访问并不意味着编译器 不需要访问。 换言之,私有成员函数都是私人给你,但不是编译器。 如果它们出现在一个头文件,这通常意味着编译器需要访问,即使在一个匿名的命名空间(这是唯一的匿名程序员,而不是倾向于使用内容的哈希值作为“真正”的命名空间名称的编译器)。

隐藏命名空间有-fvisibility =隐藏的非常不同的影响。 这是因为GCC里喷出超出那些特定类型例如,对于虚函数表,对TYPE_INFO等-fvisibility =隐藏皮的东西,你不能用任何编译器指令的方式隐藏很多符号,它的东西绝对有必要同时加载两个二进制与碰撞相同的过程,例如符号使用不同版本的Boost建了两个共享对象。

我很欣赏你试图修复所造成的破ELF符号可见性和破C ++二进制文件,并失去了很多程序员的工作效率的后果问题。 但是你不能修复他们 - 他们是在ELF本身的故障这是专为C和不是C ++。 如果它的任何安慰,我就这个话题在几个月前写了一封内部黑莓白皮书ELF符号可见性的问题是一样多的一个问题,我们在BB10,因为它们是任何大公司有显著C ++代码库。 所以,也许你可能会看到提出了C ++ 17的一些解决方案,尤其是在道格·格里高尔的C ++模块实施进展顺利。



Answer 2:

您使用的可见性属性似乎倒退到我。 我想你会使用-fvisibility =隐藏和增加知名度“默认”的库声明命名空间,因为该库的界面大概有默认的知名度,或者你无法从你的应用程序中使用有较好的效果。 如果你不想修改库头,你可以使用你的周围的#pragma#包括GCC的知名度推/弹出。

此外,如尼尔说,这标志着个人会员功能默认不工作,整个富类型需要有默认的知名度,如果它是磁带库接口的一部分。



文章来源: Symbol visibility and namespace