Комментарии 35
- Как по вашему, допустимо ли в stdafx.h использование конструкции using namespace?
- Как насчет запихнуть туда (в stdafx.h) набор любимых макросов?
- Нужно ли делать include guard, для stdafx.h?
Как по-вашему, допустимо ли в stdafx.h использование конструкции using namespace?
Смотря какой проект. В большом думаю не стоит. В маленьких и средних, я думаю не будет беды в использовании using namespace для std и т.п. Вообще это на усмотрение разработчиков.
Как насчет запихнуть туда (в stdafx.h) набор любимых макросов?
Если они везде нужны, то можно и полезно. Например, у нас в stdafx.h был свой макрос для подавления предупреждений о неиспользуемых переменных. Потом он превратился в функцию, но смысл не поменялся. Функция также живёт в stdafx.h, так как используется повсеместно:
// UNREFERENCED_PARAMETER от Герб Саттера
template void PVS_UNREFERENCED_PARAMETER( const T& ) { }
Нужно ли делать include guard, для stdafx.h?
Как-то никогда не задумывался над этим вопросом. По идеи, два раза stdafx.h включаться не должен. Он ведь включается один раз в начале *.c/*.cpp файлов. У нас на всякий случай написано "#pragma once". Думаю, лишняя защита не повредит.
Мы его вставляли в паре сотен мест, когда убирали варнинги 4 уровня в проекта в пару миллионов строк :)
Так что лучше делать так:
// pragma once in precompiled header causing a warning in non-MSVC compilers
#ifdef _MSC_VER
#pragma once
#endif // _MSC_VER
Как по вашему, допустимо ли в stdafx.h использование конструкции using namespace?
Использование using namespace в любом *.h файле ведет к приятным часам компиляции.
У вас есть
qq::foo; ww::foo;
потом вы написали using namespace qq;
using namespace ww;
а используете просто как foo.Какой из foo должен выбрать компилятор?
У нас в проекте Chromium для тестов собирается с особыми ключами, там порядка десяти тысяч файлов, сборка с нуля занимает порядка 10 минут, есть сколько-то precompiled headers в third party code, но с ними собирается меньше одного процента файлов.
Правда есть одно но: в качестве основной платформы для разработки у нас Linux, а не Windows, в частности потому, что Windows какими примочками не натирай — сборка занимает много больше, чем под Linux. Этак разика в три, если не в пять. Хотя машинки идентичны (Dual Xeon CPU E5-2690, 64GiB RAM).
P.S. я говорил про проект, на движке которого, фактически, работали первые версии ДубльГис, в этом внутреннем продукте делалось все: рисование карты, внесение фирм, рекламы, ведение рубрикатора, полный технологический цикл в общем, просто это все было разбито на проекты. Классов примерно 3000.
По поверью, дело в реализации дисковой подсистемы, которая в Windows (изначально интерактивной ОС) оптимизирована под latency, а в Linux (изначально пакетной ОС) — под throughput.
2. Замеры скорости сборки с и без Precompiled Headers будут?
3.
Идём на вкладку настроек «Advanced». Выбираем все конфигурации. В поле «Forced Included File» пишем:
StdAfx.h;%(ForcedIncludeFiles)
Теперь «stdafx.h» автоматически будет включаться в начало ВСЕХ компилируемых файлов. PROFIT!
Больше не потребуется писать #include «stdafx.h» в начале всех *.c/*.cpp файлов. Компилятор сделает это сам
Отличный совет тем, кому потом программу портировать на другую платформу/ос/компилятор…
4.
Выигрыш от того, что при препроцессировании не надо читать множество файлов и вставлять их друг друга намного больше, чем потери на синтаксический анализ лишних фрагментов кода.
Очень громкое заявление, которое ничем не подкреплено. Если разместить проект в оперативной памяти (RAMDisk), то чтение будет очень быстрым. Тем более, что в файл нужно подставить только один инлюд, а с Precompiled Headers будет вставлено очень много мегабайт текста, который нужно еще скомпилировать.
5. При наличие большого кол-во проблем, связанных с Precompiled Headers возникает вопрос об их целесобразности. Ну да, они дают N% ускорения, но есть же и другие способы повысить скорость компиляции, которые дадут больше ускорения. Например, если если система сборки cmake, то вместо того чтобы генерировать «MS Solution» можно сгенерировать ninja файл и собрать 1.5 раза*(из личного опыта на большом проекте) быстрее. Разместите файлы на RAMDisk, и вот еще прибавка к скорости, не меняя исходников.
6. А если нужно провести рефакторин, то нужно планировать и рефакторинг хидеров, так как они будут либо часто пересобираться либо вообще не нужны. Что опять же усложнит процесс разработки.
итого: я не против Precompiled Headers, я призываю подумать 100500 раз и доказать себе, что оно нужно в конкретном проекте и без него совсем ни как.
Из личного опыта: на не очень маленьком проекте с использованием boost, который компилировался около 5 минут, перенос проекта с с boost-ом и другими библиотеками на RamDisk практически не ускорил проект (ускорил, но на еле-еле). О таком же поведении когда-то упоминали на StackOverflow… Операционные системы отлично кэшируют. Ускорял компиляцию другими методами
Я так и не понял самого главного.
Раз есть опции Создать (/Yc) и Использовать (/Yu) то логично сначала создать (а при изменениях в stdafx.h создать заново), а потом использовать.
Или я чего-то не так понимаю?
У меня MSVC 2022 в настройках:
Предварительно откомпилированный заголовок | Создать (/Yc)
Предварительно скомпилированный заголовочный файл | stdafx.h
Предварительно скомпилированный заголовочный выходной файл | (IntDir)(TargetName).pch
Файлы stdafx.h (содержащий стандартные и системные заголовки) и stdafx.cpp (содержащий только #include "stdafx.h") есть. Во всех файлах проекта первой строчкой включено #include "stdafx.h"
Всё компилируется, но что-то у меня большие сомнения в том что ускорение компиляции срабатывает...
Изменяю в настройках студии: Создать (/Yc) на Использовать (/Yu) - по моей логике тут то и должно подключиться ускорение, но вместо него получаю ошибку:
Ошибка C1854 нельзя перезаписать данные, сформированные во время создания предкомпилированного заголовка в объектном файле: D:\VS_2022_prj\MyWinTemplate_002\tmp\x64\Release\stdafx.obj MyWinTemplate_002 D:\VS_2022_prj\MyWinTemplate_002\MyWinTemplate_002\stdafx.cpp 1
Исключаю из проекта stdafx.cpp, выбираю Создать (/Yc), затем "пересобрать решение". После этого подключаю обратно stdafx.cpp и выбираю Использовать (/Yu).Теперь всё компилируется и вроде бы как есть ускорение.
Но создавать предкомпилированный заголовок таким танцем с бубном как то странно.
Эти опции работают не между сборками, а между модулями. То есть надо поставить опцию "создать" на stdafx.cpp, а "использовать" на все остальные модули (на весь проект, где оно по умолчанию и стоит).
То, чего пытаетесь добиться вы - это инкрементальной сборки, когда файл не создаётся если он уже есть и актуален. Однако, система сборки, насколько я знаю, уже умеет пропускать бесполезные шаги. Не надо закатывать солнце вручную - просто перестаньте менять настройки и позвольте инкрементальной компиляции сделать своё дело.
А менять настройки проекта каждый раз - к корне неправильно. Они на то и настройки проекта, чтобы, ну, настраивать проект. Проект, а не конкретный запуск сборки.
Разобрался.
Просто я сразу не понял как редактировать Создать (/Yc) / Использовать (/Yu) для отдельного файла, а не для проекта целиком.
После того как нашёл, всё заработало по инструкции из статьи.
Итоги моих экспериментов с предкомпиляцией:
1) VS 2022 уже шибко умная и сама предкомпилирует всё подряд. Соответственно необходимость как то специально настраивать stdafx отпала. Думаю поэтому теперь это и отключено по умолчанию в новых проектах. Я не смог заметить выигрыша от его включения. (Статья написана в 2014г и тогда настройка stdafx имела смысл).
2) На скорость компиляции сильно влияет закольцованное взаимное включение заголовочных файлов (как раз с ним то, как выяснилось, я и боролся). Скорость компиляции может замедлиться, а размер предкомпилированных файлов увеличиться в несколько раз (у меня было в 4-5 раз).
- эту закольцованность сложно заметить - глаз легко замыливается;
- VS никак не предупреждает о такой закольцованности, (могут быть глюки с тем что компилятор не увидит некоторые объявления, а могут и не быть - всё компилируется без ошибок - просто медленно, а суммарный размер .ipch файлов переваливает за Гигабайт в небольшом проекте);
- ни #pragma once, ни настройка stdafx не решают проблему медленной компиляции при закольцованности;
- хороший признак, что надо тщательнее искать закольцованность в .h файлах - операция "Перестроить проект" выполняется быстрее, чем "Собрать".
Для новичков про stdafx.h