Come posso collegare staticamente solo alcune librerie specifiche al mio binario quando mi collego a GCC?
gcc ... -static ...
cerca di collegare staticamente tutte le librerie collegate, ma non ho la versione statica di alcune di esse (es: libX11).
Come posso collegare staticamente solo alcune librerie specifiche al mio binario quando mi collego a GCC?
gcc ... -static ...
cerca di collegare staticamente tutte le librerie collegate, ma non ho la versione statica di alcune di esse (es: libX11).
Risposte:
gcc -lsome_dynamic_lib code.c some_static_lib.a
code.c
file garantisce che i simboli in esso contenuti verranno ignorati a meno che non ci siano una main()
funzione in uno dei file oggetto della libreria.
Puoi anche usare l' ld
opzione-Bdynamic
gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2
Tutte le librerie successive (comprese quelle di sistema collegate automaticamente da gcc) verranno collegate dinamicamente.
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2
puoi anche usare: -static-libgcc -static-libstdc++
flag per le librerie gcc
tieni presente che se libs1.so
ed libs1.a
entrambi esistono, il linker sceglierà libs1.so
se è prima -Wl,-Bstatic
o dopo -Wl,-Bdynamic
. Non dimenticare di passare -L/libs1-library-location/
prima di chiamare -ls1
.
-static
da qualche parte nel comando fallisce (presumo che cerchi di collegare più cose staticamente che solo le librerie che voglio).
-Wl,-Bstatic
e -Wl,-Bdynamic
è importante.
Dalla manpage di ld
(questo non funziona con gcc), facendo riferimento --static
all'opzione:
Puoi usare questa opzione più volte sulla riga di comando: influenza la ricerca nella libreria delle opzioni -l che la seguono.
Una soluzione è mettere le tue dipendenze dinamiche prima del file --static
dell'opzione sulla riga di comando.
Un'altra possibilità è di non utilizzare --static
, ma di fornire invece il nome / percorso completo del file oggetto statico (cioè non usando l'opzione -l) per il collegamento statico di una libreria specifica. Esempio:
# 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)
Come puoi vedere nell'esempio, libX11
non è nell'elenco delle librerie collegate dinamicamente, poiché era collegata staticamente.
Attenzione: un .so
file è sempre collegato dinamicamente, anche se specificato con un nome file / percorso completo.
ldd a.out
?
ldd
restituisce le librerie condivise richieste e libX11 non appare in quell'elenco.
Il problema a quanto ho capito è il seguente. Hai diverse librerie, alcune statiche, alcune dinamiche e alcune sia statiche che dinamiche. Il comportamento predefinito di gcc è di collegare "principalmente dinamico". Cioè, gcc si collega a librerie dinamiche quando possibile, ma per il resto ricorre a librerie statiche. Quando si utilizza l' opzione -static per gcc, il comportamento è di collegare solo le librerie statiche e di uscire con un errore se non è possibile trovare alcuna libreria statica, anche se esiste una libreria dinamica appropriata.
Un'altra opzione, che in diverse occasioni avrei voluto che gcc avesse, è quella che chiamo -mostly-static ed è essenzialmente l'opposto di -dynamic (l'impostazione predefinita). -mostly-static , se esistesse, preferirebbe collegarsi a librerie statiche ma ricorrerebbe a librerie dinamiche.
Questa opzione non esiste ma può essere emulata con il seguente algoritmo:
Costruire la riga di comando del collegamento senza includere -static .
Ripeti le opzioni di collegamento dinamico.
Accumula i percorsi delle librerie, ovvero quelle opzioni della forma -L <dir_lib> in una variabile <percorso_lib>
Per ciascuna opzione di collegamento dinamico, ovvero quelle della forma -l <lib_name> , eseguire il comando gcc <lib_path> -print-file-name = lib <lib_name> .a e acquisire l'output.
Se il comando stampa qualcosa di diverso da quello che hai passato, sarà il percorso completo della libreria statica. Sostituire l'opzione della libreria dinamica con il percorso completo della libreria statica.
Risciacquare e ripetere fino a quando non hai elaborato l'intera riga di comando del collegamento. Facoltativamente, lo script può anche prendere un elenco di nomi di libreria da escludere dal collegamento statico.
Il seguente script bash sembra fare il trucco:
#!/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
Per esempio:
mostlyStatic gcc -o test test.c -ldl -lpthread
sul mio sistema restituisce:
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 un'esclusione:
mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread
Quindi ottengo:
gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
C'è anche una -l:libstatic1.a
variante (meno l due punti) dell'opzione -l in gcc che può essere utilizzata per collegare la libreria statica (grazie a https://stackoverflow.com/a/20728782 ). È documentato? Non nella documentazione ufficiale di gcc (che non è esatta anche per le librerie condivise): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
-llibrary -l library
Cerca nella libreria denominata libreria durante il collegamento. (La seconda alternativa con la libreria come argomento separato è solo per la conformità POSIX e non è raccomandata.) ... L'unica differenza tra l'uso di un'opzione -l e la specifica di un nome file è che -l circonda la libreria con 'lib' e '.a' e cerca in diverse directory.
Il documento binutils ld lo descrive. L' -lname
opzione cercherà libname.so
quindi per libname.a
aggiungere il prefisso lib e .so
(se abilitato al momento) o il .a
suffisso. Ma l' -l:name
opzione cercherà esattamente solo il nome specificato:
https://sourceware.org/binutils/docs/ld/Options.html
-l namespec --library=namespec
Aggiungere l'archivio o il file oggetto specificato da
namespec
all'elenco dei file da collegare. Questa opzione può essere utilizzata un numero qualsiasi di volte. Senamespec
è nel formato:filename
, ld cercherà nel percorso della libreria un file chiamatofilename
, altrimenti cercherà nel percorso della libreria un file chiamatolibnamespec.a
.Sui sistemi che supportano le librerie condivise, ld può anche cercare file diversi da
libnamespec.a
. In particolare, sui sistemi ELF e SunOS, ld cercherà una libreria chiamata in una directorylibnamespec.so
prima di cercarne una chiamatalibnamespec.a
. (Per convenzione,.so
un'estensione indica una libreria condivisa.) Notare che questo comportamento non si applica a:filename
, che specifica sempre un file chiamatofilename
.Il linker cercherà in un archivio solo una volta, nella posizione in cui è specificato sulla riga di comando. Se l'archivio definisce un simbolo che era indefinito in un oggetto apparso prima dell'archivio sulla riga di comando, il linker includerà i file appropriati dall'archivio. Tuttavia, un simbolo indefinito in un oggetto che appare in seguito sulla riga di comando non farà sì che il linker esegua nuovamente la ricerca nell'archivio.
Vedere l'
-(
opzione per un modo per forzare il linker a cercare negli archivi più volte.È possibile elencare lo stesso archivio più volte sulla riga di comando.
Questo tipo di ricerca nell'archivio è standard per i linker Unix. Tuttavia, se si utilizza ld su AIX, notare che è diverso dal comportamento del linker AIX.
La variante -l:namespec
è documentata dalla versione 2.18 di binutils (2007): https://sourceware.org/binutils/docs-2.18/ld/Options.html
Alcuni caricatori (linker) forniscono interruttori per l'attivazione e la disattivazione del caricamento dinamico. Se GCC è in esecuzione su un sistema del genere (Solaris e forse altri), è possibile utilizzare l'opzione pertinente.
Se sai quali librerie vuoi collegare staticamente, puoi semplicemente specificare il file della libreria statica nella riga di collegamento - per percorso completo.