Why does GNU Make try to compile an object file that doesn't exist, for a rule without a recipe? - linux

If you run make test on the following Makefile (with an otherwise empty directory):
test.%:
#echo $*
test: test.dummyextension
you get the following output:
dummyextension
o
cc test.o test.dummyextension -o test
clang: error: no such file or directory: 'test.o'
clang: error: no such file or directory: 'test.dummyextension'
clang: error: no input files
make: *** [test] Error 1
Why?
I suspect it has something todo with implicit rules, but I searched make -p on my machine, and can't find any implicit rules that match %: %. I would expect the output to simply be dummyextension, but it's almost like there's a phantom test.o file in my directory (despite my checking ten times that there is not).
If you put a ; after the test.dummyextension prerequisite, or add any content to the test rule, everything works as expected. This is the minimal failing example I can come up with, and I haven't a clue why you'd see this behaviour. Any ideas?

Make can chain multiple rules to create a target. In this case it has the following built-in rule:
%: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
This tells make that it can make test if it can find a way to make intermediate file test.o. So now it looks for a way to make test.o and it sees your pattern rule test.%:, which matches with stem o. So it has found a way!
You have also told make that test needs test.dummyextension, so it looks for a way to make that and again the pattern test.%: matches, this time with stem dummyextension.
So make first runs the test.% recipe twice to make the two prereqs. Then it runs the %: %.o recipe to make the final target. The $^ in the recipe is all prerequisites, so both test.o, gained from the built-in pattern rule, and test.dummyextension, gained by the explicit dependency in your Makefile, appear in the command.
You can test this by using the -r flag to disable built-in rules and then add the above pattern rule manually to your Makefile.
The key points to understand here are:
A line of the form:
test: test.dummyextension
Only adds a dependency to a target. It is not a rule to make the target. That can come from elsewhere. Make does not see this and decide test should be created with a blank recipe.
A stanza of the form:
test: test.dummyextension
;
This is a rule to make the target. Being an explicit rule it has a higher priority than a pattern rule that might also match. This does tell make it has found the rule to make test using the recipe ; and it stops looking for another rule.
Make will search for an implicit rule to make any target if it does not find an explicit one. If you don't want it to do this, you can either give it an explicit rule, like above, or declare the target as phony, with .PHONY: target. Implicit rules are not searched for phony targets.

Related

What does ‘$#’ mean when it isn't in a rule of a Makefile?

# Linker scripts preprocessor (.lds.S -> .lds)
# ---------------------------------------------------------------------------
quiet_cmd_cpp_lds_S = LDS $#
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -U$(ARCH) \
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $# $<
$(obj)/%.lds: $(src)/%.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
Above is the code in scripts/Makfile.build.I was reading the arch/arm/kernel/vmlinux.lds.S and I couldn't find the 'INPUT' for the linker script.I guessed the 'INPUT' is setted when the vmlinux.lds.S is compiled.Then I found the code above.I've learned that '$#' is the file name of the target of a rule.But this one is not in a rule.So what it represents and where is the 'INPUT'?
You don't show it, but it is almost certainly the case that if_changed_dep is another macro defined elsewhere in that makefile that expands to either $(quiet_cmd_$1) or $(cmd_$1) (probably depending on how make was invoked, or what arguments it was given), so as applied ends up generating one of those two macro definitions as the action for the rule.

Makefile rule with percent symbol is not evaluated

I'm trying to port linux kernel's kconfig util to my product
while compiling I got next error:
make[6]: *** No rule to make target `zconf.tab.c', needed by `zconf.tab.o'. Stop.
I found next rule in Makefile.lib for this file
$(obj)/%: $(src)/%_shipped
$(call cmd,shipped)
It looks ok for me and it just works in kernel but not in my product.
Then I added another rule right after previous one.
$(obj)/%c: $(src)/%c_shipped
$(call cmd,shipped)
And now it works just fine.
Can someone explain me what's wrong with original rule?
In my case obj=. and src=. (both = dot). Current dir contains appropriate *_shipped file.
My guess is that $(obj)/%: $(src)/%_shipped qualifies as a match-anything pattern rule. (The manual doesn't mention how targets and prerequisites with with directory components are handled, but it would make sense.)
Note the following in the manual:
A non-terminal match-anything rule cannot apply to a file name that indicates a specific type of data. A file name indicates a specific type of data if some non-match-anything implicit rule target matches it.
Since there are already built-in implicit rules for creating .c files (using parser generators for example), the match-anything rule is never considered.
The reason the error doesn't happen for the kernel makefiles is that they run make with -r, which eliminates built-in implicit rules. It's done in the top-level makefile by setting the MAKEFLAGS variable:
# Do not use make's built-in rules and variables
# (this increases performance and avoids hard-to-debug behaviour);
MAKEFLAGS += -rR
As a simple experiment, I created a file test.c_foo and the following makefile:
MAKEFLAGS += -r
%: %_foo
#echo building
make test.c without the first line gives
make: *** No rule to make target 'test.c'. Stop.
With the first line, it prints "building" instead.

How to pass target stem to a shell command in Makefile

I'm writing a static pattern rule to generate a list of dependencies for targets matching a pattern. The dependencies are generated through a shell command (the file content gives information about the dependencies). Here's an example of the explicit rule:
f1.o: $(shell gendep src/f1/f1.source)
... (some compilation command here) ...
While this works, I do not want to rewrite it for each new target since I'm maintaining the same file structure. My attempt at static pattern rule was like so:
%.o: $(shell gendep src/%/%.source)
...
I'm having trouble passing the stem (matched pattern for %) to the shell command. The shell command interprets it literally and operates on src/%/%.source, which of course doesn't exist.
I suspect there is way of passing the stem to the shell command but I don't seem to find it. Any experts here might be able to help me? Sorry if this is a newbie question (I'm indeed one).
What you're trying to do is difficult, because ordinarily Make will expand the $(shell ...) directive before running any rule, or even deciding which rules must be run. We can retard that by means of Secondary Expansion, a slightly advanced Make trick:
.SECONDEXPANSION:
%.o: $$(shell gendep src/$$*/$$*.source)
...
There are also other methods for automatic dependency generation.

