8

Я включил 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) 

2 ответа2

8

Короче ответ.

Ваш вопрос касается вывода cc1 -v , но это не учитывает CPP (C Pre-Processor), и он включает в себя, которые смешаны во всей цепочке компиляции. Если вы запустите в своей системе 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 / местные / включить
  • LIBDIR / ССАГПЗ / цель / версия / включить
  • / USR / цель / включить
  • / USR / включать в себя

И далее объяснил здесь:

GCC ищет заголовки, запрошенные с помощью #include "file" сначала в каталоге, содержащем текущий файл, затем в каталогах, как указано в параметрах -iquote , затем в тех же местах он будет искать заголовок, запрошенный в угловых скобках. Например, если /usr/include/sys/stat.h содержит # include "types.h" , GCC ищет 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 Pre-Processor, работа которого заключается в том, чтобы искать директивы компилятора, такие как #include и изменять исходный код в соответствии с их указаниями; в случае включения путем копирования содержимого другого файла в текущий. Вы можете увидеть, где он ищет эти файлы, передав ему флаг -v:

Знайте, что CPP (C Pre-Processor) - это первый шаг в процессе компиляции, давайте посмотрим на вывод «include» cpp -v в моей тестовой системе 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

Там вы можете ясно увидеть /usr/include/x86_64-linux-gnu . И для сравнения, вот аналогичный вывод «include» файла /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -v в той же тестовой системе 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

Обратите внимание, как /usr/include/x86_64-linux-gnu четко вставляется в микшер с помощью начального действия CPP (C Pre-Processor). И пост на этом сайте объясняет, откуда берутся эти пути; опять жирный акцент мой

этот путь фактически встроен в CPP (который является частью GCC) во время компиляции; если по какой-либо причине вы в конечном итоге удалите один из этих каталогов, он все равно будет проверяться при каждой компиляции. Каждый каталог ищется в порядке, указанном здесь; если файл найден в /usr/local/include , следующие три каталога не будут проверены.

Таким образом, все сводится к тому, что CPP (C Pre-Processor) называется первой частью цепочки компиляции C.

2

Если не считать углубления в исходный код GCC, я не могу дать вам "почему", но могу сказать, что версия GCC, которая у меня здесь есть, возвращается к /usr/include/$TARGET после исчерпания выбора, который вы и JakeGould нашли. Вы можете видеть это так:

$ 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 для всех задокументированных каталогов, прежде чем он, наконец, попробует тот, который успешно работает.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .