Подтвердить что ты не робот

Как я могу написать make файл для автоматического обнаружения и распараллеливания сборки с помощью GNU Make?

Не уверен, что это возможно только в одном Makefile, но я надеялся написать Makefile таким образом, что попытка создания какой-либо цели в файле автоматически определяет количество процессоров в текущей системе и создает целевой параллельно для количества процессоров.

Что-то вроде приведенных ниже примеров "псевдокода", но гораздо более чистых?

all:
    @make -j$(NUM_PROCESSORS) all

Или:

all: .inparallel
    ... build all here ...

.inparallel:
    @make -j$(NUM_PROCESSORS) $(ORIGINAL_TARGET)

В обоих случаях все, что вам нужно набрать, это:

% make all

Надеюсь, это имеет смысл.

UPDATE: все еще надеется на пример Makefile для вышеперечисленного. Не очень заинтересовано в поиске количества процессов, но заинтересовано в том, как писать make файл для параллельной сборки без опции -j командной строки.

4b9b3361

Ответ 1

После того, как я немного поговорил о главе 2 LDD3 и прочитал ответ dmckee, я придумал этот не очень большой ответ на использование двух make файлов (я бы предпочел только один).

$ cat Makefile
MAKEFLAGS += -rR --no-print-directory

NPROCS := 1
OS := $(shell uname)
export NPROCS

ifeq ($J,)

ifeq ($(OS),Linux)
  NPROCS := $(shell grep -c ^processor /proc/cpuinfo)
else ifeq ($(OS),Darwin)
  NPROCS := $(shell system_profiler | awk '/Number of CPUs/ {print $$4}{next;}')
endif # $(OS)

else
  NPROCS := $J
endif # $J

all:
    @echo "running $(NPROCS) jobs..."
    @$(MAKE) -j$(NPROCS) -f Makefile.goals [email protected]

%:
    @echo "building in $(NPROCS) jobs..."
    @$(MAKE) -j$(NPROCS) -f Makefile.goals [email protected]
$ cat Makefile.goals
MAKEFLAGS += -rR --no-print-directory
NPROCS ?= 1

all: subgoal
    @echo "$(MAKELEVEL) nprocs = $(NPROCS)"

subgoal:
    @echo "$(MAKELEVEL) subgoal"

Что вы думаете об этом решении?

Преимущества, которые я вижу, это то, что люди все еще набирают make для сборки. Таким образом, нет никакого "драйвера" script, который выполняет работу NPROCS и make -j$(NPROCS), которую люди должны знать, вместо ввода make.

Недостатком является то, что вам нужно будет явно использовать make -f Makefile.goals для создания последовательной сборки. И я не уверен, как решить эту проблему...

ОБНОВЛЕНО: добавлено $J в сегмент кода выше. Кажется, работа работает достаточно хорошо. Несмотря на то, что его два make файла вместо одного, его все еще довольно бесшовные и полезные.

Ответ 2

Часть обнаружения будет зависимой от ОС. Здесь фрагмент, который будет работать на Linux и Mac OS X:

NPROCS:=1
OS:=$(shell uname -s)

ifeq($(OS),Linux)
  NPROCS:=$(shell grep -c ^processor /proc/cpuinfo)
endif
ifeq($(OS),Darwin) # Assume Mac OS X
  NPROCS:=$(shell system_profiler | awk '/Number Of CPUs/{print $4}{next;}')
endif

Чтобы заставить его работать, вам, вероятно, придется повторно вызвать make. Тогда ваша проблема предотвращает бесконечную рекурсию. Вы могли бы управлять этим, имея два make файла (первый только сброс значения -j), но, вероятно, возможно утончить его.

Ответ 3

Вот что я пошел с:

ifeq ($(OS),Linux)
        NUMPROC := $(shell grep -c ^processor /proc/cpuinfo)
else ifeq ($(OS),Darwin)
        NUMPROC := $(shell sysctl hw.ncpu | awk '{print $$2}')
endif

# Only take half as many processors as available
NUMPROC := $(shell echo "$(NUMPROC)/2"|bc)

ifeq ($(NUMPROC),0)
        NUMPROC = 1
endif 

Ответ 4

Я просто добавил это в начало моего Makefile. Он позволяет создавать любое количество заданий, но пытается поддерживать среднюю нагрузку ниже числа ядер процессора.

MAKEFLAGS+="-j -l $(shell grep -c ^processor /proc/cpuinfo) "

Обратите внимание, что это конкретный Linux.

Ответ 5

Я пропущу материал обнаружения $(NPROCS), но вот как вы могли бы сделать это в одном Makefile (возможно, это GNU Make specific, но это похоже на вариант, который вы используете):

ifeq ($(NPROCS),)
# Code to set NPROCS...
%:
    $(MAKE) -j$(NPROCS) NPROCS=$(NPROCS)
else
# All of your targets...
endif

См. Определение правил по умолчанию для последнего курорта и Переопределение части другого файла Makefile в GNU Make Manual.

Ответ 6

Если вы хотите, чтобы он был автоматическим, вы можете переопределить свою типичную команду make как псевдоним для себя в своем .bashrc в вашем домашнем каталоге.

Пример:

alias make="make -j"

Или вы могли бы сделать что-то вроде:

alias jmake="make -j"

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

Ответ 7

Если я правильно прочитал вопрос, цель состоит в том, чтобы максимально распараллелить процесс сборки. На странице руководства make указано следующее

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

Разве это не решение, которое вы хотите? Если ваш Makefile имеет достаточно параллельных целей, вы будете использовать все ваши процессоры, и если цели не параллельны, опция -j не поможет никому.