102 votes

GCC : liaison statique de certaines bibliothèques seulement

Comment puis-je lier statiquement seulement quelques bibliothèques spécifiques à mon binaire lors de la liaison avec GCC ?

gcc ... -static ... essaie de lier statiquement todo les bibliothèques liées, mais je n'ai pas la version statique de certaines d'entre elles (ex : libX11).

108voto

Let_Me_Be Points 16797

gcc -lsome_dynamic_lib code.c some_static_lib.a

49voto

Dmitry Yudakov Points 6354

Vous pouvez également utiliser ld option -Bdynamic

gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2

Toutes les bibliothèques suivantes (y compris celles du système liées automatiquement par gcc) seront liées dynamiquement.

30voto

wgodoy Points 101

Gcc objectfiles -o programme -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

vous pouvez également utiliser : -static-libgcc -static-libstdc++ drapeaux pour les bibliothèques gcc

Gardez à l'esprit que si libs1.so et libs1.a existent toutes les deux, l'éditeur de liens choisira libs1.so si elle est avant -Wl,-Bstatic ou après -Wl,-Bdynamic. N'oubliez pas de passer -L/libs1-library-location/ avant d'appeler -ls1.

27voto

ypnos Points 21940

Extrait de la page de manuel de ld (cela ne fonctionne pas avec gcc), en se référant à la section --static option :

Vous pouvez utiliser cette option plusieurs fois sur la ligne de commande : elle affecte la recherche de la bibliothèque pour les options -l qui qui la suivent.

Une solution consiste à placer vos dépendances dynamiques avant la balise --static sur la ligne de commande.

Une autre possibilité est de ne pas utiliser --static mais fournissez plutôt le chemin complet du fichier objet statique (c'est-à-dire sans utiliser l'option -l) pour lier statiquement une bibliothèque spécifique. Exemple :

# 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)

Note : Si vous utilisez le chemin complet d'un fichier .so, il sera à nouveau lié dynamiquement.

18voto

jcoffland Points 1506

Le problème tel que je le comprends est le suivant. Vous avez plusieurs bibliothèques, certaines statiques, d'autres dynamiques et d'autres encore à la fois statiques et dynamiques. gcc Le comportement par défaut du site est d'établir des liens "principalement dynamiques". C'est-à-dire, gcc établit des liens avec les bibliothèques dynamiques lorsque cela est possible, mais se rabat sinon sur les bibliothèques statiques. Lorsque vous utilisez l'option -statique option pour gcc le comportement est de lier uniquement les bibliothèques statiques et de sortir avec une erreur si aucune bibliothèque statique ne peut être trouvée, même s'il existe une bibliothèque dynamique appropriée.

Une autre option, que j'ai souhaitée à plusieurs reprises. gcc avait, est ce que j'appelle -surtout statique et est essentiellement l'opposé de -dynamique (par défaut). -surtout statique préférerait, s'il existait, lier contre les bibliothèques statiques mais se rabattrait sur les bibliothèques dynamiques.

Cette option n'existe pas mais elle peut être émulée avec l'algorithme suivant :

  1. Construire la ligne de commande link sans inclure -statique .

  2. Itérer sur les options de liens dynamiques.

  3. Accumuler les chemins de la bibliothèque, c'est-à-dire les options de la forme -L<lib_dir> dans une variable <chemin_lib>

  4. Pour chaque option de lien dynamique, c'est-à-dire celles de la forme -l<nom_lib> exécutez la commande gcc <chemin_lib> -print-file-name=lib<nom_lib>.a et capturer la sortie.

  5. Si la commande imprime quelque chose d'autre que ce que vous avez passé, ce sera le chemin complet de la bibliothèque statique. Remplacez l'option dynamic library par le chemin complet de la bibliothèque statique.

Rincez et répétez jusqu'à ce que vous ayez traité la totalité de la ligne de commande de liaison. Optionnellement, le script peut aussi prendre une liste de noms de bibliothèques à exclure de la liaison statique.

Le bash script suivant semble faire l'affaire :

#!/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

Par exemple :

mostlyStatic gcc -o test test.c -ldl -lpthread

sur les retours de mon système :

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"

ou avec une exclusion :

mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread

J'obtiens alors :

gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X