Path dependency in Makefile - makefile

Here is two targets in my Makefile.
.SECONDARY:
exp-%.ans:
echo $* > eval/$#
%.scores: %.ans
cat eval/$< > eval/$#
When I write make -n exp-40.scores output would be:
echo 40 > eval/exp-40.ans
cat eval/exp-40.ans > eval/exp-40.scores
which is good except one thing. It does not aware of the dependency is already hold. If I create eval/exp-40.scores (first time) then I expect that make will say it is already in there if I run the same command. So I try to change my Makefile like this:
.SECONDARY:
exp-%.ans:
echo $* > eval/$#
%.scores: eval/%.ans
cat eval/$< > $#
When I write make -n exp-40.scores again and output would be:
echo eval/40 > eval/eval/exp-40.ans
cat eval/eval/exp-40.ans > exp-40.scores
which is completely wrong because my parameter should be 40 not eval/40.
How can I achieve the best of the these two worlds? Namely, I want to create *.scores in eval/ folder. I also want make to check whether file is already exist or not. Then make should proceed according to that file existence.
Thanks.

One of the core rules of make is that you need to build the target your rule told make that you'd build. A rule like foo : bar tells make that if it runs that recipe, the recipe will create or update a file named foo. If the recipe creates or updates a file named biz/foo instead, then your makefile is wrong and things will not work.
Make always puts the target it expects the recipe to create into the $# automatic variable. Your recipe should create or update $# and exactly $#. Not something else.
So in your case, you need to write:
eval/exp-%.ans:
echo $* > $#
eval/%.scores: eval/%.ans
cat $< > $#
If you want to be able to run make exp-40.scores and have it actually create eval/exp-40.scores, then you can add a rule like this:
%.scores: eval/%.scores ; #:
(you have to provide some kind of recipe for pattern rules, they cannot have an empty recipe; the one above does nothing).

Related

Use % pattern in variable name

I'm trying to write a Makefile that uses the same recipe for several variables. The variables are grouped into several lots which need to be built separately but with the same method.
In the example below, I want to be able to build output1.txt, output2.txt etc. using the same recipe. The catch is that each of these relies on the corresponding variable $(target1), $(target2) etc. I've tried to use the % pattern to expand these variables but that didn't work because % is expanded last.
I have found that I can modify variable calls using recursive variables, eg. $($(subst 0,$(N),target0)). However, this cannot be done unless the number is already known.
Is there a simple way to do this?
target1:=a_5_2 a_3_5 a_6_2 a_0_0 a_9_1
target2:=a_2_2 a_1_3 a_5_9 a_2_7 a_3_6
target3:=a_2_3 a_6_5 a_9_0 a_3_4 a_3_9
target4:=a_7_8 a_8_2 a_4_8 a_7_1 a_0_7
output%.txt: $($(subst 0,%,target0))
cat $^ > $# # do some actual stuff here
You can do this with secondary expansion:
.SECONDEXPANSION:
output%.txt: $$(target$$*)
...
Of course, you could also just change the variables to be prerequisite settings instead; it's about the same amount of typing:
output1.txt : a_5_2 a_3_5 a_6_2 a_0_0 a_9_1
output2.txt : a_2_2 a_1_3 a_5_9 a_2_7 a_3_6
output3.txt : a_2_3 a_6_5 a_9_0 a_3_4 a_3_9
output4.txt : a_7_8 a_8_2 a_4_8 a_7_1 a_0_7
output%.txt:
cat $^ > $# # do some actual stuff here

Issue with Makefile target rule and PHONY

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)

How to build make dependency when the target name is not the file name

I am trying to write a very simple Makefile which I can't make it to work as I expect.
target_a : file.txt
echo "this is target_a"
touch 0_$#
target_b : 0_target_a
echo "executing target_b"
touch 0_$#
Whenever I run make taget_b it gives out an error:
make: *** No rule to make target '0_target_a', needed by 'target_b'. Stop.
I can just change touch 0_$# to touch $#. But I really want a solution for touch 0_$# (a free choice of filename).
From GNU-man page ftp://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_2.html
A target is usually the name of a file that is generated by a program; examples of targets are executable or object files. A target can also be the name of an action to carry out
I want to know how to build the Make dependency when the target name is an:
Action
I am afraid you cannot directly do just that and you'd have to help yourself with an intermediate target that makes the connection between target and its output clear (and hence gives make a chance to decide when it does or does not need to be remade:
0_target_a: file.txt
echo "this is target_a"
touch $#
target_b: 0_target_a
echo "executing target_b"
touch 0_$#
I.e. defining rule for target 0_target_a and updating touch accordingly will give you the behavior you wanted as make now understand the rule the connection between target and file 0_target_a and know when it does not need to be remade as a dependency of target_b. Now if you still want to also have a standalone target_a that would generate file 0_target_a, you can define it as follows:
target_a: 0_target_a
Since we know this target is not really creating a file itself, we can spare make a little effort looking for its result (target_a) and also prevent clashes should such file be created by declaring it as phony.
As a matter of fact you may want to give your target_b the same treatment, as otherwise (again make does not have enough information to understand the relation between target_b and 0_target_b) make target_b is always remade even though the file has already been generated.
The whole make file would look like this:
.PHONY: target_a target_b
target_a: 0_target_a
target_b: 0_target_b
0_target_a: file.txt
echo "this is target_a"
touch $#
0_target_b: 0_target_a
echo "executing target_b"
touch $#
If that is a reoccurring theme throughout the file, you could also express the relation on second and third line by defining a static pattern rule:
target_a target_b: %: 0_%
This defines a rule that a any target (first '%' without anything else) has a prerequisite of 0_ prefix followed by that target name (0_%, 0_ plus stem which in this case is a target name in its entirety as matched by previous %). and makes this rule applicable to targets target_a and target_a. This rule has no recipe and hence only describe target/prerequisite relation between the two.
In other words it means the same thing as the full example lines 2 and 3 combined.
The dependency of target_b should be a valid target itself, or a file which already exists
target_a : file.txt
echo "this is target_a"
touch 0_$#
target_b : target_a
echo "executing target_b"
touch 0_$#
if you want to "alias" creation of 0_target_a file to the target_a "action" you can add intermediate rule:
0_target_a : file.txt
echo "creating 0_target_a"
touch 0_$#
target_a : 0_target_a
target_b : target_a
echo "executing target_b"
touch 0_$#

