exemple d'utilisation de -rpath option de construction ld simple (bonjour-monde esque) avec $ ORIGIN

StackOverflow https://stackoverflow.com/questions/6311016

  •  26-10-2019
  •  | 
  •  

Question

Note: Exemple de travail complète maintenant ci-dessous. suite originale question:

Je vais avoir des problèmes en utilisant le paramètre -rpath de ld avec $ORIGIN.
Comme je ne pouvais pas trouver un exemple complet, je pensais que je vais essayer d'écrire moi-même, de sorte que moi et d'autres de pouvoir l'utiliser plus tard. Une fois que je l'obtiens, je vais travailler range vers le haut.

Je demandé à ce sujet avant , mais Je pense que mon poste était un peu déroutant.

L'exemple de projet construit une bibliothèque partagée et un exécutable que les liens vers ladite banque.
Il est très petit (3 fichiers, 22 lignes) y compris buildscript.
Vous pouvez télécharger le projet de


Structure de fichier (avant la construction):

  • 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

A partir du répertoire project, exécutez make.sh (assurez-vous qu'il est exécutable).


Structure de fichiers (après la construction):

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

run/main.run devrait maintenant charger lib/foo.sh sur l'exécution, où que vous soyez.

Problèmes

À l'heure actuelle, cela ne fonctionne que partiellement.
Les fichiers Compilez et liez OK, mais il ne parvient pas à lien lorsqu'il est exécuté à partir de tout répertoire sauf project (qui est le point de l'exercice).

main.run avec des spectacles Contrôle de readelf -d:
0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib] Ce qui ressemble beaucoup (je préfère avoir [foo.sh] que [lib/foo.sh] mais je vais arranger cela plus tard).

AFAICT le $ORIGIN dans des moyens de -Wl,-rpath,'$ORIGIN/../../lib' project/run/main.run donc ce rpath devrait devenir project/lib.

J'ai essayé $ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../.., $ORIGIN/../../lib en vain.

Note: J'utilise -l: ce qui nécessite le nom du fichier de bibliothèque complète (entre autres raisons, il est plus facile de script avec des variables lorsque toutes les fonctions prennent le même format de nom).

Quelqu'un sait pourquoi cela ne fonctionne pas?
Ou alternativement, quelqu'un at-il ou si vous connaissez un exemple de travail complet?

Était-ce utile?

La solution

(je préfère avoir [foo.sh] que [lib/foo.sh] mais je vais arranger cela plus tard).

Il y a plus de votre problème. Le / au nom arrête l'éditeur de liens dynamique de faire la magie rpath

(Votre rpath est faux aussi Pensez-y.? De la coquille, si vous étiez actuellement dans le répertoire où votre exécutable est, comment voulez-vous obtenir dans le répertoire où votre bibliothèque est Ici, vous aurez besoin de cd ../lib . Ainsi, votre rpath devrait être $ORIGIN/../lib.)

Si vous avez construit votre objet comme libfoo.so et en liaison avec un -Llib -lfoo, l'éditeur de liens fonctionnerait ce que vous aviez l'intention, et faire la bonne chose. Mais si vous allez utiliser les conventions de nommage inhabituelles, vous devrez l'aider à sortir:

  1. Modifier la ligne de liaison de la bibliothèque pour définir explicitement la SONAME pour votre bibliothèque juste foo.sh:

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

  2. Fixer le rpath:

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

Il est utile d'exécuter ldd main/main.run pour voir ce qui se passe. Dans votre cas de défaut d'origine, vous verrez quelque chose comme:

    lib/foo.sh (0xNNNNNNNN)

(l'absence de => /some/resolved/path montrant qu'il ne se fait pas une résolution de chemin). Dans le cas fixe, vous verrez quelque chose comme:

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

Autres conseils

Ceci est un exemple de chemin relatif de liaison (avec ld) en utilisant $ORIGIN dans un rpath.

rpath est un chemin (ou un ensemble de chemins) intégrés dans des fichiers binaires (bibliothèques partagées (.so) et executables).
Ces chemins sont les chemins de recherche avant tout pour les bibliothèques partagées binaire doit être liée à l'exécution.

$ ORIGIN est un répertoire de démarrage potentiel pour un chemin rpath. Il résout le répertoire contenant le fichier d'exécution. (Par exemple: $ORIGIN/lib)

L'exemple de projet construit une bibliothèque partagée et un exécutable qui liens vers cette bibliothèque à l'aide rpath et $ORIGIN.
Vous pouvez télécharger le projet de .


Structure de fichier (avant la construction):

  • 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

A partir du répertoire project, exécutez make.sh (si elle ne fonctionne pas, assurez-vous make.sh a des autorisations d'exécution).

Si tout va bien, main.run devrait maintenant charger lib/dir/foo.so sur l'exécution, quel que soit le chemin absolu project (vous pouvez le déplacer partout), et quel que soit le répertoire de travail courant (vous pouvez l'exécuter partout).


Notes:

  • -fPIC indique au compilateur pour créer des fichiers translatables (fichiers d'objets dans la construction des bibliothèques partagées doivent être repositionnable).
  • -Wl,-soname,<NAME> intègre <NAME> dans la bibliothèque générée. Cela devrait correspondre au nom que vous fournissez pour les options de -l ou -l: lors de la liaison à cette bibliothèque.
  • -Wl,-rpath,'<PATH>' Intègre <PATH> dans la bibliothèque générée en tant que chemin de recherche de bibliothèque d'exécution (ou rpath - voir ci-dessus).
  • -L ajoute un chemin vers le chemin de recherche de bibliothèque build-temps liste. . (Note: rpath est hors de propos au moment de la construction, -L n'est pas pertinent à l'exécution)
  • -l: ajoute le nom du fichier (sans le chemin) d'une bibliothèque de lien contre. (Similaire à -l, à l'exception -l: requiert le nom complet.

Structure de fichiers (après la construction):

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

Note:. J'utilise -l: ce qui nécessite le nom du fichier de bibliothèque complète (entre autres raisons, il est plus facile de script avec des variables lorsque toutes les fonctions prennent le même format de nom)
Il est plus courant d'utiliser -l, dans lequel -l<NAME> désigne lib.so.

Limites

Pour autant que je suis au courant (corrigez-moi si je me trompe) il n'y a pas moyen d'ajouter une bibliothèque dans un sous-répertoire dans un chemin de recherche (sauf pour ajouter ce répertoire comme un sous-chemin). Cela est vrai pour les construire à temps (-L) et d'exécution (-rpath) chemins de recherche.

si vous avez deux bibliothèques avec le même nom, mais des endroits différents, vous ne serez pas en mesure de les relier à la fois. (J'espère que je me trompe ou que cela devient fixe).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top