Как настроить переносимые параллельные сборки в CMake?
-
12-12-2019 - |
Вопрос
Возможно ли каким-то образом обеспечить параллельную сборку независимо от того, какой инструмент сборки используется?
В Unix мы можем добавить make -jN
где N — количество потоков, а под Windows я добавил к CXX_FLAG "/MP"
который затем используется в Visual Studio для параллельной сборки...(?) Как я могу сделать свою версию такой, чтобы CMAKE_MAKE_PROGRAM
не всегда расширяется при запуске CMake?
Что такое общее решение?
Я придумал это:
# Add some multithreaded build support
MARK_AS_ADVANCED(MULTITHREADED_BUILD)
set(MULTITHREADED_BUILD 12 CACHE STRING "How many threads are used to build the project")
if(MULTITHREADED_BUILD)
if(${CMAKE_GENERATOR} MATCHES "Unix Makefiles")
message(STATUS ${CMAKE_BUILD_TOOL})
set(CMAKE_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM} -j${MULTITHREADED_BUILD}")
message(STATUS "Added arguments to CMAKE_BUILD_TOOL: ${CMAKE_MAKE_PROGRAM}")
elseif(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
message(STATUS "Added parallel build arguments to CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
endif()
endif()
Решение
В CMake 3.12 это возможно.Из примечаний к выпуску:
Режим инструмента «Cmake (1)» («Cmake –build») получил параллельные варианты «-параллельно []» и «-J []», чтобы указать параллельный уровень сборки.Они соответствуют соответствующим параметрам встроенного инструмента сборки.
Как упоминал dkg, вы также можете установить переменную среды CMAKE_BUILD_PARALLEL_LEVEL
.
Ссылки на документацию CMake:
Другие советы
Если у вас CMake v2.8.8 или выше, вы можете использовать Ниндзя как альтернатива ГНУ make
:
mkdir build
cd build
cmake -G Ninja ..
ninja # Parallel build (no need -j12)
или
mkdir build
cd build
cmake -G Ninja ..
cmake --build . # Parallel build using Ninja
Как видите, нет необходимости использовать CMAKE_MAKE_PROGRAM
, сборка по умолчанию выполняется параллельно, оптимизируя количество заданий в зависимости от доступных ядер ЦП.
Ninja основан на низкоуровневой конфигурации JSON для ускорения этапа запуска.Поэтому его конфигурацию JSON нелегко написать вручную, и я всегда генерирую ее с помощью инструмента/IDE высокого уровня:
- CMake v2.8.8 (2012)
- Qt Создатель v2.6 (2012)
- KDevelop v4.6 (2013)
- Мезон в Linux (2013)
- ...см. генераторы конфигурации Ninja на https://github.com/ninja-build/ninja/wiki/List-of-generators-producing-ninja-build-files
Поскольку для сборки C++ часто требуется много памяти, ваш компьютер должен предоставлять столько же памяти, сколько ядер ЦП.
Как указывает Руслан, CMake 3.12 (2018) есть новый вариант cmake --build -j <N>
ограничить сборку <N>
ядер (заданий), тем самым ограничивая потребление памяти (см. также документация).Если вы используете более старую версию CMake, вы все равно можете использовать cmake --build -- -j <N>
.Опция --
сообщает CMake передать остальное непосредственно базовому инструменту сборки, здесь это Ninja.
Вы не можете сделать эту кроссплатформу.Опция -jn - это параметр, чтобы сделать, а не часть созданного makefile.Тем не менее, вы можете получить CMake генерировать скрипт Bash, который работает для вашего проекта, используя -jn (где скрипт выглядит вверх по количеству сердечников, которые у вас есть).
Я устроил вниз, чтобы написать сценарию parallelmake.sh
для генераторов на основе Unix Makefiles
.Это делается здесь: https://github.com/gabyx/aproxmvbb
и соответствующие части в файле Cmake:
https://github.com/gabyx/appoxmvbb/blob/master/cmakelists.txt#l89
# Add some multithreaded build support =====================================================================================================
MARK_AS_ADVANCED(MULTITHREADED_BUILD)
SET(MULTITHREADED_BUILD ON CACHE BOOL "Parallel build with as many threads as possible!")
if(MULTITHREADED_BUILD)
if(${CMAKE_GENERATOR} MATCHES "Unix Makefiles")
file(COPY ${ApproxMVBB_ROOT_DIR}/cmake/parallelmake.sh DESTINATION ${PROJECT_BINARY_DIR}
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
NO_SOURCE_PERMISSIONS
)
SET(CMAKE_MAKE_PROGRAM "${PROJECT_BINARY_DIR}/parallelmake.sh")
MESSAGE(STATUS "Set make program to ${PROJECT_BINARY_DIR}/parallelmake.sh")
elseif(MSVC)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" "/MP")
MESSAGE(STATUS "Added parallel build arguments to CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
endif()
endif()
# ========================================================================================================================================
.