Collegamento di librerie statiche ad altre librerie statiche


138

Ho un piccolo pezzo di codice che dipende da molte librerie statiche (a_1-a_n). Vorrei impacchettare quel codice in una libreria statica e renderlo disponibile ad altre persone.

La mia libreria statica, chiamiamola X, si compila bene.

Ho creato un semplice programma di esempio che utilizza una funzione da X, ma quando provo a collegarlo a X, ricevo molti errori sui simboli mancanti dalle librerie a_1 - a_n.

C'è un modo in cui posso creare una nuova libreria statica, Y che contiene X e tutte le funzionalità richieste da X (bit selezionati da a_1 - a_n), in modo da poter distribuire solo Y affinché le persone colleghino i loro programmi?


AGGIORNARE:

Ho esaminato semplicemente il dumping di tutto con ar e la creazione di un mega-lib, tuttavia, che finisce per includere molti simboli non necessari (tutti i file .o sono circa 700 MB, tuttavia, un eseguibile collegato staticamente è 7 MB). C'è un bel modo per includere solo ciò che è effettivamente necessario?


Questo sembra strettamente correlato a Come combinare diverse librerie C / C ++ in una? .

Risposte:


76

Le librerie statiche non si collegano con altre librerie statiche. L'unico modo per farlo è usare il tuo strumento bibliotecario / archiviatore (ad esempio ar su Linux) per creare una nuova nuova libreria statica concatenando le librerie multiple.

Modifica: in risposta al tuo aggiornamento, l'unico modo che conosco per selezionare solo i simboli richiesti è creare manualmente la libreria dal sottoinsieme dei file .o che li contengono. Questo è difficile, richiede tempo e soggetto a errori. Non sono a conoscenza di strumenti che lo aiutino (per non dire che non esistono), ma sarebbe un progetto abbastanza interessante per produrne uno.


Ciao Neil, ho aggiornato la domanda: conosci un modo per includere solo i file .o necessari?
Jason Sundram,

Aggiornamento: se ti accorgi di voler fare questo, fai un passo indietro e persegue qualcos'altro (a meno che, come sottolinea John Knoeller, stai usando Visual Studio). Ho sprecato molto tempo in questo approccio e non ho ottenuto nulla di utile.
Jason Sundram,

