Makefile parallèle nécessite un ordre de dépendance
j'ai le fichier makefile suivant:
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
maintenant si j'essaye d'invoquer "make-j4 release" la cible propre est souvent exécutée au milieu des fichiers de construction qui provoquent l'échec de la compilation. Ma question Est de savoir comment s'assurer que la cible clean est terminée avant de commencer la construction de la version.
5 réponses
Ma préférence est pour
release:
$(MAKE) clean
$(MAKE) test1
ceci oblige les deux cibles à être faites consécutivement sans perturber leur parallélisme interne (s'il y en a).
vous pouvez diviser l'exécution en non-parallèle (pour release
) et les phases parallèles (pour les autres cibles).
ifneq ($(filter release,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif
release: clean
$(MAKE) test1
.NOTPARALLEL
la cible supprimera l'exécution parallèle si release
cible est mentionné dans la ligne de commande. release
la cible elle-même va recommencer à faire après nettoyage et construire test1
en parallèle.
UPD.
une solution plus intelligente permettrait également de réinvestir chaque cible au cas où il y aurait plus de une cible donnée sur la ligne de commande, de sorte qu'une présence de release
la cible ne forcerait pas le reste à exécuter non-parallèle aussi.
ifneq ($(words $(MAKECMDGOALS)),1)
.NOTPARALLEL:
$(sort all $(MAKECMDGOALS)):
@$(MAKE) -f $(firstword $(MAKEFILE_LIST)) $@
else
# ...
endif
mise à Jour James Johnston
la solution intelligente ci-dessus ne fonctionne pas sur les versions de GNU make qui ne prennent pas en charge les serveurs de travail. Par exemple, les versions MinGW/native de GNU make publiées avant la version 4.0 ne prennent pas en charge les serveurs de tâches. (Cygwin / MSYS construit GNU make do. Le code ci-dessous utilise la .FEATURES
variable introduit dans make 3.81 Pour détecter si les serveurs de tâches sont pris en charge. Le symptôme de ne pas utiliser cette solution quand elle est nécessaire est que votre construction "parallèle" sera sérialisée.
# 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
Dans la libération cas, vous devez vous assurer que clean
se termine avant la compilation. Ainsi vous (juste) l'ajoutez comme une dépendance à la règle de compilation (et non à la cible bidon). Plusieurs façons de le faire, comme des variables spécifiques à la cible, ou:
$(OBJDIR)/%.o: %.cpp $(if $(filter release,${MAKECMDGOALS}),clean)
...
Je ne sais pas exactement dans quelles versions cette fonctionnalité est prise en charge, mais vous pouvez utiliser le order-only
caractéristique:
my_target: dep1 dep2 | must_run_1st must_run_2nd
toutes les dépendances restantes du |
les caractères sont traités comme normaux. Dépendances à droite de |
sont exécutées 'ordre'
Cette fonctionnalité est décrite à la page:
https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html
dans votre cas, la définition suivante des règles suffire:
release: | clean test1
test1: | clean
pour une solution sans invocation récursive de la marque, vous pouvez essayer ceci.
ifneq ($(filter release,$(MAKECMDGOALS)),)
test1: clean
endif