No rule to make target `–f'

I am trying to make a c file like
make –f makefile1
This is my make file:
TestAssn1: test_assign1_1.o dberror.o storage_mgr.o
cc -o TestAssn1 test_assign1_1.o dberror.o storage_mgr.o
test_assign1_1.o: test_assign1_1.c test_helper.h dberror.h storage_mgr.h
cc -c test_assign1_1.c
dberror.o: dberror.c dberror.h
cc -c dberror.c
storage_mgr.o: storage_mgr.c storage_mgr.h dberror.h
cc -c storage_mgr.c
But I only get this message:
make: *** No rule to make target `–f'. Stop.
How should I correct this?
You need to use a normal dash (-), not an en dash, in the command.
My guess is you copied this command from a blog or other web source. Many blog/web frameworks have a bug where they will replace typewriter punctuation with their typographically correct counterparts even within code formatted text.
This is very odd as your make usage is correct per http://linux.die.net/man/1/make
Please try some of the other formats for this option:
-f file, --file=file, --makefile=FILE
Use file as a makefile.
Otherwise, perhaps your make is not the one listed in that man page (which is GNU make).

Recursive make is recursing too much and requires a dummy prerequisite

I have a very simple Makefile that isn't doing what I expect it would do. The ultimate goal is that it should call itself recursively, including the appropriate file each time, resulting in a build specific to what was included (I'm building several projects that all share the same code base, but utilize different combinations of the source files). I've never really dealt with recursive calls to make, so I must be missing something obvious. At the moment, I only have one .mk file in the same folder as my Makefile. It's a simple one-liner just for the purposes of this test. It will eventually contain various per-project settings.
Makefile:
SHELL = /bin/sh
ifdef MYFILE
include $(MYFILE)
PROGRAM = $(basename $(MYFILE))
endif
all: $(wildcard *.mk)
dummy:
#echo -- Entering dummy stub ... why do I need this?
%.mk: dummy
#echo Calling $(MAKE) MYFILE=$# $*
$(MAKE) MYFILE=$# $*
$(PROGRAM): objs
#echo Time to link!
objs:
#echo Building objs!
test.mk
SOMEVAR = SomeValue
I have the following two problems:
Problem 1
If I remove the dummy prerequisite from my pattern rule, the pattern rule never gets called (I get the dreaded 'Nothing to be done for all' error). Is there a way I can get the recipes under the %.mk rule to run without needing that dummy prerequisite?
Problem 2
Given the two aforementioned files, I would expect make to do the following:
make[1] starts and hit the all rule
make[1] jumps down to the %.mk pattern rule
make[1] calls itself recursively (the call would look like make MYFILE=test.mk test)
make[2] starts, includes the test.mk file, and sets up the PROGRAM variable
make[2] jumps down to the $(PROGRAM) rule (since we were explicitly called with that target)
make[2] jumps to the objs rule, runs the recipes, and returns back up the chain
In actuality, make gets stuck on the %.mk pattern rule and enters an infinite loop. I don't understand why it's insisting on hitting the pattern rule, when I explicitly told it to build test in my first recursive call (which should correspond to the $(PROGRAM) target). What am I missing here?
Problem 0:
This is overdesigned. You don't need to use recursive Make here.
Problem 1:
The reason Make doesn't try to rebuild test.mk (without a dummy preq) is that test.mk is up to date. A better approach is to switch to a static pattern rule and use PHONY:
MKS = $(wildcard *.mk)
.PHONY: $(MKS)
$(MKS): %.mk:
#echo Calling $(MAKE) MYFILE=$# $*
$(MAKE) MYFILE=$# $*
An even better approach is not to use the name of a real file as a target of a rule that doesn't rebuild (or even "touch") that file.
Problem 2:
In make[2], the makefile includes test.mk. If a makefile includes another file, Make will attempt to rebuild that file before doing anything else. If there is a rule for that file (which there is) and if it succeeds (which it does) Make then reinvokes itself.
You should reconsider this design from the ground up. There are many ways to get the behavior you're looking for, depending on the specifics (how many variable will be defined in a foo.mk? do you really want to manage the build by manually moving those files around? and so on).
P.S. Here's one kludge that springs to mind. Whether it suits your case depends on the specifics:
makefile:
# includes nothing
%.mk: dummy
#echo Calling $(MAKE) MYFILE=$# -f $# $*
$(MAKE) MYFILE=$# -f $# $*
test.mk:
SOMEVAR = SomeValue
include makefile

Resources