Frage

HINWEIS: Full Working Beispiel jetzt unten. Die ursprüngliche Frage folgt:

Ich habe Probleme mit LDs -rpath Parameter mit $ORIGIN.
Da ich kein vollständiges Beispiel finden konnte, dachte ich, ich würde versuchen, selbst eines zu schreiben, damit ich und andere es später verwenden können. Sobald ich es zum Laufen gebracht habe, werde ich es aufräumen.

ich gefragt danach vorher, aber ich denke, mein Beitrag war ein bisschen verwirrend.

Das Beispielprojekt erstellt eine gemeinsame Bibliothek und eine ausführbare Datei, die zu dieser Bibliothek verlinkt.
Es ist sehr klein (3 Dateien, 22 Zeilen inklusive Buildscript).
Sie können das Projekt aus herunterladen hier


Dateistruktur (vor dem Erstellen):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • make.sh

project/src/foo.cpp


int foo()
  { return 3; }

project/src/main.cpp


int foo();

#include <iostream>
int main()
  {
    std::cout << foo() << std::endl;
    return 0;
  }

project/make.sh


# Make directories:
mkdir -p -v obj
mkdir -p -v lib
mkdir -p -v run

# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/foo.sh obj/foo.o

# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../../lib' -Llib -l:foo.sh

Von dem project Verzeichnis, rennen make.sh (Stellen Sie sicher, dass es ausführbar ist).


Dateistruktur (nach dem Erstellen):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • obj/
      • foo.o
      • main.o
    • lib/
      • foo.so
    • run/
      • main.run
    • make.sh

run/main.run sollte jetzt laden lib/foo.sh bei der Ausführung von überall.


Probleme

Derzeit funktioniert dies nur teilweise.
Die Dateien kompilieren und verlinken OK, aber es kann nicht verknüpft werden, wenn sie aus einem Verzeichnis ausgeführt werden, außer außer project (Welches ist der Punkt der Übung).

Inspizieren main.run mit readelf -d zeigt an:
0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib]Was aussieht (ich hätte lieber es haben [foo.sh] als [lib/foo.sh] Aber ich werde das später beheben).

Afaict the $ORIGIN in -Wl,-rpath,'$ORIGIN/../../lib' meint project/run/main.run Also sollte dieser Rpath werden project/lib.

Ich habe versucht $ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../.., $ORIGIN/../../lib umsonst.

Hinweis: Ich benutze -l: Dies erfordert den vollständigen Bibliotheksfileinamen (unter anderem ist es einfacher, mit Variablen zu skriptieren, wenn alle Funktionen das gleiche Namensformat annehmen).

Weiß jemand, warum das nicht funktioniert?
Oder hat oder kennt man abwechselnd ein vollständiges Arbeitsbeispiel?

War es hilfreich?

Lösung

(Ich würde lieber haben [foo.sh] als [lib/foo.sh] Aber ich werde das später beheben).

Es gibt das meiste Problem: die / Im Namen hindert der dynamische Linker die RPATH -Magie.

(Ihr RPath ist auch falsch. Denken Sie darüber nach: Wenn Sie derzeit im Verzeichnis wären, wo Ihre ausführbare Datei ist, wie würden Sie in das Verzeichnis kommen, wo Ihre Bibliothek ist? cd ../lib. Ihr Rpath sollte also sein $ORIGIN/../lib.)

Wenn Sie Ihr Objekt als erstellt haben libfoo.so und verbunden mit -Llib -lfoo, Der Linker würde herausfinden, was Sie beabsichtigt haben, und das Richtige tun. Aber wenn Sie ungewöhnliche Namenskonventionen verwenden, müssen Sie es helfen:

  1. Ändern Sie die Link -Zeile für die Bibliothek, um den Sonamen Ihrer Bibliothek explizit festzulegen foo.sh:

    g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o

  2. Fix den RPath:

    g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib' -Llib -l:foo.sh

Es ist nützlich zu laufen ldd main/main.run um zu sehen, was los ist. In Ihrem ursprünglichen fehlgeschlagenen Fall sehen Sie so etwas wie:

    lib/foo.sh (0xNNNNNNNN)

(das Fehlen eines jeden => /some/resolved/path zeigen, dass es keine Pfadauflösung getan hat). Im festen Fall sehen Sie so etwas wie:

    foo.sh => /your/path/to/run/../lib/foo.sh (0xNNNNNNNN)

