aboutsummaryrefslogtreecommitdiff
path: root/rules.mak
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-01-24 16:25:59 +0000
committerPeter Maydell <peter.maydell@linaro.org>2020-02-03 10:46:32 +0000
commite0f3728d819001f4e2ae0dd6a77ca29acfdc04d4 (patch)
tree66162fb55ebb34950ecf4e9316aa9e209ca2bc49 /rules.mak
parent035b21977ce1791a630c5cbf46e482e54552e05b (diff)
Makefile: Ensure we don't run Sphinx in parallel for manpages
Sphinx will corrupt its doctree cache if we run two copies of it in parallel. In commit 6bda415c10d966c8d3 we worked around this by having separate doctrees for 'html' vs 'manpage' runs. However now that we have more than one manpage produced from a single manual we can run into this again when trying to produce the two manpages. Use the trick described in 'Atomic Rules in GNU Make' https://www.cmcrossroads.com/article/atomic-rules-gnu-make to ensure that we only run the Sphinx manpage builder once for each manual, even if we're producing several manpages. This fixes doctree corruption in parallel builds and also avoids pointlessly running Sphinx more often than we need to. (In GNU Make 4.3 there is builtin support for this, via the "&:" syntax, but we can't wait for that to be available in all the distros we support...) The generic "one invocation for multiple output files" machinery is provided as a macro named 'atomic' in rules.mak; we then wrap this in a more specific macro for defining the rule and dependencies for the manpages in a Sphinx manual, to avoid excessive repetition. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20200124162606.8787-2-peter.maydell@linaro.org
Diffstat (limited to 'rules.mak')
-rw-r--r--rules.mak36
1 files changed, 36 insertions, 0 deletions
diff --git a/rules.mak b/rules.mak
index c8558876f3..e39b073d46 100644
--- a/rules.mak
+++ b/rules.mak
@@ -399,3 +399,39 @@ GEN_SUBST = $(call quiet-command, \
%.json: %.json.in
$(call GEN_SUBST)
+
+# Support for building multiple output files by atomically executing
+# a single rule which depends on several input files (so the rule
+# will be executed exactly once, not once per output file, and
+# not multiple times in parallel.) For more explanation see:
+# https://www.cmcrossroads.com/article/atomic-rules-gnu-make
+
+# Given a space-separated list of filenames, create the name of
+# a 'sentinel' file to use to indicate that they have been built.
+# We use fixed text on the end to avoid accidentally triggering
+# automatic pattern rules, and . on the start to make the file
+# not show up in ls output.
+sentinel = .$(subst $(SPACE),_,$(subst /,_,$1)).sentinel.
+
+# Define an atomic rule that builds multiple outputs from multiple inputs.
+# To use:
+# $(call atomic,out1 out2 ...,in1 in2 ...)
+# <TAB>rule to do the operation
+#
+# Make 4.3 will have native support for this, and you would be able
+# to instead write:
+# out1 out2 ... &: in1 in2 ...
+# <TAB>rule to do the operation
+#
+# The way this works is that it creates a make rule
+# "out1 out2 ... : sentinel-file ; @:" which says that the sentinel
+# depends on the dependencies, and the rule to do that is "do nothing".
+# Then we have a rule
+# "sentinel-file : in1 in2 ..."
+# whose commands start with "touch sentinel-file" and then continue
+# with the rule text provided by the user of this 'atomic' function.
+# The foreach... is there to delete the sentinel file if any of the
+# output files don't exist, so that we correctly rebuild in that situation.
+atomic = $(eval $1: $(call sentinel,$1) ; @:) \
+ $(call sentinel,$1) : $2 ; @touch $$@ \
+ $(foreach t,$1,$(if $(wildcard $t),,$(shell rm -f $(call sentinel,$1))))