gcc 如何找到以下头文件?

gcc 如何找到以下头文件?

我已将其纳入sys/ptrace.h我的 C 程序中。

输出/usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -v给出了 gcc 查找头文件的以下路径

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

我的程序的输出gcc -M给出了以下头文件位置

    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/第一个输出中不包含,gcc 如何找到sys/ptrace.h

编辑:

echo '#include <sys/ptrace.h>' | gcc -fsyntax-only -xc -v -H -结果输出

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) 

答案1

简短的回答。

您的问题是关于 的输出cc1 -v,但其中没有考虑 CPP(C 预处理器)及其混入整个编译链的包含项。如果您cpp -v在系统上运行,您应该会看到包含项的混合,其看起来类似于 的输出,cc1 -v但至少/usr/include/x86_64-linux-gnu在其中添加了路径。

较长的答案。

由于/usr/include/x86_64-linux-gnu/第一个输出中不包含,gcc 如何找到sys/ptrace.h

从技术上讲,/usr/include/x86_64-linux-gnu/第一个输出中没有明确设置,但/usr/include/肯定是。这是一个默认搜索路径如官方 GNU GCC 文档中所述

GCC 在几个不同的地方查找标头。在普通的 Unix 系统上,如果您没有另行指示,它将#include <file>在以下位置查找请求的标头:

  • /usr/local/包含
  • libdir/gcc/目标/版本/包含
  • /usr/目标/包含
  • /usr/include

这里进一步解释:

GCC#include "file"首先在包含当前文件的目录中查找 所请求的头文件,然后在选项指定的目录中-iquote查找,然后在与查找尖括号所请求的头文件相同的位置查找。例如,如果 /usr/include/sys/stat.h包含 # ,GCC首先在 中include "types.h"查找 ,然后在其通常的搜索路径中查找。types.h/usr/include/sys

所以这意味着x86_64-linux-gnu/路径简单地插入/usr/include/*/sys/如下:

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

至少我最初是这么想的该问题的早期版本。 但在查看此网站后对正在发生的事情的解释更为详细,该网站对与我上面发布的内容等效的内容的直接回应已转载如下;粗体强调是我的:

但这是一个模棱两可的答案(而且不完整)。肯定有办法让 GCC 准确地告诉你它最终会在哪里寻找它的头文件吧?好吧,虽然把 GCC 想象成一个单一的整体应用程序很方便,它接收源代码文件并输出工作程序,但从技术上讲,它是其他程序的集合,这些程序链接在一起生成最终编译的目标文件。其中第一个是 CPP,是C 预处理器,其工作是查找类似的编译器指令 #include并根据其指定修改源代码;对于包含,通过将另一个文件的内容复制到当前文件中。您可以通过传递 -v 标志来查看它在哪里查找这些文件:

知道 CPP(C 预处理器)是编译器流程的第一步,让我们看看cpp -v我的 Ubuntu 12.04.5 测试系统上的“include”输出:

#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

在那里你可以清楚地看到。为了比较,这里是在同一个 Ubuntu 12.04.5 测试系统上/usr/include/x86_64-linux-gnu的类似“include”输出:/usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -v

#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

请注意,初始 CPP(C 预处理器)操作如何/usr/include/x86_64-linux-gnu明确地插入到混合中。该网站上的帖子进一步解释了这些路径的来源;再次强调:

这个路径实际上是在编译时内置到 CPP(GCC 的一部分)中的;如果由于某种原因您最终删除了其中一个目录,它仍然会在每次编译时进行检查。每个目录都按照此处列出的顺序进行搜索;如果在中找到文件/usr/local/include,则不会检查接下来的三个目录。

因此,一切都归结为 CPP(C 预处理器)被称为 C 编译链的第一部分。

答案2

/usr/include/$TARGET除非深入研究 GCC 源代码,否则我无法告诉你“为什么”,但我可以告诉你,在你用尽所有选择之后,我这里使用的 GCC 版本会退化为和 Giacomo1968 发现。您可以看到如下内容:

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

其中foo.c包含#include <sys/ptrace.h>

这里需要-f参数,因为gcc会生成子进程来完成实际的编译工作。需要参数,2>&1因为strace会将其结果写入 stderr,而不是 stdout。

请注意,ENOENT在最终尝试成功的目录之前,所有记录的目录都会出现错误。

相关内容