I've been using Makefile and to keep some stuff sepparate I decided to include a new common makefile. The problem I faced is that my First makefile looks like this:
Filename Makefile.test
include ./Makefile.a
all: a b c
b:
#echo "b"
c:
#echo "c"
Filename Makefile.a
a:
#echo "a"
When I execute my makefile: make -f Makefile.test I only get "a" printed out and it finishes.
The only way to make it work is place the include bellow (anywhere) the all: target
Is there a reason why this behaves liks this?
Thanks!
When you say this:
include ./Makefile.a
make just pulls Makefile.a into the current Makefile in the same way that #include <x.h> does in C: it inserts the contents of Makefile.a to replace the include statement and keeps going. The result is that make sees this when it starts figuring out what to do:
a:
#echo "a"
all: a b c
b:
#echo "b"
c:
#echo "c"
So the first target in source-order will be a and since you didn't specify a target, make will use the first one. That's where your result comes from.
You could explicitly specify the all target if you wanted:
make -f Makefile.test all
That would use the all target regardless of where it appears in the Makefile.
If you're using GNU Make, then you could use .DEFAULT_GOAL to specify a default target inside Makefile.test and then you wouldn't have to worry about the order:
include ./Makefile.a
all: a b c
b:
#echo "b"
c:
#echo "c"
.DEFAULT_GOAL := all
Thanks to Idelic for the reminder about this.
Related
I want to call rule inside another rule. So I tried to write the following test makefile
var = 11
a:
echo $(var)
$(eval var=22)
echo $(var)
$(MAKE) b
b:
echo $(var)
The problem is that when I run make a, the $(MAKE) b will still output 11, but I wish it should be 22. So my problem is : Is there a way to inherit variable values across different rules?
If you're in the same file, you should avoid this altogether -- stop thinking of make as some "advanced scripting tool". It is not. It's a tool for building files doing the minimum necessary work while respecting all dependencies and therefore, your job is to exactly state these dependencies using prerequisites.
Look at this example and what it does:
var = 11
printvar:
echo $(var)
setvar:
$(eval var=22)
a: printvar setvar b
b:
echo $(var)
.PHONY: a b printvar setvar
Note that none of these rules create an actual file. Normally, a rule should create its target, if it isn't, it must be listed as a prerequisite of the special target .PHONY to let make know this. This should be an exception -- the primary use of make is that it can decide whether it has to apply a rule by comparing the timestamps of the prerequisites with that of the target. A rule's recipe is only executed if there's a prerequisite that is newer than the target. With a .PHONY rule, the recipe has to be executed each and every time.
When talking about recursive make, the question would make some more sense. One easy way to pass a variable from a parent make process to a child is to export it to the environment. In your example, the following would do:
var ?= 11 # only set var if it doesn't have a value yet
export var # export var to the environment, so it's available to child make
a:
echo $(var)
$(eval var=22)
echo $(var)
$(MAKE) b
b:
echo $(var)
.PHONY: a b
Of course, this only makes sense in practice when you have different Makefiles, so not just call $(MAKE) b, but e.g. $(MAKE) -C [some subdir] b. IMHO, recursive make should be avoided as it's very hard to get the dependencies correct with recursive make. But anyways, this would work.
When you invoke make again from the recipe of a, you really launch a new make process that will parse again your makefile and thus, its first line, that assigns value 11 to variable var. Next, this second make invocation builds target b and echoes 11...
If you want to pass a variable value to a sub-make invocation you can do it on the command line with the make VAR=VALUE ... syntax. In your example, you could, for instance:
$ cat Makefile
var = 11
a:
echo $(var)
$(eval var=22)
echo $(var)
$(MAKE) var=$(var) b
b:
echo $(var)
$ make a
echo 11
11
echo 22
22
make var=22 b
make[1]: Entering directory 'foo'
echo 22
22
make[1]: Leaving directory 'foo'
It works because variables that are assigned on the command line, by default, override the definitions found in the makefile (see the make manual).
This command line assignment may look strange because it seems to assign the value of variable var to itself but it does not. It assigns the current value of variable var of the first (top) make invocation to variable var of the sub-make invocation.
Yes. IMHO you should revert the order: ‘a’ depends on ‘b’
var = 11
b:var =22
b: a
echo b:$(var)
a:
echo: a:$(var)
I'm reading a big Makefile, part of which I don't understand:
$(IREJECTION): $(IREJECTION:%$(MACH64).o=%.cpp)
$(CPP) $(CPPDLIBOPTS) -c $(#:%$(MACH64).o=%.cpp) -o $#
In this script (note that I removed unnecessary variables to avoid verbosity), what does the following mean
$(IREJECTION:%$(MACH64).o=%.cpp) (on the first line)
$(#:%$(MACH64).o=%.cpp) ? (on the second line)
Also, what does this form A: B mean? As in :
$(IREJECTION): $(IREJECTION:%$(MACH64).o=%.cpp) #on the first line
<---- A ----> <------------ B ---------------> #first instance of A: B
<--- A ----> <-------- B ------> #second instance of A: B
As you see, there are two instances of the form A:B — the second one is inside B itself. I see similar thing here as well:
$(#:%$(MACH64).o=%.cpp) #on the second line
<A> <---------B------->
Please help me understand this.
You got quite complex example I think. It has many things in it.
Rule / Recipe
A: B
<command>
A - target
B - dependency
<command> - command to be executed to build A ("Recipe")
target: dependency is called a 'rule'.
So all in all, above example is 'rule' with appropriate 'recipe'.
(to make A, which depends on B, one needs to execute <command>)
make compares modifications dates of B and A. If B is newer, then it executes <command>
Variables
$(IREJECTION) is make's variable (it should be defined somewhere before in the file, like IREJECTION:=somefile.o)
During make execution $(IREJECTION) is replaced to actual value of the variable.
Variable substitution
From link below:
$(var:a=b) <..> take the value of the variable var, replace every 'a' at the end of a word with 'b' in that value, and substitute the resulting string.
And:
For example:
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
sets bar to a.c b.c c.c.
In your case $(IREJECTION:%$(MACH64).o=%.cpp), it takes variable named IREJECTION, tries to find $(MACH64).o (which also references variable MACH64) at the end of the word and replace it with .cpp.
Automatic variable
$# is called automatic variable.
It is reference to the 'target'.
Futher reading
http://www.gnu.org/software/make/manual/make.html
A: B meant that you add a make target A that depends on B. That means when B was changed, it has to be run before A is done.
You can use the target A by calling make A.
I'll go tep by step:
lets say you have some object file irejection.mach64.o and the source file irejection.cpp
to generate object from source you typically write a rule smth like
irejection.mach64.o : irejection.cpp # means target : dependencies
$(CC) irejection.cpp -o $# # $# is a special variable - the target (output)
Now lets say $(MACH64) is .mach64 and $(IREJECTION) is irejection$(MACH64).o, ie irejection.mach64.o
$(IREJECTION:%$(MACH64).o=%.cpp) will expand to irejection.cpp
$(#:%$(MACH64).o=%.cpp) will expand to the same, since $# is $(IREJECTION)
In essence, given object file target with a architecture extensions, rewrite the file name to its source file counterpart.
Seems unncessearily convoluted to me tho. Cleaner way would be smth like:
%$(MACH64).o : %.cpp
$(CC) -c $# $<
% are "wildcards", $< is the first dependency, $# is the output
see: http://www.gnu.org/software/make/manual/make.html#Automatic-Variables
http://www.gnu.org/software/make/manual/make.html#Pattern-Rules
SUBDIRS = foo bar baz
.PHONY: dirs $(SUBDIRS)
dirs: $(SUBDIRS)
$(SUBDIRS):
#echo $#
#ls $#
Anybody can just help me out to understand this make-file?
If possible explain me each statement (why do we need it?, what is the purpose? etc.)
And how exactly this make-file works?
It have wrong formatting, so i can only guess what it was before... Well, so it is:
first line assignes list "foo bar baz" to variable named SUBDIRS
second line is special command that makes all specified targets 'phonetical' - you can invoke "make dirs" or "make foo", and it will find target with that name and execute it, but it's no actual file with this name (like usual non-phony targets)
third one - creates target named 'dirs' which depends on value of SUBDIRS variable. space-separated list. this target have no real actions
fourth line creates rules for SUBRIDS variable contents, with no dependencies. The rest of text is actions that have to be performed to 'make' this target (so, in your case - if you just call "make", it will call "make dirs" (because it's the first target), which depends on foo, bar and baz - so these targets will be invoked. to perform each of these targets, make will call echo and ls - so eventually you'll get these three directory names and list of their files)
.PHONY: b
c: a
#touch c
#echo "Changed"
a: b
b:
#date +%s > a
Running make with the sample make file causes "Changed" to be printed the 1st time it is run; but "Changed" is only printed then on the 3rd, 5th, etc execution. This is because make doesn't seem to recognize that executing the recipe for target "b" updates a.
Changing the rule with "a" as the target into an empty recipe causes "Changed" to be printed for each time make is run (as you would expect - where phony targets are always considered "out of date"). E.g.
a: b ;
Make should skip the implicit rule search for PHONY targets, but "a" is not PHONY. If no implicit rule is found for "a", is make correct to not consider that "a" may have been changed by its PHONY dependency "b"?
Make can't analyze the effects of commands, so it is the user's responsibility to organize the rules correctly.
Consider a slightly different case:
d: c b
c: a
#touch c
#echo "Changed"
a:
b:
#date +%s > a
This has the same behavior as your example; there's no way Make could be expected to know that c "really" depends on b. The author of the makefile is at fault.
Now the way it should be written:
c: a
#touch c
#echo "Changed"
.PHONY: a
a:
#date +%s > a
The a rule modifies the file a (and PHONY is there just to force the a rule to run). This is the way to tell make that the #date ... command modifies a. This makefile works correctly.
Your example is midway between these two. If a rule modifies a file which is the target of another rule, the makefile is badly organized, and Make is not at fault. Yes, Make could assume that a target that depends on a PHONY rule may have been updated when that rule is run, but it could just as well assume that any target may have been updated when any rule is run. And if Make were that paranoid, it wouldn't be very efficient.
I would like a makefile where I can call:
'make' / 'make <subdir>' / 'make clean' / 'make <subdir> clean'
But I do not want it to attempt to resolve clean when called on a subdir!
Here's an example of my makefile:
SUBDIRS := a b c
all :
#echo building a b and c
clean :
#echo cleaning a b and c
$(SUBDIRS) :
make - C $# $(MAKECMDGOALS)
All the calls work well except make <subdir> clean which calls make -C <subdir> clean, but then attempts to also resolve target clean separately. How can I get make to stop processing later targets?
To both answers:
thank you for your explanation. it is helpful to know what is and what is not meant to be done. i will not attempt this anymore.
Sigh
Yes, you can do this, but it'll be an ugly hack and totally contrary to the way Make is designed to work.
The set of targets you pass to Make is a set of targets, not a structured command with syntax. Make is expected to build them all. If the makefile includes a recipe for the target foo, then Make should build the target foo a certain way, regardless of whether it is invoked as Make foo or Make foo bar or Make bar foo. What you are attempting to do breaks the accepted behavior of Make, so you should try a different approach.
If you still wanted to do it, you could do it like this:
SUBDIRS := a b c
.PHONY: clean
ifneq ($(filter $(SUBDIRS), $(MAKECMDGOALS)),)
$(SUBDIRS) :
#echo make - C $# $(MAKECMDGOALS)
clean:
#: # do nothing
else
all :
#echo default
clean :
#echo cleaning
endif
I fully agree with Beta's statements on misusing make. Another way of achieving what you want, would be to introduce explicit targets for cleaning the subdirectories. This way, for instance, you can call make clean_<subdir>.
SUBDIRS := a b c
all:
#echo building a b and c
clean:
#echo cleaning a b and c
$(SUBDIRS):
make - C $#
$(addprefix clean_, $(SUBDIRS)): clean_%:
make -C $* clean