Frage

Ich habe drei Header-Dateien in meinem Projekt die Objekte beschreiben Rational, Complex, Und RubyObject.Die ersten beiden sind Vorlagen.Alle können mithilfe von Kopierkonstruktoren, die in den Header-Dateien definiert sind, ineinander konvertiert werden – mit Ausnahme derjenigen, die konstruieren Rational Und Complex aus const RubyObject&s, die definiert sind in einer Quelldatei.

Notiz: Diese Definitionen sind notwendigerweise vorhanden.Wenn sie alle Gehen Sie in die Kopfzeilen, Sie erhalten zirkuläre Abhängigkeit.

Vor einiger Zeit bin ich zufällig darauf gestoßen einige ungelöste Symbolfehler mit den beiden in der Quelldatei definierten Kopierkonstruktoren.Ich konnte die folgende Funktion in die Quelldatei einfügen

void nm_init_data() {
    nm::RubyObject obj(INT2FIX(1));
    nm::Rational32 x(obj);
    nm::Rational64 y(obj);
    nm::Rational128 z(obj);
    volatile nm::Complex64 a(obj);
    volatile nm::Complex128 b(obj);
}

und dann Anruf nm_init_data() vom Bibliothekseinstiegspunkt in der Hauptquelldatei.Dadurch wurde eine ordnungsgemäße Verknüpfung dieser Symbole erzwungen.

Leider habe ich kürzlich GCC aktualisiert und die Fehler sind wieder aufgetreten.Tatsächlich scheint es mit GCC 4.6 an einer etwas anderen Stelle zu passieren (z. B. auf Travis-CI).

Aber es ist kein versionenspezifisches Problem (wie ich vorher gedacht hatte).Wir sehen es weiter Das Ubuntu-basierte System von Travis CI, auf dem GCC 4.6 ausgeführt wird.Auf einem Ubuntu-Rechner mit GCC 4.8.1 oder 4.8.2 sehen wir es jedoch nicht.Aber wir Tun Sehen Sie es auf einem Mac OS X-Rechner mit 4.8.2 – und nicht auf dem gleichen Rechner mit 4.7.2.Auch das Ausschalten der Optimierung scheint nicht zu helfen.

Wenn ich renne nm In meiner Bibliothek ist das Symbol definitiv undefiniert:

$ nm tmp/x86_64-darwin13.0.0/nmatrix/2.0.0/nmatrix.bundle |grep RationalIsEC1ERKNS
                 U __ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
00000000004ca460 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache
00000000004ca458 D __ZZN2nm8RationalIsEC1ERKNS_10RubyObjectEE18rb_intern_id_cache_0

Ich bin mir nicht sicher, warum es zwei definierte Einträge gibt, die dem undefinierten Symbol untergeordnet sind, aber ich weiß auch nicht so viel über Compiler, wie ich gerne hätte.

Es sieht auch so aus, als ob der Kopierkonstruktor ein undefiniertes Symbol für jede Version von ist Rational Vorlage:

__ZN2nm8RationalIiEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIsEC1ERKNS_10RubyObjectE
__ZN2nm8RationalIxEC1ERKNS_10RubyObjectE

„Nun, das ist seltsam“, dachte ich."Complex64 Und Complex128 werden darin auch genannt nm_init_data Funktion, aber beide werden ordnungsgemäß aufgelöst – und sind nicht in der aufgeführt nm -u Ausgabe.“ Also habe ich versucht hinzuzufügen volatile Auch vor der Rational-Kopierkonstruktion dachte ich, dass der Compiler vielleicht etwas optimierte, was wir nicht optimieren wollten.Aber das hat das Problem leider auch nicht behoben.Dies geschah mit einer Einschränkung:

