Как подключить библиотеку stdafx h

Как подключить библиотеку stdafx h

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

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

[Опция /Yc]

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

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

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

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

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

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

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

[Опция /Yu]

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

Аргумент 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, то компилятором будет сгенерировано сообщение об ошибке, и компиляция не будет успешно завершена.

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

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

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

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

был скомпилирован с помощью командной строки 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 предоставляет путь для имени файла предварительно скомпилированных заголовков вместо использования имени пути по умолчанию.

Используйте эту опцию с опцией /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-файл.

Читайте также:  Свекла с белыми прожилками что это значит

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

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

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

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

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

Вы можете предварительно компилировать как программы на языке 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-файла:

• Макросы, созданные с помощью опции препроцессора (/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-файл, могут использовать отладочную информацию.

Целостность путей подключения. 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 и кода, который им обслуживается.

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

Структура Makefile, который использует файл 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).

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

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

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

NMAKE
NMAKE DEBUG=0

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

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

Источник

Для новичков про stdafx.h

Для чего нужны Precompiled Headers

Precompiled headers предназначены для ускорения сборки проектов. Обычно программисты начинают знакомиться с Visual C++, используя крошечные проекты. На них сложно заметить выигрыш от precompiled headers. Что с ними, что без них, на глаз программа компилируется одинаковое время. Это добавляет путаницы. Человек не видит для себя пользы от этого механизма и решает, что он для специфичных задач и ему никогда не понадобится. И иногда считает так многие годы.

На самом деле, precompiled headers весьма полезная технология. Пользу от него можно заметить, даже если в проекте всего несколько десятков файлов. Особенно выигрыш становится заметен, если используются такие тяжёлые библиотеки как boost.

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

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

На самом деле, делается ещё ряд шагов. Можно хранить не просто текст, а более обработанную информацию. Я не знаю, как именно устроено в Visual C++. Но, например, можно хранить текст уже разбитый на лексемы. Это ещё больше ускорит процесс компиляции.

Как работают Precompiled Headers

Файл, который содержит precompiled headers, имеет расширение «.pch». Имя файла обычно совпадает с названием проекта. Естественно, это и другие используемые имена можно изменить в настройках. Файл может быть весьма большим и зависит от того, как много заголовочных файлов в нём раскрыто. Например, в проекте PVS-Studio он занимает около 3 мегабайт.

Файл *.pch возникает после компиляции stdafx.cpp. Файл собирается с ключом «/Yc». Этот ключ как раз и говорит компилятору, что нужно создать precompiled headers. Файл stdafx.cpp может содержать одну строчку: #include «stdafx.h».

В файле «stdafx.h» находится самое интересное. Сюда нужно включить заголовочные файлы, которые будут заранее препроцессироваться. В качестве примера, вот файл stdafx.h, используемый нами в PVS-Studio (файл сокращён для статьи):

Директивы «#pragma warning» нам нужны, чтобы избавиться от предупреждений, выдаваемых на стандартные библиотеки.

