2016-08-30 07:37:57 +00:00
|
|
|
# (A)
|
|
|
|
.KEEP_STATE:
|
|
|
|
|
|
|
|
all: hello
|
|
|
|
|
|
|
|
clean:
|
|
|
|
rm foo.x foo.y
|
|
|
|
|
|
|
|
foo.x:
|
|
|
|
touch foo.x
|
|
|
|
|
|
|
|
# <- workaround: disable command dependencies
|
|
|
|
# ?touch foo.x
|
|
|
|
|
|
|
|
foo.y: foo.x
|
|
|
|
cat foo.x foo.x > foo.y
|
|
|
|
|
|
|
|
# <- workaround: disable command dependencies
|
|
|
|
# ?cat foo.x foo.x > foo.y
|
|
|
|
|
|
|
|
# (B)
|
|
|
|
include foo.y
|
|
|
|
|
|
|
|
|
|
|
|
hello:
|
|
|
|
echo hello
|
|
|
|
|
|
|
|
# The perhaps unintuitive effect of `.KEEP_STATE`
|
|
|
|
# on the generation of include files.
|
|
|
|
#
|
|
|
|
# Effects:
|
|
|
|
#
|
|
|
|
# 1) comment out the line after (A)
|
|
|
|
#
|
|
|
|
# $ somake -f empty_cmd.mf clean
|
|
|
|
# rm foo.x foo.y
|
|
|
|
# $ rm .make.state
|
|
|
|
# $ somake -f empty_cmd.mf
|
|
|
|
# touch foo.x
|
|
|
|
# cat foo.x foo.x > foo.y
|
|
|
|
# echo hello
|
|
|
|
# hello
|
|
|
|
# $ somake -f empty_cmd.mf
|
|
|
|
# echo hello
|
|
|
|
# hello
|
|
|
|
#
|
|
|
|
# -> meaning that the include file foo.y is only updated
|
|
|
|
# if it doesn't exist or foo.x is newer. This is
|
|
|
|
# the expected behavior.
|
|
|
|
#
|
|
|
|
# 2) comment in (A) and comment out (B)
|
|
|
|
#
|
|
|
|
# $ somake -f empty_cmd.mf clean
|
|
|
|
# rm foo.x foo.y
|
|
|
|
# $ rm .make.state
|
|
|
|
# $ somake -f empty_cmd.mf foo.y
|
|
|
|
# touch foo.x
|
|
|
|
# cat foo.x foo.x > foo.y
|
|
|
|
# $ somake -f empty_cmd.mf foo.y
|
|
|
|
# `foo.y' is up to date.
|
|
|
|
#
|
|
|
|
# -> again, as expected the foo.y action is only executed once.
|
|
|
|
#
|
|
|
|
# 3) comment in (A) and (B)
|
|
|
|
#
|
|
|
|
# $ somake -f empty_cmd.mf clean
|
|
|
|
# touch foo.x
|
|
|
|
# cat foo.x foo.x > foo.y
|
|
|
|
# rm foo.x foo.y
|
|
|
|
# $ rm .make.state
|
|
|
|
# $ somake -f empty_cmd.mf
|
|
|
|
# touch foo.x
|
|
|
|
# cat foo.x foo.x > foo.y
|
|
|
|
# echo hello
|
|
|
|
# hello
|
|
|
|
# $ somake -f empty_cmd.mf
|
|
|
|
# touch foo.x
|
|
|
|
# cat foo.x foo.x > foo.y
|
|
|
|
# echo hello
|
|
|
|
# hello
|
|
|
|
#
|
|
|
|
# -> this is unexpected because foo.y is generated each time.
|
|
|
|
# This is caused by an interaction between KEEP_STATE and
|
|
|
|
# include. Make reads in the `.make.state` file after
|
|
|
|
# include directives are being processed. But, as part of the
|
|
|
|
# dependency checking of the include files the usual KEEP_STATE
|
|
|
|
# logic is applied such that make assumes that the foo.y action
|
|
|
|
# command changed from '' (empty) to 'cat foo.x foo.x > foo.y'.
|
|
|
|
#
|
|
|
|
# (make basically looks up the 'old' command in an empty database)
|
|
|
|
#
|
|
|
|
# When calling make with `-d` the log contains messages like:
|
|
|
|
#
|
|
|
|
# different from empty old command
|
|
|
|
# Building foo.x because new command longer than old
|
|
|
|
# Building foo.y because new command longer than old
|
|
|
|
#
|
|
|
|
# A workaround is to disable command dependencies for the involved
|
|
|
|
# actions, i.e. `?touch foo` and `?cat foo.x foo.x > foo.y`
|
|
|
|
#
|
|
|
|
# This is a bug.
|
|
|
|
#
|
2016-08-30 08:24:40 +00:00
|
|
|
# Possible fix:
|
|
|
|
# i) Just don't use the make.state database before it is loaded.
|
|
|
|
# This effectively would disable command dependencies for
|
|
|
|
# generated include files. Similar effect as the described
|
|
|
|
# workaround.
|
|
|
|
# ii) or, preferably, load the make.state file before any
|
|
|
|
# processing of include directives. This would have
|
|
|
|
# the advantage that an include file is regenerated if a
|
|
|
|
# variable that is used in the generate action has
|
|
|
|
# changed (think: `generate.sh $(CC) $(LD) > tool_dependent.mf`
|
|
|
|
|
2016-08-30 07:37:57 +00:00
|
|
|
|