statische Verknüpfung nur einiger Bibliotheken

Antworten:

112

gcc -lsome_dynamic_lib code.c some_static_lib.a

Šimon Tóth
quelle
5
Verknüpfen Sie Bibliotheken nach Objektdateien - insbesondere statische Bibliotheken. In alten und modernen Versionen der Link-Umgebung (ich bin mir nicht sicher, welchen Status Quo für bescheiden alte Versionen ab November 2010 hat) code.cgarantiert das Auflisten der statischen Bibliothek vor der Datei, dass die darin enthaltenen Symbole ignoriert werden, sofern dies nicht der Fall ist eine main()Funktion in einer der Bibliotheksobjektdateien.
Jonathan Leffler
44
Könnten Sie bitte näher erläutern, wie dies funktioniert? Nur-Code-Antworten sind für Anfänger nicht hilfreich.
jb.
8
@jb Standardmäßig verknüpft gcc dynamisch. Wenn Sie -lsome_dynamic_lib verwenden, wird es wie erwartet dynamisch verknüpft. Wenn gcc jedoch explizit eine statische Bibliothek erhält, wird immer versucht, diese statisch zu verknüpfen. Es gibt jedoch einige knifflige Details über die Reihenfolge, in der Symbole aufgelöst werden. Ich bin mir nicht ganz sicher, wie das funktioniert. Ich habe erfahren, dass Sie im Zweifelsfall versuchen, die Reihenfolge der Bibliotheksflags neu zu ordnen :-)
bchurchill
4
Es gibt ein Problem mit Weihrauch, wenn Sie beispielsweise eine GPL-Bibliothek
HiB
1
@ HiB GPL wendet den gleichen Weg auf statische und dynamische Verknüpfung an
osvein
50

Sie können auch die ldOption verwenden-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.

Dmitry Yudakov
quelle
19
-Wl, -Bdynamic erfordert GNU ld, daher funktioniert diese Lösung nicht auf Systemen, auf denen gcc das System ld verwendet (z. B. Mac OS X).
Punkte
33
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

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

Denken Sie daran, dass der Linker , wenn libs1.sound libs1.abeides vorhanden ist, auswählt, libs1.soob es vorher -Wl,-Bstaticoder nachher ist -Wl,-Bdynamic. Vergessen Sie nicht zu bestehen, -L/libs1-library-location/bevor Sie anrufen -ls1.

wgodoy
quelle
1
Zumindest funktioniert diese Lösung mit statischen Links gegen libgomp!
Jérôme
Dies funktioniert gut für mich, wenn die Verwendung -staticirgendwo im Befehl fehlschlägt (ich gehe davon aus, dass versucht wird, mehr Dinge statisch zu verknüpfen als nur die gewünschten Bibliotheken).
nh2
4
NB. Die Reihenfolge von -Wl,-Bstaticund -Wl,-Bdynamicist wichtig.
Pavel Vlasov
27

In der Manpage von ld(dies funktioniert nicht mit gcc) wird auf die --staticOption verwiesen:

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

Eine Lösung besteht darin, Ihre dynamischen Abhängigkeiten vor die --staticOption in der Befehlszeile zu stellen.

Eine andere Möglichkeit besteht darin --static, den vollständigen Dateinamen / Pfad der statischen Objektdatei nicht zu verwenden , sondern stattdessen anzugeben (dh die Option -l nicht zu verwenden), um eine bestimmte Bibliothek statisch zu verknüpfen. 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, libX11befindet es sich nicht in der Liste der dynamisch verknüpften Bibliotheken, da es statisch verknüpft wurde.

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

ypnos
quelle
Was ist die Beziehung zwischen libX11.a und der Ausgabe von ldd a.out?
Raffi Khatchadourian
1
Ah ich sehe. lddgibt die erforderlichen gemeinsam genutzten Bibliotheken aus und libX11 wird in dieser Liste nicht angezeigt.
Raffi Khatchadourian
das ist nicht klar. Sie sagen "diese Option" und "diese Option". welche Option?
Octopus
19

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

