Из настройки CMake "make" использовать опцию -j "по умолчанию

Я хочу, чтобы проект CMake был создан make -j N, когда я вызываю make из терминала. Я не хочу каждый раз устанавливать параметр -j вручную.

Для этого я устанавливаю переменную CMAKE_MAKE_PROGRAM в конкретную командную строку. Я использую функцию ProcessorCount(), которая дает количество процессоров для параллельной сборки.

Когда я делаю make, я не вижу никакой скорости. Однако, если я делаю make -j N, то он будет построен определенно быстрее.

Не могли бы вы помочь мне в этом вопросе? (Я разрабатываю это на Linux.)

Вот фрагмент кода, который я использую в CMakeList.txt:

include(ProcessorCount)
ProcessorCount(N)
message("number of processors: "  ${N})
if(NOT N EQUAL 0)
  set(CTEST_BUILD_FLAGS -j${N})
  set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${N})
  set(CMAKE_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM} -j ${N}")      
endif()
message("cmake make program" ${CMAKE_MAKE_PROGRAM})

Большое спасибо.

Ответ 1

Устанавливая переменную CMAKE_MAKE_PROGRAM, вы хотите повлиять на процесс сборки. Но:

  1. Эта переменная влияет только на сборку через cmake --build, а не на собственный вызов инструмента (make):

    Переменная CMAKE_MAKE_PROGRAM установлена для использования кодом проекта. Это значение также используется инструментами cmake (1) --build и ctest (1) --build-and-test для запуска собственного процесса сборки.

  2. Эта переменная должна быть CACHEd. Он используется таким образом в генераторах, похожих на make:

    Эти генераторы хранят CMAKE_MAKE_PROGRAM в кеше CMake, чтобы пользователь мог его редактировать.

    То есть вам нужно установить эту переменную с

    set(CMAKE_MAKE_PROGRAM <program> CACHE PATH "Path to build tool" FORCE)
    
  3. Эта переменная должна ссылаться на сам исполняемый файл, а не на программу с аргументами:

    Значение может быть полным путем к исполняемому файлу или просто именем инструмента, если ожидается, что он будет в PATH.

    То есть значение "make -j 2" не может использоваться для этой переменной (разделение аргументов в виде списка

    set(CMAKE_MAKE_PROGRAM make -j 2 CACHE PATH "Path to build tool" FORCE)
    

    тоже не поможет).

Таким образом, вы можете переопределить поведение вызовов cmake --build установив переменную CMAKE_MAKE_PROGRAM в сценарий, который вызывает make с параллельными параметрами. Но вы не можете повлиять на поведение прямых make вызовов.

Ответ 2

Если вы хотите ускорить сборку, вы можете запускать несколько процессов make параллельно, но не cmake. Чтобы выполнить каждую сборку с заранее определенным числом параллельных процессов, вы можете определить это в MAKEFLAGS.

Установите MAKEFLAGS в вашем скрипте окружения, например ~/.bashrc, как вы хотите:

export MAKEFLAGS=-j8

В Linux для MAKEFLAGS устанавливается следующее число CPU-1: (оставьте один CPU свободным для других задач во время сборки) и полезно в средах с динамическими ресурсами, например VMware:

export MAKEFLAGS=-j$(($(grep -c ^processor /proc/cpuinfo) - 0))

Ответ 3

Вы можете установить переменную MAKEFLAGS env с помощью этой команды

export MAKEFLAGS=-j$(nproc)

Ответ 4

Можно ли использовать этот метод для вызова нескольких функций? подобная функция1,2,3 параллельна довольно последовательной, любые другие идеи оцениваются.

Пример:

 if(FLAG1)
#some variables/options settings
    function1(${OPTIONS})
    function2(${OPTIONS})
    function3(${OPTIONS})
     ....
endif()

function(fucntion1)
#some variables/options parsing and passed to command.
      execute_process(COMMAND COMMAND1
                    WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
                    RESULT_VARIABLE res
                    TIMEOUT 60)
endfunction()
function(fucntion2)
#some variables/options parsing and passed to command.
      execute_process(COMMAND COMMAND2
                    WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
                    RESULT_VARIABLE res
                    TIMEOUT 60)
endfunction()

Ответ 5

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

Я называю свой скрипт mk и выполняю ./mk chmod 755 mk чтобы запустить его с ./mk в корне моего проекта. У меня также есть несколько флагов, чтобы можно было запускать различные вещи с помощью простой командной строки. Например, работая над кодом и получая много ошибок, я предпочитаю направлять вывод less. Я могу сделать это с ./mk -l без необходимости перепечатывать все тяжелые вещи Unix...

Как видите, у меня есть -j4 в нескольких местах, где это имеет смысл. Для опции -l я не хочу, потому что в этом случае это в конечном итоге приведет к печати нескольких ошибок одновременно (я пробовал это раньше!)

#!/bin/sh -e
#
# Execute make

case "$1" in
"-l")
    make -C ../BUILD/Debug 2>&1 | less -R
    ;;

"-r")
    make -j4 -C ../BUILD/Release
    ;;

"-d")
    rm -rf ../BUILD/Debug/doc/lpp-doc-?.*.tar.gz \
           ../BUILD/Debug/doc/lpp-doc-?.*
    make -C ../BUILD/Debug
    ;;

"-t")
    make -C ../BUILD/Debug
    ../BUILD/Debug/src/lpp tests/suite/syntax-print.logo
    g++ -std=c++14 -I rt l.cpp rt/*.cpp
    ;;

*)
    make -j4 -C ../BUILD/Debug
    ;;

esac

# From the https://github.com/m2osw/lpp project

С CMake это не сработает, если, как упомянул Циварев, вы не создадите свой собственный скрипт. Но я лично не считаю разумным вызывать make из вашего скрипта make. Плюс это может нарушить процесс сборки, который не будет ожидать этого странного скрипта. Наконец, мой сценарий, как я уже упоминал, позволяет мне изменять параметры в зависимости от ситуации.