Construyendo un ejemplo simple (Hello-World-Desque) de usar la opción de LD -rpath con $ origen

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

  •  26-10-2019
  •  | 
  •  

Pregunta

Nota: Ejemplo de trabajo completo ahora a continuación. La pregunta original sigue:

Tengo problemas para usar LD -rpath parámetro con $ORIGIN.
Como no pude encontrar un ejemplo completo, pensé en tratar de escribir uno yo mismo, para que yo y otros podamos usarlo más tarde. Una vez que lo haga funcionar, lo ordenaré.

yo preguntó sobre esto antes, pero creo que mi publicación fue un poco confusa.

El proyecto de ejemplo construye una biblioteca compartida y un ejecutable que se vincula a dicha biblioteca.
Es muy pequeño (3 archivos, 22 líneas include BuildScript).
Puedes descargar el proyecto desde aquí


Estructura de archivo (antes de la construcción):

  • 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

Desde el project directorio, ejecutar make.sh (Asegúrese de que sea ejecutable).


Estructura de archivo (después de la construcción):

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

run/main.run ahora debería cargar lib/foo.sh en ejecución, desde cualquier lugar.


Problemas

Actualmente, esto solo funciona en parte.
La compilación de archivos y el enlace OK, pero no se enlaza cuando se ejecuta desde cualquier directorio, excepto project (cuál es el punto del ejercicio).

Inspección main.run con readelf -d Mostrar:
0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib]Que parece cercano (prefiero tener [foo.sh] que [lib/foo.sh] Pero lo arreglaré más tarde).

Afaict the $ORIGIN en -Wl,-rpath,'$ORIGIN/../../lib' medio project/run/main.run Entonces este rpath debería convertirse project/lib.

Yo he tratado $ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../.., $ORIGIN/../../lib en vano.

Nota: Estoy usando -l: que requiere el nombre de archivo completo de la biblioteca (entre otras razones, es más fácil escribir con variables cuando todas las funciones toman el mismo formato de nombre).

¿Alguien sabe por qué esto no funciona?
O alternativamente, ¿alguien tiene o conoce un ejemplo de trabajo completo?

¿Fue útil?

Solución

(Yo preferiría tener [foo.sh] que [lib/foo.sh] Pero lo arreglaré más tarde).

Hay la mayor parte de tu problema: el / En el nombre, evita que el enlazador dinámico haga la magia rpath.

(Su rpath también está mal. Piénselo: desde el shell, si actualmente estuviera en el directorio donde está su ejecutable, ¿cómo llegaría al directorio donde está su biblioteca? Aquí, necesitaría cd ../lib. Entonces tu rpath debería ser $ORIGIN/../lib.)

Si construyó su objeto como libfoo.so y vinculado con -Llib -lfoo, el enlazador resolvería lo que pretendía y haría lo correcto. Pero si vas a usar convenciones de nombres inusuales, tendrás que ayudarlo:

  1. Cambie la línea de enlace para la biblioteca para establecer explícitamente el soname para su biblioteca a solo foo.sh:

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

  2. Arregle el rpath:

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

Es útil ejecutar ldd main/main.run Para ver lo que está pasando. En su caso de falla original, verá algo como:

    lib/foo.sh (0xNNNNNNNN)

(la falta de cualquier => /some/resolved/path mostrando que no ha hecho ninguna resolución de ruta). En el caso fijo, verá algo como:

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

Otros consejos

Este es un ejemplo de vinculación de rango relativo (con LD) usando $ORIGIN en un rpath.

rpath es una ruta (o conjunto de rutas) incrustada en archivos binarios (bibliotecas compartidas (.so) y ejecutables).
Estas rutas son las rutas de búsqueda más importantes para las bibliotecas compartidas que el binario debe estar vinculado en tiempo de ejecución.

$ Origen es un directorio de inicio potencial para una ruta RPATH. Se resuelve en el directorio que contiene el archivo de ejecución. (p.ej: $ORIGIN/lib)

El proyecto de ejemplo construye una biblioteca compartida y un ejecutable que vincula a dicha biblioteca usando rpath y $ORIGIN.
Puedes descargar el proyecto desde aquí.


Estructura de archivo (antes de la construcción):

  • 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

Desde el project directorio, ejecutar make.sh (Si no se ejecuta, asegúrese make.sh tiene permisos de ejecución).

Si todo salió bien main.run ahora debería cargar lib/dir/foo.so en ejecución, independientemente del camino absoluto a project (Puede moverlo a cualquier lugar), y independientemente del directorio de trabajo actual (puede ejecutarlo desde cualquier lugar).


Notas:

  • -fPIC instruye al compilador que cree archivos de objetos reubicables (los archivos de objetos construidos en bibliotecas compartidas deben ser reubicables).
  • -Wl,-soname,<NAME> incrustaciones <NAME> en la biblioteca generada. Esto debería coincidir con el nombre que suministra para el -l o -l: opciones al vincular a esta biblioteca.
  • -Wl,-rpath,'<PATH>' incrustaciones <PATH> en la biblioteca generada como una ruta de búsqueda de biblioteca de tiempo de ejecución (o rpath - ver arriba).
  • -L agrega un camino al Tiempo de construcción Lista de ruta de búsqueda de biblioteca. (Nota: rpath es irrelevante en el tiempo de construcción, -L es irrelevante en tiempo de ejecución).
  • -l: agrega el nombre de archivo (sin ruta) de una biblioteca para vincular. (Similar a -l, excepto -l: requiere el nombre de archivo completo.

Estructura de archivo (después de la construcción):

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

Nota: Estoy usando -l: que requiere el nombre de archivo completo de la biblioteca (entre otras razones, es más fácil escribir con variables cuando todas las funciones toman el mismo formato de nombre).
Es más común usar -l, por lo que -l<NAME> denota lib.so.

Limitaciones

Hasta donde sé (corrígeme si me equivoco) no hay forma de agregar una biblioteca dentro de un subdirectorio dentro de una ruta de búsqueda (excepto para agregar ese directorio como un subpatamento). Esto es cierto tanto para el tiempo de construcción (-L) y tiempo de ejecución (-rpath) rutas de búsqueda.

Entonces, si tiene dos bibliotecas con el mismo nombre pero diferentes ubicaciones, no podrá vincularlas a ambas. (Espero estar equivocado o que esto se solucione).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top