Флаг gcc -include игнорируется при компиляции файлов .i или .ii - PullRequest
1 голос
/ 14 июня 2019

Я недавно обнаружил, что gcc пропускает предварительную обработку, если окончание файла равно .i или .ii, и решил попробовать. Компиляция программы hello world без включения stdio.h:

gcc -Wall file.c; # compiles with preprocessor, implicit declaration of puts
gcc -Wall file.i; # compiles without preprocessor, implicit declaration of puts 

Я не могу включить stdio.h без директивы препроцессора, но я помню, что флаг -include для gcc можно использовать для «принудительного включения» заголовков. Это привело к следующему тесту:

gcc -Wall -include stdio.h file.c; # no warnings, "hello world". hooray
gcc -Wall -include stdio.h file.i; # implicit declaration of puts WAIT WHAT?!

Мне странно, что gcc не включает stdio.h при компиляции файла без предварительной обработки. Еще более странно, как не выдается предупреждение; -include stdio.h не имеет видимого эффекта, что в лучшем случае является ошибочным использованием gcc.

Почему это не работает?

GCC версия 6.3.0.

Ответы [ 3 ]

1 голос
/ 14 июня 2019

-include указан под Опции препроцессора :

3.12 Опции, управляющие препроцессором

Эти параметры управляют препроцессором C, который запускается в каждом исходном файле C перед фактической компиляцией.

[...]

-include <em>file</em>

Обрабатывать файл , как если бы #include "file" отображалось как первая строка первичного исходного файла. [...]

Однако для файлов .i препроцессор никогда не запускается, поэтому опция не действует.

GCC обычно не предупреждает об опциях, которые не имеют никакого эффекта. Вы также можете запустить gcc -Wall -funsigned-char foo.o, который даже не вызывает компилятор. -Wall и -funsigned-char просто игнорируются.

Вы можете думать о компиляции как о конвейере:

  1. C-код (.c) проходит через препроцессор, который выдает ...
  2. предварительно обработанный код C (.i), который обрабатывается компилятором, выдающим ...
  3. код ассемблера (.s), который обрабатывается ассемблером, производящим ...
  4. код объекта (.o), который обрабатывается компоновщиком, давая вам ...
  5. исполняемый файл.

Имя файла указывает GCC, с какой стадии начинать.

Опции могут использоваться для указания GCC, где остановиться:

  • -P останавливается после предварительной обработки
  • -S останавливается после компиляции
  • -c останавливается после сборки

Другие опции передаются на соответствующую стадию в конвейере. Если эта часть конвейера никогда не запускается, ничего не происходит.

0 голосов
/ 14 июня 2019

Это имеет смысл.Файлы .i уже были предварительно обработаны, поэтому нет шага предварительной обработки, поэтому нет включения.

Работа с уже предварительно обработанными файлами - чрезвычайно сложная тема, поэтому, возможно, они просто предполагали, что кто-либо, кто делает это, знает, что делает.

Или, может быть, это просто недосмотр, и вы должны получить предупреждение.

0 голосов
/ 14 июня 2019

Из документации GCC :

-включить файл

Процесс файл как будто #include "file" появилось как первая строка первичного исходного файла.Однако первым каталогом, в котором был найден файл file , является рабочий каталог препроцессора вместо каталога, содержащего основной исходный файл.Если он там не найден, поиск выполняется в оставшейся части цепочки поиска #include "…" как обычно.

Если задано несколько -include options, файлы включаются в порядке их появления в командной строке.

Эта первая фраза

Обрабатывать файл , как если бы #include "file" появилась в качестве первой строки первичного исходного файла.

означает, что можно ожидать поведения, которое вы видите.

Если GCC не применяет директивы предварительной обработки, он не будет включать этот файл, поскольку не добавляет содержимое * 1035 вслепую *в начале компилируемого файла он действует так, как если бы он добавил директиву препроцессора include.

...