gcc - atributo - enlace estático solo algunas bibliotecas
alt title (8)
¿Cómo puedo vincular estáticamente solo algunas bibliotecas específicas a mi binario cuando me enlace con GCC?
gcc ... -static ...
intenta vincular estáticamente todas las bibliotecas vinculadas, pero no tengo la versión estática de algunas de ellas (p. ej .: libX11).
Algunos cargadores (vinculadores) proporcionan interruptores para activar y desactivar la carga dinámica. Si GCC se ejecuta en un sistema de este tipo (Solaris, y posiblemente otros), puede utilizar la opción correspondiente.
Si sabe qué bibliotecas desea vincular estáticamente, puede simplemente especificar el archivo de biblioteca estática en la línea de enlace, por ruta completa.
Desde la página de manual de ld
(esto no funciona con gcc), refiriéndose a la opción --static
:
Puede usar esta opción varias veces en la línea de comando: afecta a la biblioteca que busca las opciones -l que lo siguen.
Una solución es colocar sus dependencias dinámicas antes de la opción --static
en la línea de comando.
Otra posibilidad es no usar --static
, sino proporcionar el nombre de archivo / ruta de acceso completo del archivo de objeto estático (es decir, no usar la opción -l) para vincular estáticamente una biblioteca específica. Ejemplo:
# echo "int main() {}" > test.cpp
# c++ test.cpp /usr/lib/libX11.a
# ldd a.out
linux-vdso.so.1 => (0x00007fff385cc000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f9a5b233000)
libm.so.6 => /lib/libm.so.6 (0x00007f9a5afb0000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f9a5ad99000)
libc.so.6 => /lib/libc.so.6 (0x00007f9a5aa46000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a5b53f000)
Como puede ver en el ejemplo, libX11
no está en la lista de bibliotecas vinculadas dinámicamente, ya que estaba vinculado estáticamente.
Cuidado: un archivo .so
siempre está vinculado dinámicamente, incluso cuando se especifica con un nombre de archivo / ruta de acceso completo.
El problema tal como lo entiendo es el siguiente. Tiene varias bibliotecas, algunas estáticas, algunas dinámicas y otras tanto estáticas como dinámicas. El comportamiento predeterminado de gcc es vincular "principalmente dinámico". Es decir, gcc se vincula a bibliotecas dinámicas cuando es posible, pero de lo contrario vuelve a las bibliotecas estáticas. Cuando usa la opción -static para gcc, el comportamiento es solo vincular bibliotecas estáticas y salir con un error si no se puede encontrar una biblioteca estática, incluso si hay una biblioteca dinámica apropiada.
Otra opción, que en varias ocasiones he deseado que tenga GCC , es lo que llamo -más-estático y es esencialmente lo opuesto a -dinámico (el predeterminado). -más que nada estático , si existiera, preferiría vincularse con bibliotecas estáticas pero recurriría a bibliotecas dinámicas.
Esta opción no existe pero puede ser emulada con el siguiente algoritmo:
Construir la línea de comando de enlace sin incluir estático .
Itera sobre las opciones de enlace dinámico.
Acumula rutas de biblioteca, es decir, aquellas opciones de la forma -L <lib_dir> en una variable <lib_path>
Para cada opción de enlace dinámico, es decir, las de la forma -l <nombre_de_búsqueda> , ejecute el comando gcc <ruta_de_libro> -print-file-name = lib <nombre_de_búsqueda> .a y capture la salida.
Si el comando imprime algo diferente a lo que pasó, será la ruta completa a la biblioteca estática. Reemplace la opción de biblioteca dinámica con la ruta completa a la biblioteca estática.
Enjuague y repita hasta que haya procesado toda la línea de comando del enlace. Opcionalmente, el script también puede tomar una lista de nombres de bibliotecas para excluir del enlace estático.
El siguiente script bash parece ser el truco:
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Usage: $0 [--exclude <lib_name>]. . . <link_command>"
fi
exclude=()
lib_path=()
while [ $# -ne 0 ]; do
case "$1" in
-L*)
if [ "$1" == -L ]; then
shift
LPATH="-L$1"
else
LPATH="$1"
fi
lib_path+=("$LPATH")
echo -n "/"$LPATH/" "
;;
-l*)
NAME="$(echo $1 | sed ''s/-l/(.*/)//1/'')"
if echo "${exclude[@]}" | grep " $NAME " >/dev/null; then
echo -n "$1 "
else
LIB="$(gcc $lib_path -print-file-name=lib"$NAME".a)"
if [ "$LIB" == lib"$NAME".a ]; then
echo -n "$1 "
else
echo -n "/"$LIB/" "
fi
fi
;;
--exclude)
shift
exclude+=(" $1 ")
;;
*) echo -n "$1 "
esac
shift
done
echo
Por ejemplo:
mostlyStatic gcc -o test test.c -ldl -lpthread
en mi sistema regresa:
gcc -o test test.c "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libdl.a" "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
o con una exclusión:
mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread
Entonces obtengo:
gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
También existe la variante -l:libstatic1.a
(menos 1 coma) de la opción -l en gcc que se puede usar para vincular la biblioteca estática (gracias a https://.com/a/20728782 ). Está documentado? No en la documentación oficial de gcc (que tampoco es exacta para bibliotecas compartidas): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
-llibrary -l library
Busque en la biblioteca llamada biblioteca al enlazar. (La segunda alternativa con la biblioteca como argumento separado es solo para cumplimiento con POSIX y no se recomienda) ... La única diferencia entre usar una opción -l y especificar un nombre de archivo es que -l rodea la biblioteca con ''lib'' y ''.a'' y busca en varios directorios.
El binutils ld doc lo describe. La opción -lname
buscará libname.so
luego para libname.a
añadiendo libname.a
lib y .so
(si está habilitado en este momento) o .a
sufijo. Pero la opción -l:name
solo buscará exactamente el nombre especificado: https://sourceware.org/binutils/docs/ld/Options.html
-l namespec --library=namespec
Agregue el archivo de archivo o objeto especificado por
namespec
a la lista de archivos para vincular. Esta opción se puede usar cualquier cantidad de veces. Sinamespec
tiene el formato:filename
, ld buscará en la ruta de la biblioteca un archivo llamadofilename
, de lo contrario buscará en la ruta de la biblioteca un archivo llamadolibnamespec.a
.En los sistemas que admiten bibliotecas compartidas, ld también puede buscar archivos que no sean
libnamespec.a
. Específicamente, en sistemas ELF y SunOS, ld buscará en un directorio una biblioteca llamadalibnamespec.so
antes de buscar una llamadalibnamespec.a
. (Por convención, una extensión.so
indica una biblioteca compartida.) Tenga en cuenta que este comportamiento no se aplica a:filename
, que siempre especifica un archivo llamadofilename
.El vinculador buscará un archivo solo una vez, en la ubicación donde se especifica en la línea de comando. Si el archivo define un símbolo que no estaba definido en algún objeto que apareció antes del archivo en la línea de comando, el vinculador incluirá los archivos correspondientes del archivo. Sin embargo, un símbolo indefinido en un objeto que aparece más adelante en la línea de comando no hará que el vinculador busque nuevamente en el archivo.
Consulte la opción
-(
opción para forzar al enlazador a buscar archivos varias veces).Puede enumerar el mismo archivo varias veces en la línea de comando.
Este tipo de búsqueda de archivos es estándar para los vinculadores de Unix. Sin embargo, si está utilizando ld en AIX, tenga en cuenta que es diferente del comportamiento del vinculador de AIX.
La variante -l:namespec
está documentada desde la versión 2.18 de binutils (2007): https://sourceware.org/binutils/docs-2.18/ld/Options.html
También puedes usar la opción ld
-Bdynamic
gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2
Todas las bibliotecas posteriores (incluidas las del sistema vinculadas por gcc automáticamente) se vincularán dinámicamente.
para vincular la biblioteca dinámica y estática dentro de una línea, debe poner las bibliotecas estáticas después de las bibliotecas dinámicas y los archivos de objetos, como este:
gcc -lssl main.o -lFooLib -o main
De lo contrario, no funcionará. me toma algún tiempo resolverlo.
gcc -lsome_dynamic_lib code.c some_static_lib.a
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2
también puede usar: -static-libgcc -static-libstdc++
flags para las bibliotecas de gcc
tenga en cuenta que si libs1.so
y libs1.a
, el enlazador seleccionará libs1.so
si está antes -Wl,-Bstatic
o después de -Wl,-Bdynamic
. No olvide pasar -L/libs1-library-location/
antes de llamar a -ls1
.