Newsgroup: it.comp.lang.c
Titolo: Problema compilazione header + libreria + Makefile

Ciao a tutti,
ho il seguente problemino: sto ultimando un esercizio per l'università
composto da più files, ma ho dei seri problemi durante la compilazione.
In realtà, prima adoperavo due headers (uno con tutti i #define, le
strutture e le variabili, l'altro con le funzioni in comune ai vari
programmi) e le cose funzionavano, poi oggi ho letto il thread "creare
libreria" qui sul NG e mi sono incuriosito e ho voluto provare a fare la
mia libreria per questo programma. In pratica, il programma è così
strutturato:
* un file header che contiene tutte le definizioni del caso (come prima)
* un sorgente C che contiene solo le definizioni delle funzioni dichiarate
nell'header (e che quindi #include l'header) con lo scopo di diventare la
libreria da linkare (cioè il file ".o")
* 5 sorgenti C (che diverranno 5 binari indipendenti) che a loro volta
#includono l'header
Il problema è che la libreria (ovvero il file oggetto) viene compilato
prima degli altri 5 binari (che sono da essa dipendenti), ma siccome sia
essa che i binari includono la libreria, risulta che essa viene compilata
due volte, e questo è quello che "make" mi dice (in realtà è GCC):
lib.o:(.data+0x0): multiple definition of `file1'
main.o:(.data+0x0): first defined here
lib.o:(.data+0x4): multiple definition of `file2'
main.o:(.data+0x4): first defined here
lib.o:(.data+0x8): multiple definition of `file3'
main.o:(.data+0x8): first defined here
lib.o:(.data+0xc): multiple definition of `foo1'
main.o:(.data+0xc): first defined here
lib.o:(.data+0x10): multiple definition of `foo2'
main.o:(.data+0x10): first defined here
collect2: ld returned 1 exit status
make: *** [main] Error 1
in questo caso, "lib.o" è la libreria (compilata correttamente) e
"main.o" è il file oggetto di uno dei 5 programmi (che no riesco a
linkare perchè si pianta).
Qui c'è uno snippet del Makefile:
lib.o: lib.c
	$(CC) $(CFLAGS) -c lib.c
main.o: main.c
	$(CC) $(CFLAGS) -c main.c
main: main.o lib.o
	$(CC) $(CFLAGS) main.o lib.o -o main
Dove diavolo è che sbaglio?
Come posso fare per risolvere?
Grazie 1000 a tutti quanti!
Ciao ciao :)
-- 
      ______________
(*)--[::::::::::::::]--(*)
(*)--[>::d1s4st3r::<]--(*)
(*)--[::::::::::::::]--(*)
(*)--[::wonder'ing::]--(*)
(*)--[::what's::::::]--(*)
(*)--[::^happening::]--(*)
(*)--[::|^::::::::::]--(*)
(*)--[__||__________]--(*)

 
Ora non ho tempo di leggere tutto, ma sembra che definisci una variabile 
o una funzione in piu' t.u. diverse.
-- 
Devaraja (Xdevaraja87^gmail^c0mX)
Linux Registerd User #338167
http://counter.li.org

 o una funzione in piu' t.u. diverse.
Esattamente. In realtà le variabili non sono definite più volte (sono
definite una volta sola nell'header, e basta), ma se ad esempio l'header
viene incluso da lib.c e main.c (e ciò mi è indispensabile), le
variabili definite nell'header risultano definite più di una volta
(infatti, vengono compilate sia in main.o che in lib.o, dove lib.o
contiene solo delle funzioni che servono agli altri programmi e deve
quindi essere linkato insieme ai file oggetto dei suddetti altri...).
Uff che casino, non ci capisco più niente.
Grazie comunque, ora vedo di cercare più info possibili per cercare di
risolvere sta' questione.
-- 
      ______________
(*)--[::::::::::::::]--(*)
(*)--[>::d1s4st3r::<]--(*)
(*)--[::::::::::::::]--(*)
(*)--[::wonder'ing::]--(*)
(*)--[::what's::::::]--(*)
(*)--[::^happening::]--(*)
(*)--[::|^::::::::::]--(*)
(*)--[__||__________]--(*)
 |......................|
http://xoomer.virgilio.it/
 +------> mental_insomnia/
(*) <-------------------+

Forse ho capito. Le definizioni di funzioni, le variabili, ecc. sono
viste due volte nei file sorgenti perchè l'header non è stato scritto
secondo una struttura del genere:
#ifndef NOME_HEADER_H
#define NOME_HEADER_H
    /* codice dell'header */
#endif
Questo evita che le definizioni di funzioni e le variabili siano
incluse più di una volta nei sorgenti, evitando gli errori di
"multiple definition". Prova e fammi sapere

 variabili definite nell'header risultano definite più di una volta
Hai capito il problema, quindi ti potresti praticamente rispondere da solo, 
anche perché è una questione che è stata discussa diverse volte.
Se un header contiene la definizione di una variabile globale, non può 
essere incluso in diverse unità di compilazione. Di conseguenza, 
se un header deve essere incluso di diverse unità di compilazione, non può 
contenere definizioni di variabli globali.
La soluzione è spostare ogni definizione in modo che compaia in un'unica 
unità di compilazione, e mantenere nel file header soltanto le 
dichiarazioni.
Dichiarazione:  extern int a;
Definizione:    int a = 42;
Questa è in realtà la pratica da adottare in C++, che funziona anche in C.
Però la distinzione tra dichiarazione e definizione è uno di quei punti in 
cui C e C++ divergono leggermente. In C la keyword extern può essere omessa 
in determinate circostanze. Inoltre, in C c'è anche il concetto di 
'tentative definition', che in C++ non esiste. In ogni caso, come ho detto, 
la regola esposta funziona perfettamente anche in C.
Max

 Forse ho capito.
No. Il problema dell'OP riguarda la definizione della stessa variabile in 
*diverse* unitą di compilazione. Il trucco del #define riguarda invece 
l'inclusione multipla nella *stessa* unitą di compilazione.
Max

 cui C e C++ divergono leggermente. 
Mi puoi spiegare come?


 Max
Esatto, le variabili incriminate che risultato "definite più volte" sono
delle "const char *" (ovvero delle costanti stringhe che devo usare
in tutti i programmi). Con i vari #define, invece, non c'è il minimo
problema.
Comunque provo subito il trucco della parola chiave "extern" e vedo se
funzia.
Intanto vi ringrazio per l'aiuto! ;-)


 
Il modo migliore è comunque quello, però in C puoi specificare semplicemente
         int a; // senza inizializzazione!
in un header e includerlo in diverse unità di compilazione, perché 'extern' 
in questo caso è assunto implicitamente. (Le cose sono un po' più 
complicate di così, ma io non conosco bene il C negli aspetti in cui si 
differenzia dal C++, quindi non sono la persona più indicata per fare 
chiarezza.)
In C++, quando non c'è 'extern', l'espressione è una definizione.
Max

 In C++, quando non c'è 'extern', l'espressione è una definizione.
Cosi' e' piu' chiaro cosa si vuole fare.


 
Utile?!?!?!?
Sei stato un benefattore!!!!!!!!!!!!!!!
L'hai spiegato in una maniera perfetta e con una semplicità quasi
imbarazzante! Grazie infinite! Meno male che ci sono persone come te che
dedicano del tempo a spiegare in maniera efficace cose poco chiare ai
più, e fa ancora più piacere quando penso che all'Università non c'è
stato neanche un docente (dico, *uno*) che abbia anche solo provato a
spiegare questi concetti in maniera chiara. Ti riempiono la testa con le
liste e gli alberi binari, mentre saltano le cose più fondamentali.
Vabbè, grazie Giovanni!
Ora il mio prog funziona, devo solo più apportare delle piccole
rifiniture!
Ciaooo :-PPP


 Vabbè, grazie Giovanni!
E` stato un piacere.
Ciao
