GCC / Оптимизация времени сборки

У нас есть проект, который использует GCC и make файлов. Проект также содержит один большой подпроект (SDK) и множество относительно небольших подпроектов, которые используют этот SDK и некоторую общую платформу.

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

существуют ли какие-либо известные методы и инструменты для оптимизации времени сборки? Или, может быть, вы знаете некоторые статьи / ресурсы об этом или связанных темах?

10 ответов


вы можете решить эту проблему с двух сторон: рефакторинг кода, чтобы уменьшить сложность компилятор видит, или ускорить исполнение компилятора.

не касаясь кода, Вы можете добавить в него больше мощности компиляции. Используйте ccache, чтобы избежать перекомпиляции файлов, которые вы уже скомпилировали, и distcc для распределения времени сборки между другими машинами. Используйте make-j, где N-количество ядер+1, Если вы компилируете локально, или большее число для распределенных сборок. Этот флаг будет запуск нескольких компиляторов параллельно.

рефакторинг кода. Предпочитайте прямое объявление includes (simple). Отделите столько, сколько сможете, чтобы избежать зависимостей (используйте идиому PIMPL).

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


лучшее, что я могу придумать с make - Это . Это говорит make выполнить как можно больше заданий параллельно:

make -j

если вы хотите ограничить количество параллельных заданий n вы можете использовать:

make -j n


убедитесь, что зависимости верны, поэтому make не запускает задания, которые ему не нужны.


еще одна вещь, чтобы принять в счет оптимизаций, что gcc С -O переключатель. Можно задать различные уровни оптимизации. Чем выше оптимизация, тем больше время компиляции и ссылок. Проект, с которым я работаю, выполняется за 2 минуты до связи с -O3, и полминуты с -O1. Вы должны убедиться, что не оптимизируете больше, чем вам нужно. Вы можете строить без оптимизации для сборок разработки и с оптимизацией для развертывания опирающийся.


компиляция с отладочной информацией (gcc -g), вероятно, увеличит размер исполняемого файла и может повлиять на ваше время сборки. Если вам это не нужно, попробуйте удалить его, чтобы увидеть, если это влияет на вас.


тип связывания (статический и динамический)должен иметь значение. Насколько я понимаю, статическая связь занимает больше времени (хотя я могу ошибаться здесь). Вы должны увидеть, влияет ли это на вашу сборку.


из описания проекта Я предполагаю, что у вас есть один Makefile на каталог и вы используете рекурсивный make много. В этом случае методы из "Рекурсивный Сделать Считается Вредным" должно очень помочь.


Если у вас есть несколько компьютеров, доступных gcc хорошо распределяется по distcc.

вы также можете использовать класс ccache дополнительно.

все это работает с очень небольшими изменениями в файлах Makefile.


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

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

что-то еще, что не тем не менее, упомянутый в любом из предыдущих ответов, делает символьную связь как можно более "частной", т. е. предпочитает статическую связь (функции, переменные) для вашего кода, если она не должна быть видимой извне.

кроме того, вы также можете посмотреть на использование GNU gold linker, которая составляет гораздо более эффективным!--8--> для компиляции кода C++ для целей ELF.

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


вы можете рассмотреть возможность перехода на другую систему сборки (которая, очевидно, не будет работать для всех), например SCons. SCons гораздо умнее, чем сделать. Он автоматически сканирует зависимости заголовков, поэтому у вас всегда есть наименьший набор зависимостей перестроения. Добавив строку Decider('MD5-timestamp') для вашего файла SConstruct SCons сначала посмотрит на отметку времени файла, и если она новее, чем ранее построенная отметка времени, она будет использовать MD5 файла, чтобы убедиться, что вы действительно изменили что-то. Это работает не только на исходных файлах, но и на объектных файлах. Это означает,что при изменении комментария, например, вам не нужно повторно связываться.

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


Если у вас есть LAN с машинами разработчика, возможно, вам следует попробовать реализовать решение распределенного компилятора, такое как distcc.

Это может не помочь, если все время во время сборки тратится на анализ зависимостей или выполнение какой-либо одной последовательной задачи. Для необработанного сжатия компиляции многих исходных файлов в объектные файлы, очевидно, помогает параллельное построение, как предложил (на одной машине) Натан. Распараллеливание на нескольких машинах может занять это еще дальше.


http://ccache.samba.org/ ускоряет время.

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


можно использовать distcc распределенный компилятор для сокращения времени сборки, если у вас есть доступ к нескольким машинам. Вот статья из IBM developerWorks, связанная с distcc, и как вы можете ее использовать: http://www.ibm.com/developerworks/linux/library/l-distcc.html

другой способ сократить время сборки-использовать предварительно скомпилированные заголовки. Вот отправная точка для gcc.

также не забудьте использовать -j при строительстве с если ваша машина имеет более одного процессора/ядра(2х количество ядер/процессоров-это просто отлично).


использование небольших файлов не всегда может быть хорошей рекомендацией. Диск имеет минимальный размер сектора 32 или 64K, при этом файл занимает по крайней мере сектор. Таким образом, 1024 файла размером 3K (небольшой код внутри) фактически займет 32 или 64 Мег на диске вместо ожидаемого 3 Мег. 32/64 Мег, которую нужно прочитать на диске. Если файлы рассредоточены по диску, вы увеличиваете время чтения еще больше со временем поиска. Это помогает с дисковым кэшем, очевидно, до предела. предварительно скомпилированный заголовок также может быть хорошим помочь облегчить это.

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