Verknüpfen statischer Bibliotheken mit anderen statischen Bibliotheken

138

Ich habe einen kleinen Code, der von vielen statischen Bibliotheken abhängt (a_1-a_n). Ich möchte diesen Code in eine statische Bibliothek packen und anderen Personen zur Verfügung stellen.

Meine statische Bibliothek, nennen wir sie X, lässt sich gut kompilieren.

Ich habe ein einfaches Beispielprogramm erstellt, das eine Funktion von X verwendet, aber wenn ich versuche, sie mit X zu verknüpfen, erhalte ich viele Fehler bezüglich fehlender Symbole aus den Bibliotheken a_1 - a_n.

Gibt es eine Möglichkeit, eine neue statische Bibliothek Y zu erstellen, die X und alle von X benötigten Funktionen enthält (ausgewählte Bits von a_1 - a_n), sodass ich nur Y verteilen kann, mit dem Benutzer ihre Programme verknüpfen können?


AKTUALISIEREN:

Ich habe mir angesehen, einfach alles mit ar zu sichern und eine Mega-Lib zu erstellen, die jedoch viele Symbole enthält, die nicht benötigt werden (alle .o-Dateien sind ungefähr 700 MB groß, eine statisch verknüpfte ausführbare Datei ist jedoch 7 MB). Gibt es eine gute Möglichkeit, nur das einzubeziehen, was tatsächlich benötigt wird?


Dies hängt eng mit dem Kombinieren mehrerer C / C ++ - Bibliotheken zu einer zusammen. .

Jason Sundram
quelle

Antworten:

76

Statische Bibliotheken sind nicht mit anderen statischen Bibliotheken verknüpft. Der einzige Weg , dies zu tun ist Ihren Bibliothekar / Archivierungs - Tool verwenden (zum Beispiel ar unter Linux) eine einzige neue statische Bibliothek zu erstellen , indem die mehrere Bibliotheken verketten.

Bearbeiten: Als Reaktion auf Ihr Update kann ich nur die erforderlichen Symbole auswählen, indem ich die Bibliothek manuell aus der Teilmenge der .o-Dateien erstelle, in denen sie enthalten sind. Dies ist schwierig, zeitaufwändig und fehleranfällig. Mir sind keine Tools bekannt, die dazu beitragen (um nicht zu sagen, dass sie nicht existieren), aber es wäre ein ziemlich interessantes Projekt, eines zu produzieren.


quelle
Hallo Neil, ich habe die Frage aktualisiert. Kennen Sie eine Möglichkeit, nur die erforderlichen .o-Dateien einzuschließen?
Jason Sundram
Update - Wenn Sie dies tun möchten, treten Sie einen Schritt zurück und verfolgen Sie etwas anderes (es sei denn, Sie verwenden Visual Studio, wie John Knoeller betont). Ich habe viel Zeit in diesen Ansatz gesteckt und nichts Nützliches bekommen.
Jason Sundram
Das GNU ld-Tool bietet die Option, -rdass die Ausgabe als Eingabe für ld verwendet werden kann. Wenn Sie einmal verlinken, sollten Sie einen Umzug erhalten, der Ihre Bibliotheken ersetzen kann. (habe es thogh versucht).
Harper
49

Wenn Sie Visual Studio verwenden, können Sie dies tun.

Mit dem mit Visual Studio gelieferten Tool zum Erstellen von Bibliotheken können Sie Bibliotheken über die Befehlszeile zusammenfügen. Ich kenne jedoch keine Möglichkeit, dies im visuellen Editor zu tun.

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib
John Knoeller
quelle
5
Wenn Sie in VS2008 in den Projekteigenschaften von compositelib unter Librarian / General [x] Link Library Dependencies aktivieren, wird dies für Sie erledigt, wenn lib1 und lib2 Abhängigkeiten von compositelib sind. Es scheint etwas fehlerhaft zu sein, ich würde das Kontrollkästchen in jeder Build-Konfiguration separat aktivieren, nicht einmal in "Alle Konfigurationen".
Spike0xff
2
VS2015 IDE - Verwenden Sie nicht "Zusätzliche Abhängigkeiten" unter "Bibliothekar / Allgemein", um zusätzliche Bibliotheken direkt mit der Bibliothek zu verknüpfen, die Ihr Projekt erstellt?
Davidbak
@davidbak Ich versuche dies in den letzten Tagen herauszufinden und anscheinend ist diese Option veraltet und macht nichts?
Montaldo
20

