collegamento statico solo ad alcune librerie


Risposte:


112

gcc -lsome_dynamic_lib code.c some_static_lib.a


5
Collega le librerie dopo i file oggetto, in particolare le librerie statiche. Nelle versioni antiche e moderne dell'ambiente di collegamento (non sono sicuro dello status quo per versioni modestamente vecchie a partire da novembre 2010), elencare la libreria statica prima del code.cfile 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.
Jonathan Leffler

44
Coule, per favore, spieghi come funziona? Le risposte solo codice non sono utili per i principianti.
jb.

8
@jb per impostazione predefinita, gcc si collega dinamicamente. Quando usi -lsome_dynamic_lib viene collegato dinamicamente come previsto. Ma, quando gcc riceve esplicitamente una libreria statica, proverà sempre a collegarla staticamente. Ci sono, tuttavia, alcuni dettagli complicati sull'ordine in cui i simboli vengono risolti; Non sono abbastanza sicuro di come funzioni. Ho imparato che, in caso di dubbio, prova a riorganizzare l'ordine delle bandiere della libreria :-)
bchurchill

4
c'è un problema di licenza se colleghi staticamente, ad esempio, una libreria GPL
HiB

1
@HiB GPL si applica allo stesso modo al collegamento statico e dinamico
osvein

50

Puoi anche usare l' ldopzione-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.


19
-Wl, -Bdynamic richiede GNU ld, quindi questa soluzione non funziona su sistemi in cui gcc utilizza il sistema ld (ad esempio Mac OS X).
punti

33
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.soed libs1.aentrambi esistono, il linker sceglierà libs1.sose è prima -Wl,-Bstatico dopo -Wl,-Bdynamic. Non dimenticare di passare -L/libs1-library-location/prima di chiamare -ls1.


1
Almeno, questa soluzione funziona con il collegamento statico contro libgomp!
Jérôme

Questo funziona bene per me, mentre l'uso -staticda qualche parte nel comando fallisce (presumo che cerchi di collegare più cose staticamente che solo le librerie che voglio).
nh2

4
NB. L'ordine di -Wl,-Bstatice -Wl,-Bdynamicè importante.
Pavel Vlasov

27

Dalla manpage di ld(questo non funziona con gcc), facendo riferimento --staticall'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, libX11non è nell'elenco delle librerie collegate dinamicamente, poiché era collegata staticamente.

Attenzione: un .sofile è sempre collegato dinamicamente, anche se specificato con un nome file / percorso completo.


Qual è il rapporto tra libX11.a e l'output di ldd a.out?
Raffi Khatchadourian

1
Ah, capisco. lddrestituisce le librerie condivise richieste e libX11 non appare in quell'elenco.
Raffi Khatchadourian

questo non è chiaro. dici "questa opzione" e "quell'opzione". quale opzione?
Octopus

19

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:

  1. Costruire la riga di comando del collegamento senza includere -static .

  2. Ripeti le opzioni di collegamento dinamico.

  3. Accumula i percorsi delle librerie, ovvero quelle opzioni della forma -L <dir_lib> in una variabile <percorso_lib>

  4. 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.

  5. 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"

7

C'è anche una -l:libstatic1.avariante (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' -lnameopzione cercherà libname.soquindi per libname.aaggiungere il prefisso lib e .so(se abilitato al momento) o il .asuffisso. Ma l' -l:nameopzione 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 namespecall'elenco dei file da collegare. Questa opzione può essere utilizzata un numero qualsiasi di volte. Se namespecè nel formato :filename, ld cercherà nel percorso della libreria un file chiamato filename, altrimenti cercherà nel percorso della libreria un file chiamato libnamespec.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 directory libnamespec.soprima di cercarne una chiamata libnamespec.a. (Per convenzione, .soun'estensione indica una libreria condivisa.) Notare che questo comportamento non si applica a :filename, che specifica sempre un file chiamato filename.

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


Questa opzione sembra funzionare dove tutto il resto fallisce. Ci siamo appena imbattuti in un caso in cui dovevamo collegare in modo statico libjsoncpp.a, perché le nostre macchine di compilazione avrebbero prodotto binari collegati a libjsocpp.so.0, mentre il sistema operativo di destinazione fornisce solo libjsoncpp.so.1. Fino a quando non saremo in grado di chiarire questa differenza, questa è stata l'unica soluzione che ha prodotto risultati adeguati nel nostro caso.
Tomasz W

4

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.


6
Anche se questa risposta è stata accettata, non affronta completamente il problema. Come ha spiegato @peoro, il problema che sta cercando di risolvere è che non ha versioni statiche di tutte le librerie, il che implica che vorrebbe collegare staticamente quante più librerie possibile. Vedi la mia risposta.
jcoffland

2

per collegare le librerie dinamiche e statiche all'interno di una riga, è necessario inserire le librerie statiche dopo le librerie dinamiche e i file oggetto, in questo modo:

gcc -lssl main.o -lFooLib -o main

altrimenti non funzionerà. mi ci vuole un po 'di tempo per capirlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.