Visual Studio: /Yc, /Yu, #pragma hdrstop, stdafx.h Печать
Добавил(а) microsin   

Опции /Yc, /Yu, директива препроцессора #pragma hdrstop, подключаемый заголовок stdafx.h - все эти функции относятся к так называемым предварительно компилируемым заголовкам (precompiled headers).

Технология precompiled headers появилась для языков программирования C/C++, когда стало ясно, что множество подключаемых заголовочных файлов (файлы с расширением *.h) слишком замедляет процесс компиляции. Поскольку подключаемые заголовки обычно изменяются намного реже, чем модули исходного кода (*.c, *.cpp), то было принято решение "предварительно" компилировать заголовки, создавая для них временные файлы, где будут сохраняться результаты компиляции. Формат этих файлов у каждого компилятора свой (у компилятора Visual Studio файлы результата компиляции заголовков имеют расширение *.pch). Файлы предварительной компиляции заголовков создаются заново только тогда, когда поменялся один из используемых заголовочных файлов, поэтому процесс компиляции проекта, когда заголовки не претерпели изменений, существенно сокращается.

Подробнее про предварительно компилируемые заголовки см. врезку "Что такое precompiled headers" в конце статьи.

[Опция /Yc]

Опция /Yc компилятора инструктирует создать файл precompiled header (с расширением *.pch), который будет хранить в себе текущее состояние компиляции.

Синтаксис:

/Yc
/Ycfilename

Аргумент filename указывает заголовочный файл (*.h). Когда в опции используется этот аргумент, компилятор компилирует весь код до директивы #include этого указанного заголовочного файла, включая также и его код.

Когда опция /Yc в командной строке компилятора указана без аргумента filename, компилятор будет компилировать все подключенные заголовки до самого конца компилируемого модуля, или до точки, где в этом модуле появилась директива #pragma hdrstop [5].

Результирующий .pch файл получит то же самое имя, что и базовый исходный модуль, если Вы не укажете другое имя с помощью прагмы hdrstop или с помощью опции /Fp (см. далее). Скомпилированный файл *.pch будет использоваться при последующих компиляциях в том случае, если в строке компилятора встретится опция /Yu (см. далее).

Если опции /Ycfilename и /Yufilename встречаются в одной командной строке и обе они ссылаются прямо или косвенно на один и тот же файл, то опция /Ycfilename получает преимущество. Эта функция упрощает написание файлов makefile.

Чтобы настроить эту опцию компилятора в среде разработки Visual Studio:

1. Выберите файл *.cpp. В этом .cpp-файле должен подключаться заголовочный файл (*.h), который содержит информацию precompiled header. Настройка проекта /Yc может быть отменена на уровне этого файла.
2. Откройте окно диалога редактирования свойств проекта.
3. Откройте свойства конфигурации (Configuration Properties) -> C/C++ -> Precompiled Headers.
4. Измените свойство Precompiled Header.
5. Для установки filename измените свойство Precompiled Header File.

Примечание: есть возможность программной установки этой опции компилятора [2, 3].

Рассмотрим следующий пример на C++:

// Модуль prog.cpp, компилировался с командной строкой:
// cl /c /Ycmyapp.h prog.cpp
#include < afxwin.h>   // подключаемый заголовок библиотеки классов
#include "resource.h" // подключение определений ресурсов приложения
#include "myapp.h"    // подключение информации, относящейся к этому приложению
// ...

[Опция /Yu]

Опция /Yu инструктирует компилятор использовать существующий файл предварительно скомпилированных заголовков (.pch).

Синтаксис:

/Yu[filename]

Аргумент filename задает имя файла заголовка, который подключен в компилируемом исходном файле с помощью директивы препроцессора #include.

Имя подключаемого файла должно быть одинаковым с опцией /Yc, с помощью которой был создан precompiled header.

Для /Yc аргумент filename задает точку, на которой останавливается процесс предварительной компиляции заголовков; компилятор будет предварительно компилировать весь код до этого filename (и код самого filename включительно), сохраняя информацию в результирующий файл precompiled header с тем же именем, что и базовый файл и расширением *.pch.

