How can I call a specific target from my makefile? - makefile

a:
#echo 1
b:
#echo 2
c:
#if [ ! -d somefolder ]; \
then \
# how do I invoke target b here?
fi;
How can I invoke target b inside target c, based on my condition? Sort of like an antcall, if you're familiar with ant.

Just say make b

Related

Makefile ifeq always true

I have the following Makefile target:
target1:
$(eval count_abc := $(shell grep -c "ABC" myFileA))
$(eval count_def := $(shell grep -c "DEF" myFileB))
echo $(count_abc)
echo $(count_def)
ifeq ($(count_abc),$(count_def))
echo "TRUE"
else
echo "FALSE"
endif
But the output is always TRUE, e.g.:
echo 22
22
echo 21
21
echo TRUE
TRUE
What am I doing wrong here? What I want is INSIDE the target do 2 greps and compare their outputs and do something or something else based on the result. Please note that the greps must be done within the target since myFileA and myFileB get created on the target before and don't exist at the beginning when running make.
Thanks,
Amir
The rule file for "make" is declarative in nature - the makefile defines rules and targets, and then the make program evaluate the rules, and decide which action to take based on the target. As a result, execution is not always in the order the lines are entered into the file.
More specifically, the "ifeq" is evaluated at the rule definition stage, but the actions for building the target (eval count_abc ...) are executed when the target is built. As a result, when the ifeq is processed, both count_abc and count_def are still uninitialized, expanded to empty strings.
For the specific case you described - building a target that will compare the grep -c output from the two files, you can try something like below, effectively using shell variables (evaluated when target is evaluated), and not make variables (which are mostly declarative, evaluated when makefile is read)
target1:
count_abc=$(grep -c "ABC" myFileA) ; \
count_def=$(grep -c "DEF" myFileB) ; \
echo $(count_abc) ; \
echo $(count_def) ; \
if [ "$count_abc" -eq "$count_def" ] ; then echo TRUE ; else echo FALSE ; fi
Disclaimer: I did not run the revised makefile, not having access to desktop at this time.

Makefile: Running a specific target in parallel