Lo strumento GNU ld fornisce un'opzione -rcon cui l'output può essere usato come input per ld. Se ti colleghi una volta, dovresti ottenere un trasferimento trasferibile che può surrogare le tue librerie. (l'ho provato thogh).
Harper il

49

Se si utilizza Visual Studio, sì, è possibile farlo.

Lo strumento per la creazione di librerie fornito con Visual Studio consente di unire le librerie nella riga di comando. Non conosco alcun modo per farlo nell'editor visivo però.

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib

5
In VS2008, nelle proprietà del progetto di compositelib in Bibliotecario / Generale, se si seleziona [x] Dipendenze libreria link, lo farà per voi se lib1 e lib2 sono dipendenze di compositelib. Sembra un po 'difettoso, impostarei la casella di controllo separatamente in ogni configurazione di build, non una volta in "Tutte le configurazioni".
Spike0xff,

2
VS2015 IDE - non usi "Dipendenze aggiuntive" in Bibliotecario / Generale per ottenere ulteriori librerie collegate direttamente alla biblioteca che il tuo progetto sta costruendo?
davidbak,

@davidbak Sto cercando di capirlo negli ultimi due giorni e apparentemente questa opzione è obsoleta e non fa nulla?
Montaldo,

20

Su Linux o MingW, con toolchain GNU:

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

Se non si elimina liba.ae libb.a, è possibile creare un "archivio sottile":

ar crsT libab.a liba.a libb.a

Su Windows, con la toolchain MSVC:

lib.exe /OUT:libab.lib liba.lib libb.lib

Bello da sapere, ma non risolve davvero il problema del PO, dal momento che stai includendo tutto da libb.a nella lib comune, che può diventare molto grande se hai bisogno solo di alcuni moduli di libb.
Elmar Zander,

1
@ElmarZander Ma puoi usare ar crsT, che fa qualcosa come "symlinking" invece di copiare, quindi devi solo spedire una copia dei dati.
Star Brilliant,

Gli archivi thin sono utilizzati in particolare sul kernel Linux v4.19: unix.stackexchange.com/questions/5518/…
Ciro Santilli 21 冠状 病 六四 事件 法轮功

10

Una libreria statica è solo un archivio di .ofile oggetto. Estrarli con ar(supponendo Unix) e rimetterli in una grande libreria.


6

In alternativa alle Link Library Dependenciesproprietà del progetto esiste un altro modo per collegare le librerie in Visual Studio.

  1. Apri il progetto della libreria (X) che desideri combinare con altre librerie.
  2. Aggiungi le altre librerie che desideri combinate con X (tasto destro, Add Existing Item...).
  3. Vai alle loro proprietà e assicurati che lo Item TypesiaLibrary

Ciò includerà le altre librerie in X come se avessi eseguito

lib /out:X.lib X.lib other1.lib other2.lib

Ciao, sto usando Intel IPP e ho costruito le mie funzioni che voglio che siano tutte racchiuse in una lib (statica). Tuttavia quando creo la lib e poi invio il progetto ad un altro computer che voglio poter compilare il progetto solo usando la lib che ho creato, ricevo un errore che dice che è richiesto un file .h della libreria Intel IPP. Qualche idea?
Royi,

il file lib di solito non è abbastanza. Se si desidera utilizzarlo, è necessario includere anche i file di intestazione. Ma è fuori tema qui come questo thread parla di collegamenti e il tuo problema è in fase di compilazione.
evpo,

ok. Per aiutarti avrò bisogno di ulteriori informazioni. Guarda l'output o il log della build e vedi cosa si lamenta del file .h mancante. Penso che sia cl.exe. In tal caso, ti darà il nome del file .cpp / .cc / .c compilato che utilizza l'intestazione. Qual è il nome di quel file .cpp e a quale progetto appartiene?
evpo,

Sono così confuso. Prima di leggere questo, non sembrava aver mai funzionato (è così che i miei progetti sono già configurati). Ma ora che ho letto questo e resettato i miei progetti, sembra funzionare. Vai a capire! :(
Mordachai

1
@Mordachai questo haiku di seguito descrive perfettamente la tua esperienza: ieri ha funzionato oggi non funziona Windows è così
evpo

5

Nota prima di leggere il resto: lo script di shell mostrato qui non è certamente sicuro da usare e ben testato. Utilizzare a proprio rischio!

Ho scritto uno script bash per compiere quel compito. Supponiamo che la tua libreria sia lib1 e quella da cui devi includere alcuni simboli è lib2. Lo script ora viene eseguito in un ciclo, dove controlla innanzitutto quali simboli indefiniti di lib1 possono essere trovati in lib2. Quindi estrae i file oggetto corrispondenti da lib2 con ar, li rinomina un po 'e li mette in lib1. Ora potrebbero esserci più simboli mancanti, perché le cose che hai incluso da lib2 hanno bisogno di altre cose da lib2, che non abbiamo ancora incluso, quindi il ciclo deve essere eseguito di nuovo. Se dopo alcuni passaggi del loop non ci sono più modifiche, ovvero nessun file oggetto da lib2 aggiunto a lib1, il loop può fermarsi.

Nota che i simboli inclusi sono ancora riportati come non definiti da nm, quindi tengo traccia dei file oggetto, che sono stati aggiunti a lib1, stessi, per determinare se il loop può essere fermato.

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

Ho chiamato questo script libcomp, quindi puoi chiamarlo, ad esempio con

./libcomp libmylib.a libwhatever.a

dove libwhatever è dove vuoi includere simboli. Tuttavia, penso che sia più sicuro copiare prima tutto in una directory separata. Non mi fiderei tanto della mia sceneggiatura (tuttavia, ha funzionato per me; potrei includere libgsl.a nella mia libreria numerica con quella e tralasciare quel parametro del compilatore -lgsl).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.