¿Cómo especificar la preferencia de la ruta de la biblioteca?

96

Estoy compilando un programa en C ++ usando g++y ld. Tengo una .sobiblioteca que quiero usar durante la vinculación. Sin embargo, existe una biblioteca con el mismo nombre /usr/local/liby ldestá eligiendo esa biblioteca sobre la que estoy especificando directamente. ¿Cómo puedo arreglar esto?

Para los ejemplos siguientes, mi archivo de biblioteca es /my/dir/libfoo.so.0. Cosas que he probado que no funcionan:

  • mi comando g ++ es g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • agregando /my/diral principio o al final de mi $PATHvariable en`
  • agregar /my/dir/libfoo.so.0como argumento a g ++
Heinrich Schmetterling
fuente
1
¿Qué otros libfoo.*archivos existen y donde - .sow / o la .0, .a, etc, etc?
Alex Martelli

Respuestas:

94

Agregue la ruta a donde está su nueva biblioteca LD_LIBRARY_PATH(tiene un nombre ligeramente diferente en Mac ...)

Su solución debería funcionar con el uso de las -L/my/dir -lfooopciones, en tiempo de ejecución use LD_LIBRARY_PATH para apuntar a la ubicación de su biblioteca.

Cuidado con el uso de LD_LIBRARY_PATH - en resumen (desde el enlace):

..implicaciones ..:
Seguridad : ¿Recuerda que los directorios especificados en LD_LIBRARY_PATH se buscan antes (!) de las ubicaciones estándar? De esa manera, una persona desagradable podría hacer que su aplicación cargue una versión de una biblioteca compartida que contiene código malicioso. Esa es una de las razones por las que los ejecutables setuid / setgid descuidan esa variable.
Actuación: El cargador de enlaces tiene que buscar en todos los directorios especificados, hasta que encuentre el directorio donde reside la biblioteca compartida; para TODAS las bibliotecas compartidas, la aplicación está vinculada. ¡Esto significa muchas llamadas al sistema para abrir (), que fallarán con "ENOENT (No existe tal archivo o directorio)"! Si la ruta contiene muchos directorios, el número de llamadas fallidas aumentará linealmente, y puede saberlo desde el momento de inicio de la aplicación. Si algunos (o todos) los directorios están en un entorno NFS, el tiempo de inicio de sus aplicaciones puede ser realmente largo, ¡y puede ralentizar todo el sistema!
Inconsecuencia: Este es el problema más común. LD_LIBRARY_PATH obliga a una aplicación a cargar una biblioteca compartida a la que no estaba vinculada, y que probablemente no sea compatible con la versión original. Esto puede ser muy obvio, es decir, la aplicación falla, o puede conducir a resultados incorrectos, si la biblioteca seleccionada no hace lo que habría hecho la versión original. Especialmente este último es a veces difícil de depurar.

O

Use la opción rpath a través de gcc para enlazar: se usará la ruta de búsqueda de la biblioteca en tiempo de ejecución en lugar de buscar en el directorio estándar (opción gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Esto es bueno para una solución temporal. El vinculador primero busca bibliotecas en LD_LIBRARY_PATH antes de buscar en los directorios estándar.

Si no desea actualizar LD_LIBRARY_PATH de forma permanente, puede hacerlo sobre la marcha en la línea de comandos:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Puede comprobar lo que el vinculador de bibliotecas sabe sobre el uso (ejemplo):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

Y puede verificar qué biblioteca está usando su aplicación:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
StefanB
fuente
23
LD_LIBRARY_PATHse busca en tiempo de ejecución, en el tiempo de compilación que desea establecer LIBRARY_PATH. Ver gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren
1
Si su biblioteca es completamente diferente de la biblioteca del sistema, es decir, es la que siempre debe usar, use la solución rpath. LD_LIBRARY_PATH es un truco para realizar pruebas y no debería ser necesario para que un ejecutable funcione correctamente.
user2746401
1
es DYLD_LIBRARY_PATH para Mac
cbinder
Aquí hay un comando de muestra completo (para C) que funciona según esta respuesta:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
25

Ésta es una vieja pregunta, pero nadie parece haberla mencionado.

Tuviste suerte de que la cosa se vincule.

Necesitabas cambiar

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

a esto:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Su vinculador realiza un seguimiento de los símbolos que necesita resolver. Si lee la biblioteca primero, no tiene ningún símbolo necesario, por lo que ignora los símbolos que contiene. Especifique las bibliotecas después de las cosas que deben vincularse a ellas para que su vinculador tenga símbolos para encontrar en ellas.

Además, -lfoohace que busque específicamente un archivo con el nombre libfoo.ao libfoo.sosegún sea necesario. No libfoo.so.0. Por lo tanto, lnel nombre o el cambio de nombre de la biblioteca según corresponda.

Para citar la página de manual de gcc:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Agregar el archivo directamente a g++la línea de comando debería haber funcionado, a menos que, por supuesto, lo pusiera antes bar.cpp, haciendo que el enlazador lo ignore por no tener los símbolos necesarios, porque todavía no se necesitaban símbolos.

Michael Speer
fuente
22

Especificar la ruta absoluta a la biblioteca debería funcionar bien:

g++ /my/dir/libfoo.so.0  ...

¿Se acordó de eliminar -lfoouna vez que agregó la ruta absoluta?

R Samuel Klatchko
fuente
1
Esta solución también funcionó bien para mí, tratando de vincularme con una versión de Qt5 que no sea el paquete de desarrollo de distribución. Gracias.
wump
¿Cómo hacer que esto funcione para @símbolos versionados? Ejemplo mínimo: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
11

Como alternativa, puede usar las variables de entorno LIBRARY_PATHy CPLUS_INCLUDE_PATH, que indican respectivamente dónde buscar bibliotecas y dónde buscar encabezados ( CPATHtambién funcionará), sin especificar las opciones -L y -I.

Editar: CPATHincluye encabezado con -Iy CPLUS_INCLUDE_PATHcon -isystem.

Alexandre Hamez
fuente
¿Podría agregar un ejemplo de uso?
Hanna Khalil
export LIBRARY_PATH = /path/to/liben la misma sesión de consola donde está compilando
Alexandre Hamez
0

Si uno está acostumbrado a trabajar con DLL en Windows y le gustaría omitir los números de versión .so en linux / QT, agregar CONFIG += plugineliminará los números de versión. Para usar la ruta absoluta a .so, darle al enlazador funciona bien, como mencionó el Sr. Klatchko.

Pekka Lehtikoski
fuente