Simply put I want to give a name to a rule in my Makefile:
A.ext : B.ext
compute A.ext from B.ext
so that I get something like this:
.PHONY : my_rule
A.ext : my_rule
my_rule : B.ext
compute A.ext from B.ext
But this is not yet equivalent to the first, since my_rule is always executed even if B.ext hasn't changed. How can I achieve equivalence?
This is the trimmed output of make -d:
Considering target file `A.ext'.
Considering target file `my_rule'.
File `my_rule' does not exist.
Considering target file `B.ext'.
Finished prerequisites of target file `B.ext'.
No need to remake target `B.ext'.
Finished prerequisites of target file `my_rule'.
Must remake target `my_rule'.
(The reason I want this is that I have another rule C.ext :| my_rule.)
.PHONY : my_rule
my_rule: A.ext
A.ext : B.ext
compute A.ext from B.ext
Or better:
.PHONY : my_rule
my_rule: A.ext
A.ext : B.ext
compute $# from $<
Related
Hopefully this is a very simple question. I have a makefile pattern rule that looks like this:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
I want the makefile to build a number of .so files, so I tried to get it to build two files (radgrd_py.so and lodiso_py.so) by doing this:
radgrd_py.so lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
and then tried this:
radgrd_py.so:
lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
But in each case, it only builds the first target that I specify. If I run 'make radgrd_py.so' it works fine, I'm just not sure how to specify a list of files that need to be built so I can just run 'make'.
The usual trick is to add a 'dummy' target as the first that depends on all targets you want to build when running a plain make:
all: radgrd_py.so lodiso_py.so
It is a convention to call this target 'all' or 'default'. For extra correctness, let make know that this is not a real file by adding this line to your Makefile:
.PHONY: all
Best way is to add:
.PHONY: all
.DEFAULT: all
all: radgrd_py.so lodiso_py.so
Explanations:
make uses the first target appearing when no .DEFAULT is specified.
.PHONY informs make that the targets (a coma-separated list, in fact) don't create any file or folder.
all: as proposed by schot
I am trying to understand how makefiles work. If I try the following
1.out : 1.inp
cat 1.inp
it, works as expected (if 1.inp is newer as 1.out or if 1.out does not exist, the content of 1.inp is printed).
Then I need to do the following:
cat 1.inp
cat 2.inp
cat 3.inp
I thought that for that I can use
%.out : %.inp
cat $<
but it does not work. Can anybody please explain to me the use of %?
In your first makefile:
1.out: 1.inp
cat 1.inp
1.out is a target with a prerequisite 1.inp and a command cat 1.inp. This constitutes a rule for
making 1.out and if you run the makefile, specifying either no explicit target or the target 1.out, the
rule will be executed.
In your second makefile:
%.out: %.inp
cat $<
you have only expressed a pattern rule for making a target of the form something.out from a prerequisite of the form something.inp You have not specified any actual targets that the makefile can make.
You can specify 1.out as a target with a makefile like this:
%.out: %.inp
cat $<
1.out:
In that case 1.inp will be cat-ed when 1.inp is newer that 1.out
Or you can specify a phony target, e.g. all, that has prerequisite targets 1.out, 2.out, 3.out in a makefile like this:
.PHONY: all
%.out: %.inp
cat $<
all: 1.out 2.out 3.out
In this case each of 1.inp, 2.inp and 3.inp will be cat-ed when it is newer than the corresponding .out file.
Whenever make discovers that it has to make a target of the form something.out, it will recognize that the pattern rule is applicable and will execute the matching instance of the pattern rule.
Is it possible to add a prerequisite if another file is found in the workspace? Or how else could I achieve the following idea? Basically if my workspace has a lcf file in a specific location I need to make another file.. Something like this:
lcf := ../base_sw/lcf/base.lcf
.PHONY :
all : $(objects)
# if $(lcf) file exists then
all : $(objects) sup.a2l
sup.a2l :
# Perl script runs here to produce sup.a2l
#echo Chris > $#
This should do it:
lcf := $(wildcard ../base_sw/lcf/base.lcf)
.PHONY :
all : $(objects) $(lcf)
Think I've managed to answer this one myself!
The wildcard function returns nothing if lcf file does not exist:
lcf := $(wildcard ../base_sw/lcf/base.lcf)
Start to build the files that need making:
make_these_file := $(obejcts)
If lcf variable is not empty, append to files list:
ifneq ($(lcf),)
make_these_file += sup.a2l
endif
Now our target with files required to make:
.PHONY :
all : $(make_these_file)
sup.a2l :
# Perl script here to produce sup.a2l
#echo Chris > $#
Works for me :)
BUILT_DIR = /tmp/obj
SRC = /source/dir
/tmp/obj/%/builtin.o : $(SRC)/%/*.c
gcc $^ -o $#
But you know :
In order for the pattern rule to apply, its target pattern must match the file name under consideration and all of its prerequisites (after pattern substitution) must name files that exist or can be made.
If i execute make /tmp/obj/hfa/builtin.o,make will complain :
make: *** No rule to make target/tmp/obj/hfa/builtin.o'. Stop.`
How can i modify the Makefile to satisfy my requirement?
You can use Secondary Expansion
BUILT_DIR = /tmp/obj
SRC = /source/dir
.SECONDEXPANSION:
/tmp/obj/%/builtin.o : $$(wildcard $(SRC)/%/*.c)
gcc $^ -o $#
The error you see indicates that there are no .c files which match the pattern $(SRC)/hfa/*.c since the % translates into hfa. So make cannot use the rule you've defined.
Make then starts to use the implicit rules for building and it would not match either.
Finally make gives up.
I just confirmed that the same Makefile and I get the same error only when there are no *.c files in the $(SRC)/hfa directory.
Otherwise, I see the gcc command getting executed.
And from your question, it is not quite clear what your requirement is.
The rule configuration that worked for me:
bar-%-foo:
#touch $#
.SECONDEXPANSION:
foo-%-bar: bar-$$*-foo
#echo "#: $#"
#echo "<: $<"
#touch $#
foo-bar: foo-biz-bar foo-baz-bar
.PHONY: foo-bar
And demo:
$:make foo-bar
#: foo-biz-bar
<: bar-biz-foo
#: foo-baz-bar
<: bar-baz-foo
rm bar-biz-foo bar-baz-foo
$:ls | grep foo
foo-baz-bar
foo-biz-bar
I'm trying to get GNU make to produce multiple outputs from a single input. The most simple example I can demonstrate is:
a b : test
cp $< $#
which, I believe, should copy the file test to the files name a and b. However, it only makes the file a, which seems to me to be contrary to the instructions listed here:
http://www.gnu.org/software/automake/manual/make/Multiple-Targets.html
Am I doing something wrong?
Thanks,
Tom
If you run a rule that depends on a, it will run your rule with $< as test and $# as a. If you run a rule that depends on b, $# will be b instead. If you make a rule above your current rule like:
all: a b
It will run the rules for a and b, which is that same rule twice. Otherwise, if your rule is the first in the file it will run it with the first target only, which is a
A small clarification to #MichaelMrozek's answer.
This:
a b : test
cp $< $#
Is exactly the same as:
a : test
cp $< $#
b : test
cp $< $#
a is the first target in the file, so it's the default target. Only the rule for a runs, since there's no dependency on b.
Like #MichaelMrozek said, you can add another rule, or you can run
make a b
Everything is OK. The manual says :
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$#) > $#
is equivalent to
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
So your Makefile is also equivalent to
a : test
cp $< $#
b : test
cp $< $#
and when you'd entered the command 'make', the program defaulted to build the first target, i.e. 'a'.