Теперь во все файлы *.c/*.cpp следует включить «stdafx.h». Заодно стоит удалить из этих файлов заголовки, которые уже включаются с помощью «stdafx.h».

Как использовать Precompiled Headers

При создании нового проекта Wizard в Visual Studio создаёт два файла: stdafx.h и stdafx.cpp. Именно с помощью них и реализуется механизм precompiled headers.

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

В *.c/*.cpp файле можно использовать только один precompiled header. Однако, в одном проекте может присутствовать несколько разных precompiled headers. Пока будем считать, что он у нас только один.

Итак, если вы воспользовались wizard-ом, то у вас уже есть файлы stdafx.h и stdafx.cpp. Плюс выставлены все необходимые ключи компиляции.

Для всех *.c/*.cpp файлов мы указали, что они должны использовать precompiled headers. Этого мало. Теперь в каждый из файлов нужно добавить #include «stdafx.h».

Заголовочный файл «stdafx.h» должен включаться в *.c/*.cpp файл самым первым. Обязательно! Иначе всё равно возникнут ошибки компиляции.

Если подумать, в этом есть логика. Когда файл «stdafx.h» находится в самом начале, то можно подставить уже препроцессированный текст. Этот текст всегда одинаков и ни от чего не зависит.

Представьте ситуацию, если бы мы могли включить до «stdafx.h» ещё какой-то файл. А в этом файле возьмём и напишем: #define bool char. Возникает неоднозначность. Мы меняем содержимое всех файлов, в которых упоминается «bool». Теперь просто так нельзя взять и подставить заранее препроцессированный текст. Ломается весь механизм «precompiled headers». Думаю, это одна из причин, почему «stdafx.h» должен быть расположен в начале. Возможно, есть и другие.

Life hack

Прописывать #include «stdafx.h» во все *.c/*.cpp файлы достаточно утомительно и не интересно. Дополнительно получится ревизия в системе контроля версий, где будет изменено огромное количество файлов. Нехорошо.

Читайте также:  Кто такой кардинал ришелье

Ещё одно неудобство вызывают сторонние библиотеки, включаемые в проект в виде файлов с кодом. Править эти файлы нет смыла. По правильному для них нужно отключить использование «precompiled headers». Однако, если используется несколько мелких сторонних библиотек, это неудобно. Программист постоянно спотыкается об precompiled headers.

Есть вариант, как использовать precompiled headers легко и просто. Способ подойдёт не везде и всегда, но мне он часто помогал.

Можно не прописывать во все файлы #include «stdafx.h», а воспользоваться механизмом «Forced Included File».

Идём на вкладку настроек «Advanced». Выбираем все конфигурации. В поле «Forced Included File» пишем:

Теперь «stdafx.h» автоматически будет включаться в начало ВСЕХ компилируемых файлов. PROFIT!

Больше не потребуется писать #include «stdafx.h» в начале всех *.c/*.cpp файлов. Компилятор сделает это сам.

Что включать в stdafx.h

Это очень важный момент. Бездумное включение в «stdafx.h» всего подряд не только не ускорит компиляцию, но и наоборот замедлит её.

Все файлы, включающие «stdafx.h», зависят от его содержимого. Пусть в «stdafx.h» включен файл «X.h». Если вы поменяете хоть что-то в «X.h», это может повлечь полную перекомпиляцию всего проекта.

Правило. Включайте в «stdafx.h» только те файлы, которые никогда не изменяются или меняются ОЧЕНЬ редко. Хорошими кандидатами являются заголовочные файлы системных и сторонних библиотек.

Если включаете в «stdafx.h» собственные файлы из проекта, соблюдайте двойную бдительность. Включайте только те файлы, которые меняются очень-очень редко.

Если какой-то *.h файл меняется раз в месяц, это уже слишком часто. Как правило, редко удаётся сделать все правки в h-файле с первого раза. Обычно требуется 2-3 итерации. Согласитесь, 2-3 раза полностью перекомпилировать весь проект — занятие неприятное. Плюс полная перекомпиляция потребуется всем вашим коллегам.

Несколько Precompiled Headers

Зачем в одном проекте может понадобиться несколько precompiled headers? Действительно, это нужно не часто. Но приведу пару примеров.

В проекте используются одновременно *.c и *.cpp файлы. Для них нельзя использовать единый *.pch файл. Компилятор выдаст ошибку.

Нужно создать два *.pch файла. Один должен получаться при компилировании C-файла (xx.c), а другой при компилировании C++-файла (yy.cpp). Соответственно, в настройках надо указать, чтобы в С-файлах использовался один precompiled header, а в С++-файлах — другой.

Примечание. Не забудьте указать разные имена для *.pch файлов. Иначе один файл будет перетирать другой.

Другая ситуация. Одна часть проекта использует одну большую библиотеку, а другая часть другую большую библиотеку.

Естественно, не стоит всем участкам кода знать про обе библиотеки. В (неудачных) библиотеках могут пересекаться имена каких-то сущностей.

Логично сделать два precompiled headers и использовать их в разных участках программы. Как уже отмечалось, можно задать произвольные имена файлов, из которых генерируются *.pch файлы. Да и имя *.pch файла тоже можно изменить. Всё это, конечно, требуется делать аккуратно, но ничего сложного в использовании двух precompiled headers нет.

Типовые ошибки при использовании Precompiled Headers

Прочитав внимательно материал выше, вы сможете понять и устранить ошибки, связанные с stdafx.h. Но давайте ещё раз пройдёмся по типовым ошибкам компиляции и разберём их причины. Повторенье — мать ученья.

Fatal error C1083: Cannot open precompiled header file: ‘Debug\project.pch’: No such file or directory

Fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add ‘#include «stdafx.h»’ to your source?

Сообщение говорит само за себя, если его прочитать. Файл компилируется с ключом /Yu. Это значит, что следует использовать precompiled header. Но в файл не включён «stdafx.h».

Нужно вписать в файл #include «stdafx.h».

Если это невозможно, то следует не использовать precompiled header для этого *.c/*.cpp файла. Уберите ключ /Yu.

Fatal error C1853: ‘project.pch’ precompiled header file is from a previous version of the compiler, or the precompiled header is C++ and you are using it from C (or vice versa)

В проекте присутствуют как C (*.c), так и C++ (*.cpp) файлы. Для них нельзя использовать единый precompiled header (*.pch файл).

Из-за precompiled header компилятор глючит

Скорее всего, что-то сделано не так. Например, #include «stdafx.h» расположен не в самом начале.

Этот код не скомпилируется. Компилятор выдаст на первый взгляд странное сообщение об ошибке:

Компилятор считает, что все, что указано до строчки #include «stdafx.h» (включительно), является precompiled header. При компиляции файла компилятор заменит все, что до #include «stdafx.h» на текст из *.pch файла. В результате теряется строчка «int A = 10».

Содержимое файла «my.h» не будет использоваться. В результате, нельзя будет использовать функции, объявленные в этом файле. Такое поведение очень сбивает программистов с толку. Они «лечат» его полным отключением precompiled headers и потом рассказывают байки о глючности Visual C++. Запомните, компилятор — это один из наиболее редко глючащих инструментов. В 99.99% случаев надо не злиться на компилятор, а искать ошибку у себя (Proof).

Чтобы таких ситуаций не было, ВСЕГДА пишите #include «stdafx.h» в самом начале файла. Комментарии перед #include «stdafx.h» можно оставить. Они всё равно никак не участвуют в компиляции.

Ещё один вариант — используйте Forced Included File. См. выше раздел «Life hack».

Из-за precompiled headers проект постоянно перекомпилируется целиком

В stdafx.h включён файл, который регулярно редактируется. Или случайно включён автогенерируемый файл.

Внимательно проверьте содержимое файла «stdafx.h». В него должны входить только заголовочные файлы, которые не изменяются или изменяются крайне редко. Учтите, что включённые файлы могут не меняться, но внутри они ссылаются на другие изменяющиеся *.h файлы.

Творится что-то непонятное

Иногда может возникнуть ситуация, что вы поправили код, а ошибка не исчезает. Отладчик показывает непонятные вещи.

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

Это ОЧЕНЬ редкая ситуация. Но она возможна и про неё надо знать. Я за многие годы программирования сталкивался с ней только 2-3 раза. Помогает полная перекомпиляция проекта.

Проект, использующий precompiled headers не удаётся проверить с помощью PVS-Studio

Это наиболее частая ситуация, с которой к нам обращаются в поддержку. Подробности изложены в документации: «Устранение неисправностей при работе PVS-Studio». Здесь опишу ситуацию кратко.

Если решение (solution) компилируется, это вовсе не значит, что оно правильно устроено. Часто одно решение (solution) содержит множество проектов. В каждом проекте используются свои precompiled headers (имеется свой stdafx.h и stdafx.cpp).

Возникают проблемы, когда начинают использовать файлы из соседнего проекта. Это удобно и так часто делается. Вот только забывают, что в *.cpp файле написано: #include «stdafx.h».

И, какой из stdafx.h подхватится, это интересный вопрос. Но раз программа компилируется — программисту везёт.

К сожалению, нам сложно повторить поведение, которое возникает при использовании *.pch файла. «Честный» препроцессор работает по-другому.

В том, что solution, на самом деле, устроен не верно, можно убедиться, временно отключив precompiled headers. Сразу может вылезти масса интересных ошибок, и программист будет искренне удивляться, каким же чудом компилировался его проект.

За подробностями вновь делаю отсылку к документации. Плюс, если что-то всё равно не ясно, мы подскажем в поддержке.

Заключение

Как вы увидели, ничего сложного в precompiled headers нет. Все «многочисленные глюки компилятора», с которыми сталкивается программист при их использовании, на самом деле, являются непониманием принципов работы. Надеюсь, эта статья поможет устранить непонимание.

Precompiled headers являются очень полезным механизмом, позволяющим существенно увеличить скорость компиляции проектов.

Источник

Познавательно-развлекательный портал