Construyendo un ejemplo simple (Hello-World-Desque) de usar la opción de LD -rpath con $ origen
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?
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:
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
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).