Як gcc знаходить наступний файл заголовка?


10

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

Це рекурсивно дивиться на /usr/include.. Яку проблему ви намагаєтеся вирішити?
Рамхаунд

Це не виглядає так, як рекурсивно виглядає наскрізь. Якби це було, не було б необхідності включати sys / префікс. Наприклад, включаючи просто ptrace.h, не працює.
користувач912083132

Я не думаю, що ти включив, /sys/ptrace.hале sys/ptrace.h, правда?
користувач253751

Це майже напевно помилка в "багатоархівних" патчах для GCC. Каталог /usr/include/x86_64-linux-gnu буде розглядаються як система включає каталог і повинна бути включена в списку шляху пошуку надрукованого gcc -v. Я не впевнений, як комусь вдалося досягти цієї помилки; якщо я правильно пам'ятаю, найочевидніший спосіб додавання системних каталогів додає їх до того, що друкується -v. (Я писав ~ 50% препроцесора GCC, але це було 15 років тому, тож, можливо, я щось помиляю.)
zwol

@Ramhound Це, безумовно, не рекурсивно шукати нижче /usr/include. Це порушить майже кожну бібліотеку С у світі.
zwol

Відповіді:


12

Коротша відповідь.

Ваше запитання стосується виходу 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 / target / версія / включати
  • / usr / target / включати
  • / 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) - це перший крок у процесі компілятора, давайте подивимось на результат "включити" 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. І для порівняння, ось аналогічний вихід «включити» для /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 Попередній процесор). І публікація на цьому веб-сайті продовжує пояснювати, звідки беруться ці шляхи; знову сміливий акцент - мій:

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

Отже, все зводиться до того, що CPP (C Попередній процесор) називається першою частиною ланцюга компіляції C.


Чому x86_64-linux-gnu / забивається в середину?
користувач912083132

@ user912083132: Це та $TARGETчастина, яку я згадав у своїй відповіді та коментарі. Це результат того, config.guessколи було складено GCC або якому було надано його configureсценарій із --targetпрапором. Справжнє питання полягає в тому, як цей шлях збирається? Чи просто повертається через той самий список, додаючи $TARGETдо кожного, після того, як не вдалося вперше знайти заголовок?
Воррен Янг

@ user912083132 Оновив мою відповідь деякою нещодавно зібраною інформацією. Будь ласка, перечитайте його; відповідь пояснює, що вона надходить від CPP (C Попередній процесор).
JakeGould

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міститься a #include <sys/ptrace.h>.

Тут вам потрібен -fаргумент, оскільки gccнерестить дітей робити фактичну компіляційну роботу. Вам потрібно 2>&1тому strace, що записує його результати на stderr, а не на stdout.

Зверніть увагу, що ви отримуєте ENOENTпомилки для всіх документально підтверджених каталогів, перш ніж він остаточно спробує той, який вдається.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.