Makefile: Declaring dependencies between included files

Using make's ''Remaking Makefiles'' feature I am generating parts of my makefile with include directives (see Makefile: defining rules and prerequisites in recipes). Now I'm stuck with being unable to see how I can express dependencies between included makefiles. They seem to be all evaluated at once.
Consider the following minimal makefile that illustrates my problem:
all:
-include foo.make
-include bar.make
foo.make: Makefile
echo FOO:=blub bla baz > foo.make
bar.make: Makefile foo.make
echo BAR:=$(FOO) > bar.make
If I now run make I will get:
$ cat foo.make
FOO:=blub bla baz
$ cat bar.make
BAR:=
Why? Since bar.make depends on foo.make, shouldn't the evaluation of bar.make wait until it successfully included foo.make?
And how do I fix this problem and make sure that bar.make is either re-evaluated later or only evaluated once foo.make exists, is included and can define the variable BAR?
The reason I cannot combine foo.make and bar.make into a single makefile and rule is two-fold:
Firstly, in my real setup, bar.make depends on more intermediate targets which in turn transitively depend on foo.make. So at the time foo.make can be created, the content of bar.make cannot yet be made.
Secondly, in my real setup, foo.make and bar.make do not just define variables but also eval() define/endef blocks. So I have to write:
-include makefile_with_prerequisite_variables
define MYDEF
sometarget-$1: $(TARGET_$1_PREREQUISITES)
[...]
endf
-include makefile_with_eval_call_statements
The content of makefile_with_prerequisite_variables and makefile_with_eval_call_statements cannot go into a single makefile snippet:
If I would put makefile_with_eval_call_statements above MYDEF together with makefile_with_prerequisite_variables then the $eval( $call( MYDEF)) statements in it would not work because MYDEF is only declared afterward.
If I would put makefile_with_prerequisite_variables below MYDEF together with makefile_with_eval_call_statements then the recipes defined in MYDEF would not have proper prerequisits because the $(TARGET_$1_PREREQUISITES) variables would then be declared afterward by makefile_with_prerequisite_variables.
In summary, I need to include two different makefiles where one depends upon the other. I do not know how I can express this relationship such that the content of one makefile would only be created after the other makefile is up-to-date and included into the main makefile.
First, your makefile creation in this simple example can easily be fixed by escaping the value of $(FOO) so that it's not expanded when bar.make is created but rather deferred until it's read in. So:
bar.make: Makefile foo.make
echo 'BAR:=$$(FOO)' > $#
However, that might not be sufficient in your more complex real-life makefiles.
GNU make works like this: first parse all the makefiles. Then for every included makefile, treat it as a goal and try to build it (e.g., act as if the user invoked make include1.mk include2.mk include3.mk ...). Then at the end of that, if any of the included makefiles was rebuilt, re-exec ourselves and start the entire process over from scratch.
GNU make does NOT work like this: parse makefiles, try to rebuild the first included makefile and if it's rebuilt, re-exec; if it's not rebuilt go on to the next included makefile, etc.
A simple trick you can use if you have to have this type of order is to put the include of bar.make into foo.make:
all:
-include foo.make
foo.make: Makefile
printf -- '-include bar.make' > $#
echo FOO:=blub bla baz >> $#
bar.make: Makefile foo.make
echo 'BAR:=$$(FOO)' > $#
By doing this you ensure that if foo.make doesn't exist, make can't see the include of bar.make and so it won't try to build it. Only after the first re-exec will make see the include of bar.make and try to build it.
One thing: if you get the latest version of GNU make you no longer need to use the -include trick. You can just use include even with generated makefiles.

Auto delete hook in GNU Make

By default make authomatically deletes targets when they are not needed anymore.
For example:
do_it: write_bar write_baz
echo done > $#
.INTERMEDIATE: write_foo write_bar write_baz
write_foo:
echo foo > $#
write_bar: write_foo
cat $< > $#
echo bar >> $#
write_baz: write_foo
echo buz > $#
Here write_foo will be deleted after execution of both write_bar and write_baz.
I want not to simply remove file, but to do some actions just before write_foo deleted.
Can I change command for auto deletion or assign any hook for this action?
Update: autodeletion is applicable only for intermediate rules.
make (at least GNU Make) does not automatically delete successfully built targets (it does delete target if make was killed).
.DEFAULT does not do what you expect it to do. See https://www.gnu.org/software/make/manual/html_node/Special-Targets.html
Invoking make on command line executes first target. Since your first target is write_foo, only write_foo will be executed.
If you invoke make do_it, all targets will be executed (and 3 files will appear in current directory).
Added after question update:
According to https://www.gnu.org/software/make/manual/html_node/Special-Targets.html, including intermediate target in prerequisites for .PRECIOUS special target prevents deleting it.

Resources