Файл *.pch должен быть создан с помощью опции /Yc (см. выше).

Компилятор обрабатывает весь код, который встретился в модуле до *.h файла как предварительно скомпилированный. Весь этот подключенный код, включая код связанного *.h файла, пропускается с использованием информации из *.pch файла, и затем компилируется весь код после filename.

В командной строки не допускается пробелов между /Yu и filename.

Когда Вы указываете опцию /Yu без имени файла, то тогда компилируемый модуль должен содержать директиву #pragma hdrstop, которая указывает имя предварительно скомпилированных заголовков (файл *.pch) заданный с помощью опции /Fp. Компилятор пропустит подключением заголовков до строки, где находится #pragma hdrstop, восстановит скомпилированное состояние из файла precompiled header, указанное директивой #pragma hdrstop, и затем компилирует только тот код, который находится за этой прагмой. Если #pragma hdrstop не указывает имя файла, то компилятор ищет имя *.pch файла, вычисленное из базового имени модуля исходного кода, заменяя расширение *.cpp на расширение *.pch. Вы также можете использовать опцию командной строки /Fp, чтобы указать другой файл *.pch.

Если Вы укажете опцию /Yu без имени файла и также не укажете #pragma hdrstop, то компилятором будет сгенерировано сообщение об ошибке, и компиляция не будет успешно завершена.

Из-за того, что файлы .pch содержат информацию о текущем рабочем окружении компьютера, а также адреса памяти, относящиеся к программе, Вы должны использовать pch-файл только на том компьютере, где он был создан.

Чтобы настроить эту опцию компилятора в среде разработки Visual Studio:

1. Укажите опцию /Yc для выбранного модуля *.cpp в проекте (как это делается, см. выше).
2. Откройте окно диалога редактирования свойств проекта.
3. Кликните на папку C/C++.
4. Кликните на страничку свойств Precompiled Headers.
5. Измените свойство Create/Use PCH Through File или свойство Create/Use Precompiled Header.

Примечание: есть возможность программной установки этой опции компилятора [2, 3].

Рассмотрим пример. Если следующий код:

#include < afxwin.h>   // подключаемый заголовок библиотеки классов
#include "resource.h" // подключение определений ресурсов приложения
#include "myapp.h"    // подключение информации, относящейся к этому приложению
...

был скомпилирован с помощью командной строки CL /YuMYAPP.H PROG.CPP, то компилятор не будет обрабатывать эти три директивы #include, используя вместо этого предварительно скомпилированный код из MYAPP.pch, экономя тем самым время, которое иначе было бы потрачено на компиляцию этих трех заголовков (а также тех заголовочных файлов, которые могли бы в них подключаться).

Вы можете использовать опцию /Fp (указывающую имя pch файла) вместе с опцией /Yu, чтобы указать имя pch-файла, если имя этого файла отличается либо отличается от аргумента опции /Yc, или от базового имени исходного файла. Пример командной строки компилятора:

CL /YuMYAPP.H /FpMYPCH.pch PROG.CPP

Эта команда указывает имя файла предварительно скомпилированных заголовков MYPCH.pch. Компилятор использует содержимое этого файла для восстановления предварительно скомпилированного состояния всех заголовочных файлов до подключения MYAPP.h и информацию самого файла MYAPP.h включительно. Тогда компилятор будет заново компилировать только тот код, который встретится после строки директивы #include MYAPP.h.

[Опция /Fp]

Опция /Fp предоставляет путь для имени файла предварительно скомпилированных заголовков вместо использования имени пути по умолчанию.

Синтаксис:

/Fppathname

Используйте эту опцию с опцией /Yc (создать файл предварительно скомпилированных заголовков, см. выше) или опцией /Yu (использовать файл предварительно скомпилированных заголовков, см. выше), чтобы предоставить путь и имя для precompiled header вместо использования имени пути по умолчанию. Вы можете также использовать /Fp вместе с опцией /Yc для указания использовать файл precompiled header, который отличается и от аргумента из опции /Ycfilename, и от базового имени исходного файла.

