Как настроить переносимые параллельные сборки в CMake?
Возможно ли каким-то образом иметь возможность иметь параллельную сборку независимо от того, какой инструмент сборки используется?
Под 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()
6 ответов
Если у вас есть cmake
v2.8.8 или выше, вы можете использовать ninja
как альтернатива GNU 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 Creator v2.6 (2012)
- KDevelop v4.6 (2013)
- ... увидеть генераторы
ninja
Конфигурация по адресу https://github.com/ninja-build/ninja/wiki/List-of-generators-producing-ninja-build-files
Поскольку сборка C++ часто требует много памяти, ваш компьютер должен предоставлять столько же памяти, сколько и количество ядер ЦП.
С CMake 3.12 это возможно. Из примечаний к выпуску:
Режим инструмента сборки "cmake(1)" ("cmake –build") получил опции "- parallel []" и "-j []" для указания уровня параллельной сборки. Они сопоставляются с соответствующими параметрами родного инструмента сборки.
Редактировать: Как уже упоминалось @dkg, вы также можете установить переменную среды CMAKE_BUILD_PARALLEL_LEVEL
,
Ссылки на документацию CMake:
Как уже упоминалось выше, можно использовать
--parallel [<jobs>]
(или же
-j [<jobs>]
) опция CMake для создания решения параллельно.
Но хотелось бы отметить, что в Windows команда
cmake.exe --build --parallel <jobs>
запускает корневой процесс MSBuild со следующими аргументами:
msbuild.exe /m:<jobs> /p:CL_MPCount=1 <another-useful-arguments>
Это означает, что будет запущено несколько процессов MSBuild --
/maxcpucount:<jobs>
он же
/m:<jobs>
. Но каждый из них запускает не более одного процесса компилятора (подробнее по этой ссылке). Другими словами, каждый MSBuild может одновременно компилировать не более одного исходного файла.
Чтобы обойти это ограничение, можно вызвать CMake следующим образом:
cmake.exe --build --parallel <n_msbuild> -- /p:CL_MPcount=<n_cl>
Этот подход задает параметр, тем самым разрешая несколько процессов компилятора в каждом экземпляре MSBuild.
И для записи. Чтобы настроить сборки, запущенные из графического интерфейса Visual Studio, нужно перейти в « Настройки » :
- Параметр «Проекты и решения → Сборка и запуск → максимальное количество параллельных проектов сборки» влияет на
maxcpucount
. - Параметр «Проекты и решения → Настройки проекта VC++ → Сборка → Максимальное количество одновременных компиляций C++» представляет границу по умолчанию для
/MP
.
Теперь параллельную сборку с cmake очень просто. Вы можете добавить "-j job_number" при использовании "cmake --build". Например:
cmake --build . -j 24
Более подробную информацию можно найти в руководстве CMAKE: https://cmake.org/cmake/help/latest/manual/cmake.1.html.
--parallel [], -j [] Максимальное количество параллельных процессов для использования при построении. Если не указан, используется номер встроенного инструмента сборки по умолчанию.
Переменная среды CMAKE_BUILD_PARALLEL_LEVEL, если она установлена, задает уровень параллелизма по умолчанию, когда этот параметр не указан.
Некоторые встроенные инструменты сборки всегда строят параллельно. Значение 1 можно использовать для ограничения одного задания.
Вы не можете сделать это кроссплатформенным. Опция -jN - это параметр, который нужно создать, а не часть сгенерированного файла Makefile. Однако вы можете заставить CMake сгенерировать bash-скрипт, который запускает make для вашего проекта, используя -jN (где скрипт ищет количество ядер, которые у вас есть).
Поскольку этот пост уже немного стар:
Мой подход, к которому я привык, - это написать parallelmake.sh
сценарий для Unix Makefiles
на основе генераторов Это делается здесь: https://github.com/gabyx/ApproxMVBB
И соответствующие части в файле cmake:
https://github.com/gabyx/ApproxMVBB/blob/master/CMakeLists.txt
#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()
# ========================================================================================================================================