Как сократить время компиляции для большой библиотеки C++ отдельных файлов.cpp?

Мы разрабатываем библиотеку C++ с более чем 500 сотнями отдельных файлов.cpp. Каждый из них компилируется и архивируется в статическую библиотеку. Даже при параллельной сборке это занимает несколько минут. Я хотел бы сократить это время компиляции.

Каждый файл имеет в среднем 110 строк с функцией или двумя внутри. Однако для каждого файла.cpp существует соответствующий заголовок.h, который часто включается во многие файлы.cpp. Например, A.h может быть включен A.cpp, B.cpp, C.cpp, и так далее.

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

Если такого рода вещи являются виновником, каковы лучшие методы для сокращения времени компиляции?

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

3 ответа

Это действительно трудно сказать.

Я работал над улучшением времени компиляции нашего проекта на работе и обнаружил, что один файл занял 15 минут (при компиляции в -O2, но около 15 секунд -O0) и компилируется дважды, поэтому для общего времени компиляции около 60-70 минут это было примерно вдвое меньше. Отключение ОДНОЙ функции оптимизации привело к тому, что один файл сократился до 20 секунд вместо 15 минут... Этот файл создавал одну функцию, сгенерированную машиной, и несколько десятков тысяч строк, что заставляет компилятор совершать магические действия. длинные вещи (предположительно, некоторый алгоритм O(N^2)).

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

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

В целом, мой опыт (как с моим собственным проектом компилятора, так и с компиляторами других людей / компании) заключается в том, что не разбор и чтение файлов занимают время, а различные этапы оптимизации и генерации кода. Вы можете попробовать это, скомпилировав все файлы, используя -fsyntax-only или как там это называется для вашего компилятора. Это ПРОСТО прочитает источник и проверит его синтаксически правильно. Попробуйте также скомпилировать с -O0 если ты еще не Часто конкретный проход оптимизации является проблемой, а некоторые проходы хуже, чем другие, поэтому полезно проверить, какие отдельные проходы оптимизации существуют в конкретном -O опция - в gcc, которая может быть указана с -Q -O2 --help=optimizers [в этом случае для -O2].

Вам действительно нужно выяснить, на что компилятор тратит время. Нет смысла менять код, если проблема в том, что вы проводите большую часть времени, оптимизируя код. Нет смысла сокращать оптимизаторы, если время потрачено на разбор, а оптимизация не добавляет дополнительного времени. Без фактического построения ВАШЕГО проекта очень сложно сказать наверняка.

Еще один совет, чтобы проверить top чтобы увидеть, использует ли каждый ваш процесс компиляции 100% процессор - если нет, то, вероятно, у вас недостаточно памяти на вашем компьютере компиляции. У меня есть опция сборки для моего рабочего проекта, которая "убивает" мой настольный компьютер, выполняя так много памяти, что вся система просто останавливается - даже переключение с одной вкладки на другую в веб-браузере занимает 15-30 секунд. Единственное решение - меньше бегать -j [но, конечно, я обычно забываю, и в этот момент - поэтому, если я не хочу прерывать его, я иду на обед, долгий перерыв на кофе или что-то подобное, пока он не закончится, потому что машина просто непригодна для использования]. Это только для отладочных сборок, потому что сбор отладочной информации для большой базы кода занимает много памяти [очевидно!]

Если такого рода вещи являются виновником, каковы лучшие методы для сокращения времени компиляции?

Если ваш препроцессор поддерживает #pragma once директива, используйте это. Это гарантирует, что файл.h не будет прочитан более одного раза.

Если нет, используйте #include охранники в.cpp файлах.

Скажи у тебя

Ах:

#ifndef A_H
#define A_H

...

#endif

Вы можете использовать следующий метод в A.cpp:

#ifndef A_H
#include "A.h"
#endif

Вам нужно будет повторить этот шаблон для каждого файла.h. Например

#ifndef B_H
#include "B.h"
#endif

#ifndef C_H
#include "C.h"
#endif

Вы можете прочитать больше об использовании #include Охранники в.cpp файле в Какова функция включения охранника в.cpp (не в.h)?,

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

Следует ли использовать предварительные декларации вместо включений везде, где это возможно?

Другой способ уменьшить время компиляции - использовать ccache, Кэширует результаты предыдущих компиляций.

https://ccache.samba.org/

Структурируйте свой код в соответствии с используемой парадигмой PIMPL. Два основных преимущества:

  • Вы можете скрыть от пользователя всю реализацию (переменные-члены и т. Д.)
  • Если вы изменяете файлы реализации, то "обычно" только эта область требует перекомпиляции, а не полной перестройки.

Хороший обзор смотрите здесь

Другие вопросы по тегам