Unter Linux oder MingW mit GNU-Toolchain:

ar -M <<EOM
    CREATE libab.a
    ADDLIB liba.a
    ADDLIB libb.a
    SAVE
    END
EOM
ranlib libab.a

Von wenn Sie nicht löschen liba.aund libb.aSie können „thin - Archiv“ machen:

ar crsT libab.a liba.a libb.a

Unter Windows mit der MSVC-Toolchain:

lib.exe /OUT:libab.lib liba.lib libb.lib
Star Brilliant
quelle
Gut zu wissen, löst aber das Problem des OP nicht wirklich, da Sie alles von libb.a in die gemeinsame Bibliothek aufnehmen, was sehr groß werden kann, wenn Sie nur wenige Module von libb benötigen.
Elmar Zander
1
@ElmarZander Aber Sie können verwenden ar crsT, was so etwas wie "Symlinking" macht, anstatt zu kopieren, dann müssen Sie nur eine Kopie der Daten versenden.
Star Brilliant
Dünne Archive werden insbesondere auf dem Linux-Kernel v4.19 verwendet: unix.stackexchange.com/questions/5518/…
Ciro Santilli 21 冠状 病 六四 事件 21
10

Eine statische Bibliothek ist nur ein Archiv von .oObjektdateien. Extrahieren Sie sie mit ar(unter der Annahme von Unix) und packen Sie sie wieder in eine große Bibliothek.

Nikolai Fetissov
quelle
5

Alternativ zu den Link Library DependenciesProjekteigenschaften gibt es eine andere Möglichkeit, Bibliotheken in Visual Studio zu verknüpfen.

  1. Öffnen Sie das Projekt der Bibliothek (X), das Sie mit anderen Bibliotheken kombinieren möchten.
  2. Fügen Sie die anderen Bibliotheken hinzu, die Sie mit X kombinieren möchten (Rechtsklick, Add Existing Item...).
  3. Gehen Sie zu ihren Eigenschaften und stellen Sie sicher, Item TypeistLibrary

Dies schließt die anderen Bibliotheken in X ein, als ob Sie ausgeführt hätten

