Edit I expanded the Makefile.
Take the following makefile:
VERILATOR:=/usr/sbin/verilator
COMMONPREPARAMS:=-Wall
COMMONPOSTPARAMS:=--trace
# Multishot timer
MULTISHOT_TIMER_OBJDIR:=multishot_timer_dir
MULITSHOT_TIMER_VERILOG_FILES:=common/multishot_timer_tb.v common/multishot_timer.v
MULITSHOT_TIMER_TOPLEVEL:=multishot_timer_top.cpp
MULTISHOT_TIMER_TARGET:=$(MULTISHOT_TIMER_OBJDIR)/multishot
#incrementer
INCREMENTER_OBJDIR:=incrementer_dir
INCREMENTER_VERILOG_FILES:=common/incrementer.v
INCREMENTER_TOPLEVEL:=src/incrementer_top.cpp
INCREMENTER_TARGET:=$(INCREMENTER_OBJDIR)/incrementer
ALLTARGETS := $(MULTISHOT_TIMER_TARGET)
ALLOBJDIRS := $(MULTISHOT_TIMER_OBJDIR)
.PHONY: all multishot_timer incrementer
all: multishot_timer incrementer
multishot_timer: OBJDIR:=$(MULTISHOT_TIMER_OBJDIR)
multishot_timer: VERILOG_FILES:=$(MULITSHOT_TIMER_VERILOG_FILES)
multishot_timer: TOPLEVEL:=$(MULITSHOT_TIMER_TOPLEVEL)
multishot_timer: $(MULTISHOT_TIMER_TARGET)
incrementer: OBJDIR:=$(INCREMENTER_OBJDIR)
incrementer: VERILOG_FILES:=$(INCREMENTER_VERILOG_FILES)
incrementer: TOPLEVEL:=$(INCREMENTER_TOPLEVEL)
incrementer: $(INCREMENTER_TARGET)
$(ALLTARGETS): $(TOPLEVEL) $(VERILOG_FILES)
$(VERILATOR) $(COMMONPREPARAMS) -cc $(VERILOG_FILES) --exe $(TOPLEVEL) -o $#
My actual problem is that the prerequisites of $(ALLTARGETS) is evaluated too early so that the rule never has any prerequisites.
What I want to to defer the evaluation of the prerequisites of the ALLTARGETS rule until after the evaluation of the target prerequisites, because that is the point where variables such as $(TOPLEVEL) are declared. Moreover, I want to be able to type all and then start multiple different targets, each with its own variables like $(TOPLEVEL).
A way to do this would be to create a new rule for every target in $(ALLTARGETS), but since the work for every target is exactly the same, I would like to do it with only one target. Is it possible?
You seem confused. I am confused.
multishot_timer: TOPLEVEL := $(MULITSHOT_TIMER_TOPLEVEL)
This is a target-specific variable.
${TOPLEVEL} will only have the value multishot_timer_top.cpp when make is expanding the recipe for multishot_timer, or the recipes for any of its pre-requisites. This is not the case when make expands this line:
$(ALLTARGETS): $(TOPLEVEL) $(VERILOG_FILES)
Fix? Simply make TOPLEVEL an ordinary global variable.
TOPLEVEL := $(MULITSHOT_TIMER_TOPLEVEL)
Methinks though that you have a larger pattern that you are not telling us about.
Edit
OK. Two things to manage.
Dependencies
A target can have many dependency lines, but only one of them can have a recipe.
multishot_timer: common/multishot_timer_tb.v common/multishot_timer.v
incrementer: common/incrementer.v
multishot_timer incrementer:
${VERILATOR} ${COMMONPREPARAMS} -cc $^ --exe ${TOPLEVEL} -o $#
Changing the recipe depending on target
Many options here. Here's a suggestion for the problem at hand:
Basically ${TOPLEVEL} is different depending on whether $# is multishot_timer or incrementer.
TOPLEVEL<multishot_timer> := multishot_timer_top.cpp
TOPLEVEL<incrementer> := src/incrementer_top.cpp
TOPLEVEL = ${TOPLEVEL<$#>}
Nice. Probably not worth defining TOPLEVEL (notice that =, it's important that it's a lazy variable), and just use ${TOPLEVEL<$#>} directly in the recipe.
For extra points: the list of targets
Get all the variable names of the form TOPLEVEL<%>, and remove the TOPLEVEL< prefix and > suffix.
ALLTARGETS := $(patsubst TOPLEVEL<%>,%,$(filter TOPLEVEL<%>,${.VARIABLES}))
(Notice how I reserve ${…} for variables, and $(…) for functions. I find it helps. YMMV.)
You can do this if you're using GNU make, with secondary expansion.
In your example, you would use:
.SECONDEXPANSION:
$(ALLTARGETS): $$(TOPLEVEL) $$(VERILOG_FILES)
Note the extra $ escaping in the prerequisites list.
Related
I have the following wildcard "programming" make rule that uploads a binary to a device. This obviously does not produce a real file, so should be marked phony. However, how do you mark a % percent wildcard rule phony?
%-tangnano-prog: %-tangnano.fs
openFPGALoader -b tangnano $^
.PHONY: %-tangnano-prog clean all
The phony rule does not give any error whatever you put there, so hard to tell if it worked. But I believe it did not:
$ touch blinky-tangnano-prog
$ make blinky-tangnano-prog
make: 'blinky-tangnano-prog' is up to date.
Thee are basically two possibilities:
You know in advance what %-tangnano-prog targets you can encounter. Just assign all their prefixes to a make variable, use make functions to compute the full target names and declare them as phony:
P := blinky foo bar
T := $(addsuffix -tangnano-prog,$(P))
.PHONY: tangnano-prog $(T)
tangnano-prog: $(T)
%-tangnano-prog: %-tangnano.fs
openFPGALoader -b tangnano $^
You do not know in advance what targets you can encounter. Use the same Makefile but pass the list of target prefixes to build on the command line:
$ make tangnano-prog P="blinky foo bar"
Given the following GNU Makefile:
OBJS = a.o b.o
LIB = libX.a
$(LIB): $(OBJS)
$(AR) cr $# $^
$(LIB): CPPFLAGS = $(shell P)
When I build $(LIB), I can see that external program P is called twice, once each to build a.o and b.o (I have it just printing getpid() to stderr).
In my case, P will always produce the same result, so it's wasted cycles/time having P called for creation of every .o . LIB could be made of MANY .o's of course, and the problem worse.
Is there a way to get target-specific variables to only be evaluated once, i.e evaluated for the target $(LIB) and that VALUE, verbatim, be passed to the prerequisite recipes (.o from .c)? Or am I misunderstanding their usage (I suspect that I am!)
Tried various variable assignment syntaxes, e.g. = and :=, even ::=, all by trial and error. Read the manual over and over.
Is there a way to get target-specific variables to only be evaluated once, i.e evaluated for the target $(LIB) and that VALUE, verbatim, be passed to the prerequisite recipes (.o from .c)? Or am I misunderstanding their usage (I suspect that I am!)
The docs don't seem to specify the exact semantics of when and how target-specific variables are set for building the affected target's prerequisites. Your best bet for the behavior you want was to use simple variable assignment (:= or ::=), but you say that doesn't work. make seems to be behaving as if the variable assignment were included, separately, in the rule for each prerequisite, and that makes sense because in general, there is no guarantee that the prerequisites will all be built one after another or immediately before the main target, and where they aren't all built one right after another, the variable must resume its global value between.
Really, I'd like to encourage you to minimize your use of features specific to GNU make. Every one of them is a convenience, not a necessity, though occasionally, some of them are very convenient indeed. You might consider instead deploying Autoconf +/- Automake to (semi-)dynamically insert flags into your makefile.
But if you must use $(shell) in your makefile, and you want to be certain that the command is executed only once per make run, then your best bet is probably to run it outside any rule. If you don't want to modify the global CPPFLAGS then store the result instead in some other variable:
OBJS = a.o b.o
LIB = libX.a
X_CPPFLAGS := $(shell P)
$(LIB): $(OBJS)
$(AR) cr $# $^
$(LIB): CPPFLAGS = $(X_CPPFLAGS)
I know that make usually executes the first target if called without any arguments. But what happens if the first target is a pattern rule? I have a Makefile here that looks as follows:
%.o: %.cc
gcc -c -o $# $<
main: main.o helper.o
gcc main.o helper.o -o $#
From my understanding of make, just calling it w/o any arguments should probably lead to some kind of error in this case because the first target, which is as far as I understood always the default target, does not make sense if make is not given any arguments. But when I call make with this Makefile, it instead builds the main target (and, of course, recursively the targets main.o and helper.o as well).
So, is it always true that make will ignore the pattern rules when looking for the first target? And is it somehow considered bad style to put those in front of the target that one really wants to be the default one? In my opinion, this is somehow confusing.
From the GNU make manual:
The order of rules is not significant, except for determining the
default goal: the target for make to consider, if you do not otherwise
specify one. The default goal is the target of the first rule in the
first makefile. If the first rule has multiple targets, only the first
target is taken as the default. There are two exceptions: a target
starting with a period is not a default unless it contains one or more
slashes, ‘/’, as well; and, a target that defines a pattern rule has
no effect on the default goal. (See Defining and Redefining Pattern
Rules.)
I would like to make a complete text document from several sources (since one of the file source change, I want the doc to change).
I have to pass it through a translator I develop. I would like to pass the language as argument, to make it cleaner.
Yesterday, late at night, I dreamed of a makefile like this...
#makefile
# ...
my_complete_doc.%.html: my_trans_exe header.%.html $(wildcard source/*.%.html)
$< --language $(variable_for_%) > $#
(?) Does it replace % by all the languages which have their own header.language.html files. And does the file my_completed_doc.language.html get changed as soon as one of the source/*.language.html get changed?
(?) How to get the % replaced in several prerequisites, possibly into the wildcard and necessarily in the recipe?
First, the easy problem: you wish to use the '%' variable in the recipe. The answer is to use the '$*' automatic variable:
my_complete_doc.%.html: my_trans_exe ...
$< --language $* > $#
Then the easy question: yes, the header.%.html prerequisite is correct. When you try to build my_complete_doc.dutch.html then Make will evaluate it as header.dutch.html, when you try to build my_complete_doc.french.html, Make will evaluate it as header.french.html.
Now the tricky problem: the prerequisite $(wildcard source/*.%.html). Ordinarily, Make expands $(wildcard ...) statements before executing any rule, or deciding which targets to build. So it searches for any files such as source/foo.%.html or source/bar.%.html (that is, files whose names contain the character '%'), finds none, and evaluates the statement as an empty string. But Make will defer this evaluation until it has chosen the rule, if you use SECONDEXPANSION:
.SECONDEXPANSION:
my_complete_doc.%.html: my_trans_exe header.%.html $$(wildcard source/*.%.html)
$< --language $* > $#
(Note the '$$'. In the first -- ordinary -- expansion, Make reduces "$$(...)" to "$(...)", and in the second -- when '%' has a value -- it expands "$(...)".) Now if you modify any file such as source/foo.german.html, Make will consider the file my_complete_doc.german.html out of date and in need of rebuilding.
Given this bit of Makefile:
# for pattern matching
$(OBJDIR) := build
# just to see if a level of indirection will work
my_dir = $(dir $(1))
$(OBJECTS) : $(OBJDIR)/% : $(HEADERS) $(SRCDIR)/% | % $(dir %) $(call my_dir,%)
#echo output-only = $|
This is a static pattern rule with order-only prerequisites.
Consider the target "build/utility/debug.js". The output of the above rule will be this:
output-only = utility/debug.js ./
The first component, "utility/debug.js", is properly copied from the stem (%).
The second component, "./", is the output of calling the dir function in the prerequisites list.
The third component, an empty string, is the output of calling my my_dir function in the prerequisites list.
If I change my_dir to this:
my_dir = $(1)
The output remains the same. If I change it to this:
my_dir = "foo"
Then make complains there is no rule to make "foo" (which is expected). It appears, then, that $(1) is not getting bound in the call to my_dir.
What's going on? Why can't I pass the stem to a function? I have a workaround that uses secondary expansion, but I want to know why I can't write my rule this way.
EDIT: I'm new to stackoverflow, forgive me if this is not the way things are done here.
I want $(1) because I am passing the stem as an argument to my_dir, as Alex pointed out.
I don't know why it was suggested I want "$". I don't believe $ by itself expands to anything in any context.
I know that automatic variables are only available in the recipe. I am not using an automatic variable in the prerequisites - I am using the stem:
Each target is matched against the target-pattern to extract a part of the target name, called the stem. This stem is substituted into each of the prereq-patterns to make the prerequisite names (one from each prereq-pattern). - the manual
The fact that the stem is available is demonstrated by the example: the stem expands to the correct value when used alone, but not when passed to a function.
As can be seen in this section of the GNU make manual, variable and function references in the list of prerequisites are immediately expanded, during the read in phase. This means, before any pattern matching is done, so the % has no special meaning yet; it is interpreted as a literal character in the two function references, $(dir %) and $(call my_dir,%), both having ./ as a result, which get merged in the reference to $| in the recipe.
I don't know of any other workaround than the one you already found, i.e. secondary expansion.
Note $1 is not a special variable that expands to anything interesting related to pattern rules (or static pattern rules). The $1 variable only has unique behavior within the context of a user-defined macro invoked by the $(call ...) function.
You wanted to use $*, not $1; $* is an automatic variable which expands to the stem of the target of the rule.
However, in all versions of make (including the POSIX standard definition of make), automatic variables (including $*, $<, $#, $^, etc.) are only available in the context of the recipe. They are not available in the context of the target or prerequisite lists. See the GNU make manual section on Automatic Variables for more details.
As you suggest, there is a GNU make-specific feature enabled by the .SECONDEXPANSION pseudo target which provides a way to avoid this limitation.