All
I just want to using $# at prerequisite in a Makefile like this
test.v: $(#:%.v=%.tv)
echo $< $#
It suppose output
test.tv test.v
but it only output
test.v
Anything I miss?
In order to reference target variable from dependency list you first need to enable secondary expansion, then you can delay evaluation of targets and functions with $$ instead of $, i.e.:
$ cat Makefile
.SECONDEXPANSION:
test.v: $$(patsubst %.v,%.tv,$$#)
echo $# $<
test.tv:
$ make
echo test.v test.tv
test.v test.tv
Note that you cannot use shortened notation of $$(#:%.v=%.tv) due to some parser limitations around static pattern rules.
Anyway, what you are trying to do is doable with simple pattern rules:
$ cat Makefile2
%.v: %.tv
echo $# $<
%.tv: ;
$ make -f Makefile2 test.v
echo test.v test.tv
test.v test.tv
This would make a generic rule for creating .v files out of .tv files, but will require explicit call of a target (as a pattern rule does not create a specific file to build on its own).
If you wish to limit allowed file naming to follow the rule, you may go with a static pattern rule:
$ cat Makefile3
test.v: %.v: %.tv
echo $# $<
test.tv:
$ make -f Makefile3
echo test.v test.tv
test.v test.tv
Related
I'm trying to take some source files, create some customised versions of those sources, then process those customised sources down to output files I can use. I'm using this make file. Note that this file is not fully complete, currently it only does the CSS* make, once that's working I will add the PHP* make which is similar:
# root sources
CSSSOURCES = $(wildcard *.scss)
PHPSOURCES = $(wildcard *.phtml)
# partials, creates a configed source
CSSMSOURCES = $(addprefix m.,$(CSSSOURCES:.scss=.m))
CSSDSOURCES = $(addprefix d.,$(CSSSOURCES:.scss=.d))
PHPMSOURCES = $(addprefix m.,$(PHPSOURCES:.phtml=.m))
PHPDSOURCES = $(addprefix d.,$(PHPSOURCES:.phtml=.d))
# targets
CSSMTARGETS = $(CSSMSOURCES:.m=.css)
CSSDTARGETS = $(CSSDSOURCES:.d=.css)
PHPMTARGETS = $(PHPMSOURCES:.m=.php)
PHPDTARGETS = $(PHPDSOURCES:.d=.php)
# ensure no clash with built in rules
.SUFFIXES: .m .d .scss .css .phtml .php
all: $(CSSMTARGETS)
%.m: %.scss
echo "%define MOBILE" | cat - $< >tmp
mv tmp $#
%.d: %.scss
echo "%define DESKTOP" | cat - $< >tmp
mv tmp $#
%.css: %.m %d
cat $< | mym1.pl >$#
rm $<
.PHONY: test
test:
#echo "sources - $(CSSSOURCES)"
#echo "msources - $(CSSMSOURCES)"
#echo "targets - $(CSSMTARGETS)"
Instead of creating the CSS targets I get this error:
make: *** No rule to make target 'm.page.css', needed by 'all'. Stop.
make operates on file names; if there is no file named m.page.m and no file named m.page.d - which is what m.page.css depends on in accordance with your declared dependencies - then Make will conclude that it needs to create these. If it does not have any rules (built-in or by way of a recipe) to create those, the error message you get tells you pretty much exactly that.
I'm guessing what you actually want is something like
m.%: %
echo "%define MOBILE" | cat - $< >$#
d.%: %
echo "%define DESKTOP" | cat - $< >$#
This tells make how to create m.whatever and d.whatever from whatever; so it now knows how to create m.x.phtml from x.phtml and d.y.scss from y.scss etc.
(Notice also how this avoids the separate mv of a static temporary file name, as discussed in comments.)
%.css: %.scss
mym1.pl <$< >$#
%.php: %.phtml
mym1.pl <$< >$#
This tells make how to create m.z.css from m.z.scss, d.w.php from d.w.phtml, etc. I'm guessing here that mym1.pl can handle both cases.
(Notice also the refactoring to avoid useless use of cat.)
This does away with the somewhat mysterious .m and .d suffixes so you probably have to refactor the variables at the top of your Makefile.
Instead of creating the CSS targets I get this error:
make: *** No rule to make target 'm.page.css', needed by 'all'. Stop.
Your makefile provides exactly one rule by which m.page.css could be built or updated:
%.css: %.m %d
cat $< | mym1.pl >$#
rm $<
In order for that rule to apply, however, both of the prerequisites, expressed as %.m and %d [sic] need to exist or be able to be built. There are problems with both.
The former in this case represents a file m.page.m. This apparently does not already exist, but you have a rule by which it could be built from m.page.scss. Except you don't have an m.page.scss or any rule to build one. The corresponding root source file is actually page.sccs.
The latter prerequisite, %d, would have an analogous problem, but it doesn't even get that far because you have omitted a period from the prerequisite name (should be %.d, not %d).
The rule quoted above is moreover bogus because it designates two prerequisites but only uses one. That's not inherently wrong, but it does not do anything useful to serve you here.
Replacing your current pattern rules with these should help:
m.%.m: %.scss
echo "%define MOBILE" | cat - $< >tmp
mv tmp $#
d.%.d: %.scss
echo "%define DESKTOP" | cat - $< >tmp
mv tmp $#
%.css: %.m
cat $< | mym1.pl >$#
rm $<
%.css: %.d
cat $< | mym1.pl >$#
rm $<
Pattern rules work:
$ ls
Makefile hello.txt world.txt
$ cat Makefile
all: hello.out world.out
%.out: %.txt
cp $< $#
$ make
cp hello.txt hello.out
cp world.txt world.out
However, when I try to replace them with what I think is the exact equivalent suffix rules, they don't work:
$ ls
Makefile hello.txt world.txt
$ cat Makefile
.POSIX:
.SUFFIXES:
.SUFFIXES:.txt.out
all: hello.out world.out
.txt.out:
cp $< $#
$ make
make: *** No rule to make target 'hello.out', needed by 'all'. Stop.
I don't understand why.
This line is the problem:
.SUFFIXES: .txt.out
It declares a single suffix, .txt.out, not two of them. You can change it to this:
.SUFFIXES: .txt .out
Note that I do not want to redirect all make output to file. I only want the output from a $(warning) command to file.
someTarget:
$(warning building $# using $?) >> someLogFile.txt
My example above does not redirect the output from $(warning to someLogFile. Is there a way to do it? Maybe redirect it to a variable and then echo that to a file?
Thanks.
is there a way to redirect $(warning) or $(info) statements to file?
Here's one for GNU Make, but it's not pretty:
Makefile
LOG := log.txt
TARGET_ACQUIRED = \
$(shell echo 'NO_SUCH_TARGET:' | $(MAKE) --eval='$$(info Target acquired: $#...)' -s -f - >> $(LOG))
target_a: target_b
$(TARGET_ACQUIRED)
touch $#
target_b:
$(TARGET_ACQUIRED)
touch $#
clean:
rm -f target_* $(LOG)
With which you'll get:
$ make
touch target_b
touch target_a
$ cat log.txt
Target acquired: target_b...
Target acquired: target_a...
To understand this ruse, see the GNU make commandline options.
If you want this for the purpose of debugging a makefile, you'd probably
fare better with GNU Make's --debug options, documented at the same place.
I'm currently learning how to use makefiles. But I'm struggling with % pattern rules. I've boiled down my failing makefile to this very simple example:
I fill an empty directory with:
echo aaa > a.in && echo bbb > b.in
A first makefile like this works very well:
a.out : a.in
cat $< > $#
as
make && echo *.out && cat *.out
returns
cat a.in > a.out
a.out
aaa
but when I try to use a pattern rule modifying the makefile as follows:
%.out : %.in
cat $< > $#
make then returns me:
make: *** No targets. Stop.
It seems like a very simple problem but I can't get to what I am missing...
If you have a makefile with no targets lists (only patterns), and you just type make, then you haven't told make that it should build anything specific, so it won't do anything.
A pattern rule doesn't mean "go find all the files that match this pattern and build them". A pattern rule tells make "if you need to find a way to build a file that matches this target pattern, then here's how you do it".
If you type make a.out so make knows that you want to build a target a.out, then make will use your pattern rule to build it.
Alternatively, you can add the target to your makefile, something like this:
.PHONY: all
all: a.out
%.out : %.in
cat $< > $#
In the GNU make docs, '%' is documented to match "any nonempty substring". However, it seems it actually only matches non-empty substrings that do not contain whitespace. For example, say you do this:
mkdir /tmp/foo
cd /tmp/foo
echo 'int main() { return 0; }' > "test.c"
echo 'int main() { return 0; }' > "test space.c"
Now, you should be able to build these using GNU Make's built-in pattern rules:
anthony#Zia:/tmp/foo$ make "test"
cc test.c -o test
anthony#Zia:/tmp/foo$ make "test space"
make: *** No rule to make target `test space'. Stop.
The same problem happens when you write a makefile.
anthony#Zia:/tmp/foo$ rm test
anthony#Zia:/tmp/foo$ echo 'all: test test\ space' > Makefile
anthony#Zia:/tmp/foo$ make
cc test.c -o test
make: *** No rule to make target `test space', needed by `all'. Stop.
Even if you explicitly add in a %: %.c rule, the result is the same. But if you add in an explicit rule to the Makefile, like this, it works:
test\ space: test\ space.c
$(CC) -o "$#" "$<" # first char is tab, of course.
Is there a trick to get spaces to work with implicit rules?
edit
I've sent a bug report: http://lists.gnu.org/archive/html/bug-make/2011-06/msg00002.html
I don't believe so. The notion of a list of whitespace-separated tokens being passed around as a string is pretty deeply ingrained in make. Those lists are parsed and reparsed. There's a reason why spaces in directory and file names is considered bad practice in the UNIX world.
This is a kludge, but as of today, people still get given paths with spaces in sometimes.
Anyway, making a link instead of directly accessing the directory in the % rule works OK.
# GNU makefile
DIR_WITH_SPACE=/c/Users/me/My\ Code
# *** DOESN'T WORK ***
%.h : $(DIR_WITH_SPACE)/%.h
cp -v "$<" "$#"
fix:
ln -s $(DIR_WITH_SPACES) dir_fixed
# Does work :)
%.h : dir_fixed/%.h
cp -v "$<" "$#"