summaryrefslogtreecommitdiff
path: root/debian/Explanations
diff options
context:
space:
mode:
Diffstat (limited to 'debian/Explanations')
-rw-r--r--debian/Explanations204
1 files changed, 204 insertions, 0 deletions
diff --git a/debian/Explanations b/debian/Explanations
new file mode 100644
index 00000000..090974ec
--- /dev/null
+++ b/debian/Explanations
@@ -0,0 +1,204 @@
+ This file is a presentation of explanations of make's behaviour that
+ users have found puzzling over time, along with explanations of the
+ behaviour by make's author.
+
+######################################################################
+######################################################################
+######################################################################
+
+ Case 1:
+
+> I have always thought that a normal (non-pattern) rule with multiple
+> targets gets run multiple times, once per each target that is out of
+> date. At least, that's what the manual says. Sometimes one would
+> like a different behavior, namely to update all the targets at once
+> with one run, but as long as it's documented and established I am
+> willing to live with it. But there seems to be more to it.
+
+==============================================================================
+ MODULES := \
+ Blah \
+ Bleh \
+
+ SOURCES := $(addsuffix .sml,$(MODULES))
+
+ TEX := $(addsuffix .tex,$(MODULES))
+
+ modules.tex : $(TEX)
+ cat $(TEX) > modules.tex
+
+ $(TEX) : $(SOURCES)
+ ./bin/plit $(SOURCES)
+==============================================================================
+
+> I have files Blah.sml and Bleh.sml.
+> Surprise #1: make modules.tex runs the last rule _once_ (which
+> happens to be which happens in this case).
+
+That's because of the way make processes the makefile. First, it builds
+Blah.tex, but that command also updates Bleh.tex. So, when make comes
+around looking to decide if Bleh.tex needs to be updated, it doesn't
+have to be because it's already up to date, so make doesn't run the rule
+again.
+
+The best way to see this problem is to try a parallel build: in that
+case often make will try to invoke the script once for each target, in
+parallel.
+
+> Surprise #2: add a flag to the command, so now the last rule is
+> $(TEX) : $(SOURCES)
+> ./bin/plit -n $(SOURCES)
+> touch one of the .sml files, make modules.tex again. Now plit runs twice!
+
+I don't know what the -n flag does so I can't say: I can't find any docs
+for "plit" via Google or on my system. Maybe it doesn't actually update
+the files with -n?
+
+Needless to say I can't reproduce this behavior with a simplified
+makefile that doesn't invoke plit but rather just uses touch, etc. to
+try to mimic its behavior.
+
+>
+> Surprise #3: refactor like this
+> $(TEX) : junk
+> junk: $(SOURCES)
+> ./bin/plit -n $(SOURCES)
+> touch Blah.sml. Now make modules.tex runs the last rule (once), but
+> not the first rule (for modules.tex itself), even though it clearly
+> is out of date!
+
+I can only assume that you created a file "junk" by hand in this
+directory during your testing: no other explanation fits the facts as
+you describe them.
+
+This makefile is broken, because you never have any command that updates
+the file "junk".
+
+If that file "junk" doesn't exist already then make will always run the
+plit script every time, regardless of the relative timestamps of the
+.sml files, and then it will always update modules.tex.
+
+If that file "junk" does exist, then it will re-run "plit" if any of the
+.sml files is newer than the file "junk". But since the script doesn't
+update "junk" itself, make doesn't consider the two .tex files out of
+date (they are still newer than their prerequisite, "junk") so it
+doesn't rebuild modules.tex.
+
+If you change your rule so that it updates "junk", all will work as you
+expect:
+
+ $(TEX): junk
+
+ junk: $(SOURCES)
+ ./bin/plit -n $(SOURCES)
+ @touch $@
+
+######################################################################
+######################################################################
+######################################################################
+
+ Case 2
+
+> In some cases, GNU make ignores some double-colon rules when dry-run.
+======================================================================
+ all: foo.1 foo.2
+ foo.1:
+ touch foo.1
+ foo.2:
+ touch foo.2
+
+ install.man:: foo.1
+ @echo install foo.1
+
+ install.man:: foo.2
+ @echo install foo.2
+
+ install.man::
+ @echo install done
+======================================================================
+> I've got the following results
+
+> % make
+> touch foo.1
+> touch foo.2
+> % make -n install.man
+> echo install foo.1
+> echo install done
+
+> I expect "echo install foo.2", but make dry-run shows not to
+> run "install foo.2". However, if I run make actually
+
+> % make install.man
+> install foo.1
+> install foo.2
+> install done
+
+> "install foo.2" is executed. Is this an intentional behavior or a
+> bug of GNU make?
+
+It is intentional behavior. When GNU make runs with -n it must assume
+that your command script does what you say it will do: since it doesn't
+run the script itself it can't know what the script _really_ does.
+
+For a rule like this:
+
+ install.man:: foo.1
+ <some script>
+
+GNU make _must_ assume that <some script> updates the target
+"install.man"... how can it know that it really doesn't?
+
+So, when you run with -n it assumes that the target is now updated,
+which automatically makes it newer than "foo.2", so the rule depending
+on "foo.2" does not get run.
+
+The last install.man rule is run because there is a special condition
+for double-colon rules, that if they have no prerequisites the command
+is run even if the target exists (see the section "Double-Colon Rules"
+in the GNU make manual).
+
+However, double-colon rules that _DO_ have prerequisites are only
+invoked if the prerequisites are newer than the target, just as with
+normal rules.
+
+You can see the behavior "make -n" is emulating without using -n if you
+have your scripts actually create the target your makefile says it will:
+
+ install.man:: foo.1
+ @echo install foo.1
+ touch $@
+ install.man:: foo.2
+ @echo install foo.2
+ touch $@
+ install.man::
+ @echo install done
+ touch $@
+
+
+ $ make -n
+ install foo.1
+ install done
+
+ $ make
+ install foo.1
+ install done
+
+ ms> Note that pmake run as I expected
+
+ ms> % pmake -n install.man
+ ms> echo install foo.1
+ ms> echo install foo.2
+ ms> echo install done
+
+Most likely pmake behaves differently; it may always run all
+double-colon scripts, even if there's a satisfied prerequisite
+relationship.
+
+Try the above makefile with the touch lines in it: does it run all three
+rules even though the touch lines exist?
+
+######################################################################
+######################################################################
+######################################################################
+
+arch-tag: b9738368-cd5f-43ad-aed0-6853f020811f