W jaki sposób gcc znajduje następujący plik nagłówkowy?

10

Dołączyłem sys/ptrace.hdo mojego programu C.

Dane wyjściowe polecenia /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -vpodaje następujące ścieżki, w których gcc szuka plików nagłówkowych

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

Dane wyjściowe gcc -Mdla mojego programu podaje następujące lokalizacje plików nagłówkowych

    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

Ponieważ /usr/include/x86_64-linux-gnu/gcc nie znajduje się w pierwszym wyjściu, jak to się znajduje sys/ptrace.h?

EDYTOWAĆ:

Wynik echo '#include <sys/ptrace.h>' | gcc -fsyntax-only -xc -v -H -wyników w

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) 
użytkownik912083132
źródło
Rekurencyjnie patrzy na /usr/include... Jaki problem próbujesz rozwiązać?
Ramhound,
Nie wygląda na to, że rekurencyjnie przegląda. Gdyby tak było, nie byłoby potrzeby dołączania prefiksu sys /. Na przykład włączenie tylko ptrace.h nie działa.
user912083132
I nie sądzę, żebyś włączone /sys/ptrace.h, ale sys/ptrace.h, prawda?
user253751
Jest to prawie na pewno błąd w łatkach „multiarch” do GCC. Katalog /usr/include/x86_64-linux-gnu jest traktowany jako katalog zawierający system i powinien zostać uwzględniony na wydrukowanej liście ścieżek wyszukiwania gcc -v. Nie jestem pewien, jak komuś udało się osiągnąć ten błąd; jeśli dobrze pamiętam, najbardziej oczywistym sposobem dodania katalogów dołączanych do systemu jest dodanie ich do tego, co jest drukowane -v. (Napisałem ~ 50% preprocesora GCC, ale to było 15 lat temu, więc mogę coś źle zapamiętać.)
zwolnij
@Ramhound To zdecydowanie nie wyszukuje rekurencyjnie poniżej /usr/include. To zepsułoby prawie każdą bibliotekę C na świecie.
zwolnienie

Odpowiedzi:

12

Krótsza odpowiedź.

Twoje pytanie dotyczy wyniku cc1 -v, ale to nie bierze pod uwagę CPP (C Pre-Processor) i obejmuje, które są mieszane w całym łańcuchu kompilacji. Jeśli uruchamiasz się cpp -vw swoim systemie, powinieneś zobaczyć, że zestaw zawiera wygląd podobny do wyjścia, cc1 -vale z /usr/include/x86_64-linux-gnudodaną przynajmniej ścieżką.

Dłuższa odpowiedź.

Ponieważ /usr/include/x86_64-linux-gnu/gcc nie znajduje się w pierwszym wyjściu, jak to się znajduje sys/ptrace.h?

Technicznie rzecz biorąc, /usr/include/x86_64-linux-gnu/nie jest wyraźnie ustawiony na pierwszym wyjściu, ale na /usr/include/pewno jest. Jest to domyślna ścieżka wyszukiwania, jak wyjaśniono w oficjalnej dokumentacji GNU GCC :

GCC szuka nagłówków w kilku różnych miejscach. W normalnym systemie uniksowym, jeśli nie zalecisz inaczej, będzie szukał nagłówków wymaganych #include <file>w:

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

I dalej wyjaśnione tutaj:

GCC szuka żądanych nagłówków #include "file"najpierw w katalogu zawierającym bieżący plik, następnie w katalogach określonych przez -iquoteopcje, a następnie w tych samych miejscach szukałby nagłówka z nawiasami kątowymi. Na przykład, jeśli /usr/include/sys/stat.hzawiera # include "types.h", GCC szuka types.hnajpierw w /usr/include/sys, a następnie w zwykłej ścieżce wyszukiwania.

