Cmake и параллельное здание с "make -jN"

Я пытаюсь настроить параллельную сборку на основе CMake для моего исходного дерева, но когда я выдаю

$ cmake .
$ make -j2

Я получаю предупреждение jobserver unavailable: using -j1. Add '+' to parent make rule. Есть ли у кого-нибудь идея, можно ли как-то это исправить?

Ответы

Ответ 1

похоже, что это не проблема cmake, а только сделать.

Ответ 2

В сгенерированном Makefile при вызове в суб-make ему нужно либо использовать $(MAKE) (а не просто "make" ), либо предшествует строке с+. То есть правило должно выглядеть так:

mysubdir:
    $(MAKE) -C mysubdir

или вот так:

mysubdir:
    +make -C mysubdir

Если вы не сделаете это одним из двух способов, make даст вам это предупреждение.

Я ничего не знаю о cmake, так что, возможно, он генерирует Makefiles, что неверно. Или, может быть, вы сделали что-то неправильно с вашей стороны.

Ответ 3

В моем случае (с CMake 3.5.2) тривиальный cd build && cmake .. && make -j5 работает просто отлично.

Но я получаю сообщение о недоступности сервера jobserver при создании пользовательских целей (как зависимостей других целей) с помощью cmake --build . --target foo idiom.

Вот так:

add_custom_target(buildroot
   COMMAND ${CMAKE_COMMAND} --build . --target install
   COMMENT "Populating buildroot..."
)
add_dependencies(deb buildroot)
add_dependencies(rpm buildroot) #... etc

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

Конечно, мне бы хотелось make -j15 deb - но это не удалось.


Теперь, когда объяснил в списке рассылки разработчиками CMake, основная причина заключается в том, что она неожиданно (или нет) внутри GNU Make; есть обходное решение.

Основная причина в том, что make не передаст среду рабочих серверов дочерним процессам, которые, по ее мнению, не являются make.

Чтобы проиллюстрировать, вот ветка дерева процессов (ps -A f): … \_ bash \_ make -j15 deb \_ make -f CMakeFiles/Makefile2 deb \_ make -f CMakeFiles/buildroot.dir/build.make CMakeFiles/buildroot.dir/build \_ /usr/bin/cmake --build . --target install ⦿ \_ /usr/bin/gmake install …

В точке, make отключается среда jobserver, что в конечном итоге вызывает однопоточную компиляцию.


Обходной путь , который отлично работал у меня, как указано в связанном письме, - это префикс всех пользовательских команд с +env. Вот так:

add_custom_target(buildroot
   #-- this ↓↓↓ here -- https://stackoverflow.com/a/41268443/531179
   COMMAND +env ${CMAKE_COMMAND} --build . --target install
   COMMENT "Populating buildroot..."
)
add_dependencies(deb buildroot)
add_dependencies(rpm buildroot) #... etc

В конце, это появляется в правиле для buildroot в соответствующем make файле (CMake генерирует кучу из них) и заставляет GNU Make правильно вести себя и уважать -j.

Надеюсь, что это поможет.

Ответ 4

Просто от googling, похоже, вы используете distcc (например, здесь)