Ответ 1
Концепция называется сборка единства
Я нахожу, что если есть много классов, время компиляции резко возрастает, когда я использую один *.h и один *.cpp файл для каждого класса. Я уже использую предварительно скомпилированные заголовки и инкрементную привязку, но время компиляции очень велико (да, я использую boost;)
Итак, я придумал следующий трюк:
Таким образом, вместо 100 единиц перевода я получил всего 8 единиц перевода. Время компиляции сократилось в 4-5 раз.
Недостатки в том, что вы должны вручную включать все *.cpp файлы (но это не кошмар для обслуживания, так как если вы забудете включить что-то, на которое ссылается компоновщик) и что некоторые удобства VS IDE не работают с эта схема, например Go To/Move to Реализация и т.д.
Итак, вопрос в том, действительно ли множество единиц перевода cpp действительно является единственным истинным способом? Является ли мой трюк известным шаблоном, или, может быть, я что-то упускаю? Спасибо!
Концепция называется сборка единства
Один существенный недостаток этого подхода обусловлен наличием одного файла .obj для каждой единицы перевода.
Если вы создаете статическую библиотеку для повторного использования в других проектах, вы часто сталкиваетесь с большими двоичными файлами в этих проектах, если у вас есть несколько огромных единиц перевода вместо многих маленьких, потому что компоновщик будет включать только файлы .obj, содержащие функции/переменные на самом деле ссылки из проекта с использованием библиотеки.
В случае больших единиц перевода, более вероятно, что на каждую единицу ссылаются и соответствующий файл .obj включен. В некоторых случаях могут возникнуть проблемы с большими двоичными файлами. Также возможно, что некоторые линкеры достаточно умны, чтобы включать только необходимые функции/переменные, а не все .obj файлы.
Кроме того, если включен файл .obj и включены все глобальные переменные, то их конструкторы/деструкторы будут вызываться, когда программа запускается/останавливается, что наверняка займет время.
Я видел, что вы делаете в видеоиграх, так как он помогает компилятору делать оптимизации, которые в противном случае не могли бы сделать, а также сэкономить много памяти. Я видел, что "сборщик uber" и "массовая сборка" относятся к этой идее. И если это помогает ускорить вашу сборку, почему бы и нет.
Объединение большого количества файлов исходного кода С++ в один файл - это подход, о котором упоминалось несколько раз недавно, особенно когда люди строят большие системы и вытягивают сложные файлы заголовков (это будет повышаться).
Как вы говорите о VS, я обнаружил, что количество включенных файлов в проекте и особенно размер входящего пути, по-видимому, влияет на время компиляции Visual С++ намного больше, чем на время компиляции g++. Это особенно относится к множеству вложенных включений (опять-таки, делает это), так как требуется большое количество поисков файлов для поиска всех включенных файлов, требуемых исходным кодом. Объединение кода в один исходный файл означает, что компилятор может быть намного умнее в поиске упомянутых включений, плюс их, очевидно, будет меньше, так как вы ожидаете, что файлы в одном и том же подпроекте будут, вероятно, включать очень похожие набор файлов заголовков.
Подход "большого количества единиц компиляции" к разработке на С++ обычно возникает из-за желания разделить классы и минимизировать зависимости между классами, поэтому компилятору нужно только перестроить минимальный набор файлов, если вы вносите какие-либо изменения. Это, как правило, хороший подход, но часто не реализуемый в подпроекте просто потому, что файлы там имеют зависимости друг от друга, поэтому в конечном итоге у вас появятся довольно большие перестройки.
Я не думаю, что сокращение количества единиц компиляции - хорошая идея. Вы пытаетесь решить проблему с большим временем компиляции, и этот подход, похоже, помогает в этом, но то, что вы получаете дополнительно:
У вас может быть некоторая помеха между файлами .cpp, включенными в один файл .cxx:
а. Общепринятой практикой является определение локально в файле cpp file (for debug builds) new new для проверки утечки памяти. К сожалению, это невозможно сделать, прежде чем включать заголовки с использованием нового места размещения (как это делают некоторые заголовки STL и BOOST)
б. Обычно использовать добавления объявлений в файлах cpp. С вашим подходом это может привести к проблемам с заголовками, включенными позже
с. Конфликты имен более вероятны
IMHO, намного более чистый (но, возможно, более дорогой способ), чтобы ускорить время компиляции, - это использовать некоторую распределенную систему сборки. Они особенно эффективны для чистых сборок.
Я не уверен, что это актуально в вашем случае, но, возможно, вы можете использовать объявление вместо определения, чтобы уменьшить количество #include
, которое вам нужно сделать. Кроме того, возможно, вы можете использовать идиому pimpl для той же цели. Это, мы надеемся, уменьшит количество исходных файлов, которые нужно перекомпилировать каждый раз, и количество заголовков, которые нужно вытащить.
Большие и меньшие единицы перевода не используют параллельную компиляцию. Я не знаю, какие компиляторы и какие платформы вы используете, но компиляция в параллельном множестве единиц перевода может значительно уменьшить время сборки...
Следуя за столбиком sharptooths, я бы попытался подробно изучить результирующие исполняемые файлы. Если они отличаются друг от друга, я бы склонен ограничивать вашу технику отладкой сборки и прибегать к исходной конфигурации проекта для основной сборки релиза. При проверке исполняемого файла я также рассмотрел его объем памяти и использование ресурсов при запуске и во время работы.