Как я могу написать make-файл для автоматического определения и распараллеливания сборки с GNU Make? - PullRequest
27 голосов
/ 27 марта 2010

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

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

all:
    @make -j$(NUM_PROCESSORS) all

Или:

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

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

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

% make all

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

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

Ответы [ 7 ]

23 голосов
/ 27 марта 2010

Часть обнаружения будет зависеть от ОС. Вот фрагмент, который будет работать на 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), но, вероятно, его можно уточнить.

7 голосов
/ 09 февраля 2014

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

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

Обратите внимание, что это специфично для Linux.

6 голосов
/ 12 августа 2011

Вот что я сделал:

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 
6 голосов
/ 28 марта 2010

Немного покопавшись в главе 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 $@

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

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

subgoal:
    @echo "$(MAKELEVEL) subgoal"

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

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

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

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

5 голосов
/ 04 октября 2010

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

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

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

2 голосов
/ 08 апреля 2011

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

Пример:

alias make="make -j"

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

alias jmake="make -j"

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

1 голос
/ 18 марта 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...