wake-up-neo.com

statische Verknüpfung nur einiger Bibliotheken

Wie kann ich beim Verknüpfen mit GCC nur einige bestimmte Bibliotheken statisch mit meiner Binärdatei verknüpfen?

gcc ... -static ... versucht, alle die verknüpften Bibliotheken statisch zu verknüpfen, aber ich habe nicht die statische Version einiger von ihnen (zB: libX11).

97
peoro

gcc -lsome_dynamic_lib code.c some_static_lib.a

103
Let_Me_Be

Sie können auch ld option -Bdynamic

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

Alle Bibliotheken danach (einschließlich der von gcc automatisch verknüpften Systembibliotheken) werden dynamisch verknüpft.

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

sie können auch Folgendes verwenden: -static-libgcc -static-libstdc++ Flags für gcc-Bibliotheken

beachten Sie, dass der Linker, wenn libs1.so und libs1.a beide vorhanden sind, libs1.so auswählt, wenn es vor -Wl,-Bstatic oder nach -Wl,-Bdynamic steht. Vergessen Sie nicht, -L/libs1-library-location/ Zu übergeben, bevor Sie -ls1 Aufrufen.

28
wgodoy

In der Manpage von ld (dies funktioniert nicht mit gcc), unter Bezugnahme auf die Option --static:

Sie können diese Option mehrmals in der Befehlszeile verwenden: Sie wirkt sich auf die Bibliothek aus, die nach den darauf folgenden Optionen -l sucht.

Eine Lösung besteht darin, Ihre dynamischen Abhängigkeiten in der Befehlszeile vor die Option --static Zu setzen.

Eine andere Möglichkeit besteht darin, nicht --static Zu verwenden, sondern stattdessen den vollständigen Dateinamen/Pfad der statischen Objektdatei anzugeben (d. H. Die Option -l nicht zu verwenden), um eine bestimmte Bibliothek statisch einzubinden. Beispiel:

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

Wie Sie im Beispiel sehen können, ist libX11 Nicht in der Liste der dynamisch verknüpften Bibliotheken enthalten, da es statisch verknüpft wurde.

Achtung: Eine .so - Datei wird immer dynamisch verknüpft, auch wenn sie mit einem vollständigen Dateinamen/Pfad angegeben wird.

27
ypnos

Das Problem, wie ich es verstehe, ist wie folgt. Sie haben mehrere Bibliotheken, einige statisch, einige dynamisch und einige sowohl statisch als auch dynamisch. Das Standardverhalten von gcc besteht darin, "größtenteils dynamisch" zu verknüpfen. Das heißt, gcc verlinkt nach Möglichkeit auf dynamische Bibliotheken, greift ansonsten aber auf statische Bibliotheken zurück. Wenn Sie die Option - static für gcc verwenden, werden nur statische Bibliotheken verknüpft und mit einem Fehler beendet, wenn keine statische Bibliothek gefunden werden kann, auch wenn eine geeignete vorhanden ist dynamische Bibliothek.

Eine andere Option, die ich mir mehrmals gewünscht habe gcc, ist das, was ich - meistens-statisch nenne und im Wesentlichen das Gegenteil von - dynamisch (der Standard). - most-static würde, falls vorhanden, eine Verknüpfung mit statischen Bibliotheken bevorzugen, würde jedoch auf dynamische Bibliotheken zurückgreifen.

Diese Option existiert nicht, kann aber mit dem folgenden Algorithmus emuliert werden:

  1. Erstellen der Verbindungsbefehlszeile ohne das Einschließen von - static.

  2. Iterieren Sie über die Optionen für dynamische Links.

  3. Akkumulieren Sie Bibliothekspfade, d. H. Die Optionen der Form - L <lib_dir> in einer Variablen <lib_path>

  4. Führen Sie für jede dynamische Linkoption, dh solche der Form - l <lib_name>, den Befehl gcc <lib_path> -print-file-name = lib <lib_name> .a aus = und erfassen die Ausgabe.

  5. Wenn der Befehl etwas anderes ausgibt als das, was Sie übergeben haben, ist dies der vollständige Pfad zur statischen Bibliothek. Ersetzen Sie die Option für die dynamische Bibliothek durch den vollständigen Pfad zur statischen Bibliothek.

Spülen Sie und wiederholen Sie, bis Sie die gesamte Verbindungsbefehlszeile verarbeitet haben. Optional kann das Skript auch eine Liste von Bibliotheksnamen verwenden, um statische Verknüpfungen auszuschließen.

