![34BannerBlogJomitechC++builder660x300 | Embarcadero RAD Studio Delphi C++Builder Blogs 34 banner blog jomitech cbuilder 660x300](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/34_Banner_Blog_Jomitech_Cbuilder_660x300-8855983-1656732.jpg?resize=660%2C300&ssl=1)
В этом посте мы рассмотрим советы и рекомендации о том, как оптимизировать проекты C ++ Builder для максимально быстрой компиляции. Хотя мы определенно потратим некоторое время на оптимизацию, предназначенную для использования с TwineCompile, некоторые из этих приемов применимы к C ++ Builder в целом.
C ++ Builder и TwineCompile включают множество функций, предназначенных для оптимизации скорости компиляции, но их часто приходится настраивать, поскольку каждый проект уникален и имеет разные условия и настройки. Мы рассмотрим различные советы, а также когда и как применять их к разным типам и структурам проектов.
Table of Contents
Уловка №1 — TwineCompile
Первый трюк прост — начните использовать TwineCompile! TwineCompile — это подключаемый модуль IDE, который интегрируется в C ++ Builder и добавляет многопоточность, кэширование и другие мощные улучшения компиляторам C ++ Builder (как Classic, так и CLANG). В некоторых случаях простая установка TwineCompile ускоряет компиляцию проектов в 50 раз на рабочих станциях сборки последнего поколения.
TwineCompile доступен бесплатно всем пользователям C ++ Builder 10.4.1+ с активной подпиской на обновления через диспетчер пакетов GetIt. Это должно быть первой остановкой в поисках более быстрого времени компиляции, поскольку вы можете воспользоваться преимуществами этих улучшений производительности без необходимости вносить единственное изменение в структуру или файлы вашего проекта (в отличие от следующих советов).
Чтобы получить TwineCompile, откройте диспетчер пакетов GetIt в среде IDE и найдите TwineCompile. Следуйте инструкциям по установке.
Интеграция TwineCompile с IDE автоматически подключает команды IDE Compile / Make / Build для вызова TwineCompile вместо процесса сборки IDE. Это позволяет вам продолжать использовать среду IDE, как сегодня, и в полной мере использовать производительность компиляции, предлагаемую TwineCompile.
![Picture1 | Embarcadero RAD Studio Delphi C++Builder Blogs picture1](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture1-4896473.png?resize=496%2C294&ssl=1)
Уловка TwineCompile # 2 — PCH с поддержкой CLANG (предварительно скомпилированные заголовки)
У C ++ Builder давно есть секретное оружие, которое может творить чудеса при медленной компиляции. Часто наиболее эффективным улучшением является правильная настройка и использование предварительно скомпилированных заголовков в проекте. Введение компилятора CLANG значительно улучшило эту функциональность и упростило ее использование. Если в вашем проекте в настоящее время используется компилятор CLANG, я настоятельно рекомендую воспользоваться преимуществами поддержки PCH в CLANG, так как это существенно повлияет на время компиляции. Если в вашем проекте по-прежнему используется классический компилятор, я бы рекомендовал обновить его для использования компилятора CLANG — вы не только получите возможность использовать современный, совместимый со стандартами компилятор C ++ с поддержкой C ++ v17, но и сможете также сможете использовать систему CLANG PCH.
![BannerCCONTEST1220x3003913431 | Embarcadero RAD Studio Delphi C++Builder Blogs banner c contest 1220x300 3913431 2](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/06/Banner_C-CONTEST_1220x300-3913431-1024x252-1999939.jpg?resize=750%2C185&ssl=1)
Концепция предварительно скомпилированных заголовков довольно проста — возьмите набор заголовков, которые используются в большинстве (если не во всех) единицах проекта, и скомпилируйте их в двоичное представление. Когда модуль проекта включает эти предварительно скомпилированные заголовки, компилятор не должен повторно обрабатывать / компилировать заголовки с нуля, но может просто загрузить предварительно скомпилированное представление с диска и перейти к компиляции кода в модуле. .
Требуется некоторая дисциплина, поскольку порядок заголовков в каждом модуле должен быть идентичным, чтобы компилятор мог использовать предварительно скомпилированный заголовок. Кроме того, предварительно скомпилированный заголовок не должен содержать заголовки, которые часто изменяются, поскольку накладные расходы на компиляцию заголовков довольно значительны, и вы потеряете все преимущества предварительно скомпилированного заголовка, если его придется все время перестраивать.
- Начните с анализа вашего проекта и определения заголовков, которые включают в себя большинство модулей. Это может потребовать некоторой реорганизации, чтобы большинство или все блоки включали один и тот же набор заголовков. Обратите внимание, что включая дополнительные, неиспользованные,
заголовки не имеют отрицательного эффекта, поэтому, если некоторые модули не используют все заголовки, все в порядке. Чем больше заголовков предварительно скомпилировано, тем эффективнее будет время компиляции.
- Если в вашем проекте уже есть файл заголовка PCH (например, файл PCH .h, автоматически созданный IDE для новых проектов), перейдите к шагу №6.
- Если в вашем проекте нет файла заголовка PCH (например, файла PCH .h, автоматически созданного IDE для новых проектов), добавьте в проект новый файл заголовка:
![Picture2 | Embarcadero RAD Studio Delphi C++Builder Blogs picture2](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture2-5176476.jpg?resize=347%2C264&ssl=1)
- Сохраните новый файл заголовка с описательным именем, например ProjectNamePCH.h
- Щелкните правой кнопкой мыши файл заголовка на панели «Проекты» и выберите параметр «Использовать для предварительной компиляции»:
![Picture3 | Embarcadero RAD Studio Delphi C++Builder Blogs picture3](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture3-3146603.jpg?resize=225%2C229&ssl=1)
- Откройте этот файл заголовка предварительной компиляции и поместите все операторы include, которые вы собрали на шаге №1. Например:
#include <vcl.h>
#include <tchar.h>
- Просмотрите все модули в своем проекте и удалите операторы #include, которые относятся к заголовкам, расположенным в заголовке PCH. В верхней части каждого модуля, перед любыми другими операторами, поместите следующий оператор прагмы, чтобы сообщить компилятору, что модуль не корректирует предварительно скомпилированный заголовок:
#pragma hdrstop
- Откройте параметры проекта, перейдите в раздел «Предварительно скомпилированные заголовки» в разделе «Компилятор C ++» и выберите «Создать и использовать» для параметра использования PCH.
- Постройте проект. Он потратит некоторое время на компиляцию файла заголовка PCH в двоичное представление, а затем последующие блоки будут компилироваться во много раз быстрее, так как эти заголовки больше не нужно будет обрабатывать для каждого блока снова и снова.
Уловка # 3 — TwineCompile PCH с одним заголовком для классического компилятора
Если в вашем проекте по-прежнему используется классический компилятор, и вы не можете перенести его на более новый компилятор CLANG, все еще можно получить значительный прирост скорости компиляции за счет использования предварительно скомпилированных заголовков, поскольку классический компилятор имеет удивительно мощную систему PCH. TwineCompile был создан, чтобы в полной мере использовать эту систему и организовать процесс сборки таким образом, чтобы классический компилятор автоматически запускался с правильными параметрами для каждого файла, который использует предварительно скомпилированный заголовок.
В отличие от компилятора CLANG, классический компилятор предназначен для создания и использования предварительно скомпилированного заголовка как части компиляции обычных исходных файлов. Для компиляции файла, обозначенного как предварительно скомпилированный заголовочный файл, не требуется отдельного этапа компиляции.
Есть два способа настроить проект для использования PCH с одним заголовком с классическим компилятором:
- Использование команды внедрения для автоматического включения файла PCH с одним заголовком в каждый модуль как часть процесса компиляции.
- Ручное добавление оператора #include для файла PCH с одним заголовком вверху каждого модуля.
Первый подход, очевидно, самый простой, поскольку он обеспечивает автоматическую доступность заголовка в каждом модуле. Второй подход может быть полезен, поскольку заголовок фактически включен в каждый блок, поэтому он доступен для просмотра и других применений, таких как инструмент анализа кода.
- Как и в случае с шагами CLANG, начните с анализа вашего проекта и определения заголовков, которые включают в себя большинство модулей.
Это может потребовать некоторой реорганизации, чтобы большинство или все блоки включали один и тот же набор заголовков. Обратите внимание, что включение дополнительных неиспользуемых заголовков не имеет отрицательного эффекта, поэтому, если в некоторых модулях используются не все заголовки, все в порядке. Чем больше заголовков предварительно скомпилировано, тем эффективнее будет время компиляции.
- Создайте новый файл заголовка в своем проекте:
![Picture4 | Embarcadero RAD Studio Delphi C++Builder Blogs picture4](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture4-3009902.jpg?resize=346%2C264&ssl=1)
- Сохраните новый файл заголовка с описательным именем, например ProjectNamePCH.h
- Откройте этот файл заголовка предварительной компиляции и поместите все операторы include, которые вы собрали на шаге №1. Например:
#include <vcl.h>
#include <tchar.h>
5а. Подход A — если вы хотите использовать функциональность Injection, откройте Project Options, перейдите в раздел Pre-compiled headers в C ++ Compiler и введите имя файла заголовка в опцию Inject header:
![Picture6 | Embarcadero RAD Studio Delphi C++Builder Blogs picture6](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture6-1913515.jpg?resize=491%2C199&ssl=1)
5б. Подход B — если вы хотите вручную добавить заголовок в свои модули, поместите оператор #include для этого файла заголовка, за которым следует строка #pragma hdrstop в самом верху любых модулей. Например:
#include "ProjectNamePCH.h"
#pragma hdrstop
- Откройте Параметры проекта, перейдите в раздел Предварительно скомпилированные заголовки в Компиляторе C ++:
6а. Выберите параметр «Создать и использовать» для использования PCH. Это указывает TwineCompile использовать первый файл исходного кода для создания файла PCH и его использования для всех последующих модулей.
6б. Выберите параметр Кэшировать предварительно скомпилированные заголовки.
6c. Введите имя сгенерированного файла PCH в опцию Имя файла PCH. Например: Project.csm. Этот файл будет содержать двоичные данные, скомпилированные из заголовка, выбранного в качестве предварительно скомпилированного заголовка.
Параметры должны выглядеть примерно так:
![Picture7 | Embarcadero RAD Studio Delphi C++Builder Blogs picture7](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture7-1583346.jpg?resize=526%2C219&ssl=1)
- Постройте проект. TwineCompile автоматически настроит параметры компилятора для компилируемых файлов, чтобы файл PCH создавался и использовался как часть процесса компиляции, что значительно сокращает время компиляции.
Уловка # 4 — TwineCompile автоматический PCH для классического компилятора
Для проектов, которые не могут быть перенесены в компилятор CLANG и не имеют структуры проекта для поддержки одного файла PCH, который будет работать для всех модулей, надежда не потеряна. В классическом компиляторе есть некоторые расширенные функции PCH в сочетании с TwineCompile, которые обеспечивают большинство преимуществ производительности настроенного предварительно скомпилированного заголовка для этих типов проектов. Классический компилятор поддерживает концепцию «адаптивного» (мои слова, а не официальное описание) предварительно скомпилированного заголовка, который постоянно создается и корректируется как часть сборки проекта для поддержки
различные варианты заголовков, которые могут использовать модули проекта. Хитрость заключается в том, чтобы заставить его работать в вашем проекте, и здесь на помощь приходит TwineCompile.
- Откройте Параметры проекта, перейдите в раздел Предварительно скомпилированные заголовки в Компиляторе C ++:
1а. Выберите параметр «Создать и использовать» для использования PCH. Обратите внимание, что в этом проекте нет какой-либо структуры PCH, поэтому обычно этот вариант вызывает больше проблем, чем решает.
1b. Выберите параметр Кэшировать предварительно скомпилированные заголовки.
1c. Введите имя сгенерированного файла PCH в опцию Имя файла PCH. Например: Project.csm. Этот файл будет содержать двоичные данные, скомпилированные из заголовка, выбранного в качестве предварительно скомпилированного заголовка.
Параметры должны выглядеть примерно так:
![Picture8 | Embarcadero RAD Studio Delphi C++Builder Blogs picture8](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture8-7442027.jpg?resize=525%2C219&ssl=1)
- Откройте параметры TwineCompile в меню TwineCompile, перейдите к предварительно скомпилированным заголовкам и выберите параметр «Использовать файл PCH для каждого потока». Щелкните ОК.
![Picture9 | Embarcadero RAD Studio Delphi C++Builder Blogs picture9](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture9-9127965.png?resize=350%2C244&ssl=1)
- Постройте проект. TwineCompile автоматически настроит параметры компилятора для каждого файла, чтобы они могли сгенерировать и использовать файл PCH, который будет адаптироваться к различным вариантам заголовков, включенных в каждый модуль. Производительность будет не такой хорошей, как при правильной настройке PCH, но будет значительно лучше, чем если бы PCH вообще не использовался.
Уловка TwineCompile №5 — Оптимизация макета вашего проекта
Или, используя этот трюк, другим способом — минимизировать количество файлов, которые необходимо скомпилировать при внесении изменений, но сбалансировать это время, необходимое для связывания.
Распространенной тактикой, используемой для оптимизации времени компиляции C ++, является разбиение проектов на множество небольших библиотек или пакетов. Идея состоит в том, что при изменении любого кода необходимо будет перекомпилировать только несколько файлов в этом проекте. Перекомпилированную библиотеку можно просто повторно связать с другими библиотеками для получения окончательного результата.
Это плохая идея по двум причинам, особенно если вы используете TwineCompile:
- Вы торгуете временем компиляции со временем ссылки. Совет, рекомендующий этот подход, обычно ориентирован на более медленные компиляторы C ++, такие как gcc, где время компоновки намного быстрее, чем очень медленное время компиляции. Так что может быть полезно переложить работу на компоновщик. Компиляторы C ++ Builder (как CLANG, так и Classic) довольно быстры для компиляторов C ++, поэтому добавление 15 шагов связывания, чтобы избежать компиляции 30 файлов C ++, часто приводит к значительной потере производительности.
- Связывание — это последовательный процесс. Компиляция идет параллельно. Когда вы используете TwineCompile, файлы C ++ компилируются параллельно, поэтому чем больше модулей может быть скомпилировано одновременно, тем выше производительность. Один проект с 200 модулями C ++ и одним шагом ссылки будет строиться во много раз быстрее, чем 10 проектов с 20 модулями C ++, каждый со своим собственным шагом ссылки.
Как и в большинстве случаев в жизни, существует компромисс, когда разделенная структура проекта имеет смысл. К сожалению, нет единого правильного ответа на вопрос, как должен быть структурирован проект, поэтому я оставлю вам следующие рекомендации:
- Сведите к минимуму количество файлов, которые необходимо скомпилировать для любого изменения источника.
- Сведите к минимуму количество библиотек, пакетов или приложений, которые необходимо связать. Даже статические библиотеки, хотя и довольно быстро подключаются, имеют накладные расходы.
- Максимально увеличьте ресурсы процессора. Компоновщик будет использовать только одно ядро, 16 файлов C ++ на 8-ядерном процессоре + HT будут использовать все 16 логических ядер. Таким образом, компиляция этих 16 файлов может использовать в 16 раз больше ресурсов, чем компоновщик.
Уловка №6 — Компиляция SORTA
Одной из самых мощных функций TwineCompile является его автоматическая система фоновой компиляции. По сути, эта функция автоматически компилирует ваши измененные файлы исходного кода в фоновом режиме, так что при нажатии кнопки «Создать» или «Выполнить» файлы для компиляции отсутствуют, все обновлено, а процесс сборки должен просто связать приложение.
В отличие от многих из вышеперечисленных уловок, этот не связан напрямую с ускорением процесса компиляции или сборки, а направлен на уменьшение или даже устранение необходимости компилировать исходный код.
Чтобы включить SORTA Compile, откройте параметры TwineCompile, перейдите в раздел SORTA Compile и выберите параметр Enable SORTA Compile:
![Picture10 | Embarcadero RAD Studio Delphi C++Builder Blogs picture10](https://i0.wp.com/blogs.embarcadero.com/wp-content/uploads/2021/05/Picture10-7637455.png?resize=361%2C250&ssl=1)
Существует ряд триггеров, которые используются для вызова этой функции, в том числе при сохранении объекта, при изменении вкладки редактора или при изменении файла, к которому не прикасались в течение определенного периода времени.
Эффективное использование SORTA Compile требует корректировки рабочего процесса кодирования, но может дать огромные преимущества традиционному четырехэтапному процессу эволюции проекта: редактировать, компилировать, запускать, тестировать, повторять.
Уловка TwineCompile №7 — Статическое и динамическое связывание
Если вы примените упомянутые выше приемы к своим проектам, вы, вероятно, обнаружите, что начнете все время ждать компоновщика. Ожидание компилятора почти полностью исчезнет. Это и хорошо, и плохо. Хорошо, потому что это
означает, что вы экономите все это время, плохо, потому что вы больше не сможете оптимизировать производительность сборки.
С учетом сказанного, некоторые приложения можно реструктурировать, чтобы поместить различные функциональные возможности в отдельные библиотеки DLL, которые загружаются приложением во время выполнения. Это означает, что когда изменения кода вносятся в определенную часть приложения, только этот конкретный код компилируется и связывается с его собственным файлом DLL. Остальную часть приложения не нужно перестраивать, потому что она связывается с этой DLL во время выполнения.
Очевидно, что этот подход добавляет накладные расходы на развертывание и управление дополнительными файлами DLL, которые должны быть связаны с приложением, но экономия на производительности сборки часто может стоить дополнительных накладных расходов.
Уловка №6 — Аппаратное обеспечение
Наш последний прием — старый и хорошо известный прием, часто известный как «прибегать к аппаратному обеспечению для решения проблемы». В то время как новое и более быстрое оборудование в прошлом давало лишь незначительные преимущества, последние достижения в области аппаратного обеспечения в сочетании со способностью TwineCompile максимально использовать системные ресурсы могут дать некоторые значительные преимущества.
Следует сосредоточить внимание на двух ключевых областях:
1. Производительность диска
Это означает, что SSD-диски используют соединения NVMe / PCIe. Твердотельные накопители SATA хороши, но им не хватает производительности произвольного доступа, как у твердотельных накопителей, работающих по шине PCIe.
Шпиндели категорически запрещены. Если ваши проекты, временные каталоги, операционная система или путь установки C ++ Builder не работают, производительность сборки будет ужасной.
2. Ядра ЦП
Прямолинейная одноядерная производительность для компиляции C ++ в наши дни менее полезна, чем наличие большого количества ядер. Выбирайте максимальное количество доступных ядер.
Процессоры AMD Threadripper с 64 ядрами (128 потоков) идеально подходят для компиляции C ++ в C ++ Builder с TwineCompile. Обратите внимание, что для такого процессора, если в вашем проекте меньше 128 файлов C ++, вы тратите ресурсы ЦП — это восходит к тому моменту, который мы сделали в Уловке № 5 об оптимизации макета вашего проекта для максимального использования ЦП. ресурсов, скомпилировав множество файлов в одном проекте.
Последние мысли
Мы прошли долгий путь со времен компиляции C ++, когда сборка занимала много времени, и с этим ничего нельзя было поделать. Были разработаны инструменты и методы, которые имеют большое значение для проектов любого масштаба. Мы рассмотрели некоторые из них в этом посте, и, надеюсь, вы сможете применить их в своих собственных проектах, чтобы ускорить, упростить и упростить разработку на C ++.
RAD Studio C ++ Builder, почему бы не попробовать его сегодня?
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition