Как сократить время компиляции для большой библиотеки 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
, Кэширует результаты предыдущих компиляций.
Структурируйте свой код в соответствии с используемой парадигмой PIMPL. Два основных преимущества:
- Вы можете скрыть от пользователя всю реализацию (переменные-члены и т. Д.)
- Если вы изменяете файлы реализации, то "обычно" только эта область требует перекомпиляции, а не полной перестройки.
Хороший обзор смотрите здесь