Pull to refresh

Comments 9

А чем плох такой подход:
1. Статические библиотеки не должны зависеть друг от друга.
2. При линковке бинаря достаточно указать все статические библиотеки в нужном порядке, и не надо мучиться с метазависимостями.
М? Постоянно так делаю, сборка параллелится без проблем.

Отличный подход. Просто, с большим проектом со множеством библиотек может возникнуть проблема, и избежать зависимостей не удасться.


Например, у нас используется очень разветвленная структура проекта, и путь к исходникам одной библиотеки может выглядеть вот так: project/sdks/utils/window-utils


Можно было бы использовать target_include_directories, или include_directories, но мы используем описанный в статье подход, так как он более удобен.


Кроме INTERFACE_INCLUDE_DIRECTORIES можно добавить к мета-пакету INTERFACE_COMPILE_DEFINITION и INTERFACE_COMPILE_OPTIONS. Никогда не видел использование этой возможности, но она есть.


Кроме того, у нас генерируются заголовочные файлы через configure для одних библиотек, которые потом используются в cpp-файлах в других. Так вот, можно выполнить слудующую последовательность шагов:


  • добавляем цель для генерации файла
  • через add_dependencies указываем, что мета-пакет зависит от цели генерации
  • необходимый заголовочный файл будет сгенерирован перед сборкой любых зависимых библиотек
Иногда сложно добиться отсутствия зависимостей. Да и надо ли?
Мы у себя похожий подход как у автора используем, удобно особенно если количество библиотек за сотню

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

На самом деле я бы не назвал это проблемой, особенно для небольшого проекта. Если Вы ожидаете завершения сборки 30 секунд, то тут вряд ли можно существенно ускорить сборку.


Однако, если в проекте задействовано 20 библиотек и сборка производится на мощном многоядерном проце, то эффект будет куда больше.


CMake не выполняет параллельную сборку статических библиотек (по крайней мере в паре с make).Для примера из статьи CoherentDeps, вывод сборки будет следующим:


build-CoherentDeps-Desktop-Debug$ make -j4
Scanning dependencies of target staticA
[ 12%] Building CXX object staticA/CMakeFiles/staticA.dir/source_a.cpp.o
[ 25%] Linking CXX static library libstaticA.a
[ 25%] Built target staticA
Scanning dependencies of target staticB
[ 37%] Building CXX object staticB/CMakeFiles/staticB.dir/source_b.cpp.o
[ 50%] Linking CXX static library libstaticB.a
[ 50%] Built target staticB
Scanning dependencies of target staticC
[ 62%] Building CXX object staticC/CMakeFiles/staticC.dir/source_c.cpp.o
[ 75%] Linking CXX static library libstaticC.a
[ 75%] Built target staticC
Scanning dependencies of target CoherentDeps
[ 87%] Building CXX object CMakeFiles/CoherentDeps.dir/main.cpp.o
[100%] Linking CXX executable CoherentDeps
[100%] Built target CoherentDeps

Это говорит о последовательном выполнении этапов.
В то же время, для другого примера из статьи NonCoherentDeps, обработка статических бибилиотек выполняется параллельно:


build-NonCoherentDeps-Desktop-Debug$ make -j4
Scanning dependencies of target staticC
Scanning dependencies of target staticA
Scanning dependencies of target staticB
[ 25%] Building CXX object staticC/CMakeFiles/staticC.dir/source_c.cpp.o
[ 25%] Building CXX object staticA/CMakeFiles/staticA.dir/source_a.cpp.o
[ 37%] Building CXX object staticB/CMakeFiles/staticB.dir/source_b.cpp.o
[ 50%] Linking CXX static library libstaticC.a
[ 75%] Linking CXX static library libstaticA.a
[ 75%] Linking CXX static library libstaticB.a
[ 75%] Built target staticC
[ 75%] Built target staticB
[ 75%] Built target staticA
Scanning dependencies of target NonCoherentDeps
[ 87%] Building CXX object CMakeFiles/NonCoherentDeps.dir/main.cpp.o
[100%] Linking CXX executable NonCoherentDeps
[100%] Built target NonCoherentDeps

Ну я к тому что если можно было бы сделать эффективнее, почему бы не сделать это сразу. С другой стороны насколько здесь от самого сборщика зависит, что например сделает ninja. Мне бы надо бы запустить ваши сэмплы и проверить, но не уверен что хватит времени.

А что конкретно (время каких действий в рамках сборки) экономится в предложенном подходе?

Ведь все, что должно быть (пере)собрано, как ни крути придется собрать, в том или ином порядке. При сборке в несколько потоков CPU оказывается загружен на 100% и не сможет выполнить больше работы независимо от ее порядка.

Не какая ли тогда разница, соберутся ли две библиотеки за одну минуту параллельно (каждая за минуту) или последовательно (каждая за полминуты)?

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

Sign up to leave a comment.

Articles