Ответ 1
Я предпочитаю
release:
$(MAKE) clean
$(MAKE) test1
Это заставляет две цели выполняться последовательно, не нарушая их внутренних parallelism (если они есть).
У меня есть следующий файл makefile:
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 [email protected] $(OBJS)
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -MD -c -o [email protected] $<
-include $(SRCS:.cpp=.d)
clean:
rm -rf $(OBJDIR)/*
.PHONY: all clean release
Теперь, если я пытаюсь вызвать "make -j4 release", чистая цель часто получает выполнение в середине файлов зданий, что приводит к сбою компиляции. Мой вопрос заключается в том, как обеспечить, чтобы чистая цель была завершена до начала сборки релиза.
Я предпочитаю
release:
$(MAKE) clean
$(MAKE) test1
Это заставляет две цели выполняться последовательно, не нарушая их внутренних parallelism (если они есть).
Вы можете разделить выполнение на непараллельные (для release
) и параллельные (для остальных целей) фазы.
ifneq ($(filter release,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif
release: clean
$(MAKE) test1
.NOTPARALLEL
target будет подавлять параллельное выполнение, если в командной строке указан release
target. Сама цель release
перезапустит Make после очистки и построит test1
параллельно.
Более умное решение также повторно запустит Make для каждой отдельной цели в случае, если в командной строке указано несколько целей, так что наличие целевого объекта release
не заставило бы остальных выполнять непараллельные.
ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
$(sort all $(MAKECMDGOALS)):
@$(MAKE) -f $(firstword $(MAKEFILE_LIST)) [email protected]
else
# ...
endif
Умное решение выше не работает над версиями GNU make, которые не поддерживают серверы заданий. Например, выпущенные версии MinGW/native GNU make до версии 4.0 не поддерживают серверы заданий. (Создание Cygwin/MSYS GNU make.) В приведенном ниже коде используется переменная .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)) [email protected]
else
# Put remainder of your makefile here.
endif
В случае релиза вам нужно убедиться, что clean
завершается перед компиляцией. Таким образом, вы (просто) добавляете его как зависимость от правила компиляции (а не к фальшивой цели). Несколько способов сделать это, например целевые переменные, или:
$(OBJDIR)/%.o: %.cpp $(if $(filter release,${MAKECMDGOALS}),clean)
...
Я не совсем уверен, какие версии этой функции поддерживаются, но вы можете использовать функцию 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
Для решения без рекурсивного вызова make вы можете попробовать это.
ifneq ($(filter release,$(MAKECMDGOALS)),)
test1: clean
endif