Как я могу написать 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 командной строки.
Ответы
Ответ 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
не поможет никому.