Принцип действия предкомпилированных заголовков




Для управления предкомпилированными предназначена директива компилятора #pragma hdrstop. Все заголовочные файлы, включенные до этой директивы, помещаются в один образ, например:

#include <vcl.h>

#include <string>

#pragma hdrstop

Такая последовательность создаст образ, содержащий скомпилированные vcl.h и string. Этот образ будет использован для другого cpp-файла, если в нем до директивы hdrstop будут включены те же файлы, в том же порядке. Обращу внимание, что важен не только состав, но и порядок следования заголовков - даже если следующий cpp-файл включает те же заголовки, но сначала указан string, а потом vcl.h, то для этого cpp-файла будет создан новый образ.

Таким образом, для повторного использования предкомпилированного заголовка необходимо выполнение двух условий:

- состав включенный файлов до директивы hdrstop должен быть тем же

- последовательность включения файлов до директивы hdrstop должна быть той же

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

- ВСЕ cpp-файлы проекта имели одинаковый блок включений до директивы hdrstop

- в этот блок должны входить ВСЕ стандартные заголовочные файлы, необходимые для проекта

Выполнить эти условия достаточно просто, для этого в начало каждого cpp-файла необходимо поместить следующие строки:

#include <pch.h>

#pragma hdrstop

где pch.h - файл, содержащий включения всех стандартных заголовков:

#ifndef PCH_H

#define PCH_H

#define INC_VCLDB_HEADERS

#define INC_VCLEXT_HEADERS

#include <vcl.h>

#include <sysset.h>

#include <IniFiles.hpp>

#include <AppEvnts.hpp>

#include <ActnMan.hpp>

...

#endif

Полный текст моей версии этого файла приведен в конце статьи. На h-файлы, входящие в предкомпилированный образ, накладывается ограничение - в них не должно быть инициализированных данных, например, в math.hpp есть строки:

static const Extended NaN = 0.0 / 0.0;

static const Extended Infinity = 1.0 / 0.0;

Из-за наличия этих констант включить math.hpp в файл pch.h нельзя.

Кстати, С++ Builder при добавлении новых модулей в проект реализует описанную стратегию управления предкомпилированными заголовками. Например, при создании нового приложения, файл Unit1.cpp будет таким:

#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

....

Если посмотреть на текст vcl.h, то можно увидеть, что он является оболочкой для включения большого числа других стандартных заголовочных файлов.

Управлять составом включаемых в vcl.h заголовков можно с помощью специальных символов (INC_VCLDB_HEADERS, INC_VCLEXT_HEADERS и др.). В моей версии pch.h эти символы определяются с помощью #define до включения vcl.h, что приводит к увеличению числа включаемых файлов.

Как в существующем проекте перейти к использованию предкомпилированных заголовков

Даже в большом проекте перейти к использованию предкомпилированных заголовков достаточно просто.

В свойствах проекта нужно включить кэширование предкомпилированных заголовков и рекомендуется указать "персональный" файл, в котором будет храниться образ предкомпилированных заголовков: Project - Options - закладка Compiler, группа "Pre-compiled headers". Тут должно быть выбрано "Cache pre-compiled headers", а в поле "File Name" нужно ввести "pch.csm". При такой настройке образ с предкомпилированными заголовками будет находится в папке с проектом, в файле pch.csm.

После этого в начало каждого cpp-модуля необходимо вставить 2 строки:

#include "pch.h"

#pragma hdrstop

Все ранее включенные заголовочные файлы остаются на своих местах, их удалять не надо. Например:

#include "pch.h" // включает vcl.h, string и т.д.

#pragma hdrstop

#include <vcl.h>

#include <string>

...

Так как во всех стандартных заголовках применяются стражи повторного включения, то повторное их упоминание не влечет за собой повторного включения.

В принципе, при использовании pch.h, техническая потребность во включении стандартных заголовков исчезает. Однако, полезно все же указывать все необходимые для каждого конкретного модуля заголовки ниже директивы #pragma hdrstop. Во-первых, это в некоторой степени документирует модуль - по включаемым файлам можно судить, какими возможностями пользуется этот модуль. Во-вторых, это облегчает повторное использование модуля в других проектах, в которых либо не используется pch.h, либо его содержимое может быть другим.

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



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2019-12-28 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: