Подтвердить что ты не робот

Параллельный make файл требует упорядочения зависимостей

У меня есть следующий файл 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", чистая цель часто получает выполнение в середине файлов зданий, что приводит к сбою компиляции. Мой вопрос заключается в том, как обеспечить, чтобы чистая цель была завершена до начала сборки релиза.

4b9b3361

Ответ 1

Я предпочитаю

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

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

Ответ 2

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

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

release: clean
    $(MAKE) test1

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

UPD.

Более умное решение также повторно запустит 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

Ответ 3

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

$(OBJDIR)/%.o: %.cpp $(if $(filter release,${MAKECMDGOALS}),clean)
    ...

Ответ 4

Я не совсем уверен, какие версии этой функции поддерживаются, но вы можете использовать функцию 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

Ответ 5

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

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