2016-06-16 36 views
5

In un progetto di libreria statica, ho un file di intestazione con funzioni dichiarate ma non implementate.Perché questo non crea più simboli definiti in questa libreria statica?

Ho un file .cpp che implementa queste funzioni.

Quindi, per comprendere meglio gli errori del linker, ho copiato il file cpp in modo da avere un duplicato esatto che viene anche compilato. Quindi, entrambi i file hanno una doppia implementazione per ogni simbolo nell'intestazione.

Compila e, quando utilizzato in un altro progetto, collega.

Qui un esempio minimo per la libreria statica:

api.hpp:

void printWhatever(); 

errortest.cpp e duplicate.cpp sono identici:

#include "api.hpp" 
#include <iostream> 
void printWhatever(){ 
    std::cout << "hi " << "\n"; 
} 

compilo questo come un statico libreria con questi 2 file sorgente. Vedo il compilatore produrre report per entrambi i file.

Ora usare questa libreria compilato in un eseguibile, un progetto diverso: main.cpp:

#include <api.hpp> 
int main(int argc, const char * argv[]) { 
    printWhatever(); 

    return 0; 
} 

Corre e stampe "hi".

Perché non esiste una definizione multipla per la funzione?

+0

si dovrebbe ottenere questo errore nella * fase di collegamento *, non durante la compilazione di –

+0

@ m.s. grazie ho corretto la domanda –

+0

stai effettivamente collegando i due file oggetto insieme? –

risposta

8

Il fatto chiave che è stato aggiunto a questa domanda è il fatto che i due moduli con il simbolo duplicato erano collegate in un libreria statica.

Una libreria statica funziona in modo molto diverso da una libreria condivisa. Durante il collegamento, il linker ricerca le librerie statiche per i simboli referenziati. Il primo modulo che definisce il simbolo di riferimento viene collegato per produrre l'eseguibile finale. Il fatto che un altro modulo definisca lo stesso simbolo è irrilevante. Se l'altro modulo con il simbolo duplicato non definisce nessun altro simbolo di cui l'eseguibile ha bisogno, non viene collegato all'eseguibile.

Se volete vedere un errore di duplicato con le librerie statiche:

chiamata foo() e bar() dal main().

Definire foo() e baz() nel primo modulo nella libreria statica.

Definire bar() e baz() nel 2 ° modulo nella libreria statica.

Poiché entrambi i moduli contengono simboli a cui viene fatto riferimento da main(), sono obbligati a collegarsi con l'eseguibile, causando un errore di simbolo duplicato a causa di baz().

+0

'Il primo modulo che definisce il simbolo di riferimento viene collegato' - questo è arbitrario su quale potrebbe essere? –

+0

Sì, l'ordine dei moduli in una libreria statica è completamente arbitrario. Inoltre, in genere, ogni modulo esporta più simboli e il linker, quando tenta di trovare ogni simbolo utilizzato dal file eseguibile principale, li cerca in un ordine non specificato, il che potrebbe comportare il collegamento di entrambi i moduli all'eseguibile. –

2

Il seguente esempio genera l'errore di collegamento desiderato:

main.cpp

int demo(); 
int main() { return demo(); } 

file1.cpp

int demo() { return 1; } 

file2.cpp

int demo() { return 2; } 

compilare

g++ main.cpp file1.cpp file2.cpp 

/tmp/ccdzSL9x.o: In function demo()': file2.cpp:(.text+0x0): multiple definition of demo()' /tmp/cc7Hzvrb.o:file1.cpp:(.text+0x0): first defined here collect2: error: ld returned 1 exit status

+0

Ho aggiornato la mia domanda –

+0

ho aggiunto un taglia a questa domanda per ottenere una risposta più specifica ai miei dettagli aggiornati –

3

How to create a multiple defined symbols linking error

programma di shell abbastanza minimale per generare un abbastanza minimale programma di mal formati C++ che viola una regola definizione:

echo 'int main(){}' | tee a.cpp > b.cpp 
g++ a.cpp b.cpp 

Dovrebbe essere facile da seguire cosa sta succedendo. Ci sono due file sorgente che definiscono entrambi una funzione non in linea int main(), violando così odr.

+0

Ho aggiornato la mia domanda. Forse le regole di definizione multipla sono diverse per le librerie statiche? –

+0

@JXB legge i commenti alla domanda. Crea un [mcve] che collega con successo, ma non ti aspetti di farlo. – user2079303

+0

fatto, grazie. breve esempio. –