Ich experimentiere mit der Sichtbarkeit von C++-Symbolen unter Linux und gcc. Es scheint, dass die bevorzugte Methode darin besteht, -fvisibility=hidden zu verwenden und die verwendeten Symbole nacheinander gemäß der Visibility gcc-Wiki-Seite (http://gcc.gnu.org/wiki/Visibility). Mein Problem ist das viele Bibliotheken handhaben dies nicht gut, sie vergessen, Symbole explizit zu exportieren, was ein ernstes Problem darstellt. Nach mehreren behobenen Fehlern können sogar einige Teile des Boosts noch betroffen sein. Natürlich sollten diese Fehler behoben werden, aber bis dahin möchte ich einen “sicheren” Weg verwenden, um so viele Symbole wie möglich auszublenden.
Ich habe eine Lösung gefunden: Ich platziere alle Symbole in einem Namensraum und verwende das Symbol zum Ausblenden des Attributs und exportiere die öffentliche Schnittstelle, auf diese Weise können nur meine Symbole beeinflusst werden.
Das Problem ist, dass ich eine Warnmeldung bekomme, wenn ich für jede Klasse, die ich nicht exportiert habe, etwas gegen diese Bibliothek kompiliere und ich in der Anwendung als Klassenfeld verwende.
namespace MyDSO __attribute__ ((visibility ("hidden"))) {
struct Foo {
void bar() __attribute__ ((visibility ("default"))) {}
};
}
struct Bar {
MyDSO::Foo foo;
};
int main() {}
Die Warnmeldung kann in diesem kleinen Beispiel reproduziert werden, aber natürlich sollte sich der Namespace in einer Bibliothek der anderen Klasse in der Anwendung befinden.
$ 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]
Soweit ich die Sichtbarkeit von Symbolen verstehe, sollte das Ausblenden von Namespace einen ähnlichen Effekt haben wie die Verwendung von -fvisibility=hidden, aber ich habe bei letzterer nie ähnliche Warnungen erhalten. Ich sehe, dass die Klasse in der Anwendung auch ausgeblendet wird, wenn ich -fvisibility=hidden an die Anwendung übergebe, sodass ich keine Warnung erhalte. Aber wenn ich die Option nicht übergebe, erscheint dem Compiler keines der Symbole in den Headern verborgen, sodass ich keine Warnung mehr erhalte.
Was ist der Vorschlag dieser Warnmeldung? Ist es ein ernstes Problem? In welchen Situationen kann dies zu Problemen führen? Wie unterscheidet sich das Ausblenden von Namespace von fvisibility=hidden?

Niall Douglas
Bevor ich Ihre spezielle Frage beantworte, sollte ich für andere erwähnen, dass das Anwenden von Symbolsichtbarkeitsattributen pro Namespace eine GCC-spezifische Funktion ist. MSVC unterstützt nur dllexport für Klassen, Funktionen und Variablen, und wenn Sie möchten, dass Ihr Code portabel ist, müssen Sie dort mit MSVC übereinstimmen. Wie mein ursprünglicher Leitfaden zur GCC-Symbolsichtbarkeit (den Sie auf der GCC-Website verlinkt haben) darauf hinweist, kann die makrobasierte DLLexport-Maschinerie von MSVC leicht wiederverwendet werden, um etwas Ähnliches auf GCC zu erreichen “.
In Bezug auf Ihr spezifisches Problem ist GCC richtig, um Sie zu warnen. Wenn ein externer Benutzer versucht hat, den öffentlichen Typ Bar zu verwenden, muss er mit ziemlicher Sicherheit alles in Bar verwenden, einschließlich Bar::foo. Aus genau dem gleichen Grund müssen alle privaten Memberfunktionen sichtbar sein, obwohl sie privat sind. Viele Leute sind darüber überrascht, weil sie argumentieren, dass private Member-Funktionssymbole per Definition für niemanden zugänglich sind, aber sie vergessen, dass nur weil der Programmierer keinen Zugriff hat, dies nicht bedeutet, dass die Compiler nicht müssen Zugriff. Mit anderen Worten, private Memberfunktionen sind für Sie privat, aber nicht für den Compiler. Wenn sie in einer Header-Datei erscheinen, bedeutet dies im Allgemeinen, dass der Compiler Zugriff benötigt, selbst in einem anonymen Namespace (der nur für Programmierer anonym ist, nicht für Compiler, die dazu neigen, einen Hash des Inhalts als “echten” Namespace-Namen zu verwenden).
Das Ausblenden eines Namespace hat ganz andere Auswirkungen als -fvisibility=hidden. Dies liegt daran, dass GCC viele Symbole über die für einen bestimmten Typ hinaus ausspeist, z. B. für vtables, für type_info usw in denselben Prozess mit kollidierenden Symbolen, z. B. zwei gemeinsame Objekte, die mit verschiedenen Versionen von Boost erstellt wurden.
Ich schätze Ihre Versuche, die Probleme zu beheben, die durch die Sichtbarkeit von Symbolen in ELF verursacht werden, und die Folgen für defekte C++-Binärdateien und viel verlorene Programmierproduktivität. Sie können sie jedoch nicht beheben – sie sind Fehler in ELF selbst, das für C und nicht für C++ entwickelt wurde. Wenn es Sie tröstet, ich habe vor einigen Monaten ein internes BlackBerry-Whitepaper zu diesem Thema geschrieben, da Probleme mit der Sichtbarkeit von ELF-Symbolen für uns in BB10 genauso ein Problem darstellen wie für jedes große Unternehmen mit einer bedeutenden C++-Codebasis. Vielleicht sehen Sie also einige Lösungsvorschläge für C++17, insbesondere wenn die Implementierung der C++-Module von Doug Gregor gute Fortschritte macht.
Ihre Verwendung der Sichtbarkeitsattribute erscheint mir rückständig; Ich denke, Sie hätten bessere Ergebnisse mit -fvisibility=hidden und dem Hinzufügen von Sichtbarkeit “default” zum Namespace der Bibliotheksdeklaration, da die Schnittstelle der Bibliothek vermutlich eine Standardsichtbarkeit hat oder Sie sie nicht von Ihrer Anwendung aus verwenden können. Wenn Sie die Bibliotheksheader nicht ändern möchten, können Sie #pragma GCC-Sichtbarkeits-Push/Pop um Ihre #includes verwenden.
Wie Niall sagt, funktioniert das Markieren einzelner Memberfunktionen als Standard nicht, der gesamte Foo-Typ muss eine Standardsichtbarkeit haben, wenn er Teil der Benutzeroberfläche der Bibliothek ist.
.
2635000cookie-checkSymbolsichtbarkeit und Namespaceyes