Wie findet gcc die folgende Header-Datei?

10

Ich habe sys/ptrace.hin mein C-Programm aufgenommen.

Die Ausgabe von /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -vgibt die folgenden Pfade an, in denen gcc nach Header-Dateien sucht

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

Die Ausgabe von gcc -Mfür mein Programm gibt die folgenden Speicherorte für Header-Dateien an

    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

/usr/include/x86_64-linux-gnu/Wie findet gcc, da es nicht in der ersten Ausgabe enthalten ist sys/ptrace.h?

BEARBEITEN:

Die Ausgabe von echo '#include <sys/ptrace.h>' | gcc -fsyntax-only -xc -v -H -Ergebnissen 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) 
user912083132
quelle
Es wird rekursiv betrachtet /usr/include. Welches Problem versuchen Sie zu lösen?
Ramhound
Es sieht nicht so aus, als würde es rekursiv durchschauen. In diesem Fall wäre es nicht erforderlich, das sys / Präfix anzugeben. Das Einfügen von nur ptrace.h funktioniert beispielsweise nicht.
user912083132
Ich glaube nicht, dass du es mit einbezogen hast, /sys/ptrace.haber sys/ptrace.h?
user253751
Dies ist mit ziemlicher Sicherheit ein Fehler in den "Multiarch" -Patches für GCC. Das Verzeichnis /usr/include/x86_64-linux-gnu wird als System-Include-Verzeichnis behandelt und sollte in die von gedruckte Suchpfadliste aufgenommen werden gcc -v. Ich bin nicht sicher, wie jemand diesen Fehler erreicht hat. Wenn ich mich richtig erinnere, fügt der naheliegendste Weg, Systemeinschlussverzeichnisse hinzuzufügen, diese dem hinzu, was von gedruckt wird -v. (Ich habe ~ 50% von GCCs Präprozessor geschrieben, aber das war vor 15 Jahren, also kann ich mich an etwas erinnern.)
zwol
@ Ramhound Es wird definitiv nicht rekursiv unten gesucht /usr/include. Das würde fast jede C-Bibliothek der Welt zerstören.
zwol

Antworten:

12

Kürzere Antwort.

Ihre Frage cc1 -vbezieht sich auf die Ausgabe von , berücksichtigt jedoch nicht den CPP (C Pre-Processor) und die Includes, die in die gesamte Kompilierungskette eingemischt sind. Wenn Sie cpp -vauf Ihrem System ausgeführt werden, sollten Sie eine Mischung von Includes sehen, die der Ausgabe von ähnelt, cc1 -vaber mindestens den /usr/include/x86_64-linux-gnuPfad enthält, der dort hinzugefügt wurde.

Längere Antwort.

/usr/include/x86_64-linux-gnu/Wie findet gcc, da es nicht in der ersten Ausgabe enthalten ist sys/ptrace.h?

Technisch /usr/include/x86_64-linux-gnu/wird in der ersten Ausgabe nicht explizit gesetzt, ist es aber /usr/include/definitiv. Und das ist ein Standardsuchpfad, wie in der offiziellen GNU GCC-Dokumentation erläutert :

GCC sucht an verschiedenen Stellen nach Headern. Wenn Sie auf einem normalen Unix-System nichts anderes anweisen, sucht es nach angeforderten Headern mit #include <file>:

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

Und hier weiter erklärt:

GCC sucht nach angeforderten Headern #include "file"zuerst in dem Verzeichnis, das die aktuelle Datei enthält, dann in den durch -iquoteOptionen angegebenen Verzeichnissen und dann an denselben Stellen nach einem Header, der mit spitzen Klammern angefordert wurde. Wenn beispielsweise /usr/include/sys/stat.h# enthalten ist include "types.h", sucht GCC types.hzuerst in /usr/include/sysund dann in seinem üblichen Suchpfad.