lib /out:X.lib X.lib other1.lib other2.lib
evpo
quelle
Hallo, ich verwende Intel IPP und habe meine eigenen Funktionen erstellt, die alle in einer (statischen) Bibliothek enthalten sollen. Wenn ich jedoch die Bibliothek erstelle und das Projekt dann an einen anderen Computer sende, auf dem ich das Projekt nur mit der von mir erstellten Bibliothek kompilieren möchte, wird die Fehlermeldung angezeigt, dass eine .h-Datei der Intel IPP Library erforderlich ist. Irgendeine Idee?
Royi
lib-Datei ist normalerweise nicht genug. Wenn Sie es verwenden möchten, müssen Sie auch Header-Dateien einschließen. Aber es ist hier kein Thema, da dieser Thread über das Verknüpfen spricht und Ihr Problem sich in der Kompilierungsphase befindet.
Evpo
OK. Um Ihnen zu helfen, benötige ich weitere Informationen. Sehen Sie sich die Build-Ausgabe oder das Protokoll an und sehen Sie, was sich über die fehlende .h-Datei beschwert. Ich denke es ist cl.exe. In diesem Fall erhalten Sie den Namen der kompilierten CPP / ACC / C-Datei, die den Header verwendet. Wie heißt diese CPP-Datei und zu welchem ​​Projekt gehört sie?
evpo
Ich bin so verwirrt. Bevor ich das gelesen habe, schien es nie funktioniert zu haben (so sind meine Projekte bereits konfiguriert). Aber jetzt, wo ich das gelesen und meine Projekte zurückgesetzt habe, funktioniert es anscheinend. Stelle dir das vor! :(
Mordachai
1
@Mordachai dieses Haiku unten beschreibt Ihre Erfahrung perfekt: Gestern hat es funktioniert Heute funktioniert es nicht Windows ist so
evpo
5

Beachten Sie, bevor Sie den Rest lesen: Das hier gezeigte Shell-Skript ist sicherlich nicht sicher zu verwenden und gut getestet. Benutzung auf eigene Gefahr!

Ich habe ein Bash-Skript geschrieben, um diese Aufgabe zu erfüllen. Angenommen, Ihre Bibliothek ist lib1 und diejenige, aus der Sie einige Symbole einfügen müssen, ist lib2. Das Skript wird jetzt in einer Schleife ausgeführt, in der zunächst überprüft wird, welche undefinierten Symbole aus lib1 in lib2 gefunden werden können. Anschließend extrahiert es die entsprechenden Objektdateien aus lib2 mit ar, benennt sie ein wenig um und fügt sie in lib1 ein. Jetzt fehlen möglicherweise mehr Symbole, da die Inhalte, die Sie aus lib2 hinzugefügt haben, andere Inhalte aus lib2 benötigen, die wir noch nicht aufgenommen haben. Daher muss die Schleife erneut ausgeführt werden. Wenn nach einigen Durchläufen der Schleife keine Änderungen mehr vorgenommen werden, dh keine Objektdateien von lib2 zu lib1 hinzugefügt wurden, kann die Schleife gestoppt werden.

Beachten Sie, dass die enthaltenen Symbole immer noch als undefiniert von gemeldet werden. nmDaher verfolge ich die Objektdateien, die lib1 selbst hinzugefügt wurden, um festzustellen, ob die Schleife gestoppt werden kann.

#! /bin/bash

lib1="$1"
lib2="$2"

if [ ! -e $lib1.backup ]; then
    echo backing up
    cp $lib1 $lib1.backup
fi

remove_later=""

new_tmp_file() {
    file=$(mktemp)
    remove_later="$remove_later $file"
    eval $1=$file
}
remove_tmp_files() {
    rm $remove_later
}
trap remove_tmp_files EXIT

find_symbols() {
    nm $1 $2 | cut -c20- | sort | uniq 
}

new_tmp_file lib2symbols
new_tmp_file currsymbols

nm $lib2 -s --defined-only > $lib2symbols

prefix="xyz_import_"
pass=0
while true; do
    ((pass++))
    echo "Starting pass #$pass"
    curr=$lib1
    find_symbols $curr "--undefined-only" > $currsymbols
    changed=0
    for sym in $(cat $currsymbols); do
        for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
            echo "  Found $sym in $obj."
            if [ -e "$prefix$obj" ]; then continue; fi
            echo "    -> Adding $obj to $lib1"
            ar x $lib2 $obj
            mv $obj "$prefix$obj"
            ar -r -s $lib1 "$prefix$obj"
            remove_later="$remove_later $prefix$obj"
            ((changed=changed+1))
        done
    done
    echo "Found $changed changes in pass #$pass"

    if [[ $changed == 0 ]]; then break; fi
done

Ich habe dieses Skript benannt libcomp, damit Sie es dann zB mit aufrufen können

./libcomp libmylib.a libwhatever.a

wo libwhatever ist, wo Sie Symbole einfügen möchten. Ich denke jedoch, dass es am sichersten ist, alles zuerst in ein separates Verzeichnis zu kopieren. Ich würde meinem Skript nicht so sehr vertrauen (es hat jedoch bei mir funktioniert; ich könnte libgsl.a damit in meine numerische Bibliothek aufnehmen und diesen -lgsl-Compiler-Schalter weglassen).

Elmar Zander
quelle