Why does makefile pattern rule fail with spaces in name. How do I fix it? - makefile

For a Makefile containing...
File\ space.o: %.o : %.c
echo hello
make returns
make: *** No rule to make target 'File.c space.c', needed by 'File space.o'. Stop.
Why does it not return...
make: *** No rule to make target 'File space.c', needed by 'File space.o'. Stop.
?

Related

why my makefile works with asterisk as wildcard, but do not with percentage?

In my makefile:
default: *.s
echo $(basename $<)
Does echo the basename, but
default: %.s
echo $(basename $<)
outputs:
make: *** No rule to make target '%.s', needed by 'default'. Stop.
I have smf.s file in directory, where the makefile is. So why do not makefile use it as Prerequisite? (only shell-like * does, but % does not), why?
Your first rule:
default: *.s
echo $(basename $<)
works as you expect because * is a wildcard character in GNU Make.
On the other hand, your second rule:
default: %.s
echo $(basename $<)
has %.s as a prerequisite. Since there is no file named %.s Make needs an additional rule to generate this missing file %.s. That is what the error message is about:
make: *** No rule to make target '%.s', needed by 'default'. Stop.
You may think that % is a wildcard character. Actually, it behaves as such in pattern rules. However, your second rule isn't a pattern rule. The following is an excerpt from the documentation:
A pattern rule looks like an ordinary rule, except that its target contains the character ‘%’ (exactly one of them).
Your second rule's target – i.e., default – does not contain the character %. Therefore, it can't be qualified as a pattern rule, so the % in the prerequisite, %.s, is literally the % character.

How can I use a pattern rule to add prerequisites like I can to define variables?

I have the following Makefile:
all: foo/bar/baz
foo/%:
#echo $(VAR)
cp $#.in $#
# This works
foo/bar/%: VAR := Hello world
# This doesn't
foo/bar/%: foo/bar/%.in
foo/bar/baz.in:
touch $#
When I run it, the output is
Hello world
cp foo/bar/baz.in foo/bar/baz
cp: cannot stat ‘foo/bar/baz.in’: No such file or directory
Makefile:4: recipe for target 'foo/bar/baz' failed
make: *** [foo/bar/baz] Error 1
In other words, the pattern-specific variable rule works, but the equivalent syntax to declare an extra prerequisite doesn't. What should I do instead?
The real use case is for copying headers before a build. I wrote
obj/subdir/%.o: CPPFLAGS += -Igen/include
obj/subdir/%.o: | gen/include
gen/include:
# Copy the headers
but the headers don't get copied.
You cannot do this. Pattern rules must define all prerequisite patterns when the rule is created; they cannot be added later.
Writing a pattern rule with no recipe deletes the pattern rule.

Make: missed separator in implicit rules definition

I install Eric IDE on Windows 7, and it requires QScintilla2 library. I tried to build that library using qmake and MinGW's make and got a make error:
make -f Makefile.Release
make[1]: Entering directory `/d/Install/QScintilla-gpl-2.7.2/Qt4Qt5'
Makefile.Release:481: *** missing separator. Stop.
make[1]: Leaving directory `/d/Install/QScintilla-gpl-2.7.2/Qt4Qt5'
make: *** [release] Error 2
Makefile content:
####### Implicit rules
.SUFFIXES: .c .cpp .cc .cxx
{..\lexlib}.cpp{release\}.obj:: ## line 481
$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ #<<
$<
<<
I'm not familiar with make, so could anyone explain what does this code mean and how to fix the error?
NOTE: when I insert \t before <<, I got the following error:
make[1]: *** [{..\lexlib}.cpp{release\}.obj] Error 2
make[1]: Leaving directory `/d/Install/QScintilla-gpl-2.7.2/Qt4Qt5'
make: *** [release] Error 2

make: forcing a rule to be used

Typping make (Gnu Make) with the following Makefile (assuming files foo.x and foo.y are missing)
all: foo.z
foo.z: foo.x foo.y
cat foo.x foo.y > foo.z
produce the error message:
make: *** No rule to make target `foo.x', needed by `foo.z'. Stop.
But this Makefile:
all: foo.z
%.z: %.x %.y
cat %.x %.y > %.z
produce this error message:
make: *** No rule to make target `foo.z', needed by `all'. Stop.
In the first case, the rule is applied, and a dependency if found to be missing.
In the second case, the rule is found to be not appropriate, and that is a rule that is missing.
I want to use the second Makefile (I have a lot a *.z object to be created), but with an error message like with the first Makefile. My make output is logged, and having the expanded name of the missing files will help debugging.
Is it possible? Maybe a way to force the rule to be used?
Of course I'm not catting file, this is just a example...
I just found:
all: foo.z
OBJ=foo.z
$(OBJ): %.z: %.x %.y
cat %.x %.y > %.z
One need Static Pattern rule. Amazing make...

How to generate Makefile rule

I want to do generate rules in Makefile by this:
# $(call cc-defs, ccfiles)
define cc-defs
$1.files = $(patsubst %.cc,%.proto,$1)
$1: $1.files
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))
but failed with error message:
Makefile:19: *** commands commence before first target. Stop.
Instead that, I can do this by:
# $(call cc-defs, ccfiles)
define cc-defs
$1.files = $(patsubst %.cc,%.proto,$1)
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))
$(foreach ccfile,$(ccfiles), $(eval $(ccfile):$($(ccfile).files)))
How to make the 1st method works?
Which version of make are you using? $(eval) only appeared in 3.80 (and it only properly works in 3.81 IMHO).
To debug makefiles you'll often have to revert to printf debugging. To see what's going on, replace eval with warning. This shows what you are giving to make:
$ make --warn
Makefile:6: warning: undefined variable `ccfiles'
make: *** No targets. Stop.
(Aside: --warn-undefined-variables is always useful. Undefined variables are untidy.)
O.K., so we need to define $ccfiles. Now we get the for loop firing:
$ make --warn ccfiles=1.cc
Makefile:6: 1.c.files = 1.cc
1.cc: 1.c.files
make: *** No targets. Stop.
Fine. You have given make no recipes, nor a default target. You also have missed out on some variable expansion, and have an extra space in the $(for) invocation (naughty!). Try this:
$ cat Makefile
# $(call cc-defs,ccfiles)
define cc-defs
$1.files = $(patsubst %.cc,%.proto,$1)
$1: $$($1.files) ; echo '[$$#]'
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs,$(ccfile))))
$ make ccfiles=1.cc
make: *** No rule to make target `1.proto', needed by `1.cc'. Stop.
Note that if all you want to do is for all files in a variable to depend on (or be made from) .proto files, you don't need $(eval).
A pattern rule will do (and will work in older versions of GNU Make too):
$(ccfiles): %.cc: %.proto
echo '[$#]'
This does have the side effect of complaining when the ccfiles variable contains any entries not named *.cc (although it still executes the rule in that case).
$ make ccfiles=hello.cc
make: *** No rule to make target `hello.proto', needed by `hello.cc'. Stop.
$ touch hello.proto
$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
Makefile:1: target `hello.c' doesn't match the target pattern
[hello.c]
If the variable can contain many things but you only want to add this processing to .cc files, simply add a filter:
$(filter %.cc,$(ccfiles)): %.cc: %.proto
echo '[$#]'
This then results in:
$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
make: *** No targets. Stop.

Resources