variable definition ignored in makefile - makefile

From the docs:
There is one more special feature of target-specific variables: when
you define a target-specific variable that variable value is also in
effect for all prerequisites of this target, and all their
prerequisites, etc. (unless those prerequisites override that variable
with their own target-specific variable value).
Trying the following makefile:
all::
#: '$#'
all:: dep;
dep:
echo target is: $(target)
all : target = all
.PHONY: all dep
And runing:
$ make -j
I get:
echo target is:
target is:
Where did the definition target = all go?

If you run make instead of make -j the output is
echo target is: all
target is: all
I don't know why you need to specify -j but my initial guess is that by providing -j make is executing each all recipe as a separate job and thus the variable target = all is not set in the same job that runs
all:: dep;
dep:
echo target is: $(target)
hence why $target is empty and the output is
echo target is:
target is:

Related

Why does makefile lazy evaluation find a file in a "parent" recipe but not the current one?

This question is a follow-up to What makefile lazy evaluation rule governs this behavior?. I'm still trying to grok some of the rules of gnu make's lazy evaluation.
I want to have a make variable for the content of a directory after that directory has been updated by a recipe.
This Makefile demonstrates that $(A_FILE) is evaluated to find the created file when it's in the "parent" of the recipe that actually creates the file:
A_FILE = $(wildcard subdir/*)
all: a
#echo $(A_FILE)
a:
#mkdir ./subdir
#touch subdir/b
$ rm -rf ./subdir/ && make
subdir/b
$
But the following Makefile has a seemingly trivial change: $(A_FILE) is referenced in the recipe where its containing directory is updated - but now the variable is empty:
A_FILE = $(wildcard subdir/*)
all: a
#echo $(A_FILE)
a:
#mkdir ./subdir
#touch subdir/b
#sleep 1
#echo $(A_FILE)
$ rm -rf ./subdir/ && make
$
I added the sleep to rule out timing issues of the directory being trawled too quickly after it had been updated.
What gives? Why does $(A_FILE) get evaluated against the updated subdir content if it's referenced in the higher-layer recipe but not in the lower-layer recipe where it's actually updated?
GNU make evaluates all lines in the recipe before it starts running any line in the recipe. So, when it is getting ready to run your recipe for the rule a it first expands all the lines, including the last line with $(A_FILE) in it. At that point no parts of the recipe have been run yet so the result is empty.
Then after all the expansion, the shell is invoked to run the lines in the recipe.

How to determine if Make target is a PHONY?

I have a make target that depends on a variable, which contains both PHONY and real targets.
This target needs to depend only on the real targets in the variable.
How can I test a variable to determine if it is a PHONY or not, so I can filter them out?
(I can test for a file's existence inside the recipe, but I don't want my target to be triggered by execution of any of the PHONY targets.)
Thanks!
There is a way to do it, but I would strongly recommend against it. First of, phony targets can be also file targets. And there is no way to tell a phony file target from a non-phony file target.
It looks like the question implies that the phony targets the author wants to ignore are all non-file targets. In this case see the example below.
.PHONY: phony_target .FORCE
.FORCE:
ALL_TARGETS = phony_target file_target undetermined_target
-include detect_phony.inc
all: final_target
# All done
final_target: $(REAL_TARGETS)
# create $# triggered by $?
#touch $#
ifeq (,$(MAKE_RESTARTS))
# Generate the list of real file targets in make include file
detect_phony.inc: .FORCE
#echo 'REAL_TARGETS = ' `ls $(ALL_TARGETS) 2>/dev/null` > $# |:
endif
file_target:
touch $#
undetermined_target phony_target:
# process $#
clean:
rm -f file_target final_target
Here are the test results:
$make clean
rm -f file_target final_target
$ make
# create final_target triggered by
# All done
$ touch file_target
$ make
# create final_target triggered by file_target
# All done
$ make
# All done
As you can see it only triggers the final target when the file target is updated.
Before you criticize - Here are the flaws of this implementation:
make is always called twice, updating the generated detect_phony.inc include file at every run
if detect_phony.inc gets corrupted somehow, make execution will be locked by syntax errors, until you manually delete it.
it can't handle phony file targets as I mentioned before
if another generated include is added in this makefile that requires another restart before detect_phony.inc this functionality will break.
So it this method is hacky and has several gotchas. I would not use it in production environment. I would insist on changing the top level Makefile first.

GNU make wildcard variable target

I'm trying to create a makefile with wildcard targets but the wildcards should match on variables.
So I have a makefile like this:
A_OUT := bin/a
B_OUT := bin/b
# This does not work
$(%_OUT):
#echo $#
Output:
$ make bin/a
make: *** No rule to make target 'bin/a'. Stop.
I can not use bin/%: because the variables may point to another directory.
Is there any way to do this in GNU make?
If you just want a list of targets to all have the same recipe then just list them all in the same rule definition. e.g.
$(A_OUT) $(B_OUT):
#echo $#
You can use a variable for that too:
A_OUT := bin/a
TGTS += $(A_OUT)
B_OUT := bin/b
TGTS += $(B_OUT)
$(TGTS):
#echo $#
Depending on what you need you may also want to use Static Pattern Rules
$(TGTS) : bin/% :
#echo $# : $*

How to pass down option -f SomeMakefile to a sub-make? [here with GNUMake]

When invoking itself recursively via some $(MAKE) foo in recipes, GNUMake passes down some of the options it was called with, but not all of them. In particular it does not pass down a -f SomeMakefile option. See section 5.7.3 of manual.
How can I find whether make was invoked with some -f option and how can I pass it down to a sub-make ?
To make the question concrete, here is what my SomeMakefile contains:
%.pdf : %.tex
pdflatex $(PDFLATEXFLAGS) $*
#if [ -f $*.log ] ; then $(MAKE) --silent $*.slw; fi
The problem is that how to make foo.slw is defined in SomeMakefile and the recursive make won't use it.
You can get the name of the makefile from MAKEFILE_LIST variable. E.g.:
${MAKE} -f $(lastword $(MAKEFILE_LIST))
If your makefile includes other makefiles you may like to store the name of the makefile early into an immediately assigned variable, e.g.:
# Somewhere at the top of your makefile, before any includes
this_makefile := $(lastword ${MAKEFILE_LIST})
# and use it later
some_rule :
${MAKE} -f ${this_makefile}
Alternatively, if you know that your makefile is always the first one read by make, then it is going to be in the front of MAKEFILE_LIST, e.g. $(firstword ${MAKEFILE_LIST}).

Why does this makefile target specific variable not expand as expected?

I have the following simplified makefile and I'm trying to set different paths based on different targets. Unfortunately, I'm not getting the results that I expect. This is with make version 3.81.
.SECONDEXPANSION:
all: Debug32
# Object directory set by target
Debug32: OBJDIR = objdir32
#OBJDIR = wrongdirectory
# ObjDir is empty here. :(
OBJS = $(addprefix $(OBJDIR)/,DirUtil.o)
$(OBJDIR)/%.o : %.cpp
echo Compile: $#
Debug32: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
echo mkdir $(OBJDIR) - $#
The results are as follows with no setting of OBJDIR:
echo Compile: /DirUtil.o
If I uncomment the "OBJDIR = wrongdirectory" line, I'll get the following results, which are confusing since I see both values of the variable where I think I should only see one:
echo mkdir objdir32 - wrongdirectory -
echo Compile: wrongdirectory/DirUtil.o
I'm assuming that the variables are not being expanded when I think they should, but I can't figure out how to alter this behavior.
From the GNU info manual
Variables and functions in all parts of a makefile are expanded when
read, except for in recipes, the right-hand sides of variable
definitions using '=', and the bodies of variable definitions using
the 'define' directive.
The target-specific variable only applies within recipes. Within
$(OBJS): | $(OBJDIR)
and
$(OBJDIR):
it is getting the global variable.
So working through what happens when you run make Debug32, it sees the contents of OBJS as a prerequisite, which leads to the first rule above. $(OBJDIR) has already been substituted with the global value, and this matches the target-name in the second rule which has also been substituted the same way.
However, when we get to the recipe:
echo mkdir $(OBJDIR) - $#
$(OBJDIR) has not been substituted yet, so it gets the target-specific variable value.
A working version
.SECONDEXPANSION:
all: Debug32
# Object directory set by target
Debug32: OBJDIR = objdir32
OBJDIR = wrongdirectory
Debug32: OBJS = $(addprefix $(OBJDIR)/,obj.o)
OBJS = wrongobjs
Debug32: $$(OBJS)
echo OBJS are $(OBJS)
echo OBJDIR is $(OBJDIR)
%/obj.o: | %
touch $#
OBJDIRS = objdir32 wrongdirectory anotherdirectory
$(OBJDIRS):
# mkdir $(OBJDIR)
mkdir $#
The main change is using $$ in this line:
Debug32: $$(OBJS)
With only a single $, I get the error message
make: *** No rule to make target `wrongobjs', needed by `Debug32'. Stop.
However, with the $$, I get
echo OBJS are objdir32/obj.o
OBJS are objdir32/obj.o
echo OBJDIR is objdir32
OBJDIR is objdir32
The use of secondary expansion has allowed accessing the target-specific variable in the prerequisites.
The other change is that I made OBJS a target-specific variable (because it is). In order to have a rule to build OBJS whatever its value, I had to use a pattern rule:
%/obj.o: | %
To avoid having a separate line for each object file, you could do the following instead:
OBJ_BASENAMES=obj.o obj2.o obj3.o
$(addprefix %/,$(OBJ_BASENAMES)): | %
touch $# # Replace with the proper recipe
The line containing the addprefix macro expands to
%/obj.o %/obj2.o %/obj3.o: | %
Then running make anotherdirectory/obj2.o creates a directory called "anotherdirectory" first, and creates a file called "obj2.o" within it.
Note all possible directories have to be listed in OBJDIRS. There's no way to collect all the rule-specific values of OBJDIR, so listing them is the best choice. The alternative is a % : rule to build any directory, which be capable of matching and building any target, which could be risky. (If you abandon the use of target-specific variables, there is another way of getting a list of directories that could be built: use variables with predictable names like Debug32_OBJDIR instead, and generate a list of their values using make functions.)
Alternatively, a generic rule that doesn't require listing the object files:
SOURCE=$(basename $(notdir $#)).cpp
DIR=$(patsubst %/,%,$(dir $#))
%.o: $$(SOURCE) | $$(DIR)
touch $# # Replace with proper recipe
There is no feature to read a rule in the context of every target, substituting in target-specific variables and acquiring a new rule for each target. Generic rules cannot be written in this way using target-specific variables.
a good way to handle
%/obj.o: | %
touch $#
OBJDIRS = objdir32 wrongdirectory anotherdirectory
$(OBJDIRS):
mkdir $#
is:
%/.:
mkdir -p $#
.SECONDEXPANSION:
then later you can just write, for any target that may need a directory
target: prerequisites | $$(#D)/.
normal recipe for target

Resources