La diferencia entre -L, -rpath y -rpath-link

Difference Between L

Hay mucha información sobre la descripción de estos tres parámetros, pero después de leerla, todavía me siento vaga y no puedo distinguir la diferencia entre ellos. Este artículo utilizará métodos experimentales para explorar las diferencias entre estos tres parámetros.

1. Tres archivos .c



1.1 mundo.c



|_+_|
  1. #incluir
  2. vacío mundo(vacío) {
  3. printf('mundo. n')
  4. }
1.2 hola.c
|_+_|
  1. #incluir& ltstdio.h & gt
  2. vacío mundo(vacío)
  3. vacío Hola(vacío) {
  4. printf('hola n')
  5. mundo()
  6. }
1.3 prueba.c|_+_|
  1. vacío principal(vacío) {
  2. Hola()
  3. }
2. Genere una biblioteca dinámica

Referirse a ' Biblioteca estática de Linux y producción de biblioteca dinámica 》, Genera bibliotecas dinámicas desde hello.cy world.c respectivamente



|_+_|
  1. ubuntu $ gcc -cHola.cmundo.c
  2. ubuntu $ gcc -shared -o libhello.so hello.o
  3. ubuntu $ gcc -shared -o libworld.so world.o

En este momento, los archivos generados y sus dependencias son los siguientes:


Se puede ver en la figura anterior que libhello.so y libworld dependen de linux-gate.so.1, libc.so.6 y /lib/ld-linux.so.2, y las rutas de estas tres bibliotecas son libhello.so y libworld.so codificados de forma rígida (=> la parte derecha).



Sin embargo, aunque la función libworld.so se llama en libhello.so, esta relación no se muestra en la figura anterior. Para hacer que libhello.so dependa de libworld.so, enlace a libworld.so al generar libhello.so:

|_+_|En este momento, use ldd para verificar las dependencias de libhello.so:


Como puede verse en la figura anterior, en este momento libhello.so ya depende de libworld.so.

3. Compile test.c

3,1 -L

Dado que test.c depende directamente de libhello.so, use -lhello -L

|_+_|Los resultados son los siguientes:

Se puede ver en la figura anterior que libhello.so se ha encontrado en la ruta especificada por -L, pero libhello.so también requiere libworld.so. Aunque está en el mismo directorio, no hay forma de encontrar libworld.so automáticamente.

Entonces, ¿puedes usar -lworld para vincular libworld.so a test.c también? Intentemos a continuación:

|_+_|

No se informa ningún error, a.out se generó correctamente.

Ejecute a.out y use ldd para ver las dependencias de a.out:

Se puede ver en la figura anterior que aunque libworld.so está vinculado a a.out usando el parámetro -lworld, lo anterior solo muestra que a.out depende de libhello.so. Dado que no se puede encontrar la ruta a libhello.so (=> no encontrado), es necesario establecer la variable de entorno LD_LIBRARY_PATH

|_+_|Ejecute a.out nuevamente y use el comando ldd para ver la biblioteca dependiente de a.out:

Como puede verse en la figura anterior, libhello.so se ha encontrado a través de la variable de entorno LD_LIBRARY_PATH, y libworld.so también aparece en la dependencia de a.out!

Conclusión: -L especifica la ruta de la biblioteca en el momento del enlace, la ruta del archivo ejecutable generado en la biblioteca en tiempo de ejecución está determinada por LD_LIBRARY_PATH Especificación de variables de entorno.

3.2 -rpath

De acuerdo con la sugerencia en la primera imagen de 3.1, dado que libhello.so depende de libworld.so, solo se puede especificar con -rpath o -rpath-link. Utilice -rpath primero.

Primero borre la variable de entorno LD_LIBRARY_PATH, luego vuelva a compilar test.cy lleve el parámetro -rpath:

|_+_|
  1. ubuntu $ export LD_LIBRARY_PATH =
  2. ubuntu $ gcc test.c -lhello -L. -Wl, -rpath.
Ejecute a.out y use el comando ldd para ver las dependencias de a.out:


Se puede ver en la figura anterior que aunque no hay un enlace explícito a libworld.so, libworld.so todavía aparece en la dependencia de a.out.

Además, aunque LD_LIBRARY_PATH se ha borrado, a.out todavía se puede ejecutar, lo que muestra que la ruta de la biblioteca se ha compilado en a.out. Cabe señalar que las rutas de libhello.so y libworld.so se encuentran a través de la ruta especificada por -rpath.

3.2.1 Experimento 1

En este momento, ¿qué pasará si se cambian las rutas de libhello.so y libworld.so? Hagamos un experimento a continuación.

