2014-12-26 4 views
5

Sto effettuando una configurazione di prova di una libreria e un programma statico C. Il codice della libreria, che si trova in una sottodirectory 'pippo' del mio progetto, contiene i seguenti file:Incluso il file di intestazione dalla libreria statica

foo/pippo.c:

#include <stdio.h> 
void foo(void) { 
    printf("something"); 
} 

foo/foo.h:

#ifndef foo_h__ 
#define foo_h__ 
extern void foo(void); 
#endif 

Il mio codice progamma è il seguente:

test.c:

#include "foo.h" 
int main() { 
    foo(); 
    return 0; 
} 

Ho uno script di build, denominata 'costruire', che contiene quanto segue:

costruzione:

#!/bin/bash 
gcc -c -Wall -Werror foo/foo.c 
ar rcs libfoo.a foo.o 
gcc -static -o test test.c libfoo.a # I have also tried -L. -lfoo 

Ma quando corro costruire, mi dà il seguente errore:

test.c:1:17: fatal error: foo.h: No such file or directory 
    #include "foo.h" 
       ^
Compilation terminated 

Funziona, tuttavia, quando ometto la riga #include, ma preferirei se potessi usare i file header nelle mie librerie statiche. Cosa sto sbagliando e come posso risolverlo?

risposta

18

Le intestazioni non sono archiviate nelle librerie. Le intestazioni sono memorizzate separatamente dalle librerie. Le librerie contengono file oggetto; le intestazioni non sono file oggetto. Per impostazione predefinita, le intestazioni standard su un sistema Unix sono memorizzate in /usr/include - normalmente troverai /usr/include/stdio.h e /usr/include/string.h e /usr/include/stdlib.h, ad esempio. Per impostazione predefinita, le librerie sono memorizzate in /usr/lib (ma è possibile trovarne anche in /lib). Spesso, i compilatori sono configurati per cercare anche in altri posti. Una posizione alternativa comune è inferiore a /usr/local, quindi /usr/local/include per le intestazioni e /usr/local/lib per le librerie. Si noti, inoltre, che una singola libreria può avere molte intestazioni che definiscono i servizi. La libreria predefinita è un esempio. Ha le funzioni corrispondenti a quelle trovate in <stdio.h>, <string.h>, <stdlib.h> e molte altre intestazioni.

Guardando il codice:

  1. Se il file di intestazione è in ./foo/foo.h, allora è necessario scrivere:

    #include "foo/foo.h" 
    

    Oppure, se si continua a utilizzare #include "foo.h", è necessario specificare dove per trovare l'intestazione sulla riga di comando del compilatore con l'argomento:

    gcc -Ifoo -o test test.c -L. -lfoo 
    

    Ho deliberatamente escluso il -static; è necessario solo quando c'è una scelta tra una libreria statica e una condivisa, ma hai solo libfoo.a, quindi il linker lo userà comunque.

    Si noti che il problema è un errore di compilazione, non un errore di collegamento.Questo sarebbe più chiaro se si divide l'edificio programma in due fasi: (1) creare test.o e (2) Programma link:

    gcc -c -Ifoo test.c 
    gcc -o test test.o -L. -lfoo 
    
  2. la guardia di intestazione è difettoso. Originariamente avuto (ma hanno aggiornato la questione in modo da questo errore di battitura non è più presente):

    #ifndef foo_h__ 
    #define foo_h_ 
    

    è necessario scaricare:

    #ifndef foo_h__ 
    #define foo_h__ 
    

    I nomi di macro devono essere gli stessi in entrambe le linee. Nota che in questo caso l'errore ortografico è in gran parte innocuo, ma su Mac OS X, clang (mascherato come gcc) ha dato un avvertimento a riguardo (anche se l'avevo notato prima di fare qualsiasi compilazione). In alcuni altri casi, non si otterrebbe la protezione che le protezioni dell'intestazione sono progettate per fornire.

    ./foo/foo.h:1:9: warning: 'foo_h__' is used as a header guard here, followed by #define of a 
         different macro [-Wheader-guard] 
    #ifndef foo_h__ 
         ^~~~~~~ 
    ./foo/foo.h:2:9: note: 'foo_h_' is defined here; did you mean 'foo_h__'? 
    #define foo_h_ 
         ^~~~~~ 
         foo_h__ 
    1 warning generated. 
    

Si potrebbe legittimamente chiedersi:

  • Se ho bisogno -Ifoo durante la compilazione test.c, perché non è stato necessario durante la compilazione foo/foo.c?

Buona domanda!

  1. Non sarebbe male la compilazione di foo/foo.c
  2. GCC sembra per le intestazioni nella directory dove si trova il codice sorgente della unità di traduzione (così, durante la compilazione foo/foo.c, appare in foo directory per le intestazioni inclusi come #include "foo.h" comunque
  3. l'origine del file foo/foo.c deve aver incluso foo.h anche;., è molto importante che lo fa come che è come il compilatore fornisce il controllo incrociato necessario per garantire la coerenza Se tu avessi scritto #include "foo.h", la compilazione avrebbe funzionato. come desc ribed. Se hai scritto (in foo/foo.c) #include "foo/foo.h", la riga di comando per creare foo.o avrebbe avuto bisogno di -I. in modo che fosse possibile trovare l'intestazione.
+0

Ma l'intestazione foo.h fa parte della libreria libfoo.a, non è vero? Inoltre, il problema della protezione dell'intestazione era un refuso quando l'ho ridigitato su StackOverflow, cosa che ho fatto perché sono su Windows SSHing in un sistema Ubuntu. –

+0

No. Una libreria contiene solo ed esclusivamente file oggetto. Le intestazioni sono _not_ file oggetto. Le intestazioni non sono contenute nelle librerie. (OK: per essere assolutamente pedante, è possibile aggiungere un file di intestazione a una libreria, ma il compilatore non apparirebbe mai in una libreria: solo il linker ('ld', di solito) guarda nelle librerie, e cerca solo i file oggetto , non intestazioni). –

+0

Oh, ok. Grazie per aver chiarito questo. Ma allora perché, ad esempio, posso includere, ad esempio, "ncurses.h" dalla libreria ncurses? –