Медленное время компиляции с Boost + GCC + предварительно скомпилированный заголовок

Работает: gcc версии 4.2.1 (Apple Inc., сборка 5664)

Я создал проект Apple XCode с предварительно скомпилированным заголовком по умолчанию. Это кажется очень медленным, и тривиальный основной файл с основной функцией не включает код без кода, который компилируется за 6 секунд после того, как я обновился до нового SSD-накопителя. Я на ноутбуке, но у меня есть оговорки, что переход на рабочую станцию ​​облегчит мою проблему. Если я отключу предварительно скомпилированный заголовок, то основной файл скомпилируется менее чем за секунду. Похоже, что использование предварительно скомпилированного заголовка накладывает штраф на все файлы. Эта задержка заставляет меня избегать компиляции и экспериментов с кодом, который не очень хорош. Вот что я включаю в свой предварительно скомпилированный заголовок:

#pragma once

#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <fstream>
#include <functional>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <valarray>
#include <vector>

#include <boost/smart_ptr/scoped_ptr.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/shared_array.hpp>
#include <boost/smart_ptr/make_shared.hpp>  
#include <boost/smart_ptr/weak_ptr.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>

#include <boost/regex.hpp>
#include <boost/thread.hpp>
#include <boost/bind/bind.hpp>
#include <boost/bind/apply.hpp>
#include <boost/bind/protect.hpp>
#include <boost/bind/make_adaptable.hpp>

#include <boost/asio.hpp>
//#include <boost/asio/ssl.hpp>


#include <boost/property_tree/ptree.hpp>
#include <boost/random.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/time_zone_base.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

Я не включил дух, который действительно увеличивает время компиляции.


person user805547    schedule 09.06.2012    source источник
comment
Таким образом, тривиальный основной файл с основной функцией без включения кода требует гораздо меньше времени для компиляции, чем проект со всеми перечисленными выше включениями? Этого не следует ожидать?   -  person jedwards    schedule 09.06.2012
comment
Кроме того, я понимаю, что предварительно скомпилированные заголовки таковы, что они имеют тенденцию экономить время компиляции только тогда, когда в противном случае они были бы скомпилированы повторно, через includes из нескольких источников. Это не относится к вам, поэтому я полагаю, что ваше время компиляции с использованием предварительно скомпилированных заголовков будет похоже на без него. То есть вы не получите большого выигрыша от использования предварительно скомпилированных заголовков. Вы действительно должны ограничить свои включения тем, что вам нужно на основе исходного файла.   -  person jedwards    schedule 09.06.2012
comment
И что это значит: эта задержка заставляет меня избегать компиляции и экспериментов с нехорошим кодом?   -  person jedwards    schedule 09.06.2012


Ответы (1)


Предварительно скомпилированные заголовки GCC работают особым образом. В любом исходном файле можно использовать только один предварительно скомпилированный заголовочный файл. Используйте -H, чтобы показать, использует ли данный заголовочный файл предварительно скомпилированную версию или нет.

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

Типичный способ настройки среды PCH выглядит следующим образом:

main.cpp:

#include "allheaders.hpp"

int main() { /* ... */ }

allheaders.hpp:

#include <algorithm>
// ... everything you need

Компиляция:

g++ $CXXFLAGS allheaders.hpp                 # 1
g++ $CXXFLAGS -H -c -o main.o main.cpp       # 2
g++ $LDFLAGS -o myprogram main.o             # 3

После шага №1 у вас должен получиться файл allheaders.hpp.gch, который должен быть довольно большим. На шаге 2 флаг -H должен выдавать дополнительный вывод, указывающий на то, что используется предварительно скомпилированный заголовочный файл. Шаг № 3 связывает исполняемый файл.

Идея состоит в том, что шаг № 1 потенциально может занять очень много времени, но шаг № 2 должен стать намного быстрее.

person Kerrek SB    schedule 09.06.2012
comment
Я проанализировал команду GCC, и она ссылается на псевдотекстовый файл размером 308 МБ, который выглядит как обработанный предварительно скомпилированный заголовок. Предварительно скомпилированный заголовок автоматически включается в каждый исходный файл, что некоторые люди, кажется, не получают, и вносит задержку около 6 секунд. Я не помню, чтобы у меня была эта проблема с Visual Studio, хотя с VS я всегда запускаю ее на более мощной рабочей станции. Задержка в 6 секунд, когда я меняю одну букву в файле, неприемлема и составляет минуты/часы/дни потерянного времени в цикле разработки. - person user805547; 09.06.2012
comment
Что ж, вы должны хорошо разбираться в том, какие заголовки нужно прекомпилировать. Конечно, у вас не должно быть одного универсального PCH. В идеале вы должны создать отдельный заголовок всех заголовков для каждого исходного файла по отдельности. На практике я бы зарезервировал эту обработку для тех файлов, которые на самом деле реализуют все тяжелые вещи Boost. - person Kerrek SB; 09.06.2012
comment
Я использую boost почти везде, поэтому если не помещать их в PCH, отдельные файлы будут компилироваться медленно. Я начинаю думать, что этот ноутбук и программное обеспечение слишком медленны для серьезной разработки на C++. Это нормально для Cocoa, но Boost с его интенсивным использованием шаблонов и метапрограммирования — убийца. - person user805547; 09.06.2012
comment
Увидев ваш предварительно скомпилированный заголовок, вы могли бы провести рефакторинг некоторых из этих утилит Boost в их собственные небольшие файлы реализации. Для некоторых задач Boost представляет собой смесь #define и #include с небольшим промежуточным кодом, например, для scoped_ptr<>, который можно просто реализовать в собственном маленьком заголовке с (почти) отсутствием зависимостей и решений, зависящих от компилятора, и без пот. Перегруппировка и рефакторинг утилит Boost сэкономили мне примерно ~35% времени компиляции и ~80% головной боли, связанной с чтением исходного кода. - person Luis Machuca; 09.06.2012