Параллелизация рекурсивных заданий в GNU make

Я ищу элегантный способ распараллеливания заданий в GNU make. Вот пример того, что я сделал до сих пор. Создавайте процессы каталогов dir-1, dir-2 и dir-3 серийным образом, что логично, но не мое намерение:

SUBDIRS=dir-1 dir-2 dir-3

default: all

all:
  @for dir in $(SUBDIRS); do (cd $$dir; $(MAKE)); done

.PHONY: clean

clean:
  @for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) clean); done

Есть ли способ поддержать параллельную обработку этих каталогов с помощью опции -j, не указав конкретные цели для каждого каталога?

Ответы

Ответ 1

SUBDIRS = a b c

default: all

$(SUBDIRS)::
    $(MAKE) -C [email protected] $(MAKECMDGOALS)

all clean : $(SUBDIRS)

Ответ 2

Это, вероятно, не будет отвечать на ваш вопрос напрямую, но помимо того, что предлагают другие ответы, я бы рекомендовал изучить нерекурсивные методы создания. Это поистине элегантный способ распараллеливать сборку, хотя, в зависимости от существующих Make файлов, может потребоваться значительное усилие. Нерекурсивный make имеет преимущества, которые не ограничиваются простой параллелизацией: он видит полный график зависимостей, поэтому ему не нужно создавать слишком мало или слишком много, что означает более быстрое (иногда намного более быстрое) время сборки.

Некоторые ресурсы:

Ответ 3

Я обнаружил, что при использовании правила:: (двойное двоеточие) я не мог найти способ принудительного упорядочения, если бы были какие-то зависимости между app, lib и doc. После прочтения большей части руководства GNU Make, я применил следующие правила для обеспечения соответствия зависимостей одновременно с созданием рекурсивного make. Обратите внимание, что существует правило .PHONY, чтобы заставить make войти в каталог, даже если каталог уже существует.

SUBDIRS = app lib doc

default: all

app: lib

.PHONY: $(SUBDIRS)

$(SUBDIRS):
    $(MAKE) -C [email protected] $(MAKECMDGOALS)

all clean install: $(SUBDIRS)

Ответ 4

Являются ли dir-1, dir-2 и dir-3 взаимозависимыми или независимыми?

У меня похожая структура, но зависимость между подкаталогами, поэтому я предпочел просто использовать параллельные сборки в каждом из подкаталогов. Вы получите это через

## default to four parallel runs
MAKEFLAGS += -j 4  

all:
  @for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) ); done

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

## default to four parallel runs
MAKEFLAGS += -j 4  

SUBDIRS =    dir-1 dir-2 dir-3

$(SUBDIRS):  #whatever your depends here
             $(MAKE) -C [email protected]