Andere Tipps

Dies ist ein Beispiel für das Verknüpfen von relativem Pfaden (mit LD) durch Verwendung $ORIGIN in einem (n rpath.

rpath ist ein Pfad (oder eine Reihe von Pfaden), die in Binärdateien (gemeinsame Bibliotheken (. SO) und ausführbare Dateien) eingebettet sind.
Diese Pfade sind die wichtigsten Suchpfade für die gemeinsam genutzten Bibliotheken, mit denen die Binärdatei zur Laufzeit verknüpft werden muss.

$ Origin ist ein potenzielles Startverzeichnis für einen RPATH -Pfad. Es wird in das Verzeichnis gelöst, das die ausführende Datei enthält. (z.B: $ORIGIN/lib)

Das Beispielprojekt erstellt eine gemeinsame Bibliothek und eine ausführbare Datei, die mit dieser Bibliothek mithilfe dieser Bibliothek verlinkt rpath und $ORIGIN.
Sie können das Projekt aus herunterladen hier.


Dateistruktur (vor dem Erstellen):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • make.sh

project/src/foo.cpp


int foo()
  { return 3; }

project/src/main.cpp


int foo();

#include <iostream>
int main()
  {
    std::cout << foo() << std::endl;
    return 0;
  }

project/make.sh


# Make directories:
mkdir -p -v obj
mkdir -p -v lib/dir
mkdir -p -v run

# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/dir/foo.so -Wl,-soname,foo.so obj/foo.o

# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Llib/dir -l:foo.so

Von dem project Verzeichnis, rennen make.sh (Wenn es nicht läuft, stellen Sie sicher, dass make.sh hat Berechtigungen ausführend).

Wenn alles in Ordnung ist, main.run sollte jetzt laden lib/dir/foo.so bei der Ausführung unabhängig vom absoluten Weg zu project (Sie können es auf überall verschieben) und unabhängig vom aktuellen Arbeitsverzeichnis (Sie können es von überall aus ausführen).


Anmerkungen:

  • -fPIC Weisen Sie den Compiler an, verlängerte Objektdateien zu erstellen (Objektdateien in gemeinsam genutzte Bibliotheken müssen umschiebbar sein).
  • -Wl,-soname,<NAME> Einbettungen <NAME> in die erzeugte Bibliothek. Dies sollte mit dem Namen übereinstimmen, den Sie für die angeben -l oder -l: Optionen beim Verknüpfen mit dieser Bibliothek.
  • -Wl,-rpath,'<PATH>' Einbettungen <PATH> In die generierte Bibliothek als Laufzeitbibliothekssuche (oder RPATH - siehe oben).
  • -L fügt dem Weg zum Weg hinzu Bauzeit Liste der Bibliothekssuche. (Notiz: rpath ist bei der Bauzeit irrelevant, -L ist zur Laufzeit irrelevant).
  • -l: fügt den Dateinamen (ohne Pfad) einer Bibliothek hinzu, gegen die sie verlinken. (Ähnlich zu -l, außer -l: erfordert den vollständigen Dateinamen.

Dateistruktur (nach dem Erstellen):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • obj/
      • foo.o
      • main.o
    • lib/
      • dir/
        • foo.so
    • run/
      • main.run
    • make.sh

Hinweis: Ich benutze -l: Dies erfordert den vollständigen Bibliotheksfileinamen (unter anderem ist es einfacher, mit Variablen zu skriptieren, wenn alle Funktionen das gleiche Namensformat annehmen).
Es ist häufiger zu verwenden -l, wobei -l<NAME> bezeichnet lib.so.

Einschränkungen

Soweit ich weiß (korrigiere mich, wenn ich falsch bin), gibt es keine Möglichkeit, eine Bibliothek innerhalb eines Unterverzeichnisses innerhalb eines Suchpfads hinzuzufügen (mit Ausnahme dieses Verzeichnisses als Unterzustand). Dies gilt für beide Bauzeiten (-L) und Laufzeit (-rpath) Suchpfade.

Wenn Sie also zwei Bibliotheken mit demselben Namen, aber an verschiedenen Orten haben, können Sie beide nicht verknüpfen. (Ich hoffe, ich liege falsch oder das wird repariert).

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