Параллельный make-файл требует упорядочения зависимостей - PullRequest
23 голосов
/ 14 декабря 2011

У меня есть следующий фрагмент make-файла:

CXXFLAGS = -std=c++0x -Wall
SRCS     = test1.cpp test2.cpp
OBJDIR   = object
OBJS     = $(SRCS:%.cpp=$(OBJDIR)/%.o)

all: test1 
release: clean test1

test1: $(OBJS)
    $(CXX) -o $@ $(OBJS)

$(OBJDIR)/%.o: %.cpp
    $(CXX) $(CXXFLAGS) -MD -c -o $@ $<

-include $(SRCS:.cpp=.d)

clean:
    rm -rf $(OBJDIR)/*

.PHONY: all clean release 

Теперь, если я пытаюсь вызвать «make -j4 release», чистая цель часто выполняется в середине сборки файлов, что приводит к сбою компиляции.Мой вопрос заключается в том, как убедиться, что чистая цель выполнена до начала сборки выпуска.

Ответы [ 5 ]

29 голосов
/ 14 декабря 2011

Мои предпочтения для

release:
    $(MAKE) clean
    $(MAKE) test1

Это заставляет две цели выполняться последовательно, не нарушая их внутреннего параллелизма (если есть).

10 голосов
/ 14 декабря 2011

Вы можете разделить выполнение на непараллельную (для release) и параллельную (для остальных целей) фазы.

ifneq ($(filter release,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif

release: clean
    $(MAKE) test1

.NOTPARALLEL цель будет подавлять параллельвыполнение, если в командной строке указана цель release.Сама цель release будет перезапущена Make после очистки и параллельной сборки test1.

UPD.

Более умное решение также повторно вызовет Make для каждой отдельной цели в случае, если их большечем одна цель, указанная в командной строке, так что присутствие цели release не заставит остальных выполнять также непараллельно.

ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
$(sort all $(MAKECMDGOALS)):
    @$(MAKE) -f $(firstword $(MAKEFILE_LIST)) $@
else
# ...
endif

Обновление Джеймс Джонстон

Приведенное выше умное решение не работает с версиями GNU make, которые не поддерживают серверы заданий.Например, выпущенные версии MinGW / native GNU make до версии 4.0 не поддерживают серверы заданий.(Сборки Cygwin / MSYS GNU делают.) Приведенный ниже код использует переменную .FEATURES , введенную в make 3.81, чтобы определить, поддерживаются ли серверы заданий.Признак неиспользования этого обходного пути, когда это необходимо, заключается в том, что ваша «параллельная» сборка будет сериализована.

# Check if job server supported:
ifeq ($(filter jobserver, $(.FEATURES)),)
# Job server not supported: sub-makes will only start one job unless
# you specify a higher number here.  Here we use a MS Windows environment
# variable specifying number of processors.
JOBSARG := -j $(NUMBER_OF_PROCESSORS)
else
# Job server is supported; let GNU Make work as normal.
JOBSARG :=
endif

# .FEATURES only works in GNU Make 3.81+.
# If GNU make is older, assume job server support.
ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))),3.81)
# If you are using GNU Make < 3.81 that does not support job servers, you
# might want to specify -jN parameter here instead.
JOBSARG :=
endif

ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
# The "all" target is required in the list,
# in case user invokes make with no targets.
$(sort all $(MAKECMDGOALS)):
    @$(MAKE) $(JOBSARG) -f $(firstword $(MAKEFILE_LIST)) $@
else

# Put remainder of your makefile here.

endif
1 голос
/ 28 февраля 2013

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

$(OBJDIR)/%.o: %.cpp $(if $(filter release,${MAKECMDGOALS}),clean)
    ...
0 голосов
/ 21 ноября 2015

Я не совсем уверен, в каких версиях поддерживается эта функция, но вы можете использовать функцию order-only:

my_target: dep1 dep2 | must_run_1st must_run_2nd

Все зависимости, оставшиеся от символа |, обрабатываются как обычно. Зависимости справа от | запускаются «только для заказа»

Эта функция описана в:

https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html

В вашем случае будет достаточно следующего определения правил:

release: | clean test1
test1: | clean
0 голосов
/ 14 декабря 2011

Для решения без рекурсивного вызова make вы можете попробовать это.

ifneq ($(filter release,$(MAKECMDGOALS)),)
test1: clean
endif
...