У меня есть проект c ++ makefile.Это прекрасно работает для непараллельного строительства.Он работает на 99% для параллельного построения ... единственная проблема, которую я имею, в том, что я не могу заставить мою последнюю исполняемую линию связи работать в последнюю очередь (это должно быть последнее, что происходит).
У меня естьнекоторые ограничения: я не хочу иметь никаких PHONY-зависимостей на моей линии связи, потому что это заставляет ее повторно связываться каждый раз.Т.е. как только моя цель построена, когда я перестраиваю ее, ее не следует повторно связывать.
Вот (слегка надуманный) минимальный пример.Пожалуйста, не пытайтесь пробить дыры в этом, это действительно здесь просто, чтобы показать проблему, это не реально, но проблема, которую я показываю, есть.Вы должны быть в состоянии просто запустить это и увидеть ту же проблему, что и я.
# Set the default goal to build.
.DEFAULT_GOAL = build
#pretend subdirs (these don't really exist but it does not matter so long as they always try to be built)
MAKE_SUB_DIRS = 1 2 3
#pretend shared objects that are created by the pretend makefile sub directories (above)
OUTPUTS = out1.so out2.so out3.so
# Top level build goal - depends on all of the subdir makes and the target.out
.PHONY: build
build: $(MAKE_SUB_DIRS) target.out
@echo build finished
# Takes 1 second to build each of these pretend sub make directories. PHONY so always runs
.PHONY: $(MAKE_SUB_DIRS)
$(MAKE_SUB_DIRS):
@if [ ! -f out$@.so ] ; then echo making $@... ; sleep 1 ; echo a > out$@.so ; fi
# The main target, pretending that it needs out1,2 and 3 to link
# Should only run when target.out does not exist
# No PHONY deps allowed here
target.out:
@echo linking $@...
@ls $(OUTPUTS) > /dev/null
@cat $(OUTPUTS) > target.out
# Clean for convinience
clean:
@rm -rf *.so target.out
Теперь, мне действительно все равно, make
работает, я хочу, чтобы make -j
работал.Вот я пытаюсь запустить его:
admin@osboxes:~/sandbox$ make clean
admin@osboxes:~/sandbox$
admin@osboxes:~/sandbox$ make -j - 1st attempt
making 1...
making 2...
linking target.out...
making 3...
ls: cannot access 'out1.so': No such file or directory
ls: cannot access 'out2.so': No such file or directory
ls: cannot access 'out3.so': No such file or directory
makefile:24: recipe for target 'target.out' failed
make: *** [target.out] Error 2
make: *** Waiting for unfinished jobs....
admin@osboxes:~/sandbox$
admin@osboxes:~/sandbox$ make -j - 2nd attempt
linking target.out...
build finished
admin@osboxes:~/sandbox$
admin@osboxes:~/sandbox$ make -j - 3rd attempt
build finished
admin@osboxes:~/sandbox$
Итак, я выделил три попытки запустить его.
- Попытка 1: вы можете увидеть все 4зависимости сборки запускаются одновременно (примерно).Поскольку каждый из
makeing x...
занимает 1 секунду, а linking
почти мгновенный, мы видим мою ошибку.Однако все три «библиотеки» собраны правильно. - Попытка 2: библиотеки создаются, только если они еще не существуют (это код bash - притворяется, что сделал то, что мог сделать make-файл).В этом случае они уже созданы.Так что связывание проходит сейчас, так как для этого просто необходимы библиотеки.
- Попытка 3: ничего не происходит, потому что ничего не нужно:)
Таким образом, вы можете видеть, что все шаги есть,это просто вопрос их заказа.Я хотел бы, чтобы make sub dirs 1, 2, 3
собирался в любом порядке параллельно, и тогда только после того, как все они будут завершены, я хочу, чтобы target.out
работал (т.е. компоновщик).
Я не хочухотя это можно назвать так: $(MAKE) target.out
, потому что в моем реальном make-файле у меня много переменных, которые все настроены ...
Я попытался посмотреть (из других ответов) .NOT_PARALLEL
и использовать оператор порядка депозита|
(pipe), и я попытался упорядочить загрузку правил, чтобы target.out стал последним .... но опция -j
просто пропускает все это и разрушает мой порядок :( ... тамдолжен быть какой-то простой способ сделать это?