2009-04-30 13 views
25

L'unico utilizzo reale dell'opzione di collegamento --whole-archive che ho visto è la creazione di librerie condivise da quelle statiche. Recentemente mi sono imbattuto in Makefile (s) che usa sempre questa opzione quando si collegano con le librerie statiche interne. Ciò, naturalmente, fa sì che gli eseguibili eseguano inutilmente il codice oggetto senza riferimento. La mia reazione è stata che questo è assolutamente sbagliato, mi manca qualcosa qui?ld domanda linker: l'opzione --whole-archive

La seconda domanda che ho ha a che fare con qualcosa che ho letto sull'opzione dell'intero archivio ma che non ho potuto analizzare. Qualcosa nell'effetto che l'opzione --whole-archive debba essere usata durante il collegamento con una libreria statica se l'eseguibile si collega anche con una libreria condivisa che a sua volta ha (in parte) lo stesso codice oggetto della libreria statica. Questa è la libreria condivisa e la libreria statica si sovrappone in termini di codice oggetto. L'utilizzo di questa opzione costringerebbe tutti i simboli (indipendentemente dall'uso) a essere risolti nell'eseguibile. Questo dovrebbe evitare la duplicazione del codice oggetto. Ciò è fonte di confusione, se un simbolo è referenziato nel programma deve essere risolto in modo univoco al momento del collegamento, qual è il business della duplicazione? (Perdonami se questo paragrafo non è del tutto l'epitome di chiarezza)

Grazie

risposta

3

Sono d'accordo che l'uso -Tutto-archivio per costruire gli eseguibili non è probabilmente quello che si vuole (a causa di collegamento nel codice non necessario e creazione di software gonfiato). Se avessero una buona ragione per farlo, dovrebbero averlo documentato nel sistema di costruzione, come ora sei lasciato a indovinare.

Per quanto riguarda la seconda parte della domanda. Se un eseguibile collega sia una libreria statica che una libreria dinamica con lo libreria statica (in parte), lo stesso codice oggetto della libreria statica assicurerà che al momento del collegamento il codice della libreria statica sia preferito . Questo è solitamente quello che vuoi quando fai il collegamento statico.

50

Ci sono usi legittimi di --whole-archive quando si collega eseguibile con librerie statiche. Un esempio è la costruzione di codice C++, in cui le istanze globali "registrano" se stessi nelle loro costruttori (avvertimento: codice non testato):

main.cc

typedef void (*handler)(const char *protocol); 
typedef map<const char *, handler> M; 
M m; 

void register_handler(const char *protocol, handler) { 
    m[protocol] = handler; 
} 
int main(int argc, char *argv[]) 
{ 
    for (int i = 1; i < argc-1; i+= 2) { 
     M::iterator it = m.find(argv[i]); 
     if (it != m.end()) it.second(argv[i+1]); 
    } 
} 

http.cc (parte di libhttp.a)

class HttpHandler { 
    HttpHandler() { register_handler("http", &handle_http); } 
    static void handle_http(const char *) { /* whatever */ } 
}; 
HttpHandler h; // registers itself with main! 

Si noti che non ci sono simboli in http.cc che richiede main.cc. Se si collega questo come

g++ main.cc -lhttp 

si non ottiene un gestore HTTP linkati all'interno dell'eseguibile principale, e non sarà in grado di chiamare handle_http(). In contrasto con ciò che accade quando si collega come:

g++ main.cc -Wl,--whole-archive -lhttp -Wl,--no-whole-archive 

Lo stesso stile "autoregistrazione" è possibile anche in pianura-C, per esempio con l'estensione GNU __attribute__((constructor)).

+1

Russion Se libhttp.a può essere costruita, dimostra che la funzione register_handler esisteva in quella libhttp.a. Quindi, come può questa funzione riferirsi a register_handler in main.cc? Quindi, in questo caso, dobbiamo usare un altro modo per attuare la tua idea. – longbkit

9

Un altro uso legittimo per --whole-archive è per gli sviluppatori di toolkit per distribuire librerie contenenti più funzionalità in una singola libreria statica. In questo caso, il fornitore non ha idea di quali parti della biblioteca saranno utilizzate dal consumatore e quindi deve includere tutto.

+4

s/condiviso/statico / – Igor

1

Vecchia query, ma sulla prima domanda ("Perché"), ho visto - l'archivio intero utilizzato anche per le librerie interne, principalmente per aggirare i riferimenti circolari tra quelle librerie. Tende a nascondere la scarsa architettura delle librerie, quindi non lo consiglierei. Tuttavia è un modo veloce per far funzionare una prova rapida.

Per la seconda query, se lo stesso simbolo era presente in un oggetto condiviso e in una libreria statica, il linker soddisferà il riferimento con qualsiasi libreria che incontra per primo.
Se la libreria condivisa e la libreria statica hanno una condivisione esatta del codice, tutto ciò potrebbe funzionare. Ma dove la libreria condivisa e la libreria statica hanno implementazioni diverse degli stessi simboli, il tuo programma verrà comunque compilato ma si comporterà diversamente in base all'ordine delle librerie.

Forzare tutti i simboli da caricare dalla libreria statica è un modo per rimuovere confusione su cosa viene caricato da dove. Ma in generale questo sembra risolvere il problema sbagliato; per lo più non vorrete gli stessi simboli in diverse librerie.

0

Un altro buon scenario in cui --whole-archive è ben utilizzato è quando si tratta di librerie statiche e collegamento incrementale.

Supponiamo che:

  1. libA implementa le a() e b() funzioni.
  2. Una parte del programma deve essere collegata solo a libA, ad es. a causa di qualche funzione di incarto tramite --wrap (un esempio classico è malloc)
  3. libC implementa le c() funzioni e utilizza a()
  4. il programma finale utilizza a() e c()

incrementali passaggi collegano potrebbe essere:

ld -r -o step1.o module1.o --wrap malloc --whole-archive -lA 
ld -r -o step2.o step1.o module2.o --whole-archive -lC 
cc step3.o module3.o -o program 

Impossibile inserire --whole-archive potrebbe rimuovere la funzione c() w che è comunque utilizzato da program, impedendo il corretto processo di compilazione.

Naturalmente, questo è un caso particolare angolo in cui il collegamento incrementale deve essere fatto per evitare incarto tutte le chiamate a malloc in tutti i moduli, ma è un caso che è supportato con successo da --whole-archive.