Das folgende Bash-Skript scheint den Trick zu tun:

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

Beispielsweise:

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

auf meinem System gibt zurück:

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"

oder mit einem Ausschluss:

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

Ich bekomme dann:

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

Es gibt auch eine -l:libstatic1.a (Minus 1 Doppelpunkt) Variante der Option -l in gcc, die zum Verknüpfen der statischen Bibliothek verwendet werden kann (Dank an https://stackoverflow.com/a/20728782 ). Ist es dokumentiert? Nicht in der offiziellen Dokumentation von gcc (die auch nicht für gemeinsam genutzte Bibliotheken gilt): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-llibrary
-l library 

Durchsuchen Sie beim Verknüpfen die Bibliothek mit dem Namen library. (Die zweite Alternative mit der Bibliothek als separatem Argument dient nur der POSIX-Kompatibilität und wird nicht empfohlen.) ... Der einzige Unterschied zwischen der Verwendung der Option -l und der Angabe eines Dateinamens besteht darin, dass -l die Bibliothek mit 'lib' und umgibt '.a' und durchsucht mehrere Verzeichnisse.

Das binutils ld doc beschreibt es. Mit der Option -lname Wird nach libname.so Und dann nach libname.a Gesucht, wobei das lib-Präfix und .so (Falls im Moment aktiviert) oder .a Hinzugefügt werden. Suffix. Die Option -l:name Sucht jedoch nur genau nach dem angegebenen Namen: https://sourceware.org/binutils/docs/ld/Options.html

-l namespec
--library=namespec

Fügen Sie die mit namespec angegebene Archiv- oder Objektdatei zur Liste der zu verknüpfenden Dateien hinzu. Diese Option kann beliebig oft verwendet werden. Wenn namespec die Form :filename Hat, durchsucht ld den Bibliothekspfad nach einer Datei mit dem Namen filename, andernfalls durchsucht es den Bibliothekspfad nach einer Datei mit dem Namen libnamespec.a.

Auf Systemen, die gemeinsam genutzte Bibliotheken unterstützen, sucht ld möglicherweise auch nach anderen Dateien als libnamespec.a. Insbesondere auf ELF- und SunOS-Systemen durchsucht ld ein Verzeichnis nach einer Bibliothek mit dem Namen libnamespec.so, Bevor nach einer Bibliothek mit dem Namen libnamespec.a Gesucht wird. (Konventionell weist eine .so - Erweiterung auf eine gemeinsam genutzte Bibliothek hin.) Beachten Sie, dass dieses Verhalten nicht für :filename Gilt, das immer eine Datei mit dem Namen filename angibt.

Der Linker durchsucht ein Archiv nur einmal an der Stelle, an der es in der Befehlszeile angegeben ist. Wenn das Archiv ein Symbol definiert, das in einem Objekt, das vor dem Archiv in der Befehlszeile angezeigt wurde, undefiniert war, enthält der Linker die entsprechenden Dateien aus dem Archiv. Ein undefiniertes Symbol in einem Objekt, das später in der Befehlszeile angezeigt wird, führt jedoch nicht dazu, dass der Linker das Archiv erneut durchsucht.

Mit der Option -( Können Sie den Linker zwingen, Archive mehrmals zu durchsuchen.

Sie können dasselbe Archiv mehrmals in der Befehlszeile auflisten.

Diese Art der Archivsuche ist bei Unix-Linkern Standard. Wenn Sie jedoch ld unter AIX verwenden, beachten Sie, dass es sich vom Verhalten des AIX-Linkers unterscheidet.

Die Variante -l:namespec Ist seit Version 2.18 von binutils (2007) dokumentiert: https://sourceware.org/binutils/docs-2.18/ld/Options.html

7
osgx

Einige Lader (Linker) bieten Schalter zum Ein- und Ausschalten des dynamischen Ladens. Wenn GCC auf einem solchen System ausgeführt wird (Solaris - und möglicherweise auch andere), können Sie die entsprechende Option verwenden.

Wenn Sie wissen, welche Bibliotheken Sie statisch verknüpfen möchten, können Sie einfach die statische Bibliotheksdatei in der Verknüpfungszeile angeben - über den vollständigen Pfad.

4

um eine dynamische und eine statische Bibliothek in einer Zeile zu verknüpfen, müssen Sie statische Bibliotheken nach dynamische Bibliotheken und Objektdateien wie folgt einfügen:

gcc -lssl main.o -lFooLib -o main

andernfalls funktioniert es nicht. Ich brauche eine Weile, um es herauszufinden.

2
Vincent