符号可见性和命名空间 [英] Symbol visibility and namespace

查看:315
本文介绍了符号可见性和命名空间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Linux和gcc上试验了C ++符号可见性。似乎首选方法是使用-fvisibility = hidden,并根据Visibility gcc wiki页面一一导出使用的符号( http://gcc.gnu.org/wiki/Visibility )。
我的问题是,许多库没有处理好,他们忘记显式导出符号,这是一个严重的问题。在几个固定的bug后,即使一些部分的boost也可能会受到影响。当然这些错误应该是固定的,但是直到我想使用一个安全的方式尽可能多的隐藏符号。

I'm experimenting with C++ symbol visibility on Linux and gcc. It seems that the preferred way is to use -fvisibility=hidden, and export used symbols one-by-one according to Visibility gcc wiki page (http://gcc.gnu.org/wiki/Visibility). My problem is that many libraries does not handle this well, they forget to explicitly export symbols, which is a serious problem. After several fixed bugs even some parts of boost may still be affected. Of course those bugs should be fixed, but till that I would like to use a "safe" way to hide as much as symbols as possible.

我想出了一个解决方案:我把所有的符号放在一个命名空间,我使用符号隐藏属性,并导出公共接口,这种方式只有我的符号可以受到影响。

I came up with a solution: I place all the symbols in a namespace and I use symbol hide attribute on that and export the public interface, this way only my symbols can be affected.

是我收到一个警告消息,当我编译的东西对于每个类,我没有导出,我在应用程序中作为类字段使用该库。

The problem is that I got a warning message when I compile something against that library for every class that I haven't exported and I use in the application as class field.

namespace MyDSO __attribute__ ((visibility ("hidden"))) {
  struct Foo {
    void bar() __attribute__ ((visibility ("default"))) {}
  };
}

struct Bar {
  MyDSO::Foo foo;
};

int main() {}

警告讯息可以这个小例子,但当然命名空间应该在应用程序中的其他类的库中。

The warning message can be reproduced in this small example, but of course the namespace should be in a library the other class in the application.

$ 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 = hidden有相似的效果,但是我从来没有得到类似的警告后者。我看到,当我传递-fvisibility =隐藏到应用程序的类中的应用程序也将被隐藏,所以我不会得到一个警告。但是当我没有传递选项时,标头中的所有符号都不会对编译器隐藏,因此我不会再收到警告。

As I understand symbol visibility, hiding namespace should have quite similar effect to using -fvisibility=hidden, but I never got similar warnings using the latter. I see that when I pass -fvisibility=hidden to the application the class in the application will also be hidden, so I won't get a warning. But when I don't pass the option none of the symbols in the headers will seem hidden to the compiler, so I won't get a warning again.

什么是这个警告消息的建议?这是一个严重的问题吗?在哪些情况下可能会导致任何问题?如何隐藏命名空间与fvisibility = hidden不同?

What is the propose of this warning message? Is it a serious problem? In which situations can this cause any problem? How hiding namespace is different to fvisibility=hidden?

推荐答案

在我回答你的具体问题之前,每个命名空间的符号可见性属性是GCC特定的功能。 MSVC只支持类,函数和变量的dllexport,如果你想让你的代码是可移植的,你必须匹配MSVC。由于我的原始GCC符号可见性指南(您在GCC网站上链接的一个)指出,MSVC的基于宏的dllexport机械可以轻松地重复使用在GCC上实现类似的东西,因此移植到MSVC将获得符号可见性处理免费。

Before I answer your specific question, I should mention for others reading that applying symbol visibility attributes per namespace is a GCC-specific feature. MSVC only supports dllexport on classes, functions and variables, and if you want your code to be portable you must match MSVC there. As my original GCC symbol visibility guide (the one you linked to on the GCC website) points out, MSVC's macro based dllexport machinery can be easily reused to achieve something similar on GCC, so porting to MSVC will get you symbol visibility handling "for free".

关于您的具体问题,GCC正确地警告您。如果外部用户尝试使用公共类型Bar,他们几乎肯定需要使用Bar内的所有内容,包括Bar :: foo。出于同样的原因,所有私人成员函数,尽管是私有的,都需要可见。很多人都惊讶于这一点,推理私人成员函数符号的定义是任何人都无法访问,但他们忘记了,只是因为程序员没有访问并不意味着编译器不需要。换句话说,私有成员函数是私有的,但不是编译器。如果它们出现在头文件中,那通常意味着编译器需要访问,即使在匿名命名空间中(对于程序员来说它们是匿名的,不是编译器倾向于使用内容的散列作为真实的命名空间名称)。

Regarding your specific problem, GCC is correct to warn you. If an external user tried to use public type Bar they almost certainly need to use everything inside Bar, including Bar::foo. For the exact same reason all private member functions, despite being private, need to be visible. A lot of people are surprised at this, reasoning that private member function symbols are by definition inaccessible to anyone, but they forget that just because the programmer doesn't have access doesn't mean that the compiler doesn't need access. In other words, private member functions are private to you, but not the compiler. If they appear in a header file, that generally means the compiler needs access, even in an anonymous namespace (which are only anonymous to programmers, not to compilers which tend to use a hash of the contents as the "real" namespace name).

隐藏命名空间与-fvisibility = hidden有非常不同的效果。这是因为GCC发出了许多符号,超出了特定类型的符号。对于vtables,对于type_info等。-fvisibility =隐藏的东西,你不能隐藏任何编译器指示的方式,这是东西绝对必要的加载两个二进制文件到同一个进程与碰撞符号,例如。使用不同版本的Boost构建两个共享对象。

Hiding a namespace has very different effects to -fvisibility=hidden. This is because GCC spews out many symbols above and beyond those for a specific type e.g. for vtables, for type_info etc. -fvisibility=hidden hides stuff you can't hide by any compiler instructed way, and it's stuff absolutely essential to loading two binaries into the same process with colliding symbols e.g. two shared objects built using different versions of Boost.

我感谢您尝试修复由ELF中的符号可见性损坏导致的问题,以及损坏的C ++二进制文件的后果,程序员生产力。然而你不能修复它们 - 它们是ELF本身的错误,它是为C而不是C ++设计的。如果它是任何安慰,我写了一个内部的黑莓白皮书几个月前关于这个主题,因为ELF符号可见性问题是我们在BB10一样多的问题,因为它们对于任何大型公司具有重要的C ++代码库。所以,也许你可能会看到为C ++ 17提出的一些解决方案,特别是如果Doug Gregor的C ++模块实现进展良好。

I appreciate your attempts to fix the problems caused by broken symbol visibility in ELF and the consequences on broken C++ binaries and much lost programmer productivity. However you can't fix them - they are faults in ELF itself, which was designed for C and not C++. If it's any consolation, I wrote an internal BlackBerry white paper a few months ago on this topic as ELF symbol visibility problems are just as much a problem for us in BB10 as they are for any large corporation with a significant C++ codebase. So, maybe you might see some solutions proposed for C++17, especially if Doug Gregor's C++ Modules implementation makes good progress.

这篇关于符号可见性和命名空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