Eine weitere Option, die ich bei verschiedenen Gelegenheiten haben wollte gcc hatte, nenne ich -meist statisch und ist im Wesentlichen das Gegenteil von -Dynamic (Standardeinstellung). -mostly-static würde, falls vorhanden, lieber eine Verknüpfung mit statischen Bibliotheken herstellen, würde jedoch auf dynamische Bibliotheken zurückgreifen.

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

  1. Erstellen der Link-Befehlszeile ohne Einbeziehung von -static .

  2. Durchlaufen Sie die dynamischen Verknüpfungsoptionen.

  3. Akkumulieren Sie Bibliothekspfade, dh diese Optionen der Form -L <Lib_Dir> in einer Variablen <Lib_Pfad>

  4. Führen Sie für jede Option für dynamische Verknüpfungen, dh für die Form -l <Lib -Name > , den Befehl gcc <Lib_Pfad> -print-Dateiname = lib <Lib_name> .a aus und erfassen Sie die Ausgabe.

  5. Wenn der Befehl etwas anderes als das ausgibt, 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 und wiederholen, bis Sie die gesamte Link-Befehlszeile verarbeitet haben. Optional kann das Skript auch eine Liste von Bibliotheksnamen verwenden, um diese von der statischen Verknüpfung 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"
jcoffland
quelle
7

Es gibt auch eine -l:libstatic1.a(minus l Doppelpunkt) Variante der Option -l in gcc, mit der die statische Bibliothek verknüpft werden kann (Dank an https://stackoverflow.com/a/20728782 ). Ist es dokumentiert? Nicht in der offiziellen Dokumentation von gcc (die auch für gemeinsam genutzte Bibliotheken nicht genau ist): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-llibrary
-l library 

Durchsuchen Sie beim Verknüpfen die Bibliothek mit dem Namen Bibliothek. (Die zweite Alternative mit der Bibliothek als separatem Argument dient nur der POSIX-Konformitä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 'lib' umgibt '.a' und durchsucht mehrere Verzeichnisse.

Das binutils ld doc beschreibt es. Die -lnameOption sucht libname.sodann nach dem libname.aHinzufügen des lib-Präfixes und .so(falls derzeit aktiviert) oder nach dem .aSuffix. Die -l:nameOption sucht jedoch nur genau nach dem angegebenen Namen: https://sourceware.org/binutils/docs/ld/Options.html

-l namespec
--library=namespec

Fügen Sie die angegebene Archiv- oder Objektdatei namespeczur Liste der zu verknüpfenden Dateien hinzu. Diese Option kann beliebig oft verwendet werden. Wenn namespeces sich um ein Formular handelt :filename, durchsucht ld den Bibliothekspfad nach einer aufgerufenen Datei filename, andernfalls durchsucht es den Bibliothekspfad nach einer aufgerufenen Datei 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 aufgerufenen Bibliothek, libnamespec.sobevor nach einer aufgerufenen Bibliothek gesucht wird libnamespec.a. (Konventionell gibt eine .soErweiterung eine gemeinsam genutzte Bibliothek an.) Beachten Sie, dass dieses Verhalten nicht für gilt :filename, das immer eine aufgerufene Datei angibt filename.

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, nicht definiert 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, veranlasst den Linker jedoch nicht, das Archiv erneut zu durchsuchen.

In der -(Option finden Sie eine Möglichkeit, den Linker zu zwingen, Archive mehrmals zu durchsuchen.

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

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

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

osgx
quelle
Diese Option scheint dort zu funktionieren, wo alles andere fehlschlägt. Wir sind gerade auf einen Fall gestoßen, in dem wir libjsoncpp.a statisch verknüpfen mussten, weil unsere Build-Maschinen Binärdateien erzeugen würden, die mit libjsocpp.so.0 verknüpft sind, während das Zielbetriebssystem nur libjsoncpp.so.1 bereitstellt. Bis wir diesen Unterschied beseitigen können, war dies die einzige Lösung, die in unserem Fall zu angemessenen Ergebnissen führte.
Tomasz W
4

Einige Lader (Linker) bieten Schalter zum Ein- und Ausschalten des dynamischen Ladens. Wenn GCC auf einem solchen System (Solaris - und möglicherweise anderen) ausgeführt wird, 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.

Jonathan Leffler
quelle
6
Obwohl diese Antwort akzeptiert wurde, wird das Problem nicht vollständig behoben. Wie @peoro erklärte, besteht das Problem, das er zu lösen versucht, darin, dass er nicht über statische Versionen aller Bibliotheken verfügt, was bedeutet, dass er so viele Bibliotheken wie möglich statisch verknüpfen möchte. Siehe meine Antwort.
jcoffland
2

In den Link dynamische und statische Bibliothek innerhalb einer Zeile, müssen Sie statische Bibliotheken setzen nach dynamischen Bibliotheken und Objektdateien, wie folgt aus :

gcc -lssl main.o -lFooLib -o main

Andernfalls funktioniert es nicht. Ich brauche einige Zeit, um es herauszufinden.

Vincent
quelle