Dies bedeutet also, dass der x86_64-linux-gnu/Pfad einfach /usr/include/*/sys/wie folgt eingefügt wird :

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

Zumindest habe ich das ursprünglich in einer früheren Version dieser Frage gedacht . Aber nach dem Auschecken dieser Site ist die Erklärung dessen, was passiert, etwas detaillierter und die direkte Antwort dieser Site auf den entsprechenden Inhalt zu dem, was ich oben gepostet habe, wird unten erneut veröffentlicht. kühne Betonung liegt bei mir:

aber das ist eine Art wunschgemäße Antwort (und auch unvollständig). Sicherlich muss es eine Möglichkeit geben, GCC dazu zu bringen, Ihnen genau zu sagen, wo es am Ende nach seinen Header-Dateien suchen wird? Obwohl es praktisch ist, sich GCC als eine einzige monolithische Anwendung vorzustellen, die Quellcodedateien aufnimmt und Arbeitsprogramme ausspuckt, handelt es sich technisch gesehen um eine Sammlung anderer Programme, die miteinander verkettet werden, um die endgültige kompilierte Objektdatei zu erstellen. Das erste davon ist CPP, kurz für C Pre-Processor , dessen Aufgabe es ist, nach Compiler-Direktiven wie #includedem von ihnen angegebenen Quellcode zu suchen und diesen zu ändern. im Fall von include durch Kopieren des Inhalts einer anderen Datei in die aktuelle. Sie können sehen, wo nach diesen Dateien gesucht wird, indem Sie das Flag -v übergeben:

Da der CPP (C Pre-Processor) der erste Schritt im Compilerprozess ist, schauen wir uns die Include-Ausgabe cpp -vmeines Ubuntu 12.04.5-Testsystems an:

#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

Dort kann man deutlich sehen /usr/include/x86_64-linux-gnu. Und zum Vergleich: Hier ist die ähnliche "Include" -Ausgabe /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -vauf demselben Ubuntu 12.04.5-Testsystem:

#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

Beachten Sie, wie /usr/include/x86_64-linux-gnudurch die anfängliche CPP-Aktion (C Pre-Processor) eindeutig in die Mischung eingefügt wird. In dem Beitrag auf dieser Website wird weiter erläutert, woher diese Pfade stammen. wieder ist kühne Betonung meine:

Dieser Pfad ist zur Kompilierungszeit tatsächlich in CPP (das Teil von GCC ist) integriert. Wenn Sie aus irgendeinem Grund eines dieser Verzeichnisse löschen, wird es bei jeder Kompilierung überprüft. Jedes Verzeichnis wird in der hier angegebenen Reihenfolge durchsucht. Wenn eine Datei gefunden wird /usr/local/include, werden die nächsten drei Verzeichnisse nicht überprüft.

Alles läuft also darauf hinaus, dass der CPP (C Pre-Processor) als erster Teil einer C-Kompilierungskette aufgerufen wird.

JakeGould
quelle
Warum wird x86_64-linux-gnu / in die Mitte geschoben?
user912083132
@ user912083132: Das ist der $TARGETTeil, den ich in meiner Antwort und meinem Kommentar erwähnt habe. Es ist die Ausgabe, config.guesswann GCC kompiliert wurde oder was seinem configureSkript mit dem --targetFlag übergeben wurde. Die eigentliche Frage ist, wie dieser Weg zusammengesetzt wird. Geht es nur durch dieselbe Liste, die $TARGETan jede angehängt wird , nachdem der Header beim ersten Mal nicht gefunden wurde?
Warren Young
@ user912083132 Meine Antwort wurde mit einigen neu gesammelten Informationen aktualisiert. Bitte lesen Sie es noch einmal; Antwort erklärt, dass es vom CPP (C Pre-Processor) kommt.
JakeGould
2

Ohne mich mit dem GCC-Quellcode zu befassen, kann ich Ihnen kein "Warum" nennen, aber ich kann Ihnen sagen, dass die Version von GCC, die ich hier habe, zurückgreift, /usr/include/$TARGETnachdem Sie und JakeGould die Auswahlmöglichkeiten erschöpft haben . Sie können es so sehen:

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

wo foo.centhält a #include <sys/ptrace.h>.

Sie brauchen das -fArgument hier, weil gccKinder erzeugt werden, um die eigentliche Kompilierungsarbeit zu erledigen. Sie benötigen das, 2>&1weil stracees seine Ergebnisse in stderr schreibt, nicht in stdout.

Beachten Sie, dass Sie ENOENTFehler für alle dokumentierten Verzeichnisse erhalten, bevor es schließlich das erfolgreiche versucht.

Warren Young
quelle