Could you please help me to understand how GNU Make (version 3.81) processes simple Makefile? Here is the file:
.PHONY: a b c e f
a : b c
#echo "> a(b,c)"
e : a
#echo "> e(a)"
e : f
#echo "> e(f)"
f :
#echo "> f()"
b :
#echo "> b()"
c :
#echo "> c()"
Now I run command
make e
to build 'e' target. Make's output looks like:
Makefile:7: warning: overriding commands for target `e'
Makefile:5: warning: ignoring old commands for target `e'
> f()
> b()
> c()
> a(b,c)
> e(f)
http://www.gnu.org/software/make/manual/html_node/Error-Messages.html gives next explanation:
‘warning: overriding recipe for target `xxx'’
‘warning: ignoring old recipe for target `xxx'’
GNU make allows only one recipe to be specified per target (except for double-colon rules). If you give a recipe for a target which already has been defined to have one, this warning is issued and the second recipe will overwrite the first.
But from output we can see that commands for build 'a' target are also performed. I thought that according to description at 'Error-Messages' page make, while processing this Makefile and trying to build 'e' target (make e), should at first place decides that 'e' depends on 'a' and then overwrite this to 'e' depends on 'f'. And output should looks like:
Makefile:7: warning: overriding commands for target `e'
Makefile:5: warning: ignoring old commands for target `e'
> f()
> e(f)
But it looks like make still remember that 'e' depends on 'a' and not overwrite recipe at all.
Please help me to understand this behavior. Why are commands for building 'a' target still performed, even after recipe overwriting?
The dependencies are distinct from the commands. The dependency on a is not forgotten, but the commands are.
Related
Is it possible to make make not have a main target, meaning that invocations to make without a specified target would fail, even if a first target exists?
Not specifically that, but if you are using GNU make there are ways to ensure users provide a goal on the command line.
First, you could check MAKECMDGOALS:
ifeq ($(MAKECMDGOALS),)
$(error Missing command line goal!)
endif
Or alternatively you could use .DEFAULT_GOAL to force the default goal to be a rule that fails:
.DEFAULT_GOAL = fail
fail:; #echo Missing command line goal; exit 1
I have base Makefile for all my services, in some cases I want to use my default "test" target, in other cases I want to override\add to it. These are the files I have so far (and obviously its not working as expect..).
MakefileBase
test:
./.../run-tests.sh
Makefile
BASE_FILE := /path/to/MakefileBase
include ${BASE_FILE}
test:
#$(MAKE) -f $(BASE_FILE) test # un/comment this line in order to run the default tests.
# echo "custom test"
When I run the test with the first line commented out I get the following
Makefile:10: warning: overriding commands for target `test'
/.../MakefileBase:63: warning: ignoring old commands for target `test'
echo "no tests"
no tests
except of the warning it works as expected, the problem is when I try to use the parent function then I get the following errors:
Makefile:9: warning: overriding commands for target `test'
/.../MakefileBase:63: warning: ignoring old commands for target `test'
make[1]: test: No such file or directory
make[1]: *** No rule to make target `test'. Stop.
make: *** [test] Error 2
Actually, both answers so far are wrong or incomplete:
exit 0 in a rule will just exit the current shell (which runs only the exit 0 command, so it is a no-op in this case). So this won't override.
It's not true that you cannot override a command without warning. If it is not necessary that both targets have the same name, you can do:
MakefileBase
.PHONY: test-base
test-base:
echo base
%: %-base # handles cases where you don't want to override
Makefile1
include MakefileBase
.PHONY: test
test:
echo override
Makefile
include MakefileBase
.PHONY: test
test: test-base
echo append
As with double colon rules, the effects of each targets (on each other) have to be considered, especially if you move away from .PHONY (for example, files considered up-to-date because the other rule just updated them).
BTW, I don't see the problem with your approach (aside from the warning). For me it worked fine.
This is what double-colon rules are for:
test::
./.../run-tests.sh
and:
BASE_FILE := /path/to/MakefileBase
include ${BASE_FILE}
test::
#$(MAKE) -f $(BASE_FILE) test
This will "add to" an existing target. There is no way to override a target with a different recipe without incurring a warning.
If you want to do that the only way is to use variables to hold the recipe then override the variable value. For example:
test_recipe = ./.../run-tests.sh
test:
$(test_recipe)
and:
BASE_FILE := /path/to/MakefileBase
include ${BASE_FILE}
test_recipe = #$(MAKE) -f $(BASE_FILE) test
Hacky, but you can get add, and a limited form of override that can never be deeper than one override. Both use double colon rules.
add: use double colons on both rules
override: use double colons on both rules, appending command exit 0 to the last rule
# "addcmd" echoes "BA", "overridecmd" echoes "B"
addcmd ::
echo "A"
addcmd ::
echo "B"
overridecmd ::
echo "A"
overridecmd ::
echo "B"
exit 0
A collegue just came across this, and I thought I'd ask if there's any neat solution to the following problem: I have a GNU makefile:
a: | b
touch $#
b:c
touch $#
c:
touch $#
Then I run:
~/tmp> make a
touch c
touch b
touch a
~/tmp> make a
make: `a' is up to date.
~/tmp> touch b
~/tmp> make a
make: `a' is up to date.
~/tmp> touch c
~/tmp> make a
touch b
It rebuilds b but not a if I touch c. Is there a way to NOT rebuild b if it is being invoked by an order-only prerequisite? ( in the real-life case b is a file with hundreds of dependencies, which may not be around when make a is invoked. I can't make b's prerequisites be order-only as that would break make b)
The behavior is fully correct. You instructed make to ignore the tight dependency between a and b and depend only on b presence. Whilst a and c share a date dependency.
This is the difference between a: b and a: | b.
If one wants to investigate that case (or other make magic :) ):
Try the following, you'll see that make is keen and tells you what it is doing for b target:
% touch b
% LANG=C make -rd | awk '/^Considering/,/^$/ {print}'
Considering target file `a'.
Considering target file `b'.
Considering target file `c'.
Finished prerequisites of target file `c'.
No need to remake target `c'.
Finished prerequisites of target file `b'.
Prerequisite `c' is older than target `b'.
No need to remake target `b'.
Finished prerequisites of target file `a'.
Prerequisite `b' is order-only for target `a'. <--- "order-only"
No need to remake target `a'.
Now, add a tight dependency:
% echo "a:b" >> Makefile
And compare results:
% touch b
% LANG=C make -rd | awk '/^Considering/,/^$/ {print}'
Considering target file 'a'.
Considering target file 'b'.
Considering target file 'c'.
Finished prerequisites of target file 'c'.
No need to remake target 'c'.
Finished prerequisites of target file 'b'.
Prerequisite 'c' is older than target 'b'.
No need to remake target 'b'.
Pruning file 'b'.
Finished prerequisites of target file 'a'.
Prerequisite 'b' is order-only for target 'a'.
Prerequisite 'b' is newer than target 'a'. <--- additional "date dependency"
Must remake target 'a'.
touch a <--- 'a' is rebuilt
Putting child 0x1b09ec0 (a) PID 5940 on the chain.
Live child 0x1b09ec0 (a) PID 5940
Reaping winning child 0x1b09ec0 PID 5940
Removing child 0x1b09ec0 PID 5940 from chain.
Successfully remade target file 'a'.
I used make -r (no implicit rules) as this example doesn't use them and it's boring to read.
Comments aside, your problem statement is extremely generic, it's very far from describing an actual use case. This makes it very short and easy to read and understand. On the other hand, understanding and solving or working around your particular problem is more uncertain.
I've seen your exact same, generic problem statement apply to this other use case:
nimble_exe: nimble_srcs | big_lib
touch $#
big_lib: biglib_many_sources_and_headers
touch $#
sleep 1 # simulate a long [no-op] build time
biglib_many_sources_and_headers
touch $#
This code means: "build big_lib when it's missing for nimble_exe, but don't care when it's out of date" which superficially matches the definition of an "order-only dependency" and even used to match ninja's behavior until 2011
Unfortunately, if anyone changes anything in the biglib_many_sources_and_headers, make nimble_exe rebuilds big_lib but not nimble_exe! This shows that "order-only dependencies" were simply not designed for that use case. So I recommend this instead:
nimble_exe: nimble_srcs
test -e big_lib || $(MAKE) big_lib
touch $#
I've been trying to get a makefile, a, to include another makefile, b, if the target specified is not found in file a. I'm using this snippet to try and achieve this, but from echos I've put into the file I can see that makefile b is being accessed even when the target is found in a and run.
The snippet I'm using from the link above is:
foo:
frobnicate > foo
%: force
#echo "No target found locally, running default makefile"
#$(MAKE) -f Makefile $#
force: ;
Specifically I'm getting "Nothing to be done" outputs when makefile b is being used, and makefile a is behaving as expected. This is shown below:
$ make all # all target appears in both make files
No target found locally, running default makefile
make[1]: Entering directory `/home/user/currdir' # (b)
make[1]: Nothing to be done for `Makefile'.
make[1]: Leaving directory `/home/user/currdir'
Local all # (a)
Is there a better way to be doing this?
addition: After adding another echo to the % rule, I've found that $# is "Makefile", when it should be the target trying to be built.
I don't really understand your question based on the example you gave; there is no "a" or "b" in that example, just one Makefile.
However, the behavior you're seeing is due to GNU make's re-making makefiles capability. When you create match-anything pattern rules as you've done, you have to consider that every single target or prerequisite that make wants to build will match that rule. That's a large burden.
You can avoid having remade makefiles match by creating explicit rules for them, such as:
Makefile: ;
I have Makefile like this:
b:
#echo "b"
a:
#echo "a"
#make b
I want this Makefile to print "a\nb" after i execute 'make a'. It does the
thing, but It also prints "Entering directory" and "Leaving directory":
$ make a
a
make[1]: Entering directory `/home/bessarabov'
b
make[1]: Leaving directory `/home/bessarabov'
Actually that lines doesn't disturb me, but I'm not sure that this is the
correct way of running some targets in the end of other targets.
GNU make has a switch to silence the Entering/Leaving messages: --no-print-directory. using make usually isn't right, you probably want to change it to $(MAKE).
rationale for $(MAKE) versus "make" is given in the GNU make manual here and here