Существует два различных эффекта:
Затраты на вызов компилятора: компиляторы являются сложными исполняемыми файлами, а иногда они даже разделяются на фронтенд и исполняемый модуль бэкэнда, а внешний интерфейс порождает бэкэнд для каждогоотдельный исходный файл, даже когда все исходные файлы передаются в один и тот же вызов компилятора из внешнего интерфейса.Gcc и llvm делают это, например.
- Укажите
g++ -v
, чтобы увидеть эти избыточные вызовы компилятора.Это ответ на ваш главный вопрос. Я думаю о том, почему это происходит даже без заголовочных файлов.
Издержки из-за многократного анализа и компиляции одних и тех же заголовочных файлов с нуля.В реальных примерах эти издержки заголовка будут гораздо более значительными, чем сам вызов компилятора.
, потому что, если я включу хотя бы один файл, разница во времени будет значительно увеличена (коэффициент пять в одном случае)
Да!И это также может быть в 1000 раз медленнее, чем в 5 раз.При использовании кода с интенсивным использованием шаблонов компилятору необходимо многое сделать во время компиляции.
Замедление при разделении на множество исходных файлов особенно сильно сказывается на коде C ++, поскольку C ++ интенсивно использует заголовки .Все ваши исходные файлы *.cpp
скомпилированы отдельно, и все заголовки, которые они включают, включены избыточно для каждого отдельного исходного файла.
Теперь, если вы соберете все исходные файлы вместе, все заголовки, как вы сказали, анализируются только один раз из-за включенных защит.Поскольку компилятор тратит большую часть своего времени на синтаксический анализ и компиляцию заголовков, это очень важно, особенно при использовании тяжелого кода шаблона (например, достаточно использовать STL).
Количество исходных файлов для рукописного исходного кода C ++код, а также для сгенерированного исходного кода C ++ является компромиссом между:
Мое полное время перестроения быстрое, но мое инкрементное время сборки медленное.
- Этоэто тот случай, когда у вас есть только один исходный файл (то есть * .cpp файлы) или очень мало исходных файлов.
Полное время сборки у меня медленное, но время инкрементной сборкиэто быстро.
- Это тот случай, когда у вас есть много небольших исходных файлов (то есть файлов * .cpp).
(В любомВ этом случае количество заголовочных файлов не имеет большого значения (за исключением случаев, когда вы всегда извлекаете слишком много избыточного содержимого. Это касается количества вызовов компилятора, которое представляет собой число файлов * .cpp или * .o.)
за 1. полныйВремя компиляции с нуля короткое, так как компилятор видит все заголовки только один раз, что важно в C ++, особенно с библиотеками на основе только заголовков (или с интенсивными заголовками), такими как STL или boost.
Для 2.индивидуальное время компиляции быстрое, поскольку при изменении только одного из сотен файлов необходимо скомпилировать лишь очень небольшое количество кода.
Это сильно зависит от вашего варианта использования.
В случае, если вы генерируете код C ++, вы должны добавить опцию в свой генератор, чтобы позволить пользователю выбирать, какой путь пойти с этим компромиссом.