I am learning Makefile and trying to implement parallelism. I am aware of the "-j" option. However, for example having the following makefile (on Windows)-
all: a b c d
a:
# some build rule
b:
# some build rule with parallelism
c:
# some build rule
d:
#some build rule
I am trying to run make all with only target "b" running in parallel. Passing the -j option with the build rule for "b" doesn't work. Any pointers?
You could get b's recipe to run in the background as so:
all: a b c d
#echo running $#
.PHONY: a b c d all
a c d: | b
#echo -n _$#0 && \
sleep 1 && echo -n _$#1 && \
sleep 1 && echo _$#2
b:
#(echo -n _$#0 && \
sleep 2 && echo -n _$#1 && \
sleep 2 && echo -n _$#2\
) &
Which outputs:
_b0_a0_a1_b1_a2
_c0_c1_b2_c2
_d0_d1_d2
running all
The order-only dependency on b makes b run first, otherwise it wouldn't start until after a completes with -j1... It does of course mean that you have to build b if you build either a c or d.
Alternatively, (and I'm not recommending this) you could use some manual locking mechanism such as flock to prevent a, c, and d from running in parallel (note that the flock only protects a single shell, so you would have to collapse your recipes into a single line protected by flock for this to work).

Can you prioritize makefile targets?

I have a very large and convoluted make system that takes hours to complete. I'm researching potential optimizations, and I had a question on whether it is possible to prioritize certain targets.
Here's a sample of a simple Makefile that illustrates the concept:
Test%: Prog%
#run some post build verification on Prog{n}
# -- takes 30min or less on failure...
Prog1: A B
# do some linking
Prog2: B C
# do some linking
A B C:
# take 10 minutes each
And then I run
make -j2 Prog1 Test2
Then the fastest way to build this would be: B & C, followed by Prog2 & A, followed by Test2 and Prog2. Of course, typically, make would build A and B first, which would delay my final output by 10 minutes.
If I have foreknowledge that Test2 is going to be a bottleneck, is it possible to prioritize that target and all its dependencies over other targets in gnu make?
To add to the question, Let's say I'm building Test1, Test2 ... Test20. Then in that case, I'd like one of the targets -- say Test1 to be completed as soon as possible, as if it that fails, I would like to know as soon as possible so I can terminate the build and let someone else use the build machine.
I considered doing separate instances of make as so:
make Test2 && make Prog1
But, while the test is building, then Prog1 will not be building, resulting in wasted cycles on the build server. If I tried to build them in parrallel with priorities:
`make Test2; nice -n -10 make Prog1`
This could result in race conditions when building B.
I've not yet found any good solutions, but I thought I'd ask on in-case I missed something. (Also, I'm not sure if this should be on SO or SuperUser -- I chose here as it's technically about 'programming', but please feel free to correct me and I can move it).
GNU make offers no syntax to add a weight to a target. I.e. when make is able to start the next job and the independent(!) targets A and B are unblocked (all their dependencies have been fulfilled) and require remaking, then it depends on their order in the internal make database which one gets selected first for execution.
But you could use additional dependencies to achieve your goal. To take the example from your question:
TESTS := Test1 Test2
$(TESTS): Test%: Prog%
Prog1: A B
Prog2: B C
ifdef _PRIORITIZE_TEST2
# additional dependencies to make sure Prog2 -> Test2 is prioritized
A: B C
endif
A B C Prog1 Prog2 Test1 Test2 all:
#echo $#
.PHONY: A B C Prog1 Prog2 $(TESTS) all
Test runs:
$ make --trace -j10 Prog1 Test2
Makefile:13: target 'A' does not exist
echo A
Makefile:13: target 'B' does not exist
echo B
Makefile:13: target 'C' does not exist
echo C
A
B
C
Makefile:13: update target 'Prog1' due to: A B
echo Prog1
Makefile:13: update target 'Prog2' due to: B C
echo Prog2
Prog1
Prog2
Makefile:13: update target 'Test2' due to: Prog2
echo Test2
Test2
$ make --trace -j10 _PRIORITIZE_TEST2=1 Prog1 Test2
Makefile:13: target 'B' does not exist
echo B
Makefile:13: target 'C' does not exist
echo C
B
C
Makefile:13: update target 'A' due to: B C
echo A
Makefile:13: update target 'Prog2' due to: B C
echo Prog2
A
Makefile:13: update target 'Prog1' due to: A B
echo Prog1
Prog2
Makefile:13: update target 'Test2' due to: Prog2
echo Test2
Prog1
Test2
This will probably involve a lot of hand-crafting to get the result you want. You might even need to write different sets of additional dependencies to cover different make invocation scenarios.
You could look into dumping the GNU make database (make --no-builtin-rules --print-data-base), parsing it to extract all targets & their dependencies and visualizing the resulting graph. Here is an example how to generate a directed graph in the DOT language of Graphviz:
#!/usr/bin/perl
use warnings;
use strict;
BEGIN {
print "digraph build\n";
print "{\n";
}
my $default_goal = '???';
my #goals;
while (<STDIN>) {
if (my($target, $dependencies) = /^([\w_-]+):\s+(.*)/) {
#print "Node ${target}\n";
print " $_ -> ${target}\n"
for (split(' ', $dependencies));
} elsif (my($goals) = /^MAKECMDGOALS :=\s+(.+)/) {
#goals = split(' ', $goals);
} elsif (my($goal) = /^\.DEFAULT_GOAL :=\s+(.+)/) {
$default_goal = $goal;
}
}
END {
#goals = ( $default_goal )
unless (#goals);
#print "Root $_\n"
# for (#goals);
print "}\n";
}
exit 0;
For the above example that would result in:
$ make -n --no-builtin-rules --print-data-base Prog1 Test2 2>&1 | perl dummy.pl
digraph build
{
A -> Prog1
B -> Prog1
Prog1 -> Test1
B -> Prog2
C -> Prog2
Prog2 -> Test2
}

What is the meaning of a variable defined on the same line of a rule targets prerequisites such as "a: x = 0" in GNU Make?

I have seen code like the following following code in a Makefile:
a: x = 0
What does this line mean? Is it a rule, or something else?
That is called a target specific variable, see: https://www.gnu.org/software/make/manual/html_node/Target_002dspecific.html
It gives a different value to a variable inside a given target.
Sample usage:
x := 0
a: x := 1
a:
#echo $x
b:
#echo $x
Now:
$ make a
1
$ make b
0

GNU override target?

I'm wondering if it's possible to override a target in a makefile! The environment I'm working in does not allow me to do this due to auto generation! I was wondering if I coded the same rule above or below the static target would this achieve an override?
%_emul.flist: $(if ${GEN_FLIST},%_synth.flist,) ${rdlh_file_deps}
${QUIET}if test ${SYN_DEBUG} -eq 1 ; then set -xv ; fi; \
$(if ${TOOL_VERILOG},rm -f $#; touch $#,$(if ${TOOL_BBOX_LIBS},echo ${TOOL_BBOX_LIBS} > $#,rm -f $#; touch $#))
/bin/sed -e '/\/libs\//d' -e '/\/place\//d' $(foreach mod,$(filter %.vhd,$^),-e 's%^\(.*\/\)\{0,1\}$(basename $(notdir ${mod}))\.v$$%${mod}%') $*_synth.flist >> $#
Yes , i think that would work .... but you need to be a bit more careful in the way you code things. You don't want to override something that might be useful!
GNU make would take the most recent of the target it encounters. So, the following works (but not as i would have liked it to work :( )
Output: I think you are looking for something like this --
Kaizen ~/make_prac $ make -nf mk.name
mk.name:20: warning: overriding recipe for target `name'
mk.name:17: warning: ignoring old recipe for target `name'
arg1="Kaizen" ;
echo "hello "" ;" ;
hello ;
Code: Here the target "name" appears twice and is overridden.
Kaizen ~/make_prac $ cat mk.name
##
## make to accept name and display hello name
##
arg1="" ;
.PHONY : name \
hello
#.DEFAULT :
# hello
hello : name
+ echo "hello $(arg1)" ;
name :
echo "name given is : $(arg1)" ;
name :
arg1="Kaizen" ;
PS: Take note of the use of : -- if you use :: then both rules get executed.
Explanation for the arg1 .... not showing in the output: The variable arg1, even though it gets assigned in the first parsing, it gets ignored, since its assignment is target dependent. If you would have had a variable declaration elsewhere -- e.g. like arg1 is defined at the start -- there would not be any dereferencing issues.

Resources