I am migrating a Makefile from omake.exe (from ClearCase) to jom.exe/nmake.exe.
A simplified Makefile example:
all: bin1 bin2
rule1 rule2: rule3
#echo creating rule1 and rule2
#touch rule1 rule2
rule3:
#echo creating rule3
#touch rule3
bin1: rule1
#echo creating bin1
#touch bin1
bin2: rule2
#echo creating bin2
#touch bin2
touch simply creates a file or if it already exists it updates the timestamp.
The output with jom/namke is:
creating rule3
creating rule1 and rule2
creating rule1 and rule2
creating bin1
creating bin2
creating rule1 and rule2 is executed twice.
With omake the rule was executed only once with the meaning to create the files rule1 and rule2 in one command (here with touch).
What do I have to change that the command that creates rule1 and rule2 at the same time only is called once?
Thanks
Teddy
I don't know anything about either omake or nmake. But I can give you info about standard (POSIX) make and to the extent that those instances of make adhere to the standard, it may be useful.
In standard make, this rule:
rule1 rule2: rule3
#echo creating rule1 and rule2
#touch rule1 rule2
never means "one invocation of the recipe builds both targets". It is interpreted to be exactly the same as if you'd written:
rule1: rule3
#echo creating rule1 and rule2
#touch rule1 rule2
rule2: rule3
#echo creating rule1 and rule2
#touch rule1 rule2
So, in one sense the behavior you see from nmake could be expected. Except, it never works like that in POSIX make, because POSIX make always runs one rule at a time. So, first it tries to build rule1 and that actually builds both rule1 and rule2. So then when make investigates whether it needs to build rule2, it sees it is already up to date and doesn't do anything.
So even though make interprets this rule as two different targets, it has the same effect as only one rule: running the recipe one time updates both targets and make only runs the recipe one time.
If you use GNU make, or some other make, which supports parallel builds, then this behavior no longer works because make might detect that rule2 is out of date before the recipe for rule1 has a chance to update it. But, that's not POSIX.
I can't explain why nmake doesn't work like this... it's a pretty odd, and limited, implementation of make.
The traditional way to handle this in POSIX is by introducing a "sentinel file" that collects these multiple targets into one, like this:
rule1 rule2 : sentinel ;
sentinel: rule3
#echo creating rule1 and rule2
#touch rule1 rule2
#touch $#
I have no idea if something like that will work in nmake.
If you use GNU make, it will work or if you use the current release (4.3) you can explicitly declare grouped targets, like this:
rule1 rule2 &: rule3
#echo creating rule1 and rule2
#touch rule1 rule2
Related
In a Makefile with multiple targets, how can one prevent the prerequisites of targets that are not being used from expanding? See the following example:
thisexpands = $(warning Expanded!)
.PHONY: target1
target1: $(thisexpands)
#echo Target 1
.PHONY: target2
target2:
#echo Target 2
Calling target2 forces thisexpands to expand, even though it is lazily evaluated and it and target1 are never used.
In my real world case expanding thisexpands when calling target1 is an issue, because it is a shell command that prints errors when called out of context of target1 and it's parent targets(not shown here).
Makefiles are fully parsed before the first rule is run. As part of parsing, all the targets and prerequisites must be expanded. You can find details of when expansion happens for different parts of a makefile in How make Reads a Makefile in the GNU make manual.
One way is to use recursion:
thisexpands = $(warning Expanded!)
target1: ; $(MAKE) target1-recurse T1_DEPS='$(value thisexpands)'
T1_DEPS =
target1-recurse: $(T1_DEPS)
#echo Target 1
This doesn't work:
You can probably defer expansion by using secondary expansion, something like this:
.SECONDEXPANSION:
target1: $$(thisexpands)
Be very careful that you escape the prerequisite list appropriately.
There's no way to cancel the expansion completely. However, you can use the conditional assignment based on the value of $(MAKECMDGOALS):
thisexpands = $(if $(filter target1,$(MAKECMDGOALS)),$(warning Expanded!))
.PHONY: target1
target1: $(thisexpands)
#echo Target 1
.PHONY: target2
target2:
#echo Target 2
Note that it works if target1 is only built explicitly (make target1) and not by default, or as a part of building another target.
I have a setup where the files I want to process with make are dependent on the output of another program. Building the program and all its prerequisites
is also a complicated task so I would like to use make for this as well. Now my problem is, that it doesn't seem that one can generate rules and prerequisites in Makefile recipes. Consider the following code:
bar:
echo target1 target2 target3 > bar
foo: bar
$(eval BAR := $(shell cat bar))
define FUN
$(1):
touch a$(1)
endef
ifdef BAR
$(foreach i,$BAR,$(eval $(call FUN,$(i))))
endif
blub: foo $(BAR)
I replaced a big set of complicated recipes that lead to the generation of the list of files I want to have in the end by the bar recipe. In reality, producing the content of bar is very complicated and should be done by a set of Makefile recipes and cannot just be done by (as the above suggests):
BAR:=$(shell echo target1 target2 target3)
I would like to put the foreach loop into the recipe for foo but that fails with prerequisites cannot be defined in recipes which makes sense and is also explained in function define in makefile
But it seems that when I do make blub that at the time when foo eval's BAR to a different value, the prerequisites for blub are not re-evaluated.
So I think ultimately I'm looking for two things:
how do I generate recipes dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?
how do I update the prerequisites of a target (blub in this case) dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?
Thank you!
EDIT: SOLUTION
With the help of #user657267 the following seems to solve my problem:
.PHONY: all
all: blub
-include bar.make
.PHONY: blub
blub: $(BAR)
echo $^
bar.make: Makefile
printf 'BAR=target1 target2 target3\n' > $#
printf 'target1 target2 target3:\n' >>$#
printf '\ttouch $$#' >> $#
.PHONY: clean
clean:
rm -f target1 target2 target3 bar.make
Sounds like you should be using make's self-remaking features
-include bar.make
blub: $(BAR)
#echo $^
bar.make:
#echo BAR := target1 target2 target3 > $#
#echo target1 target2 target3: ; touch $$# >> $#
Obviously the recipes for bar.make are contrived, in the real world they'd probably invoke some kind of script that outputs a valid makefile.
Consider this makefile:
%: %.c
#echo making $#
#touch $#
.SECONDEXPANSION:
%.pid: $$(basename $$#)
$(<D)/$(<F) --pidfile=$<.pid
Here, the first rule builds a program and second rule starts it, producing a pid-file. Note: I know that secondary expansion is unnecessary in this example; the real makefile is more complex and I really need secondary expansion there.
So, typing make foo.pid, I expect Make to build foo from foo.c by the first rule and then run ./foo --pidfile=foo.pid by the second one.
However, it does not seem to work:
$ make -f Makefile.test foo.pid
make: *** No rule to make target 'foo.pid'. Stop.
This somehow relates to secondary-expanded dependencies which are provided by pattern rules. If I write either
%.pid: % in the second rule (i. e. get rid of secondary-expansion), or
foo: %: %.c in the first rule (i. e. write an explicit static pattern rule),
it all suddenly works. Why? Is this a limitation of GNU Make? In my case, I'd like to avoid pre-listing all possible programs in the first rule.
I think your situation is described in section 10.5.5 Match-Anything Pattern Rules. Whay you have here is a non-terminal match-anything rule, which is not allowed to match a file name that indicates a specific type of data.
If you had let's say
%:: %.c
#echo making $#
#touch $#
it would work.
I'm trying to generically add some behaviour to every target in a Makefile, without modifying the targets.
My current attempt is thus:
%: $*
#echo 'Logging $* target'
.PHONY: test
test:
#echo 'Inside explicit test target'
When I run make test, I'd like to match the % pattern rule, which would execute test as a prerequisite ($* expanding to the pattern stem), and then log the target that was run.
$ make test
Inside explicit test target
Logging test target
Instead, what happens is that make test matches the explicit test target (presumably since it's a closer match):
$ make test
Inside explicit test target
How can I get this to work, without changing the explicit test target?
EDIT:
Another attempt...
.SECONDEXPANSION:
%: $$*
#echo 'Logging $* target'
results in
$ make test
make: Circular Makefile <- Makefile dependency dropped.
inside actual test target
I appears from your own answer, which has beaten me to the punch, that
you're concerned only to trigger a preliminary action for targets that are
mentioned on the commandline - $(MAKECMDGOALS). From the posting I took
it that you wanted such an action for "every target in a Makefile", which
would include all targets that are prerequisite to the commandline targets or,
if there are no commandline targets, to the default target.
Anyhow, you may still be interested in a solution to the more general problem.
You want a preliminary action to be executed before the recipe for every target.
Your question is: how to match a patten rule before explicit rule?
This is an XY way of posing the problem, because make will consult pattern
rules to find a way of making a target only if you don't give it an explicit
recipe. You know, for example, that make has a pre-defined pattern rule for
making an .o file from a .c file. Even so, if my makefile is:
test.o:
#echo $#
then make prints test.o, without any attempt to find test.c and compile it.
And if my make file is:
test.o: test.c
#echo $#
test.c:
#echo $#
then make prints:
test.c
test.o
needing no resort to the pattern rule. But if my makefile is:
test.o: test.c
Then make says:
make: *** No rule to make target 'test.c', needed by 'test.o'. Stop
So you can't do what you're after in the way your question supposes,
because the preliminary action you want to provoke from the pattern
rule could be provoked only if there were no other action for the target.
In that case the reasons for the failures of your two posted attempts are fairly academic,
and you may wish to scroll to The Chase.
In your first attempt, with:
%: $*
#echo 'Logging $* target'
The pattern rule - which is unemployed by make test - is equivalent to:
%:
#echo 'Logging $* target'
because $* only assumes a value in the recipe, not in the pattern rule. You
can make this pattern rule be employed by making any target for which the
makefile does not provide a recipe, e.g. make nonsuch will print Logging nonsuch target;
but that is of no use.
The second attempt, with:
.SECONDEXPANSION:
%: $$*
#echo 'Logging $* target'
does the right thing to create the rule you intend to create. But the
meaning of that rule is:
<target>: <target>
#echo 'Logging <target> target'
making every target to which this rule is applied a prerequisite of itself.
Inevitably this will result in a circular dependency error for all such targets.
As you saw, this circularity does not affect the your test target because
it has an explicit recipe and does not employ the rule. But it does provoke
the surprising error:
make: Circular Makefile <- Makefile dependency dropped.
That happens because the first target that make automatically considers is
the makefile itself. Unlike the test target, you have no recipe for
the makefile; so the pattern rule applies to it, making the makefile dependent
on itself.
The Chase
You can achieve what you want by a different approach. In a actual project
it is more than likely that in any makefile you can compute a list of
all possible targets. From this you can generate a corresponding list of
auxiliary targets, say, target => target.prelim, where the
sole purpose of target.prelim is to provoke, when it should and not
otherwise, the required preliminary action for target; and you can get make
to generate a list of order-only rules, target: | target.prelim,
for each target, such that target.prelim will not be considered in determining whether target
must be made, but will be made before target whenever target needs to be made.
Here is an illustration:
SRCS := main.c foo.c
OBJS := $(SRCS:.c=.o)
TARGETS := all prog $(OBJS)
PRELIMS := $(patsubst %,%.prelim,$(TARGETS))
define prelim_rule =
$(1): | $(1).prelim
endef
$(foreach target,$(TARGETS),$(eval $(call prelim_rule,$(target))))
.PHONY: all
all: prog
prog: $(OBJS)
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $# $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(PRELIMS) prog
%.prelim:
#echo "Logging target $(#:%.prelim=%)"
#touch $#
And a sample session:
$ make
Logging target all
Logging target main.o
cc -c -o main.o main.c
Logging target foo.o
cc -c -o foo.o foo.c
Logging target prog
cc -o prog main.o foo.o
$ make
make: Nothing to be done for 'all'.
$ make clean
rm -f main.o foo.o all.prelim prog.prelim main.o.prelim foo.o.prelim prog
$ make main.o
Logging target main.o
cc -c -o main.o main.c
$ make main.o
make: 'main.o' is up to date.
$ # A prelim can't out-date its target...
$ touch main.o.prelim
$ make main.o
make: 'main.o' is up to date.
I realise that this isn't answering my question as asked, but it has the effect I want - executing a shell command as late in the Makefile processing as possible.
MYVAR?=foo
.PHONY: test
test:
#echo 'Inside test target'
LOG=$(shell echo 'Logging $(MAKECMDGOALS), myvar=$(MYVAR)' > log)
.SECONDEXPANSION:
force: $$(LOG)
LOG is a deferred variable, so is not expanded until Make evaluates the prerequisite list of the force target.
In a single Makefile, the .SECONDEXPANSION: part is not needed, since the force target is evaluated after MYVAR is set.
However, if I move the LOG variable and force variable into a sub-makefile, it would be easy to include subMakefile before the MYVAR?= line - which would not work.
By specifying .SECONDEXPANSION for force, the reliance on ordering is removed.
There are two pattern rules in my Makefile. target1 actually matches both these two rules. When I run the makefile, it always try to run the recipes of pattern rule1 instead of pattern rule2 I desire. For a specific target(target1 for example), is it possible to have makefile process skip matching rule1 and go ahead to find the second match(rule2)???
## pattern rule 1
%.xml: $^
recipes ....
## pattern rule 2
/opt/test1/xml/default%.xml: $^
recipes ....
## target1
/opt/test1/xml/default1.xml: prereq