Cree un directorio lib_tmp y luego mueva libhello.so y libworld.so a este directorio.

|_+_|
  1. ubuntu $ mdir lib_tmp
  2. ubuntu $ mv libhello.so lib_tmp /
  3. ubuntu $ mv libworld.so lib_tmp /
En este momento, cuando se vuelve a ejecutar a.out, indica que no se puede encontrar la biblioteca dinámica. Utilice el comando ldd para ver la ruta de la biblioteca de a.out:


Como se puede ver en el círculo rojo de la figura anterior, la ruta de libhello.so no se encuentra y libworld.so no aparece en ella. Esto es lo mismo que 3.1.

La razón es encontrar libhello.so primero y luego libworl.so, porque libhello.so depende de libworld.so, no a.out depende de libworld.so.

Se puede ver que después de usar el parámetro -rpath para especificar la ruta de la biblioteca, la ruta de la biblioteca dependiente del archivo ejecutable generado no es fija. En su lugar, primero encontrará la biblioteca dependiente en la ruta especificada por -rpath. Si no se puede encontrar, todavía informará al fondo no.

Entonces, en este momento, ¿LD_LIBRARY_PATH afecta a a.out? A continuación, establezca LD_LIBRARY_PATH en la ruta donde se encuentran libhello.so y libworld.so actuales

|_+_|Ejecute a.out nuevamente y use ldd para ver la ruta de la biblioteca dependiente de a.out en este momento:


Se puede ver en la imagen de arriba que LD_LIBRARY_PATH todavía funciona. Puede verse en la figura anterior que el efecto de especificar la ruta con -rpath es el mismo.

3.2.2 Experimento 2

Borre LD_LIBRARY_PATH, luego mueva libhello.so a lib_tmp, mientras que libworld.so permanece en el directorio de documentos.

Ejecute a.out y use ldd para ver la biblioteca dependiente de a.out en este momento:


Se puede ver en la imagen de arriba que libhello.so no se puede encontrar. En este momento, especifique la ruta de LD_LIBRARY_PATH como la ruta donde se encuentra libhello.so:

|_+_|Ejecute a.out nuevamente y use ldd para ver sus bibliotecas dependientes:

Como puede ver en la imagen de arriba, todo ha vuelto a la normalidad. En este momento, libhello.so se encuentra a través de LD_LIBRARY_PATH, y libworld.so se encuentra a través de la ruta especificada por -rpath.

3.2.3 Revisión

De hecho, después de probar, en la sección 3.1, si primero especifica el valor de LD_LIBRARY_PATH como la ruta donde se encuentran libhello.so y libworld.so, y luego compila test.c (ejecute el primer comando de compilación en la sección 3.1), puede compilar, y no informará el error de la primera imagen en la sección 3.1. En otras palabras, LD_LIBRARY_PATH no solo especifica la ruta de la biblioteca del archivo ejecutable, sino que también especifica la ruta en la que la biblioteca depende de otras bibliotecas.

3.2.4 Conclusión

Una vez que no se especifica el parámetro -rpath, la variable de entorno LD_LIBRARY_PATH se descarta, solo se agrega una ruta de biblioteca dependiente opcional.

3.3 -rpath-link

Primero borre el valor de LD_LIBRARY_PATH, luego mueva libworld.so al directorio lib_tmp y libhello.so permanezca en el directorio de documentos, use el siguiente comando para compilar test.c:

|_+_|Ejecute a.out y use ldd para ver la biblioteca dependiente de a.out:


No se esperaba que se pudiera encontrar libhello.so. Lo siguiente especifica el valor de LD_LIBRARY_PATH como la ruta de libhello.so, y luego ejecuta a.out y verifica las dependencias de a.out:


Se puede ver en la figura anterior que libhello.so se ha encontrado a través de LD_LIBRARY_PATH, pero libworld.so no está en la ruta especificada por LD_LIBRARY_PATH, y a.out no incluye la ruta de la biblioteca al compilar, por lo que no puede ser encontró. Esta

En comparación con 3.2.2, podemos concluir que tanto -rpath como -rpath-link pueden especificar la ruta de la biblioteca al vincular, pero cuando se ejecuta el archivo ejecutable, la ruta especificada por -rpath-link ya no es válida (el vinculador no no cambiar la ruta de la biblioteca se incluye en el archivo ejecutable), y la ruta especificada por -rpath sigue siendo válida (porque el vinculador ha incluido la ruta de la biblioteca en el archivo ejecutable).

Finalmente, independientemente de si se usa -rpath o -rpath-link, LD_LIBRARY_PATH sigue siendo válido.

4. El manual del hombre para el comando ld