Если Вы не укажете расширение файла как часть pathname, то будет подразумеваться расширение *.pch. Если Вы укажете директорию без имени файла, то имя файла по умолчанию будет VCx0.pch, где x задает major-версию используемой системы Visual C++.

Вы также можете использовать опцию /Fp с опцией /Yu.

Чтобы настроить эту опцию компилятора в среде разработки Visual Studio:

1. Откройте окно диалога редактирования свойств проекта.
2. Кликните на папку C/C++.
3. Кликните на страничку свойств Precompiled Headers.
4. Измените свойство Precompiled Header File.

Примечание: есть возможность программной установки этой опции компилятора [4].

Рассмотрим примеры. Если Вы хотите создать файл precompiled header для своей программы, и компилируете и файлы заголовков, и исходный код, то можете указать команду компиляции следующим образом:

CL /DDEBUG /Zi /Yc /FpDPROG.PCH PROG.CPP

Следующая команда использует файл precompiled header с именем MYPCH.pch. Компилятор подразумевает, что исходный код в PROG.cpp был предварительно скомпилирован до MYAPP.h включительно, и информация о результатах этой предварительной компиляции находится в файле MYPCH.pch. Тогда компилятор будет использовать содержимое MYPCH.pch и компилировать только остальную часть файла PROG.cpp для создания obj-файла. Конечным результатом компиляции будет двоичный файл с именем PROG.exe.

CL /YuMYAPP.H /FpMYPCH.PCH PROG.CPP

[Общие замечания]

• Вставка директивы #pragma hdrstop в исходный файл, который не был скомпилирован с опциями /Yc или /Yu, не дает никакого эффекта в принципе.
• Если Вы установили опцию /Yu для файла модуля, то тогда прагма hdrstop укажет компилятору отбросить (не компилировать) все до строки, где появилась прагма hdrstop, вставив вместо этого информацию из файла precompiled header.
• Если для этого файла была установлена опция /Yc, то hdrstop означает сохранение в файл precompiled header всего скомпилированного состояния до строки, где появляется hdrstop.

Трюк использования /Yc и /Yu без опционального имени файла состоит в том, чтобы просто установить радиокнопки 'use' или 'create' и оставить поле ввода 'through header' пустым (или можно с той же целью отредактировать файл проекта).

Предположим, что у Вас есть 1 файл, который называется PrecompiledHeader.cpp, где подключены заголовки, которые Вы хотите добавить в файл precompiled header, и в котором в конце, после всех директив #inclide находится директива #pragma hdrstop. Тогда ТОЛЬКО ЭТОТ ОДИН ФАЙЛ компилируется с опцией /Yc. Тогда во всех других cpp-файлах с директивой #pragma hdrstop после директив #include будет использоваться precompiled header. Все эти файлы компилируются с опцией /Yu. В результате компиляция PrecompiledHeader.cpp (in this example) создаст один pch-файл, и все другие файлы проекта будут использовать этот один pch-файл.

Достоинство этого метода в том, что ни один из Ваших файлов не будет нуждаться в подключении "глобального" precompiled header - ни stdafx.h, ни какого-либо другого. Это означает, что Вы можете настроить конфигурацию сборки, которая будет выполнять компиляцию БЕЗ использования precompiled headers, где все строки #pragma hdrstop будут просто игнорироваться.

Это может быть "хорошо" потому, что позволяет иметь одну конфигурацию без предварительно скомпилированных заголовков 'no precomp', которая позволяет делать быстрые глобальные модификации (Вы можете поменять только один заголовок и не заставлять весь остальной мир пересобираться заново) и другие "нормальные" конфигурации, которые будут использовать precompiled headers.