void nm_init_data() {
  volatile VALUE t = INT2FIX(1);
  volatile nm::RubyObject obj(t);
  volatile nm::Rational32 x(const_cast<nm::RubyObject&>(obj));
  volatile nm::Rational64 y(const_cast<nm::RubyObject&>(obj));
  volatile nm::Rational128 z(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex64 a(const_cast<nm::RubyObject&>(obj));
  volatile nm::Complex128 b(const_cast<nm::RubyObject&>(obj));
}

Die Einschränkung besteht darin, dass ich jetzt genau den gleichen Fehler erhalte, jedoch für die komplexen Objekte.Argh!

dyld: lazy symbol binding failed: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
  Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
  Expected in: flat namespace

dyld: Symbol not found: __ZN2nm7ComplexIdEC1ERKNS_10RubyObjectE
  Referenced from: /Users/jwoods/Projects/nmatrix/lib/nmatrix.bundle
  Expected in: flat namespace

Das ist völlig absurd.Hier sind die Definitionen für diese beiden Funktionen in derselben Quelldatei wie die nm_init_data() Funktion:

namespace nm {
  template <typename Type>
  Complex<Type>::Complex(const RubyObject& other) {
    // do some things
  }

  template <typename Type>
  Rational<Type>::Rational(const RubyObject& other) {
    // do some other things
  }
} // end of namespace nm

Hinweis: Erwähnenswert ist, dass der Fehler nicht auftritt, wenn nm_init_data() wird aufgerufen (d. h. wenn die Bibliothek geladen wird).Dies geschieht viel später, während eines weiteren Aufrufs dieser problematischen Funktionen.

Wie kann ich dieses Problem ein für alle Mal beheben, und andere mögen es?

War es hilfreich?

Lösung

Sie behaupten Folgendes, was ich bezweifle.

Diese Definitionen sind notwendigerweise vorhanden.Wenn sie alle in den Headern stehen, entsteht eine zirkuläre Abhängigkeit.

In den meisten Fällen können Sie eine solche zirkuläre Verschränkung lösen, indem Sie Ihren Code in eine zusätzliche .hpp-Datei aufteilen, die zusammen mit der Klassendefinition, die die Vorlagendefinitionen enthält, an allen benötigten Stellen eingefügt wird.

Wenn Ihr Code eine echte zirkuläre Abhängigkeit aufweist, konnte er nicht kompiliert werden.Wenn Ihre Abhängigkeiten zirkulär zu sein scheinen, müssen Sie normalerweise genauer hinschauen und auf Methodenebene gehen und prüfen, welche davon beide Typen zum Kompilieren erfordern würden.

Es könnte also sein, dass Ihre Typen einander verwenden und dann alle in einer .cpp-Datei kompilieren (z. B.über drei .hpp-Includes).Oder es gibt nur Zeiger auf einen anderen Typ, dann verwenden Sie Vorwärtsdeklarationen, um sicherzustellen, dass alle Vorlagen aufgelöst werden.Oder drittens: Sie haben eine Methode, die vorwärts und eine rückwärts abhängig ist. Dann fügen Sie die eine Art in eine Datei ein, die anderen in eine andere, und schon ist alles wieder in Ordnung.

Darüber hinaus sollten Sie anscheinend eine Vorwärtsdeklaration für Ihre fehlenden Artikel verwenden.Ich würde nach der Definition der Funktion etwa Folgendes erwarten.Z.B.:

template nm::Complex<nm::RubyObject>::Complex(const nm::RubyObject& other);

Andere Tipps

Rational, Complex...sind Vorlagen

Konstruktoren kopieren...werden in den Header-Dateien definiert – mit Ausnahme derjenigen, die erstellen Rational Und Complex aus const RubyObject&S, die in einer Quelldatei definiert sind.

Und darin liegt Ihr Problem.Seit Rational Und Complex sind Vorlagen, alle Ihre Methoden müssen in Ihrer Header-Datei verfügbar sein.

Wenn dies nicht der Fall ist, können Sie manchmal damit durchkommen, abhängig von der Reihenfolge, in der die Dinge aufgerufen werden, und der Reihenfolge, in der die Dinge verknüpft werden – aber häufiger erhalten Sie seltsame Fehler bei undefinierten Symbolen, die Genau das passiert hier.

Verschieben Sie einfach die Definitionen von Rational(const RubyObject&) Und Complex(const RubyObject&) in die jeweiligen Header und alles sollte einfach funktionieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top