Pull to refresh

Comments 31

Спасибо, за интересную статью. Вот именно из-за отсутствия объяснения подобных вещей я и не освоил C++ в свое время, потому что всех книгах пишут КАК надо написать, а не ПОЧЕМУ так надо написать. А сейчас и не сильно нужно. Жду еще интересных статей о раскрытии магии С++.
stdafx.h это не С++ — это привет от microsoft и его жутко настраиваемого монстра в лице студии
Нет, есть конечно, но только VS генерирует подобный файл при создании проекта.
И правильно делает! ;) Это очень удобная технология и ее знать надо!
Делает это без объяснений и сильно преждевременно, вот и возникают у новичков траблы с компиляцией и не пониманием нафиг это чудо-юдо нужно
UFO just landed and posted this here
Эх… не все новички читают вообще, что в этом визарде написано, и, думаю, не все новички способны провести параллель между флажком «Precompiled Headers» и файлом stdafx.h
gcc умеет. Если собирать хедеры как-нить так gcc -с xxx.h, то получится на выходе xxx.h.gch, его потом думаю можно аналогично использовать. Но мне всетаки кажется это преждевременной оптимизацией, которая все запутывает.
Спасибо за статью. Хотелось бы уточнить несколько вопросов касательно темы:
  • Как по вашему, допустимо ли в 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". Думаю, лишняя защита не повредит.
В студии есть штатный макрос DBG_UNREFERENCED_LOCAL_VARIABLE(var) и UNREFERENCED_PARAMETER
Мы его вставляли в паре сотен мест, когда убирали варнинги 4 уровня в проекта в пару миллионов строк :)
Да, есть такие макросы. Но мы собирали анализатор не только в Visual C++.
GCC и clang ругаются на "#pragma once" в хедере, если он помечен как используемый для precompiled

Так что лучше делать так:

// 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 должен выбрать компилятор?
Помню у нас большой проект даже с precompiled headers собирался 45 минут, и я вот тут подумал: а как в Qt? Что там делают, чтобы огромные проекты не собирались неделями?
А там все хорошо, вы точно также можете использовать precompiled headers.
А почему они должны собираться неделями? Что вы такое собираете?

У нас в проекте Chromium для тестов собирается с особыми ключами, там порядка десяти тысяч файлов, сборка с нуля занимает порядка 10 минут, есть сколько-то precompiled headers в third party code, но с ними собирается меньше одного процента файлов.

Правда есть одно но: в качестве основной платформы для разработки у нас Linux, а не Windows, в частности потому, что Windows какими примочками не натирай — сборка занимает много больше, чем под Linux. Этак разика в три, если не в пять. Хотя машинки идентичны (Dual Xeon CPU E5-2690, 64GiB RAM).
Странно, что под винду ощутимо дольше сборка. Насколько помню, у Chromium просто гигантская кодовая база, если это все собирается 10 мин — просто чудо)
P.S. я говорил про проект, на движке которого, фактически, работали первые версии ДубльГис, в этом внутреннем продукте делалось все: рисование карты, внесение фирм, рекламы, ведение рубрикатора, полный технологический цикл в общем, просто это все было разбито на проекты. Классов примерно 3000.
Не странно. Собираем clang под Windows и под RedHat на одинаковых машинах — под виндой действительно дольше раза в два-три.
По поверью, дело в реализации дисковой подсистемы, которая в Windows (изначально интерактивной ОС) оптимизирована под latency, а в Linux (изначально пакетной ОС) — под throughput.
Это не чудо, это норма. А вот тормоза под Windows — это беда. Когда Chrome собирается под Linux, то почти всё время все 32 процессора заняты на 95-99%. Когда же Chrome собирается под Windows, то часто работой загружены 3-5 процессоров, а остальные простаивают. Бог знает чем это чудо в этот момент занято: компиляторов в обоих случаях запущены десятки (ninja всё-таки и там и там), только под Windows они периодически останавливаются «покурить».
Отличный ликбез. уверен, что он будет полезен не только новичкам, но и более матерым программистам!
1. Отличный ликбез.

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 раз и доказать себе, что оно нужно в конкретном проекте и без него совсем ни как.
Хм, а есть замеры скорости сборки с RAMDisk?

Из личного опыта: на не очень маленьком проекте с использованием boost, который компилировался около 5 минут, перенос проекта с с boost-ом и другими библиотеками на RamDisk практически не ускорил проект (ускорил, но на еле-еле). О таком же поведении когда-то упоминали на StackOverflow… Операционные системы отлично кэшируют. Ускорял компиляцию другими методами
Спасибо, отличная статья; добавлю в must read для своих подопечных учеников.
Sign up to leave a comment.