Oznacza to, że x86_64-linux-gnu/ścieżka jest po prostu wstawiana w /usr/include/*/sys/następujący sposób:

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

Przynajmniej tak początkowo myślałem we wcześniejszej wersji tego pytania . Ale po sprawdzeniu tej strony wyjaśnienie tego, co się dzieje, jest nieco bardziej szczegółowe, a bezpośrednia odpowiedź z tej strony na równoważną treść do tego, co opublikowałem powyżej, jest zamieszczona poniżej; śmiały nacisk jest mój:

ale taka odpowiedź jest nieco mętna (i również niepełna). Z pewnością musi istnieć sposób, aby GCC powiedział dokładnie, gdzie skończy szukać plików nagłówkowych? Cóż, chociaż wygodnie jest myśleć o GCC jako o pojedynczej monolitycznej aplikacji, która pobiera pliki kodu źródłowego i wydziela działające programy, technicznie jest to zbiór innych programów, które łączą się w łańcuch, tworząc końcowy skompilowany plik obiektowy. Pierwszym z nich jest CPP, skrót od C Pre-Processor , którego zadaniem jest poszukiwanie dyrektyw kompilatora takich jak #includei modyfikowanie kodu źródłowego zgodnie z ich specyfikacją; w przypadku dołączenia, kopiując zawartość innego pliku do bieżącego. Możesz zobaczyć, gdzie szuka tych plików, przekazując flagę -v:

Wiedz, że CPP (C Pre-Processor) jest pierwszym krokiem w procesie kompilatora, spójrzmy na wynik „ cpp -vwłącz ” w moim systemie testowym 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

Tam możesz wyraźnie zobaczyć /usr/include/x86_64-linux-gnu. I dla porównania, oto podobne wyjście „ /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -vwłącz ” w tym samym systemie testowym 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

Zwróć uwagę, jak /usr/include/x86_64-linux-gnuwyraźnie wprowadza się do miksu początkowe działanie CPP (C Pre-Processor). I post na tej stronie wyjaśnia dalej, skąd pochodzą te ścieżki; znowu odważny nacisk jest mój:

ścieżka ta jest faktycznie wbudowana w CPP (który jest częścią GCC) w czasie kompilacji; jeśli z jakiegoś powodu skończysz usuwać jeden z tych katalogów, będzie on sprawdzany pod kątem każdego kompilacji. Każdy katalog jest przeszukiwany w kolejności, w jakiej jest tutaj wymieniony; jeśli plik zostanie znaleziony /usr/local/include, kolejne trzy katalogi nie zostaną sprawdzone.

Wszystko sprowadza się więc do wywołania CPP (C Pre-Processor) jako pierwszej części łańcucha kompilacji C.

JakeGould
źródło
Dlaczego x86_64-linux-gnu / zostaje wepchnięty w środek?
user912083132
@ user912083132: To jest $TARGETczęść, o której wspomniałem w mojej odpowiedzi i komentarzu. Jest to wynik config.guesskompilacji GCC lub przekazania jej configureskryptu z --targetflagą. Prawdziwe pytanie brzmi: jak ta ścieżka się składa? Czy po prostu nie wraca do tej samej listy, dołączając się $TARGETdo każdej z nich, po pierwszym znalezieniu nagłówka?
Warren Young,
@ user912083132 Zaktualizowałem moją odpowiedź o nowo zebrane informacje. Przeczytaj to ponownie; Odpowiedź wyjaśnia, że ​​pochodzi z CPP (C Pre-Processor).
JakeGould,
2

Poza zagłębianiem się w kod źródłowy GCC, nie mogę dać ci „dlaczego”, ale mogę ci powiedzieć, że wersja GCC, którą mam tutaj, wraca /usr/include/$TARGETpo wyczerpaniu wyborów, które ty i JakeGould powinniście znaleźć . Możesz to zobaczyć tak:

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

gdzie foo.czawiera #include <sys/ptrace.h>.

Potrzebujesz -ftutaj argumentu, ponieważ gccspawnuje dzieci, aby faktycznie wykonały kompilację. Potrzebujesz, 2>&1ponieważ stracepisze wyniki do stderr, a nie stdout.

Zauważ, że otrzymujesz ENOENTbłędy dla wszystkich udokumentowanych katalogów, zanim w końcu spróbuje tego, który się powiedzie.

Warren Young
źródło