4.1 -rpath = dir

|_+_|
  1. Agregar un directorioala ruta de búsqueda de la biblioteca en tiempo de ejecución. Estaesusadocuandovincular un ejecutable ELFcon compartidoobjetos.
  2. Todos los argumentos -rpath están concatenadosyaprobadoael enlazador en tiempo de ejecución, que los usaalocalizarcompartidoobjetos en
  3. tiempo de ejecución. El -rpathopción esTambién usadocuandolocalizandocompartidoobjetos que se necesitanpor compartidoobjetos explícitamente
  4. incluidoenel enlace ver la descripcióndeel -rpath-linkopción.Si-rpathes nousadocuandovincular un ELF
  5. ejecutable, el contenidodela variable de entorno'LD_RUN_PATH'se utilizarásiesoesdefinido.
  6. El -rpathopcióntambién se puede utilizarenSunOS.Por defecto,enSunOS, el enlazador formará una ruta de búsqueda en tiempo de ejecuciónde
  7. todas las opciones -Lesdado.Siun -rpathopción esutilizado, la ruta de búsqueda en tiempo de ejecución se formará exclusivamenteusando
  8. las opciones -rpath, ignorando las opciones -L. Esto puede ser útilcuando usandogcc, que agrega muchas opciones -L que pueden
  9. serenSistemas de archivos montados en NFS.
  10. Paracompatibilidadconotros enlazadores ELF,siEl ropción esseguidoporun nombre de directorio, en lugar de un nombre de archivo,
  11. estratadocomoel -rpathopción.

4.2 -rpath-link = dir

|_+_|
  1. Cuando usandoDUENDEoSunOS, unocompartidola biblioteca puede requerir otro. Esto pasacuandoun'ld -shared'el enlace incluye un
  2. compartidoBibliotecacomounodelos archivos de entrada.
  3. Cuandoel enlazador encuentra tal dependenciacuandohaciendo un no-compartido, enlace no reubicable, automáticamentetratar
  4. alocalizar el requeridocompartidoBibliotecayincluirloenel enlace,siesoes noincluido explícitamente.Entalcaso,
  5. el -rpath-linkopciónespecifica el primerocolocar dedirectoriosabuscar. El enlace -rpathopciónpuede especificar una secuencia
  6. denombres de directorio ya seaporespecificando una listadenombres separadosporcolonos,o porapareciendo varias veces.
  7. Estaopcióndebería ser usadoconprecaucióncomoesoanulala ruta de búsqueda que puede haber sido difícil de compilarenacompartido
  8. Biblioteca.Entalcasoesoesposibleausar involuntariamente una ruta de búsqueda diferente a la que usaría el vinculador en tiempo de ejecuciónhacer.

4.3 rutas de búsqueda

|_+_|
  1. El vinculador utiliza las siguientes rutas de búsquedaaubicar requeridocompartidobibliotecas:
  2. 1.Cualquier directorio especificadopor-rpath-link opciones.
  3. 2.Cualquier directorio especificadopor-rpath opciones. La diferencia entre -rpathy-rpath-linkesque directorios
  4. especificadopor-Las opciones de rpath están incluidasenel ejecutableyse utiliza en tiempo de ejecución, mientras que -rpath-linkopción es
  5. solo es efectivo en el momento del enlace. Buscando -rpathenPor aquíessolo soportadoporenlazadores nativosyenlazadores cruzados
  6. que han sido configuradosconla --con-sysrootopción.
  7. 3. Enun sistema ELF,porenlazadores nativos,siel -rpathy-rpath-link options erannousado, buscar el contenidode
  8. la variable de entorno'LD_RUN_PATH'.
  9. 4. EnSunOS,siel -rpathopciónestabanoutilizado, busque en los directorios especificadosusando-L opciones.
  10. 5. Paraun enlazador nativo, busca el contenidodela variable de entorno'LD_LIBRARY_PATH'.
  11. 6. Paraun enlazador ELF nativo, los directoriosen 'DT_RUNPATH' o 'DT_RPATH' deacompartidose buscan en la bibliotecapor compartido
  12. bibliotecas necesariasporeso. los'DT_RPATH'las entradas se ignoransi 'DT_RUNPATH'existen entradas.
  13. 7.losdefectodirectorios, normalmente /lib y/ usr /lib.
  14. 8. Paraun enlazador nativoenun sistema ELF,siel archivo /etc/ld.so.conf existe, la listadedirectorios encontradosenese
  15. expediente.

Referencias

[1] Opciones de vinculación y vinculación de bibliotecas dinámicas -L, -rpath-link, -rpath

[2] Opciones de ld -rpath y -rpath-link