Для новичков про stdafx.h
Статья рассчитана на людей, которые знакомятся со средой Visual Studio и пытаются компилировать в ней свои Си++-проекты. В незнакомой среде всё кажется странным и непонятным. Особенно новичков раздражает файл stdafx.h, из-за которого возникают странные ошибки во время компиляции. Очень часто всё заканчивается тем, что новичок долгое время везде старательно отключает Precompiled Headers. Чтобы помочь людям разобраться что к чему, и была написана эта статья.
Для чего нужны Precompiled Headers
Precompiled headers предназначены для ускорения сборки проектов. Обычно программисты начинают знакомиться с Visual C++, используя крошечные проекты. На них сложно заметить выигрыш от precompiled headers. Что с ними, что без них, на глаз программа компилируется одинаковое время. Это добавляет путаницы. Человек не видит для себя пользы от этого механизма и решает, что он для специфичных задач и ему никогда не понадобится. И иногда считает так многие годы.
На самом деле, precompiled headers весьма полезная технология. Пользу от него можно заметить, даже если в проекте всего несколько десятков файлов. Особенно выигрыш становится заметен, если используются такие тяжёлые библиотеки как boost.
Если посмотреть *.cpp файлы в проекте, то можно заметить, что во многие включаются одни и те-же наборы заголовочных файлы. Например, <vector>, <string>, <algorithm>. В свою очередь, эти файлы включают другие заголовочные файлы и так далее.
Всё это приводит к тому, что препроцессор в компиляторе вновь и вновь выполняет идентичную работу. Он должен читать одни и те же файлы, вставлять их друг в друга, выбирать #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».
- Файл A: <vector>, <string>
- Файл B: <vector>, <algorithm>
- Файл C: <string>, <algorithm>
Достаточно сделать один precompiled header, в котором будут раскрыты <vector>, <string> и <algorithm>. Выигрыш от того, что при препроцессировании не надо читать множество файлов и вставлять их друг друга намного больше, чем потери на синтаксический анализ лишних фрагментов кода.
Как использовать 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. Это делается на вкладке «Precompiled Header»:
- Выставляем для параметра «Precompiled Header» значение «Use (/Yu)».
- Для параметра «Precompiled Header File» указываем «stdafx.h».
- Для параметра «Precompiled Header Output File» указываем «$(IntDir)$(TargetName).pch».
Для всех *.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 раза полностью перекомпилировать весь проект — занятие неприятное. Плюс полная перекомпиляция потребуется всем вашим коллегам.
Не увлекайтесь с неизменяемыми файлами. Включайте только то, что действительно часто используется. Нет смысла включать <set>, если это нужно только в двух местах. Там, где нужно, там и подключите этот заголовочный файл.
Несколько 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
- Файл stdafx.cpp не компилировался и, как следствие, *.pch файл ещё не создан. Такое может быть, если, например, в начале очистить проект (Clean Solution), а потом попробовать скомпилировать один *.cpp файл (Compile Ctrl-F7). Решение: скомпилируйте проект целиком или как минимум файл stdafx.cpp.
- В настройках ни указано ни одного файла, из которого должен генерироваться *.pch файл. Речь идёт о ключе компиляции /Yc. Как правило, такая ситуация возникает у начинающих, которые захотели использовать precompiled headers для своего проекта. Как это сделать описано выше в разделе «Как использовать Precompiled Headers».
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 headers. Как показывает практика, *.с файлы препроцессируются в несколько раз быстрее, чем *.cpp файлы. Если *.c файлов не очень много, то, отключив precompiled headers для них, вы ничего не потеряете
- Завести два precompiled headers. Первый должен создаваться из stdafx_cpp.cpp, stdafx_cpp.h. Второй из stdafx_c.c, stdafx_c.h. Соответственно, в *.c и *.cpp файлах следует использовать разные precompiled headers. Имена *.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 являются очень полезным механизмом, позволяющим существенно увеличить скорость компиляции проектов.
StdAfx.h manual
This article is meant for those programmers who are only getting started with the Visual Studio environment and trying to compile their C++ projects under it. Everything looks strange and complicated in an unfamiliar environment, and novices are especially irritated by the stdafx.h file that causes strange errors during compilation. Pretty often it all ends in them diligently turning off all precompiled headers in every project. We wrote this article to help Visual Studio newcomers to figure it all out.
The purpose of precompiled headers
Precompiled headers are intended to speed up project builds. When getting started with Visual C++, programmers usually try it on very small projects that cannot show the performance gain from using precompiled headers. Both with and without them, the program seems to take the same time to compile. This is just what confuses the user: he doesn’t see any use in this option and concludes that it is needed for some specific tasks and he will never need it. This delusion may last for years.
Precompiled headers are actually a very useful technology. You can notice the benefit even with a project of just a few dozens of files. Using such heavy libraries as boost makes the performance gain especially evident.
If you examine the *.cpp files in your project, you will notice that many of them include the same sets of headers, for example <vector>, <string>, <algorithm>. These headers, in their turn, include other headers, and so on.
All this results in the compiler’s preprocessor doing the same work again and again — it must read the same files many times, insert them into each other, process #ifdef and expand macros. Because of that, the same operations are repeated a huge number of times.
The amount of work the preprocessor has to do during project compilation can be greatly reduced. The idea is to preprocess a group of files in advance and then simply insert already prepared text fragments where necessary.
It actually includes a few more steps: instead of simple text you can store more highly processed information. I don’t know how exactly it all is implemented in Visual C++, but I know that, for instance, you can store text already split into lexemes. It will speed up the compilation process even more.
How precompiled headers work
A file containing precompiled headers has the “.pch” extension. The file name usually coincides with the project name, but you can naturally change this and any other used names in the settings. The *.pch file may be pretty large, which depends on how many headers are expanded in it. In PVS-Studio, for example, it occupies about 3 Mbytes.
The *.pch file is created as a result of the stdafx.cpp file’s compilation. This file is built with the “/Yc” switch that is used specifically to tell the compiler to create precompiled headers. The stdafx.cpp file can contain one line: #include “stdafx.h”.
The most interesting stuff is stored in the “stdafx.h” file. All the header files to be precompiled should be included into it. For example, below is the stdafx.h file we use in PVS-Studio (the text is abridged for the article):
The “#pragma warning” directives are necessary to get rid of warnings generated on standard libraries.
Now the “stdafx.h” file should be included into all the *.c/*.cpp files. You should also remove from these files all the headers already included into “stdafx.h”.
But what to do when different files use somewhat similar but still different sets of headers? For example:
- File A: <vector>, <string>
- File B: <vector>, <algorithm>
- File C: <string>, <algorithm>
Should you create individual precompiled headers? Well, you can do that but you don’t need to.
You only need to create one precompiled header where <vector>, <string> and <algorithm> will be expanded. The benefit of the preprocessor not having to read numbers of files and insert them into each other overweighs the losses on syntax analysis of additional code fragments.
How to use precompiled headers
When starting a new project, Visual Studio’s Wizard creates two files: stdafx.h and stdafx.cpp. It is through them that the mechanism of precompiled headers is implemented.
These files can actually have any other names; it’s not the name that matters but the compilation parameters you specify in the project settings.
A *.c/*.cpp file can only use one precompiled header. However, one project may contain a few different precompiled headers. Suppose we have only one for now.
So if you have used the Wizard, the files stdafx.h and stdafx.cpp are already created for you, and all the necessary compilation switches are also defined.
If you didn’t use the precompiled headers option in your project, let’s find out how to enable it. I suggest the following algorithm:
- Enable precompiled headers in all configurations for all *.cpp files. It can be done on the “Precompiled Header” tab:
- Set the value “Use (/Yu)” for the “Precompiled Header” option. Set “stdafx.h” for the “Precompiled Header File” option. Set “$(IntDir)$(TargetName).pch” for the “Precompiled Header Output File” option.
- Create an stdafx.h file and add it into the project. We will include those headers we want to be preprocessed in advance into this file.
- Create an stdafx.cpp file and add it into the project. This file has only one line: #include “stdafx.h”.
- Change the settings for the stdafx.cpp file in all configurations; set the value “Create (/Yc)” for the “Precompiled Header” option.
Now we have enabled the precompiled headers option. If we run compilation now, the compiler will create the *.pch file. However, compilation will terminate just a bit later because of errors.
We have set all the *.c/*.cpp files to use precompiled headers, but it’s not enough. We need now to add #include “stdafx.h” into each file.
The “stdafx.h” header must be the very first one to be included into the *.c/*.cpp file. This is obligatory! Otherwise you are guaranteed to get compilation errors.
It really makes sense, if you come to think of it. When the “stdafx.h” file is included in the very beginning, you can substitute an already preprocessed text into the file. This text stays the same all the time and is not affected by anything.
And now imagine that we have included some other file prior to “stdafx.h” and that file contains the line #define bool char. It will make the situation undefined as we have changed the contents of all the files where “bool” is mentioned. Now you can’t just insert a preprocessed text, and the entire mechanism of “precompiled headers” gets broken. I believe this to be one of the reasons why “stdafx.h” must be included in the first place. Perhaps there are some other reasons too.
Life hack
Manually typing #include “stdafx.h” into all the *.c/*.cpp files is pretty tiresome and boring. Besides, you will get a new revision in the version control system with lots of files changed. It’s no good doing so.
Third-party libraries included into the project as source files cause some additional troubles. Changing these files won’t make sense. The best solution would be to disable precompiled headers for them, but it’s inconvenient when you use a number of small libraries. You will be constantly stumbling over precompiled headers.
But there is an easier way to handle precompiled headers. This method is not a universal one, but it did help me in many cases.
Instead of manually adding #include “stdafx.h” in all the files, you may use the “Forced Included File” option.
Go to the “Advanced” settings tab. Select all configurations. In the field “Forced Included File” write the following text:
From now on, “stdafx.h” will be automatically included in the beginning of ALL the files to be compiled. PROFIT!
You won’t need to manually add #include “stdafx.h” in the beginning of each and every *.c/*.cpp file anymore — the compiler will do it automatically.
What to include into stdafx.h
This is a very important question. Mindlessly including every single header into “stdafx.h” will slow down the compilation process instead of speeding it up.
All the files that include “stdafx.h” depend on its contents. Suppose “stdafx.h” includes the file “X.h”. Changing “X.h” just a little bit may cause complete recompilation of the whole project.
Important rule. Make sure your “stdafx.h” file includes only those files that never or VERY rarely change. The best candidates are headers from system and third-party libraries.
If you include you own project files into “stdafx.h”, be especially careful. Include only those files that change very, very rarely.
If any of the *.h files changes once in a month, it’s too frequent enough. In most cases, it takes you more than once to do all the necessary edits in an h-file — usually 2 or 3 times. Completely recompiling the entire project 2 or 3 times is quite an unpleasant thing, isn’t it? Besides, all your colleagues will need to do the same.
But don’t be too fanatical about non-changing files. Include only those headers that you use really often. Including <set> won’t make sense if you need it in just a couple of files. Instead, simply include this file where needed.
Several precompiled headers
What for may we need several precompiled headers in one project? Well, it’s a pretty rare situation indeed. But here you are couple of examples.
Imagine the project is using both *.c and *.cpp files together. You can’t use a shared *.pch file for them — the compiler will generate an error.
You have to create two *.pch files. One of them is created after compiling the C-file (xx.c), the other after compiling the C++-file (yy.cpp). Accordingly, you should specify in the settings to use one precompiled header for C-files and another for C++-files.
Note. Don’t forget to set different names for these two *.pch files. Otherwise they will be replacing each other.
Here’s another situation. One part of the project uses one large library while the other part uses another large library.
Naturally, different parts of the project should not know about both libraries: there may be (unlucky) overlapping of entities’ names in different libraries.
It is logical to create two precompiled headers and use them in different parts of the program. As we have already mentioned, you may use any names you like for the files the *.pch files are generated from. Well, even the name of the *.pch file can be changed too. It all should be done very carefully of course, but there’s nothing especially difficult about using two precompiled headers.
Typical mistakes when using precompiled headers
Now that you have attentively read the text above, you will understand and eliminate any errors related to stdafx.h. But I suggest that we quickly review novice programmers’ typical mistakes once again and investigate the reasons behind them. Practice makes perfect.
Fatal error C1083: Cannot open precompiled header file: ‘Debug\project.pch’: No such file or directory
You are trying to compile a file that uses a precompiled header while the corresponding *.pch file is missing. Possible reasons are:
- The stdafx.cpp file has not been compiled, so the *.pch file is not created yet. This may happen when, for instance, you first clean the solution and then try to compile one *.cpp file (Compile Ctrl-F7). To solve the problem, compile the entire solution or at least the stdafx.cpp file.
- No file has been specified in the settings to generate the *.pch file from — that is, the troubles are with the /Yc compilation switch. This problem is common with Visual Studio newcomers trying to use precompiled headers in their project for the first time. To find out how to do it correctly, see the above section “How to use precompiled headers”.
Fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add ‘#include “stdafx.h”’ to your source?
The error text says it all if you bother to read it. The file is compiled with the /Yu switch. It means that a precompiled header is to be used, but “stdafx.h” is missing from the file.
You need to add #include “stdafx.h” into the file.
If you can’t do it, do not use the precompiled header for this *.c/*.cpp file. Delete the /Yu switch.
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)
The project contains both C (*.c) and C++ (*.cpp) files. You cannot use a shared precompiled header (*.pch file) for them.
- Disable precompiled headers for all the C-files. Practice shows that *.c files are preprocessed several times quicker than *.cpp ones. If you have just a few *.c files, you won’t lose in performance by disabling precompiled headers for them.
- Create two precompiled headers. The first one should be generated from stdafx_cpp.cpp, stdafx_cpp.h; the second from stdafx_c.c, stdafx_c.h. Accordingly, you should use different precompiled headers for the *.c and *.cpp files. The names of the *.pch files must also be different, of course.
The compiler misbehaves when using precompiled headers
You must have done something wrong. For example, the line #include “stdafx.h” is not the first one in the file.
Take a look at this example:
This code will fail to compile, the compiler generating a seemingly strange error message:
It thinks that all text before #include “stdafx.h” (including this line) is a precompiled header. When compiling the file, the compiler will substitute the text before #include “stdafx.h” with the text from the *.pch file. It will result in losing the line “int A = 10".
The correct code should look like this:
One more example:
The contents of the file “my.h” won’t be used. As a result, you won’t be able to use the functions declared in this file. Such behavior does confuse programmers a lot. They try to “cure” it by completely disabling precompiled headers and then come up with stories about how buggy Visual C++ is. Remember one thing: a compiler is one of the least buggy tools. In 99.99% of all cases, it’s not the compiler you should be angry with, but mistakes in your own code (Proof).
To avoid such troubles, make sure you add #include “stdafx.h” in the very beginning of the file ALL THE TIME. Well, you can leave comments before #include “stdafx.h”; they don’t take part in compilation anyway.
Another way is to use Forced Included File. See the section “Life hack” above.
The entire project keeps completely recompiling when using precompiled headers
You have added into stdafx.h a file that you keep regularly editing. Or you could have included an auto-generated file by mistake.
Attentively examine the contents of the “stdafx.h” file: it must contain only headers that never or very rarely change. Keep in mind that while certain included files do not change themselves, they may contain references to other *.h files that do.
Something strange going on
You may sometimes come across an issue when an error doesn’t disappear even after fixing the code. The debugger reports something strange.
This issue may relate to the *.pch file. For some reason the compiler doesn’t notice that one of the header files has been changed, so it doesn’t recompile the *.pch file and keeps inserting previously generated text. It might have been caused by some faults related to the time of file modification.
This is an EXTREMELY rare situation. But it is possible and you should know about it. Personally I have faced this issue only 2 or 3 times during the many years of my career. It can be solved by complete full project recompilation.
A project using precompiled headers cannot be analyzed by PVS-Studio
This is the most frequent trouble users report to our support service. For details, see the documentation: “PVS-Studio: Troubleshooting”. Here I will only give a brief summary of the problem.
If a solution compiles well, it doesn’t mean that it is implemented correctly. One solution may often contain numbers of projects, each of them using their own precompiled headers (i.e. their own stdafx.h and stdafx.cpp files).
Troubles occur when programmers start using files from one project in another. It may be convenient and this method is quite popular indeed. But they also forget that the *.cpp file contains the line #include “stdafx.h”.
The question is, which of the stdafx.h files will be taken up? If the program compiles well, it means the programmer is just lucky enough.
Unfortunately, it is very difficult for us to reproduce the behavior when using the *.pch file. You see, the “honest” preprocessor works quite differently.
You can check if your solution is implemented in a wrong way by temporarily disabling precompiled headers. You may then get lots of interesting errors that will make you sincerely wonder how your project could compile at all.
Again, refer to the documentation for details. If anything is still unclear, ask our support service.
Conclusion
As you can see, working with precompiled headers is pretty easy. Programmers that try to use them and constantly face “compiler’s numerous bugs” just don’t understand the working principles behind this mechanism. I hope this article has helped you to get rid of that misunderstanding.
Precompiled headers are a very useful option that allows you to significantly enhance project compilation speed.
Introduction
The solution: use precompiled headers in Visual Studio.
On an average laptop computer (WinXP, VC++2008 express, Core2Duo 1.5GHz, 2GB RAM) the build time for the Ogre Basic Tutorial 1 goes from 20 seconds, to 1 second with precompiled headers. So that’s 20 times faster!What are precompiled headers?
We won’t explain here what precompiled headers are exactly, there are better places for that on the net.
Just know that precompiled headers are most useful when your project has lots of large includes to process. It is the case with Ogre. You tell Visual Studio which included headers rarely or never change, then Visual Studio will pre-compile them once, will save them in a file in your project folder, with a file extension of .pch (guess why ), and will use this temporary output everytime you compile your project.
There will be no speed benefit when the headers are being pre-compiled, that is when you first compile your project, or when one of the headers to pre-compile has been changed (which should rarely or never happen), but after that, the gain is generally huge.
The good thing is, if one of the headers that have been pre-compiled change, Visual Studio will recreate the .pch file automatically for you. So once setup, precompiled headers won’t get in your way.
How to setup precompiled headers
Setting up precompiled headers is easy and takes only a few steps, especially if you’re just starting a new project.
Create stdafx.h
stdafx.h is the header file where you include all those headers you need in your project that rarely or never change. These could be Ogre headers, or anything else you want. The name of this header file doesn’t matter, but by convention we name it stdafx.h.
Create stdafx.cpp
Then, you need the associated .cpp file.
Create stdafx.cpp in your project. Again the name could be anything, but it is always best to follow conventions.
You can put anything you want in your stdafx.cpp, but the only requirement is to include stdafx.h as the first statement.Include stdafx.h in every file of your project
- as the first statement
- in ALL your .h and .cpp files
With large projects where you have hundreds of files, use some scripting, for example Python, to make sure this is done automatically for you.
In visual studio, you can do the following (make sure you select «All Configurations»):
Configuration Properties -> C/C++ -> Advanced
Type «stdafx.h» in the «Force Include File» field; this will make the visual studio compiler insert the header file at the beginning of each file without having to include it manually.Configure Visual Studio to use precompiled headers
Go to your project settings, make sure you select «All Configurations», then go to
Configuration Properties -> C/C++ -> Precompiled Headers,
and choose «Use Precompiled Header».
Make sure stdafx.h is the header file to be used, and leave the rest to the default value.So now, Visual Studio will try to use precompiled headers the next time you build your project. But it won’t work, since we don’t have the precompiled header (the .pch file) yet. So let’s tell Visual Studio to create it for us.
Configure Visual Studio to create precompiled headers
Finally, in the solution explorer, right-click on stdafx.cpp -> properties
choose «All Configurations»,
then go to C/C++ -> Precompiled Headers,
choose «Create Precompiled Header», make sure stdafx.h is the header file to use, and leave the rest to the default value.
Click «OK».We’ve just told Visual Studio to create the precompiled header when compiling stdafx.cpp.
The precompiled header will be (re)created with the next build:- if it does not exist yet
- when one of the headers to precompile has been modified
- when stdafx.cpp has been modified
Conclusion
Re-build your project. You shouldn’t notice any difference since the precompiled header is first generated. It might even be slower than usual.
So try making a small change to one of your source files (for example add a space or semi colon in the main function), then build again:
enjoy the performance boost!How to include the stdafx.h from the root directory?
With «Show all files» option on in VS, i added a folder and created a new class in that folder. Since i’m using precompiled headers i also need to include the stdafx.h that’s in the root directory relative to the new class file.
In my cpp file i have
Yet I get the following error:
error C1010: unexpected end of file while looking for precompiled header. Did you forget to add ‘#include «stdafx.h»‘ to your source?
My understanding is, that the .. should instruct the compiler to go one directory level up ?
9 Answers 9
Visual C++ allows you to define several ways of setting up precompiled header files. The most common is to enable it for ALL source files at the project configuration level, Under Configuration Properties/C++/Precompiled Headers, setting «Precompiled Header», select «Use». The same location, setting «Precompiled Header File», is usually «stdafx.h». All files will get this setting (thus the configuration at the project) EXCEPT.
One file is responsible for generating the PCH file. That file is typically the stdafx.cpp file in your project, and it typically has nothing in it except #include «stdafx.h» . Configuring Precompiled Headers for THAT ONE FILE, switch from «Use» to «Create». This ensures that if the prime-header for PCH gets out of synch stdafx.cpp is ALWAYS compiled first to regenerate the PCH data file. There are other ways of configuring PCH setting in Visual Studio, but this is the most common.
That being said, your problem is definitely irritating. The filename used to prime the PCH system and specified on both the «Use. » and «Create. » setting above MUST MATCH THE TEXT IN YOUR #include EXACTLY.
Therefore, it is highly likely you can address your problem by adding «..» to your project include directories and removing the «..» from your #include statement. you could also change it at the project-configuration level to be «..\stdafx.h» as the through-header, but that might be a problem if you have source files in multiple folders hierarchically.
Oh, and if it wasn’t clear to you while perusing the PCH configuration settings, if you do NOT want to use PCH for any specific source file (and there are reasons not to sometimes) you can turn it OFF for specific source files, otherwise be sure to always have #include «your-pch-include-file.h» at the head of every source file (c/cpp,etc).
Hope you catch a break.

I generally also like to have a hierarchical order in my projects, and I’ve found there are two simple ways to include a precompiled header:
Put the directory where stdafx.h lies into the compiler’s include directories.
(Properties — VC++ Directories — Include Directories: Add $(ProjectDir) )
If there aren’t too many subdirectories, a simple way to circumvent the error message is like this:
- Put an stdafx.h file into each of your subdirectories which only includes the top-level stdafx.h :
#include «..\stdafx.h» - Write #include «stdafx.h» as first line of all source files in your subdirectories, instead of including the top-level file there.
This way, all your code files use the same precompiled header file, and there is no other complicated setup to do.
It’s interesting that the trick that I use isn’t in the answers:
- Create stdafx.h and stdafx.cpp in the root folder of the project.
- Go to project properties -> precompiled headers. Change to «use».
- Go to stdafx.cpp, right-click properties -> precompiled headers. Change to «create».
- Go to project properties -> advanced; change «Force include files» to stdafx.h;%(ForcedIncludeFiles)
Don’t change any CPP file; keep your header files as they are. Build as-is.
No typing, no RSI, no hassle with include paths, no other pain and misery. And the beauty is that it will still work when you move your solution to another platform. Awesome.

You can adjust the precompiled header settings on a per-file basis.
- In Solution Explorer right click on the .cpp file, select «Properties».
- I’d strongly recommend selecting «All Configurations» in the Configuration drop down List item.
- Browse to «C/C++» — «Precompiled Headers».
- Adjust the «Precompiled Header File» from «stdafx.h» to whatever you need (in your case for example «../stdafx.h» ).
Note this is tedious and error prone since it’s done on a per-file basis, and future developers adding files to your project will have to follow the same steps. If they don’t they will be faced with warnings and errors such as:
- warning C4627: ‘#include «<path>»‘: skipped when looking for precompiled header use.
- fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add ‘#include «stdafx.h»‘ to your source?
which don’t give much indication as to this or any other approach.
I guess they’ll eventually turn to StackOverflow and end up here. Hello, thanks for reading.
On that basis, it’s worth going with alternatives, such as putting $(ProjectDir) on the C++ Include path (under C++\General) but then that can cause confusion when including other header files.
PCH files are wierd, and even moreso in Visual Studio. When compiling a .cpp file that uses a PCH, VS expects the first non-comment/whitespace text to be #include «PCH_NAME_HERE» . The PCH_NAME_HERE is exactly the PCH’s name. No directories, nothing. Just the PCH’s name as specified in the compiler options.
If you’re going to do this directory fudging, then you need to modify your compiler settings so that the directory where the PCH is is in the directory search path. That way, you don’t need to have the ..\ part.
I would suggest to use:
as «Precompiled Header File»
and «Advanced > Force Include File»This will auto include pch for your .cpp files in the beginning, so nothing needs to be changed in the .cpp files.
And this is better than changing the include directory, because sometimes you might have multiple pch files in the include directories, and then you can’t tell which one has been used.

The cause of the confusion is that Visual Studio treats the include directive that includes the precompiled header differently to other include directives. Specifically it does not look for the precompiled header using the normal path lookup approach, instead it simply attempts to match the include directive to that defined in the project configuration by simple string comparison.
Precompiler header configuration is set gobally but can be overridden per file. The normal global config (accessed via Project Properties -> Configuration Properties -> C/C++ -> Precompiled Headers) is:
This configuration is applied to all files in the project by default. However the config for stdafx.cpp is set at the file level and overrides the Precompiled Header value to:
The effect of this is that for any source file configured to use the precompiled header (which by default is all of them except stdafx.cpp) VS will look for an include directive that matches the configured Precompiled Header File value. e.g.
Because the check uses a simple string comparison instead of any kind of directory search, then (irrespective of the location of the source file relative to the project root directory or the location of the stdafx.h file) the path and filename used in the include directive must match exactly that used by the project’s Precompiled Header File configuration setting. The unexpected side effect of this is that if you have a project subdirectory containing various source files, in those files you do not need to reference the stdafx.h file using a relative path like ..\stdafx.h (and if you do VS will raise an error stating that it encountered the end of file while looking for the precompiled header).