Когда Вы создаете новый проект в Visual Studio, в него автоматически добавляется заголовочный файл с именем "pch.h", это так называемый файл предварительно скомпилированных заголовков, или файл precompiled headers (в ранних версиях Visual Studio, этот файл назывался "stdafx.h"). Назначение этого файла - ускорить процесс компиляции, что имеет значение для средних и больших проектов. В файл precompiled headers должно быть добавлено подключение (директивой #include) любых "стабильных" заголовочных файлов (которые никогда не изменяются, или изменяются редко), например заголовки Standard Library, такие как < vector>. Файл precompiled header компилируется только когда был изменен он сам, или был изменен какой-либо из подключаемых в нем файлов. Если Вы вносите изменения только в модули исходного кода проекта, то при сборке пропускается компиляция всех файлов, которые содержаться в precompiled header.

Опции компилятора, относящиеся к precompiled headers, начинаются с /Y. На страницах свойств проекта соответствующие опции находятся в разделе Configuration Properties -> C/C++ -> Precompiled Headers. Вы можете здесь выбрать не использовать precompiled headers, и также можете указать специальное имя заголовка и путь имя и путь результата компиляции precompiled headers.

Пользовательский предварительно скомпилированный код. Для больших проектов, для которых важно экономить время на сборку, Вы можете решить создать свои собственные предварительно скомпилированные файлы (Precompile Source Code). Компиляторы Microsoft C и C++ предоставляют опции для предварительной компиляции любого кода C или C++, включая inline-код. Используя эту функцию повышения производительности, Вы можете скомпилировать стабильное тело кода, сохранить скомпилированное состояние в файл, и при последующих компиляциях комбинировать предварительно скомпилированный код с кодом, находящимся в текущей разработке. Каждая последующая компиляция будет происходить быстрее, потому что не нужно заново компилировать предварительно скомпилированный код.

[Когда следует использовать Precompile Source Code]

Precompiled-код полезен во время разработки для снижения времени компиляции, особенно в следующих ситуациях:

• Всегда есть большой объем кода, который редко изменяется.
• Ваша программа состоит из нескольких модулей, и все они используют стандартный набор подключаемых файлов и одинаковые опции компиляции. В этом случае все подключаемые файлы проекта можно предварительно скомпилировать в один precompiled header.

Первая компиляция - в которой будет создан файл precompiled header (PCH) - будет происходить дольше, чем последующие компиляции, которые будут подключать precompiled-код.

Вы можете предварительно компилировать как программы на языке C, таки и программы на языке C++. В программировании C++ общей практикой является выделение информации интерфейса класса в заголовочные файлы. Эти заголовочные файлы могут быть позже подключены в программы, которые используют эти классы. Путем предварительной компиляции этих заголовков Вы можете снизить время, которое тратится на компиляцию программы.

Примечание: хотя Вы можете использовать только один файл precompiled header (с расширением *.pch) на исходный файл, в проекте также можно использовать несколько pch-файлов.

[Два выбора для предварительного компилирования кода]

В среде Visual C++ Вы можете предварительно компилировать любой код C или C++; Вы не ограничены только заголовочными файлами.

Прекомпиляция требует предварительного планирования, однако часто эта техника позволяет значительно ускорить сборки, если предварительно компилируется код, отличающийся от простых заголовочных файлов.

Используйте precompiled-код, когда знаете, что Ваши исходные файлы используют общий набор заголовочных файлов, однако не подключают их в одинаковом порядке, или когда Вы хотите добавить исходный код в свою предварительную компиляцию.

Опциями precompiled-header служат /Yc (Create Precompiled Header File) и /Yu (Use Precompiled Header File). Используйте /Yc для создания precompiled header. Когда используется опциональная директива #pragma hdrstop, опция /Yc позволит Вам предварительно компилировать как заголовочные файлы, так и исходный код. Выберите /Yu для использования существующего файла precompiled header в имеющейся компиляции. Вы можете также использовать опцию /Fp с опциями /Yc и /Yu, чтобы предоставить альтернативное имя для precompiled header.

[Правила целостности Precompiled Header]

Поскольку PCH-файлы содержат информацию о рабочем окружении (компьютере разработчика, в том числе информацию адресов памяти программы), Вы должны использовать PCH-файл только на том компьютере, где он было создан.

Правила целостности для каждого файла. Опция /Yu компилятора позволяет Вам указать, какой PCH-файл использовать.

Когда Вы используете PCH-файл, компилятор подразумевает, что используется одно и то же рабочее окружение компиляции - используются целостные опции компилятора, прагмы, версия и т. д. - которые дают тот же эффект компиляции, который был при создании PCH-файла, если Вы не укажете нечто другое. Если компилятор определил какое-либо нарушение целостности, то он выдаст предупреждение и покажет по мере возможности, в чем было это нарушение. Такие предупреждения не обязательно показывают проблему в PCH-файле; они просто сообщают Вам о возможном возникновении конфликтов. Далее будут описаны требования целостности для PCH-файлов.

Целостность опций компилятора. Следующие опции компилятора могут привести к предупреждениям нарушения целостности при использовании PCH-файла:

• Макросы, созданные с помощью опции препроцессора (/D) должны быть одинаковыми, как были в момент компиляции создания PCH-файла и в текущей компиляции. Состояние констант #define не проверяется, однако в случае их изменений возможны непредсказуемые результаты.
• PCH-файлы не работают с опциями /E и /EP.
• PCH-файлы должны быть созданы либо с опцией Generate Browse Info (/FR), либо с опцией Exclude Local Variables (/Fr) перед последующими компиляциями, которые могут использовать PCH-файл и эти опции.

Совместимость "C 7.0" (/Z7). Если действует опция "C 7.0-Compatible" (/Z7) при создании PCH-файла, то последующие компиляции, которые используют этот PCH-файл, могут использовать отладочную информацию.

Если опция "C 7.0-Compatible" (/Z7) не применялась при создании PCH-файла, то последующие компиляции, использующие этот PCH-файл вместе с опцией /Z7, будут приводить к генерации предупреждения. Отладочная информация, помещенная в текущий .obj файл, и локальные символы в файле PCH не будут доступны для отладчика.

Целостность путей подключения. PCH-файл не содержит информацию о путях поиска подключаемых файлов (Include Path), которая действовала в момент создания этого PCH-файла. Когда Вы используете PCH-файл, компилятор всегда использует пути поиска подключаемых файлов, настроенные для текущей компиляции.

Целостность исходных файлов. Кода Вы указываете использовать Precompiled Header File (опцию /Yu), компилятор игнорирует все директивы препроцессора (включая директивы #pragma) которые появляются в исходном коде, подвергшемся предварительной компиляции. Способ компиляции, заданный этими директивами препроцессора, должен быть таким же, как использовался в момент создания Precompiled Header File (с опцией /Yc).

Целостность #pragma. Директивы #pragma, обработанные в момент создания PCH-файла, обычно влияют на файл, который будет использовать этот PCH-файл в последующих компиляциях. Прагмы comment и message не влияют на остальную часть компиляции.

Следующие директивы #pragma влияют только на код в файле PCH; они не влияют на код, который использует этот PCH-файл:

comment
page
subtitle
linesize
pagesize
title
message
skip

Следующие директивы #pragma сохраняются как часть precompiled header, и влияют на компиляцию, которая использует этот precompiled header:

alloc_text
include_alias
pack
auto_inline
init_seg
pointers_to_members
check_stack
inline_depth
setlocale
code_seg
inline_recursion
vtordisp
data_seg
intrinsic
warning
function
optimize

[Правила целостности для /Yc и /Yu]

Когда Вы используете precompiled header с опциями /Yc или /Yu, компилятор сравнивает текущее рабочее окружение компиляции и то окружение, которое существовало в момент создания PCH-файла. Убедитесь, что для текущей компиляции задаете одинаковое, целостное окружение, совпадающее с предыдущим (с использованием одинаковых опций компилятора, прагм и т. д.). Если компилятор обнаружит нарушение целостности, то он выдаст предупреждение, и если есть возможность, то укажет на его причину. Подобные предупреждения необязательно показывают проблему в файле PCH, они просто предупреждают о возможном возникновении конфликтов. В таблице ниже приведены требования целостности к опциям компилятора.

Опция Имена Правило
/D Определение констант и макросов Должно быть одинаковым между компиляцией с созданным precompiled header и текущей компиляцией. Состояние определяемых констант не проверяется, однако могут быть непредсказуемые результаты, если Ваши файлы зависят от значений измененных констант.
/E или /EP Копирование вывода препроцессора в стандартный вывод (stdout) Технология precompiled headers не работает с опцией /E или /EP.
/Fr или /FR Генерация информации Microsoft Source Browser Чтобы опции /Fr и /FR были допустимы с опцией /Yu, они должны действовать в момент создания precompiled header. Последующие компиляции, которые используют precompiled header, также генерируют информацию Source Browser. Эта информация помещается в один файл *.sbr, и к нему обращаются другие файлы таким же способом, как и к информации CodeView. Вы не можете изменить место размещения информации Source Browser.
/GA, /GD, /GE, /Gw или /GW  Опции протокола Windows Должны быть одинаковыми между компиляцией, создавшей precompiled header, и текущей компиляцией. Если эти опции различаются, то будет выведено предупреждающее сообщение.
/Zi Генерация полной отладочной информации Если эти опции действуют в момент создания precompiled header, то последующие компиляции, которые используют эту предкомпиляцию, могут использовать отладочную информацию. Если /Zi не действовала, когда был создан precompiled header, то последующие компиляции, которые используют опцию /Zi, приведут к выводу предупреждения компилятора. Отладочная информация помещается в текущий объектный файл, и локальные символы, определенные в precompiled header, будут недоступны для отладчика.

Примечание: технология precompiled предназначена только для использования в исходном коде C и C++.

[Использование Precompiled Headers в проекте]

В предыдущих секциях обзорно рассматривалось управление precompiled headers: опции /Yc, /Yu и /Fp и прагма hdrstop. В этой секции описывается метод создания опций precompiled header для проекта вручную. В конце будет приведет пример makefile и кода, который им обслуживается.

Другой способ использования вручную созданных опций в проекте - изучить один из файлов makefile, находящиеся в директории MFC\SRC, которая создается в процессе установки по умолчанию Visual C++. Эти файлы makefile дают простой способ применения precompiled header, представленный в этой секции, однако он больше использует макросы Microsoft Program Maintenance Utility (NMAKE), и дает больше возможностей по управлению процессом сборки.

PCH-файлы в процессе сборки. Кодовая база программного проекта обычно содержится в нескольких модулях исходного кода на языке C или C++, объектных файлах, библиотеках и заголовочных файлах. Обычно файлы makefile координируют комбинацию этих элементов в исполняемый файл (*.exe). На следующем рисунке показана структура makefile, который использует файл precompiled header. Имена макроса NMAKE и имена файлов в этой диаграмме соответствуют коду примера, который находится в Примере 1 Makefile для PCH и Примере 2 кода для PCH.

Структура Makefile, который использует файл Precompiled Header:

VisualStudio Makefile that uses Precompiled Header

Рисунок использует три диаграммных устройства, чтобы показать поток процесса сборки. Прямоугольники с именами представляют каждый файл или макрос; дерево макросов представляют один или большее количество файлов. Затененные области представляют каждое действие по компиляции или линковке. Стрелки показывают, какие файлы и макросы комбинируются во время процесса компиляции или линковки.

В начале верхней части диаграммы, STABLEHDRS и BOUNDRY это оба макросы NMAKE, в которых Вы перечисляете файлы, которые вряд ли нуждаются в перекомпиляции. Эти файлы компилируются строкой команды

CL /c /W3 /Yc$(BOUNDRY) applib.cpp myapp.cpp

только если файл precompiled header (STABLE.pch) не существует, или если Вы сделали изменения в файлы, перечисленные в этих двух макросах. В любом случае файл precompiled header будет содержать код только из файлов, перечисленных в макросе STABLEHDRS. Список последнего файла, который Вы хотите предварительно скомпилировать, находится в макросе BOUNDRY.

Файлы, перечисленные в этих макросах, могут быть либо заголовочными файлами (*.h), либо исходным кодом C или C++ (один PCH-файл не может использоваться с модулями обоих языков C и C++). Обратите внимание, что Вы можете использовать макрос hdrstop для остановки предварительной компиляции в некоторой точке файла BOUNDRY.

Ниже на диаграмме APPLIB.obj представляет поддержку кода, используемого в Вашем конечном приложении. Он создается из APPLIB.cpp, а также из файлов, перечисленные в макросе UNSTABLEHDRS, и предварительно скомпилированного кода из precompiled header.

MYAPP.obj представляет конечное приложение. Он создается из MYAPP.cpp, файлов, перечисленных в макросе UNSTABLEHDRS, и предварительно скомпилированного кода из precompiled header.

И наконец, исполняемый файл (MYAPP.EXE) создается линковкой файлов, перечисленных в макросе OBJS (файлы APPLIB.obj и MYAPP.obj).

Пример 1 Makefile для PCH. Следующий makefile использует макросы и структуры команд управления потоком !IF, !ELSE, !ENDIF, чтобы упростить адаптацию для Вашего проекта.

Содержимое файла makefile:

# Makefile: иллюстрация эффективного использования precompiled
#           headers в проекте
# Usage:    NMAKE option
# option:   DEBUG=[0|1]
#           (если DEBUG не определен, то это эквивалентно DEBUG=0)
#
OBJS = myapp.obj applib.obj
# Список всех стабильных (редко изменяемых) файлов в макросе STABLEHDRS:
STABLEHDRS = stable.h another.h
# Список конечного заголовочного файла, который здесь прекомпилируется:
BOUNDRY = stable.h
# Список изменяемых заголовков (хедеры, находящиеся в разработке):
UNSTABLEHDRS = unstable.h
# Список всех опций компилятора для обоих версий
# приложения, debug и final:
CLFLAGS = /c /W3
# Список всех опций линкера для обоих версий приложения, debug и final:
LINKFLAGS = /NOD /ONERROR:NOEXE
!IF "$(DEBUG)" == "1"
CLFLAGS   = /D_DEBUG $(CLFLAGS) /Od /Zi /f
LINKFLAGS = $(LINKFLAGS) /COD
LIBS      = slibce
!ELSE
CLFLAGS   = $(CLFLAGS) /Oselg /Gs
LINKFLAGS = $(LINKFLAGS)
LIBS      = slibce
!ENDIF
myapp.exe: $(OBJS)
    link $(LINKFLAGS) @<<
$(OBJS), myapp, NUL, $(LIBS), NUL;
<<
# Компиляция myapp
myapp.obj  : myapp.cpp $(UNSTABLEHDRS)  stable.pch
    $(CPP) $(CLFLAGS) /Yu$(BOUNDRY)    myapp.cpp
# Компиляция applib
applib.obj : applib.cpp $(UNSTABLEHDRS) stable.pch
    $(CPP) $(CLFLAGS) /Yu$(BOUNDRY)    applib.cpp
# Компиляция заголовков
stable.pch : $(STABLEHDRS)
    $(CPP) $(CLFLAGS) /Yc$(BOUNDRY)    applib.cpp myapp.cpp

Кроме макросов STABLEHDRS, BOUNDRY и UNSTABLEHDRS, показанных на рисунке "Структура Makefile, который использует файл Precompiled Header", используемых в PCH-файлах в процессе сборки, этот makefile предоставляет макросы CLFLAGS и LINKFLAGS. Вы должны использовать эти макросы, чтобы указать списки опций компилятора и линкера, применяемых при сборке к отладочной или финальной версии исполняемого файла приложения. Здесь есть также макрос LIBS, где Вы перечисляете библиотеки, требуемые для проекта.

Файл makefile также использует !IF, !ELSE, !ENDIF чтобы выяснить, определен ли символ DEBUG в командной строке NMAKE:

NMAKE DEBUG=[1|0]

Эта функция делает возможной использовать один и тот же makefile как для отладочной, так и для финальной версии программы — для финальной версии используйте DEBUG=0. Если ничего не указывать, то подразумевается финальная версия, следующие строки команд эквивалентны:

NMAKE
NMAKE DEBUG=0

Для дополнительной информации по файлам makefile см. руководство NMAKE [6]. Также см. описание опций компилятора [7] и линкера [8].

Пример 2 кода для PCH. Следующие файлы исходного кода используются в примере makefile, описанном выше. Обратите внимание, что комментарии содержат важную информацию.

Заголовочный файл another.h:

// ANOTHER.H: содержит интерфейс для кода, который скорее
//            всего будет редко изменяться.
#ifndef __ANOTHER_H
#define __ANOTHER_H
#include < iostream>
 
void savemoretime( void );
 
#endif // __ANOTHER_H

Заголовочный файл stable.h:

// STABLE.H: содержит интерфейс для кода, который скорее
//           всего не будет изменяться. Этот список
//           в makefile представлен макросом STABLEHDRS.
#ifndef __STABLE_H
#define __STABLE_H
#include < iostream>
 
void savetime( void );
 
#endif // __STABLE_H

Заголовочный файл unstable.h:

// UNSTABLE.H: содержит интерфейс для кода, который вероятно
//             будет подвержен изменениям. Как только этот код
//             в заголовке станет стабильным, удалите его
//             имя из макроса UNSTABLEHDR файла makefile,
//             и поместите в макрос STABLEHDRS.
#ifndef __UNSTABLE_H
#define __UNSTABLE_H
#include < iostream.h>
 
void notstable( void );
 
#endif // __UNSTABLE_H

Код пользовательской библиотеки приложения applib.cpp:

// APPLIB.CPP: этот файл содержит код, который реализует интерфейс,
//             задекларированный в заголовочных файлах STABLE.H,
//             ANOTHER.H и UNSTABLE.H.
//#include "another.h"
#include "stable.h"
#include "unstable.h"
 
// Следующие строки представляют код, который считается стабильным,
// и он скорее всего не будет меняться. Связанный код интерфейса
// будет подвержен предварительной компиляции. В этом примере
// прекомпилируются заголовочные файлы STABLE.H и ANOTHER.H.
void savetime( void )
    { cout << "Почему перекомпилируется стабильный код?\n"; }
 
void savemoretime( void )
    { cout << "Почему, в самом деле?\n\n"; }
 
// Следующие строки представляют код, который все еще находится
// в разработке. Связанный файл заголовка не прекомпилируется.
void notstable( void )
    { cout << "Unstable-код требует"
           << " частой перекомпиляции.\n";
    }

Основной модуль приложения, содержащий функцию main:

// MYAPP.CPP: приложение примера.
//            Весь прекомпилированный код, кроме файла, перечисленного
//            в макросе BOUNDRY из makefile (в этом примере stable.h),
//            должен быть подключен перед файлом, перечисленным
//            в макросе BOUNDRY. Unstable-код должен быть подключен
//            после precompiled-кода.
#include "another.h"
#include "stable.h"
#include "unstable.h"
 
int main( void )
{
    savetime();
    savemoretime();
    notstable();
}

[Ссылки]

1. /Y (Precompiled Headers) site:docs.microsoft.com.
2. VCCLCompilerTool.PrecompiledHeaderThrough Property site:docs.microsoft.com.
3. VCCLCompilerTool.UsePrecompiledHeader Property site:docs.microsoft.com.
4. VCCLCompilerTool.PrecompiledHeaderFile Property site:docs.microsoft.com.
5. hdrstop дополнительный контроль над именами файлов предварительной компиляции site:docs.microsoft.com.
6. NMAKE Reference site:docs.microsoft.com.
7. MSVC Compiler Options site:docs.microsoft.com.
8. MSVC Linker Options site:docs.microsoft.com.