¿Cómo encuentra gcc el siguiente archivo de encabezado?

10

Lo he incluido sys/ptrace.hen mi programa C.

La salida de /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -vda las siguientes rutas donde gcc busca archivos de encabezado

#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.

salida de gcc -Mpara mi programa da las siguientes ubicaciones de archivo de encabezado

    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

Como /usr/include/x86_64-linux-gnu/no está contenido en el primer resultado, ¿cómo encuentra gcc sys/ptrace.h?

EDITAR:

La salida de echo '#include <sys/ptrace.h>' | gcc -fsyntax-only -xc -v -H -resultados en

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) 
usuario912083132
fuente
Está mirando recursivamente /usr/include... ¿Qué problema estás tratando de resolver?
Ramhound
No parece que mire recursivamente. Si lo hiciera, no habría necesidad de incluir el sys / prefijo. Incluir solo ptrace.h, por ejemplo, no funciona.
user912083132
No creo que lo hayas incluido /sys/ptrace.hpero sys/ptrace.h, ¿verdad?
user253751
Esto es casi seguro un error en los parches "multiarch" para GCC. El directorio /usr/include/x86_64-linux-gnu se trata como un directorio de inclusión del sistema y debe incluirse en la lista de rutas de búsqueda impresa por gcc -v. No estoy seguro de cómo alguien logró lograr ese error; Si no recuerdo mal, la forma más obvia de agregar directorios de sistema incluye agregarlos a lo que imprime -v. (Escribí ~ 50% del preprocesador de GCC, pero eso fue hace 15 años, así que puede ser algo misremembering.)
Zwol
@Ramhound Definitivamente no busca recursivamente a continuación /usr/include. Eso rompería casi todas las bibliotecas de C del mundo.
zwol

Respuestas:

12

Respuesta más corta

Su pregunta es sobre el resultado de cc1 -v, pero eso no tiene en cuenta el CPP (preprocesador de C) e incluye que se mezclan en toda la cadena de compilación. Si ejecuta cpp -ven su sistema, debería ver, una combinación de incluye que se parece a la salida de cc1 -vpero con al menos la /usr/include/x86_64-linux-gnuruta agregada allí.

Respuesta larga

Como /usr/include/x86_64-linux-gnu/no está contenido en el primer resultado, ¿cómo encuentra gcc sys/ptrace.h?

Técnicamente, /usr/include/x86_64-linux-gnu/no se establece explícitamente en la primera salida, pero /usr/include/definitivamente sí. Y esa es una ruta de búsqueda predeterminada como se explica en la documentación oficial de GNU GCC :

GCC busca en varios lugares diferentes encabezados. En un sistema Unix normal, si no le indica lo contrario, buscará los encabezados solicitados #include <file>en:

  • / usr / local / include
  • libdir / gcc / target / version / include
  • / usr / target / include
  • / usr / include

Y más explicado aquí:

GCC busca encabezados solicitados #include "file"primero en el directorio que contiene el archivo actual, luego en los directorios según lo especificado por las -iquoteopciones, luego en los mismos lugares donde habría buscado un encabezado solicitado con corchetes angulares. Por ejemplo, si /usr/include/sys/stat.hcontiene # include "types.h", GCC busca types.hprimero en /usr/include/sys, luego en su ruta de búsqueda habitual.

Esto implica que la x86_64-linux-gnu/ruta simplemente se inserta /usr/include/*/sys/así:

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

Al menos eso es lo que inicialmente pensé en una versión anterior de esta pregunta . Pero después de revisar este sitio, la explicación de lo que está sucediendo es un poco más detallada y la respuesta directa de ese sitio al contenido equivalente al que publiqué arriba se vuelve a publicar a continuación; El énfasis en negrita es mío:

pero esa es una especie de respuesta floja (y también incompleta). ¿Seguramente debe haber una manera de que GCC le diga exactamente dónde va a terminar buscando sus archivos de encabezado? Bueno, aunque es conveniente pensar en GCC como una sola aplicación monolítica que toma archivos de código fuente y escupe programas de trabajo, técnicamente es una colección de otros programas que se encadenan para producir el archivo final compilado. El primero de ellos es CPP, abreviatura de C Preprocesador , cuyo trabajo es buscar directivas del compilador #includey modificar el código fuente según lo especificado por ellos; en el caso de incluir, copiando el contenido de otro archivo en el actual. Puede ver dónde busca estos archivos pasándole el indicador -v:

Sepa que el CPP (C preprocesador) es el primer paso en el proceso del compilador, echemos un vistazo a la salida "incluir" de cpp -vmi sistema de prueba 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

Ahí puedes ver claramente /usr/include/x86_64-linux-gnu. Y para comparar, aquí está la salida similar de "incluir" /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -ven el mismo sistema de prueba 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

Observe cómo /usr/include/x86_64-linux-gnuse inserta claramente en la mezcla mediante la acción inicial de CPP (C preprocesador). Y la publicación en ese sitio continúa explicando de dónde provienen esos caminos; Una vez más, el énfasis es mío:

esta ruta está realmente integrada en CPP (que es parte de GCC) en tiempo de compilación; si por alguna razón terminas eliminando uno de esos directorios, aún se verificará en cada compilación. Cada directorio se busca en el orden en que aparece aquí; si se encuentra un archivo /usr/local/include, los siguientes tres directorios no serán verificados.

Por lo tanto, todo se reduce a que se llame al CPP (preprocesador C) como la primera parte de una cadena de compilación C.

JakeGould
fuente
¿Por qué x86_64-linux-gnu / queda metido en el medio?
user912083132
@ user912083132: Esa es la $TARGETparte que mencioné en mi respuesta y comentario. Es la salida de config.guesscuándo se compiló GCC, o qué se le dio a su configurescript con la --targetbandera. La verdadera pregunta es, ¿cómo se ensambla ese camino? ¿Simplemente vuelve a la misma lista, agregando $TARGETa cada uno, después de no encontrar el encabezado la primera vez?
Warren Young
@ user912083132 Actualicé mi respuesta con información recién obtenida. Por favor releelo; La respuesta explica que proviene del CPP (preprocesador C).
JakeGould
2

A menos que profundice en el código fuente de GCC, no puedo darle un "por qué", pero puedo decirle que la versión de GCC que tengo aquí recurre/usr/include/$TARGET después de agotar las opciones que usted y JakeGould han encontrado . Puedes verlo así:

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

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

Necesita el -fargumento aquí porque gccgenera hijos para hacer el trabajo de compilación real. Necesita el 2>&1porque straceestá escribiendo sus resultados en stderr, no en stdout.

Observe que obtiene ENOENTerrores para todos los directorios documentados antes de que finalmente pruebe el que tiene éxito.

Warren Young
fuente