3.22 Использование предварительно скомпилированных заголовков ¶
В крупных проектах часто используется множество заголовочных файлов, которые включаются в каждый исходный файл. Время, затрачиваемое компилятором на обработку этих заголовочных файлов снова и снова, может составлять почти всё время, необходимое для сборки проекта. Для ускорения сборки GCC позволяет предварительно компилировать заголовочный файл.
Для создания предварительно скомпилированного заголовочного файла просто скомпилируйте его, как любой другой файл, при необходимости используя опцию -x, чтобы заставить драйвер обрабатывать его как заголовочный файл C или C++ . Возможно, вам захочется использовать инструмент, подобный make, чтобы поддерживать актуальность предварительно скомпилированного заголовка при изменении заголовочных файлов, которые он содержит.
Предварительно скомпилированный заголовочный файл ищется, когда #include встречается в компиляции. При поиске включаемого файла (см. Пути поиска в Препроцессоре C) компилятор ищет предварительно скомпилированный заголовок в каждом каталоге до того, как ищет включаемый файл в этом каталоге. Искомое имя — это имя, указанное в #include, с добавленным ‘.gch’. Если предварительно скомпилированный заголовочный файл не может быть использован, он игнорируется.
Например, если у вас есть #include "all.h", и у вас есть all.h.gch в том же каталоге, что и all.h, то предварительно скомпилированный заголовочный файл используется, если это возможно, а исходный заголовок используется в противном случае.
В качестве альтернативы, вы можете поместить предварительно скомпилированный заголовочный файл в каталог и использовать -I, чтобы убедиться, что этот каталог ищется перед (или вместо) каталогом, содержащим исходный заголовок. Затем, если вы хотите убедиться, что предварительно скомпилированный заголовочный файл всегда используется, вы можете поместить файл с тем же именем, что и исходный заголовок, в этот каталог, содержащий команду #error.
Это также работает с -include. Таким образом, ещё один способ использования предварительно скомпилированных заголовков, подходящий для проектов, не предназначенных для предварительно скомпилированных заголовков, заключается в том, чтобы взять большинство используемых в проекте заголовочных файлов, включить их из другого заголовочного файла, предварительно скомпилировать этот заголовочный файл и использовать -include для предварительно скомпилированного заголовка. Если заголовочные файлы имеют защитные конструкции от множественного включения, они пропускаются, так как они уже были включены (в предварительно скомпилированный заголовок).
Если вам нужно предварительно скомпилировать один и тот же заголовочный файл для разных языков, целей или опций компилятора, вы можете вместо этого создать каталог с именем, подобным all.h.gch, и поместить каждый предварительно скомпилированный заголовок в каталог, возможно, используя -o. Не имеет значения, как вы назовёте файлы в каталоге; каждый предварительно скомпилированный заголовок в каталоге рассматривается. Первый встреченный предварительно скомпилированный заголовок в каталоге, который подходит для этой компиляции, используется; они ищутся в произвольном порядке.
Существует множество других возможностей, ограниченных только вашей фантазией, здравым смыслом и ограничениями вашей системы сборки.
Предварительно скомпилированный заголовочный файл может быть использован только при соблюдении следующих условий:
- В конкретной компиляции может использоваться только один предварительно скомпилированный заголовок.
- Предварительно скомпилированный заголовок не может быть использован после появления первого токена C. Вы можете иметь директивы препроцессора перед предварительно скомпилированным заголовком; вы не можете включать предварительно скомпилированный заголовок изнутри другого заголовка.
- Предварительно скомпилированный заголовочный файл должен быть сгенерирован для того же языка, что и текущая компиляция. Вы не можете использовать предварительно скомпилированный заголовок C для компиляции C++.
- Предварительно скомпилированный заголовочный файл должен быть сгенерирован тем же исполняемым файлом компилятора, что и текущая компиляция.
- Любые макросы, определённые перед включением предварительно скомпилированного заголовка, должны быть определены так же, как и при создании предварительно скомпилированного заголовка, или не должны влиять на него, что обычно означает, что они вообще не появляются в предварительно скомпилированном заголовке.
Опция -D — один из способов определить макрос перед включением предварительно скомпилированного заголовка; использование
#defineтакже может это сделать. Существуют также некоторые опции, которые неявно определяют макросы, такие как -O и -Wdeprecated; это же правило относится к макросам, определённым таким способом. - Если при использовании предварительно скомпилированного заголовка выводятся отладочные данные, используя -g или подобные опции, должен выводиться тот же вид отладочной информации при построении предварительно скомпилированного заголовка. Однако предварительно скомпилированный заголовок, созданный с помощью -g, может быть использован в компиляции, когда отладочная информация не выводится.
- Обычно должны использоваться одинаковые опции -m при построении и использовании предварительно скомпилированного заголовка. См. Машинно-зависимые опции для случаев, когда это правило ослаблено.
- Следующие опции должны быть одинаковыми при построении и использовании предварительно скомпилированного заголовка:
-fexceptions
- Некоторые другие опции командной строки, начинающиеся с -f, -p или -O, должны быть определены так же, как и при создании предварительно скомпилированного заголовка. В настоящее время неясно, какие опции можно безопасно изменять, а какие нет; самый безопасный выбор — использовать точно те же опции при создании и использовании предварительно скомпилированного заголовка. Известно, что следующие опции безопасны:
-fmessage-length= -fpreprocessed -fsched-interblock -fsched-spec -fsched-spec-load -fsched-spec-load-dangerous -fsched-verbose=number -fschedule-insns -fvisibility= -pedantic-errors
- Случайная компоновка адресного пространства (ASLR) может привести к небинарно-идентичным файлам PCH. Если вы полагаетесь на стабильное содержимое файлов PCH, отключите ASLR при создании файлов PCH.
Во всех этих случаях, за исключением последнего, компилятор автоматически игнорирует предварительно скомпилированный заголовок, если условия не выполнены. Если вы обнаружили сочетание опций, которое не работает и не приводит к игнорированию предварительно скомпилированного заголовка, рассмотрите возможность отправить отчёт об ошибке, см. Отправка отчётов об ошибках.
Если вы используете разные опции при создании и использовании предварительно скомпилированного заголовка, фактическое поведение является смесью поведения для этих опций. Например, если вы используете -g для создания предварительно скомпилированного заголовка, но не при его использовании, вы можете или не можете получить отладочную информацию для процедур в предварительно скомпилированном заголовке.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/gcc/Precompiled-Headers.html