In che modo gcc trova il seguente file di intestazione?


10

Ho incluso sys/ptrace.hnel mio programma C.

L'output di /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -vfornisce i seguenti percorsi in cui gcc cerca i file di intestazione

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include
End of search list.

l'output di gcc -Mper il mio programma fornisce le seguenti posizioni dei file di intestazione

    pt.o: pt.c /usr/include/stdc-predef.h /usr/include/stdio.h \
 /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
 /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h \
 /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
 /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
 /usr/include/x86_64-linux-gnu/sys/ptrace.h

Dato che /usr/include/x86_64-linux-gnu/non è contenuto nel primo output, come trova gcc sys/ptrace.h?

MODIFICARE:

L'output dei echo '#include <sys/ptrace.h>' | gcc -fsyntax-only -xc -v -H -risultati in

Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) 

Sta guardando in modo ricorsivo /usr/include.. Quale problema stai cercando di risolvere?
Ramhound,

Non sembra ricorsivamente. In tal caso, non sarebbe necessario includere il sys / prefisso. Includere solo ptrace.h, ad esempio, non funziona.
user912083132

Non penso che tu abbia incluso /sys/ptrace.hma sys/ptrace.h, giusto?
user253751

Questo è quasi certamente un bug nelle patch "multiarch" di GCC. La directory /usr/include/x86_64-linux-gnu viene trattata come directory di inclusione del sistema e deve essere inclusa nell'elenco del percorso di ricerca stampato da gcc -v. Non sono sicuro di come qualcuno sia riuscito a ottenere quel bug; se ricordo bene, il modo più ovvio per aggiungere directory di inclusione del sistema le aggiunge a ciò che viene stampato -v. (Ho scritto circa il 50% del preprocessore di GCC, ma era 15 anni fa, quindi potrei non ricordare qualcosa.)
zwol,

@Ramhound E sicuramente non non ricorsivo di ricerca qui sotto /usr/include. Ciò si spezzerebbe quasi ogni libreria C del mondo.
zwol,

Risposte:


12

Risposta più breve.

La tua domanda riguarda l'output di cc1 -v, ma ciò non tiene conto del CPP (C Pre-Processor) ed è incluso che sono mescolati nell'intera catena di compilazione. Se corri cpp -vsul tuo sistema dovresti vedere, un mix di include che sembra simile all'output di cc1 -vma con almeno il /usr/include/x86_64-linux-gnupercorso aggiunto lì.

Risposta più lunga.

Dato che /usr/include/x86_64-linux-gnu/non è contenuto nel primo output, come trova gcc sys/ptrace.h?

Tecnicamente, /usr/include/x86_64-linux-gnu/non è esplicitamente impostato nel primo output, ma /usr/include/sicuramente lo è. E questo è un percorso di ricerca predefinito come spiegato nella documentazione ufficiale GNU GCC :

GCC cerca diverse intestazioni per le intestazioni. Su un normale sistema Unix, se non lo si istruisce diversamente, cercherà le intestazioni richieste con #include <file>in:

  • / usr / local / includono
  • libdir / gcc / target / versione / include
  • / Usr / target / include
  • / Usr / include

E ulteriormente spiegato qui:

GCC cerca le intestazioni richieste #include "file"prima nella directory contenente il file corrente, quindi nelle directory come specificato dalle -iquoteopzioni, quindi nelle stesse posizioni avrebbe cercato un'intestazione richiesta con parentesi angolari. Ad esempio, se /usr/include/sys/stat.hcontiene # include "types.h", GCC cerca types.hprima in /usr/include/sys, quindi nel suo solito percorso di ricerca.

Quindi questo implica che il x86_64-linux-gnu/percorso è semplicemente inserito in /usr/include/*/sys/questo modo:

/usr/include/x86_64-linux-gnu/sys/ptrace.h

Almeno questo è quello che inizialmente pensavo in una versione precedente di questa domanda . Ma dopo aver visitato questo sito la spiegazione di ciò che sta accadendo è un po 'più dettagliata e la risposta diretta da quel sito al contenuto equivalente a quello che ho pubblicato sopra è ripubblicata di seguito; grassetto enfasi è mia:

ma è una specie di risposta ambiziosa (e anche incompleta). Sicuramente ci deve essere un modo per convincere GCC a dirti esattamente dove finirà per cercare i suoi file di intestazione? Bene, sebbene sia conveniente pensare a GCC come a una singola applicazione monolitica che contiene file di codice sorgente e sputa programmi di lavoro, è tecnicamente una raccolta di altri programmi che si uniscono per produrre il file oggetto compilato finale. Il primo di questi è CPP, abbreviazione di C Pre-Processor , il cui compito è cercare direttive del compilatore come #includee modificare il codice sorgente come specificato da loro; nel caso di include, copiando il contenuto di un altro file in quello corrente. Puoi vedere dove cerca questi file passandogli il flag -v:

Sappi che il CPP (C Pre-Processor) è il primo passo nel processo del compilatore, diamo un'occhiata all'output "include" cpp -vsul mio sistema di test Ubuntu 12.04.5:

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include

Lì puoi vedere chiaramente /usr/include/x86_64-linux-gnu. E per confrontare, ecco l'output "include" simile /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -vsullo stesso sistema di test Ubuntu 12.04.5:

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
 /usr/include

Nota come /usr/include/x86_64-linux-gnuviene chiaramente inserito nel mix dall'azione iniziale CPP (C Pre-Processor). E il post su quel sito continua a spiegare da dove provengono quei percorsi; di nuovo audace enfasi è mia:

questo percorso è effettivamente incorporato in CPP (che fa parte di GCC) al momento della compilazione; se per qualsiasi motivo si finisce per eliminare una di quelle directory, verrà comunque verificato per ogni compilazione. Ogni directory viene cercata nell'ordine in cui è elencata qui; se viene trovato un file /usr/local/include, le prossime tre directory non verranno controllate.

Quindi tutto si riduce al CPP (C Pre-Processor) chiamato come la prima parte di una catena di compilazione C.


Perché x86_64-linux-gnu / viene spinto nel mezzo?
user912083132

@ user912083132: Questa è la $TARGETparte che ho citato nella mia risposta e commento. È l'output di config.guessquando è stato compilato GCC, o che è stato dato al suo configurescript con la --targetbandiera. La vera domanda è: come si riunisce quel percorso? Torna indietro attraverso lo stesso elenco, aggiungendo $TARGETa ciascuno, dopo aver fallito nel trovare l'intestazione la prima volta?
Warren Young,

@ user912083132 Ho aggiornato la mia risposta con alcune informazioni appena raccolte. Per favore rileggilo; la risposta spiega che proviene dal CPP (C Pre-Processor).
Jake Gould

2

A meno di approfondire il codice sorgente di GCC, non posso darti un "perché", ma posso dirti che la versione di GCC che ho qui ricade /usr/include/$TARGETdopo aver esaurito le scelte che tu e JakeGould avete trovato . Puoi vederlo così:

$ strace -f -e open gcc -c foo.c -o foo.o 2>&1 | grep ptrace.h

dove foo.ccontiene a #include <sys/ptrace.h>.

È necessario l' -fargomento qui perché gccgenera figli per fare il lavoro di compilazione reale. Hai bisogno del 2>&1perché stracesta scrivendo i suoi risultati su stderr, non su stdout.

Notare che si ottengono ENOENTerrori per tutte le directory documentate prima che provi finalmente quella che ha successo.

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.