web-dev-qa-db-fra.com

liens statiques que certaines bibliothèques

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

gcc ... -static ... tente de lier statiquement toutes les bibliothèques liées, mais je n’ai pas la version statique de certaines d’entre elles (par exemple: libX11).

97
peoro

gcc -lsome_dynamic_lib code.c some_static_lib.a

103
Let_Me_Be

Vous pouvez aussi utiliser ld option -Bdynamic

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

Toutes les bibliothèques qui le suivent (y compris les bibliothèques système liées automatiquement par gcc) seront liées dynamiquement.

48
Dmitry Yudakov
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

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

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

28
wgodoy

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

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

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

Une autre possibilité est de ne pas utiliser --static, mais indiquez plutôt le nom de fichier/chemin complet du fichier d’objet statique (c’est-à-dire n’utilisez pas l’option -l) pour la liaison statique dans 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)

Comme vous pouvez le voir dans l'exemple, libX11 ne figure pas dans la liste des bibliothèques liées dynamiquement, car il était lié statiquement.

Attention: un .so le fichier est toujours lié dynamiquement, même s’il est spécifié avec un nom de fichier/chemin complet.

27
ypnos

Le problème tel que je le comprends est le suivant. Vous avez plusieurs bibliothèques, certaines statiques, d'autres dynamiques et d'autres statiques et dynamiques. Le comportement par défaut de gcc est de lier "principalement dynamique". C’est-à-dire que gcc renvoie aux bibliothèques dynamiques lorsque cela est possible mais qu’il retourne aux bibliothèques statiques. Lorsque vous utilisez l'option - static pour gcc , le comportement est uniquement lier les bibliothèques statiques et quitter 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 plusieurs fois souhaitée gcc , c’est ce que j’appelle - surtout-statique et est essentiellement l'opposé de - dynamic (valeur par défaut). - dans la plupart des cas, statique préférerait, s'il existait, se lier à des bibliothèques statiques, mais revenir à des bibliothèques dynamiques.

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

  1. Construire la ligne de commande du lien sans inclure - static .

  2. Parcourez les options de liens dynamiques.

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

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

  5. Si la commande affiche autre chose que ce que vous avez passé, ce sera le chemin complet de la bibliothèque statique. Remplacez l'option de bibliothèque dynamique par le chemin complet de la bibliothèque statique.

Rincez et répétez jusqu'à ce que vous ayez traité l'intégralité de la ligne de commande du lien. Facultativement, le script peut également utiliser une liste de noms de bibliothèque à exclure des liens statiques.

Le script bash 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 mon système retourne:

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

Je reçois alors:

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

Il existe également une variante de l'option -l dans gcc -l:libstatic1.a Qui peut être utilisée pour lier une bibliothèque statique (Merci à https://stackoverflow.com/a/20728782 ). Est-ce documenté? Pas dans la documentation officielle de gcc (ce qui n’est pas exact pour les bibliothèques partagées également): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-llibrary
-l library 

Rechercher la bibliothèque nommée bibliothèque lors de la liaison. (La seconde alternative avec la bibliothèque comme argument séparé concerne uniquement la conformité POSIX et n'est pas recommandée.) ... La seule différence entre l'utilisation de l'option -l et la spécification d'un nom de fichier est que -l entoure la bibliothèque avec 'lib' et '.a' et recherche dans plusieurs annuaires.

La doc de binutils ld le décrit. L'option -lname Recherchera libname.so Puis libname.a En ajoutant le préfixe lib et .so (Si activé à ce moment) ou .a suffixe. Mais l’option -l:name Ne cherchera exactement que le nom spécifié: https://sourceware.org/binutils/docs/ld/Options.html

-l namespec
--library=namespec

Ajoutez l'archive ou le fichier objet spécifié par namespec à la liste des fichiers à lier. Cette option peut être utilisée autant de fois que vous le souhaitez. Si namespec se présente sous la forme :filename, Ld recherchera dans le chemin de la bibliothèque un fichier nommé filename, sinon il recherchera un fichier appelé libnamespec.a.

Sur les systèmes prenant en charge les bibliothèques partagées, ld peut également rechercher des fichiers autres que libnamespec.a. Plus précisément, sur les systèmes ELF et SunOS, ld recherchera dans un répertoire une bibliothèque appelée libnamespec.so Avant de rechercher celle appelée libnamespec.a. (Par convention, une extension .so Indique une bibliothèque partagée.) Notez que ce problème ne s'applique pas à :filename, Qui spécifie toujours un fichier appelé filename.

L'éditeur de liens recherchera une archive une seule fois, à l'emplacement où elle est spécifiée sur la ligne de commande. Si l'archive définit un symbole non défini dans un objet apparaissant avant l'archive sur la ligne de commande, l'éditeur de liens inclura le (s) fichier (s) approprié (s) à partir de l'archive. Cependant, un symbole non défini dans un objet apparaissant plus tard sur la ligne de commande ne fera pas que l'éditeur de liens effectue une nouvelle recherche dans l'archive.

Voir l’option -( Pour trouver un moyen de forcer l’éditeur de liens à rechercher les archives plusieurs fois.

Vous pouvez répertorier la même archive plusieurs fois sur la ligne de commande.

Ce type de recherche dans les archives est standard pour les lieurs Unix. Toutefois, si vous utilisez ld sous AIX, notez qu'il diffère du comportement de l'éditeur de liens AIX.

La variante -l:namespec Est documentée depuis la version 2.18 de binutils (2007): https://sourceware.org/binutils/docs-2.18/ld/Options.html

7
osgx

Certains chargeurs (linkers) fournissent des commutateurs pour activer et désactiver le chargement dynamique. Si GCC fonctionne sur un tel système (Solaris - et éventuellement d’autres), vous pouvez utiliser l’option correspondante.

Si vous savez quelles bibliothèques vous souhaitez lier de manière statique, vous pouvez simplement spécifier le fichier de bibliothèque statique dans la ligne de liaison - par chemin complet.

4
Jonathan Leffler

pour lier les bibliothèques dynamiques et statiques sur une ligne, vous devez mettre des bibliothèques statiques après des bibliothèques dynamiques et des fichiers objets, comme ceci:

gcc -lssl main.o -lFooLib -o main

sinon, ça ne marchera pas. cela me prend un jour pour le comprendre.

2
Vincent