I have a Makefile that looks like this:
foo: bar
touch foo
sleep 2
echo UPDATED > bar
bar: baz
cp baz bar
sleep 2
bar does not initially exist so it is copied from baz. However, a side-effect of building foo is that bar is also modified such that its timestamp might be newer than that of foo. Is there a way around this? Would order-only dependencies help somehow?
In addition, if baz is later modified, bar and foo would need rebuilding.
SOLUTION 1
It is enough to touch foo just after bar has been updated. In this way, foo is always newer than bar.
foo: bar
sleep 2
echo UPDATED > bar
touch foo
bar: baz
cp baz bar
sleep 2
SOLUTION 2
An order-only prerequisites, such as
foo: | bar
touch foo
sleep 2
echo UPDATED > bar
bar: baz
cp baz bar
sleep 2
will do, too; but keep in mind that order-only prerequisites are a GNU extension to the syntax of Makefile, hence not fully portable.
EDIT
If, in addition, you want bar and foo to be rebuilt when baz is modified, then the only feasible solution is the first one.
Yes, if you need bar to exist for foo but don't need to rebuild foo just because bar changes then an order-only prerequisite sounds like what you want.
You could also possibly just touch foo at the end of the rule instead and avoid this 'foo causes itself to get rebuilt next time' problem entirely, assuming that is workable in this environment.
Related
Is there a variable like $# which would contain instead of current target the target which required current target? Below is a simple example of what kind of functionality I am looking for. Basically "make foo" would create a directory foo, "make bar" would create bar and "make both" both. So far I haven't found anything which would enable this kind of customization.
foo: foobar
do stuff
bar: foobar
do other stuff
both: foo bar
....
foobar:
mkdir <foo or bar>
Found one solution, pattern rules.
foo: from_foo
#echo "This is foo"
from_%:
#echo "Called from $(lastword $(subst _, ,$#))"
#echo "Simpler version... $*"
What does symbol | mean in dependency list, e.g.
foobar: foo | bar
do_something ....
Where foo and bar are targets generated by makefile.
See the section on order-only prerequisites in the GNU make manual.
Basically this means that bar must be built before foobar, but that foobar won't be considered out of date because bar is newer than foobar.
I have the following code:
foo:
touch foo
$(foreach f, $(shell ls | grep foo), \
echo $f; \
)
it will not list the file foo created by the touch foo above, will list if the foo file already exists before the task starts, like this:
$ make foo # first time call, file 'foo' doesn't exists yet
$ make foo # second time call, file 'foo' already exists
foo
Is there a way to evaluate the ls after all the commands above are executed?
That's how Make works. The Makefile is parsed and any Makefile functions are called, then one or more recipes are evaluated.
Is there a reason you're not simply using a shell loop?
foo:
touch foo
for f in *foo*; do \
echo "$$f"; \
done
Notice how the dollar sign needs to be doubled to escape it from being evaluated by make, and also how shell variables should generally be double-quoted unless you specifically require the shell to perform whitespace tokenization and wildcard expansion on the value.
On the other hand, a more "make-ish" approach is to explicitly document any dependencies.
.PHONY: all
all: foo
printf '%s\n' $^
foo:
touch $#
Now all depends on foo, so Make knows it must create foo before it can perform the all recipe if foo doesn't exist, or is out of date in relation to its own dependencies (of which of course there are currently none).
The make variable $^ refers to the dependencies of the current target, and $# expands to the current recipe target. The printf shell script is just a more economical way to print one thing per line without a loop.
I have the example makefile below:
list1 = foo.txt bar.txt
list2 = foo bar
.PHONY: ${list2}
all: ${list1} ${list2}
${list1}: ${list2}
#echo $# $<
This produces the result
foo.txt foo
bar.txt foo
But what I want is
foo.txt foo
bar.txt bar
How can I do this? Just stripping .txt would work in this case and ignore list2, but not in the real file I am trying to work with. I need to pair members of lists across a large number of targets and substitutions.
As Etan points out, after you expand the variables make sees:
foo.txt bar.txt : foo bar
Make is simply not going to somehow infer that you really wanted to say foo.txt depends on foo and bar.txt depends on bar: there are many ways make could interpret this. The way it DOES interpret it, is if you had written:
foo.txt : foo bar
bar.txt : foo bar
which is why you get the results you do.
Your example is not very specific, so it's hard to help you. For example you show your two lists of files as being related by filename. If that's really true, then you have no problem. Just use this:
list1 = foo.txt bar.txt
.PHONY: ${list2}
all: ${list1}
%.txt: %
#echo $# $<
If the files you're building and using for prerequisites have no relationship (by name) to each other that you can describe with a pattern, then you have larger problems.
I have a makefile, with two variables like this
OS = foo.o bar.o baz.o
WS = -DWITH_FOO -DWITH_BAR -DWITH_BAZ
And so on. Instead of writing this out manually I want to generate these two when the makefile is executed based on an environment variable called WITH containing something like foo bar baz. If this environment variable is not set, or is empty, the makefile should use some hard-coded fallback instead.
How would I do that? I'm not too good at makefiles, all I can think is some kind of 'foreach` call but the specifics elude me.
Assuming you are using GNU Make on a UNIX-like operating system, here is a possible solution:
afineman#hotdog:/tmp$ cat Makefile
WITH = foo bar baz
WITH_UPPER = $(shell echo $(WITH) | tr a-z A-Z)
OS = $(WITH:%=%.o)
WS = $(WITH_UPPER:%=-DWITH_%)
.PHONY: env
env:
#echo WITH=$(WITH)
#echo WITH_UPPER=$(WITH_UPPER)
#echo OS=$(OS)
#echo WS=$(WS)
afineman#hotdog:/tmp$ make
WITH=foo bar baz
WITH_UPPER=FOO BAR BAZ
OS=foo.o bar.o baz.o
WS=-DWITH_FOO -DWITH_BAR -DWITH_BAZ
afineman#hotdog:/tmp$
You can supply WITH in your environment if you wish, but in general it is better to write your Makefiles so that they are self-contained. If you do have a requirement that WITH comes from the environment, just leave out the first line of the above Makefile, and $(WITH) will come from the environment.
You can also override $WITH by running Make with the -e switch, i.e.,
afineman#hotdog:/tmp$ WITH="bing bang buzz" make # Not overridden
WITH=foo bar baz
WITH_UPPER=FOO BAR BAZ
OS=foo.o bar.o baz.o
WS=-DWITH_FOO -DWITH_BAR -DWITH_BAZ
afineman#hotdog:/tmp$ WITH="bing bang buzz" make -e # Overridden
WITH=bing bang buzz
WITH_UPPER=BING BANG BUZZ
OS=bing.o bang.o buzz.o
WS=-DWITH_BING -DWITH_BANG -DWITH_BUZZ
Well, I would write something like this:
ifdef WITH
OS := $(WITH:%=%.o)
WS := $(WITH:%=-DWITH_%)
else
# Fallback.
endif
This is the most straightforward solution I see, however, it is not 100% good because WS would be -DWITH_foo ... instead of -DWITH_FOO ....
If such behavior does not fit your needs, you can use tr command to convert WS to uppercase:
WS := $(shell echo '$(WS)' | tr 'a-z' 'A-Z')
Or, as more portable option, use tr function from GMSL:
WS := $(call tr,$([a-z]),$([A-Z]),$(WS))