I'm trying to write a portable makefile using suffixes for a build target instead of the '%' wildcard syntax implemented by GNU make. Here's my Makefile:
SUFFIXES = .xml.in .xml
all: test.xml
.xml.in.xml:
echo "Hello"
Running make gives me "No rule to make target `test.xml'". However if I use the wildcard:
all: test.xml
%.xml: %.xml.in
echo "Hello"
it works. I assume I'm having issues because one of my extensions has a period in it, is there a workaround for this?
Related
I know this could be done in different ways, but I am actually looking for learning more about makefiles.
I want to be able to call make somefile.txt and run a given script.
In my current folder I have:
makefile
%.txt:
# perl -pe "s/#.*//g; s/^\n//g; s/\n/\t/g;" .txt
echo "Hi"
When I call make, I am getting
make: `somefile.txt' is up to date.
I know I would need to use .PHONY, but I am having trouble trying to use it with %.txt.
I already tried things such as
files = *.txt
.PHONY = $(files)
%.txt:
# perl -pe "s/#.*//g; s/^\n//g; s/\n/\t/g;" .txt
echo "Hi"
But that didn't actually work.
The (a) conventional way to do this is to make your real target have a phony one as a prerequisite. Phony targets are always considered initially out of date, so anything that depends on a phony target will also always be considered out of date. "force" is a conventional name for a target used for this purpose.
For example,
.PHONY: force
force:
%.txt: force
echo "Hi at $$(date)" > $#
As demonstrated in the example, this does not require the phony target to have a recipe.
If you don't want to list your targets to be built in your makefile but instead just give them on the command line, you can use this:
.PHONY: $(MAKECMDGOALS)
The variable MAKECMDGOALS will be set to the set of goals you gave make on the command line.
It's important to understand that a makefile is not the shell, and so just sticking *.txt anywhere in your makefile won't always expand it. Only particular areas of the makefile work with shell globs directly.
If you want to always expand it, you can use make's wildcard function like this:
files = $(wildcard *.txt)
According to the gnu make documentation, if a rule generates multiple targets by a single invocation (for instance with a recipe executing a tool with multiple output files), you can use the '&:' rule syntax to tell make.
I'm getting warnings when using this syntax, about target '&', however, when having multiple (but unique) targets in multiple rules. As if make mistakes the ampersand for a target name instead of being part of the target-prerequisite separator.
In my original project I've got two rules having multiple targets and a recipe generating those targets from a single statement/tool. The targets are unique for each of the two rules. I've created the following simple example to demonstrate the warning generated by make:
all: file_abbc
.PHONY: all clean
clean:
del /Q file_*
file_abbc: file_ab file_bc
copy file_ab+file_bc file_abbc
file_ab file_bc &: file_a file_b file_c
copy file_a+file_b file_ab
copy file_b+file_c file_bc
file_a file_b file_c &: content
copy content file_a
copy content file_b
copy content file_c
Warnings from running make on Windows on the above:
Makefile:17: warning: overriding recipe for target '&'
Makefile:13: warning: ignoring old recipe for target '&'
Why is make complaining about target '&' ?
You're using an old version of GNU make that doesn't understand &: rules, so just treats & as a file name. Use make --version to see which version you are running and upgrade if it is older that 4.3
I have a main Makefile that calls Makefiles placed in subfolders. For testing purposes I would like to add Match-Anything rule at the end of main Makefile.
This rule would be:
%:
make -e -C subdir $#
Are there any contrarguments for such a rule?
I think you meant "con", as in "pro or con", not "cont". "Con" is short for the Latin "contra".
For your question, the downside of adding a new "match anything" rule is that any file that doesn't exist, will try to be created using this rule. For example suppose you run include foo.mk and foo.mk doesn't exist... make will attempt to build foo.mk by running your rule. Basically it can be confusing. It's possible there could be some performance impact; if you run make -d and examine it you should see if your match-anything rule is being used at all during a normal build. I'm not sure if there are any other serious downsides.
By the way you should always only use the make variable $(MAKE) when invoking a sub-make in a recipe; never use the raw make command.
I'm trying to debug the following code:
TESTS=$(shell cat yoursourcefile)
all: $(TESTS)
%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
I got this error:
makefile_tb.vhd >> log_file.log
as if makefile is a target
this error disappears when I add a character or more before %:
T%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
This works but implies that all my targets starts with "T" which is not always the case.
My questions are:
what's exactly the function of % here ?
How to get rid of this error?
As suggested, I added
makefile: ; $#:
at the end, so I have now:
TESTS=$(shell cat yoursourcefile)
all: $(TESTS)
%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
makefile: ; $#:
then when I do:
make all
I get [all] error2 all_tb.vhd >> log_file.log
but all_tb.vhd does not exist !
The %: compile_design rule is a "match-anything" pattern rule. It says "hey make, if you ever want to build any file, with any name, then you can do it by running these commands. Oh and by the way, if you have a file you want to build and it's older than the compile_design file, then you need to rebuild it". Generally you want to avoid match-anything rules, but if your target names truly have no specific pattern, you can't.
When you add the T before it then it tells make that instead of any file, that rule can only build files that begin with T.
The reason make is trying to rebuild the makefile is that GNU make has a special feature that allows it to remake its own makefiles. So after it reads its makefile it will try to re-make it. Normally this has no effect because there's no rule to build a makefile, but here you've added a rule that you've told make can build anything. Adding the T keeps the pattern from matching Makefile because Makefile doesn't begin with T.
The simplest thing for you to do is define an explicit rule for the makefile: make always chooses an explicit rule, if it exists, over an implicit rule like a pattern rule:
Makefile: ; #:
This creates an explicit rule that does nothing (: is the shell built-in command that does nothing).
http://www.cprogramming.com/tutorial/makefiles_continued.html explains implicit targets:
There are some actions that are nearly ubiquitous: for instance, you might have a collection of .c files that you may wish to execute the same command for. Ideally, the name of the file would be the target; using the implicit target ".c" you can specify a command to execute for any target that corresponds to the name of a .c file (minus the .c extension).
However, when I try it, the implicit target is simply ignored. My test makefile is as follows:
Default: Foo.bar
echo "In default."
.bar:
echo "In .bar."
make: *** No rule to make target `Foo.bar', needed by `Default'. Stop.
What am I missing?
Try:
default: foo.bar
echo "In default."
%.bar:
echo "In .bar."
You may be asking about old-style suffix rules - for example this rule:
.c.o:
cc -c $<
tells make how to build a .o file from a .c source. The form with the '%' is known as a pattern rules and is more "modern". I suggest you read the GNU Make manual, which is very informative about such stuff, and easy to read.