How to foreach and eval function in Makefile work? - makefile

I'm trying to understand Makefile syntax and Makefile system of AOSP. But, it is difficult to a beginner like me. I understand how fereach function work but dont understand when is used with eval function like below. Can someone explain the piece of Makefile code below ? how it work step by step and the output of every step ? the final value of all_product_configs variable ? Thanks all so much !
all_product_configs := $(call get-product-makefiles,\
$(SRC_TARGET_DIR)/product/AndroidProducts.mk)
and this is definition of get-product-makefiles function :
define get-product-makefiles
$(sort \
$(foreach f,$(1), \
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
$(eval include $(f)) \
$(PRODUCT_MAKEFILES) \
) \
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR :=) \
)
endef

eval takes its argument and evaluates it as Makefile syntax -- definitions of variables and rules, and any other GNUmake syntax -- and expands to nothing (an empty string)
foreach takes its 3rd argument and repeats it once for each word in the 2nd argument, with 1st argument being defined as the corresponding word each time. The result is that (big) string.
call takes its first argument as the name of a variable and expands that variable with $(1), $(2), etc set to the other arguments of the call
So from the top, you expand get-product-makefiles with $(1) set to $(SRC_TARGET_DIR)/product/AndroidProducts.mk That is actually the 2nd arg of a foreach, and is onlye one word, so the foreach will expand the 3rd arg once, with $(f) set to that string ($(SRC_TARGET_DIR)/product/AndroidProducts.mk). So that is just
$(eval PRODUCT_MAKEFILES :=) \
$(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(SRC_TARGET_DIR)/product/AndroidProducts.mk))) \
$(eval include $(SRC_TARGET_DIR)/product/AndroidProducts.mk) \
$(PRODUCT_MAKEFILES) \
So it runs those evals which defines those variables (PRODUCT_MAKEFILES and LOCAL_DIR) and then includes the other makefile (which presumables defines PRODUCT_MAKEFILES to be something non-empty, probably appending stuff to it). It then expands to whatever that is, followed by the last two eval commands whic clear those two variables and expand to nothing. So the net result will be just whatever $(PRODUCT_MAKEFILES) was defined as in the AndroidProducts.mk while that variable itself is not actually set any more. It then sorts that (the sort command -- which incidentally deletes duplicated words after sorting), and that is what the whole thing ends up as -- and that is what all_product_configs gets set to.
This would be more interesting if there were mulitple makefiles in the call command. Then it would end up reading all of them and pulling in all the things they define in PRODUCT_MAKEFILES, concatenating and sorting the lot.

Related

how to avoid variable expansion for a bash for loop in define makefile

Usually, I use foreach call in a makefile. Notwithstanding, I wanted to try different approaches.
For that, I have created the code bellow.
I am using GNU Make 3.81
I have replaced the eval by info to understand what is happening.
I cannot avoid both the call and the eval expansion to keep the $file
I mean, when I open the file I am getting:
"for file in *.v; do echo ; echo ; done; > trial.sh;"
define create_area
$(1): $(2)
mkdir -p $$(#D); \
cp -nLr -v $(2)/* $$(#D); \
cd $$(#D); \
for file in *.v; do echo $$(file); \
done; \
" > trial.sh;
$(foreach a,$(A1) $(A2),\
$(foreach b,$(B1),\
$(eval $(call create_area,$(a),$(b)))))
Thank you in advance,
You're almost there.
If you run the loop in a shell, you must precede the variable name with '$' so that it will be expanded.
If you put that command in a makefile recipe, to prevent Make from expanding the variable name too soon (when the variable has not yet been given a value) you must precede ("escape") that '$' with another '$'.
If you put that recipe in a definition which you will expand with call, you must double each of them:
for file in *.v; do echo $$$$file; done

Insert a new-line in a Makefile $(foreach ) loop

I'm compiling a large list of files in a Makefile.
my.list : ${deps}
rm -f $#
$(foreach F,$^,echo "${F}" >> $#;)
but ${deps} can be large and the generated command-line could be too large for one SHELL call. Is it possible to replace ';' by a newline '\n' ?
As already mentioned in Jonathan Wakely's answer, the straightforward answer is
define newline
endef
Interestingly enough, for all chars except newline there is an easier way to get non-printable characters into variables with some help from the shell, e.g.:
tab := $(shell printf '\011')
It won't work here, though, because the builtin shell function replaces all newlines by spaces.
The version above is still a bit fragile though, in particular when combining with automake which will silently remove the second consecutive newline from the input file, turning newline into an empty variable. To force it to keep the newline, we can extend the snippet:
blank :=
define newline
$(blank)
endef
Finally, to actually get a separate shell command for each dependency, you need to run the generated string through eval:
define generate-rule =
my.list : $(1)
rm -f $$#
$(foreach F,$$^,$(newline)$(tab)echo "${F}" >> $#)
endef
$(eval $(call generate-rule,$(deps)))
You can define a variable that expands to a newline like so:
define NEWLINE
endef
Now you can use $(NEWLINE) to expand to a newline.
This won't change anything though, the foreach will still generate a single command with embedded newlines between the statements, rather than a single command with ; between the statements.
Possibly the most straight-forward answer is to use:
#printf "\n"
You can also use this, as I commonly do, to show a description when each new make target executes. An example target:
.PHONY: clean-version
clean-version: ## Reset version back to committed version number
#printf "\n## Reset version to last committed version number ##\n\n"; \
$(GIT) checkout $(VERSION_FILE);
Replacing ';' by a carriage-return will produce a string of the same size, subject to the same problem.
"foreach" is simply a string expansion. If you want to execute a separate command for each item, you can use a for loop.
my.list : ${deps}
rm -f $#
(for F in $^; do echo $$F >> $# ; done)
Edit -- after some revisions, it looks like the only problem with my original was not due to the whitespaces, but with MAKE_O. I've fixed it in my version, but I'll mostly be removing them below.
By the way the original post was written, I'm not sure if my solution will be relevant. However, I found myself in the middle of a define already inside a foreach, and couldn't figure out how to insert a newline using any of the other answers as given.
Solution:
define BR
$(1)
endef
define MAKE_O
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \
$(CXX) ... -c $$< \$(call BR)-o $1 ... \
\$(call BR)&& touch $$#
endef
$(foreach N,main.o,$(eval $(call MAKE_O,$(N))))
Desired output (compilation is truncated from auto-dependency generation, hence the touch):
> make obj/main.o
g++ ... -c src/main.cpp \
-o obj/main.o ... \
&& touch obj/main.o
I changed BR to perform the indentation but leave the end of the line up to you:
define BR
$(1)
$(1:%= ) #<remove this comment
endef
define MAKE_O
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \
$(CXX) ... -c $$< $(call BR,\)-o $1 ... \
$(call BR,\)&& touch $$#
endef
$(foreach N,main.o,$(eval $(call MAKE_O,$(N))))
The markup won't help to show this, but line 2 of BR is $(1:%=_space_)_tab_ (the comment itself is not allowed.) Result:
> make -n obj/main.o
g++ obj/main.o -c \
-o obj/main.o && \
echo statement on new line
I used $(call BR,\) so that the newline was not parsed as an escape of the new line, and $(1:%=space)tab so that the tab is forced (many similar rules have been defined, like SPACE:=$(SPACE) $(SPACE) without a prior value.) The variable left of the whitespace must evaluate to something. To be clear, removing the whitespace before and after the call: ...lastword$(call BR,\)firstword... yields ...lastword\n\tfirstword..., or written out,
[^]...lastword \[$]
[^]$(call BR,\)firstword...[$]
...yields...
[^]...lastword \[$]
[^] firstword...[$]
to achieve the same (using ^,$ to denote the beginning and end of the line. Someone else will probably know how to format/annotate this better.)
My syntax highlighter is decidedly unimpressed with the 'escaped' parentheses and trailing whitespace, but the result is decent.

Recursive make: correct way to insert `$(MAKEFLAGS)`

How can I use $(MAKEFLAGS) (or another way of passing variables defined on the command line to sub-make) in a way that supports invocation from shell with both make VAR=val and make -args?
I need my subprojects configurable, but I hate autotools, so I'm using make variables for this, e.g. invoking from shell:
$ make USE_SSE3=1
and USE_SSE3 needs to apply to all builds in all sub-makefiles.
The manual states that:
if you do ‘make -ks’ then MAKEFLAGS gets the value ‘ks’.
Therefore I'm using -$(MAKEFLAGS) (with a dash prefix) in my Makefile.
However, that expands into invalid arguments when variables with no flags are used. If I run:
$ make FOO=bar
then sub-make gets invalid -FOO=bar. OTOH without the dash prefix variable definitions work, then but make -s, etc. don't.
Is there a syntax/variable/hack that makes passing of arguments and lone variable definitions work with sub-makefiles?
The legacy $(MKFLAGS) doesn't have the weird dash prefix problem, but it doesn't include variable definitions either. I've tried fixing the variable with $(patsubst), but that only made things worse by trimming whitespace.
I need the solution to be compatible with the outdated GNU Make 3.81 shipped with Mac OS X Mavericks.
foo:
$(MAKE) -C subproject -$(MAKEFLAGS)
$ make foo -s # MAKEFLAGS = 's'
$ make foo BAR=baz # MAKEFLAGS = 'BAR=baz'
$ make foo -j8 # MAKEFLAGS = ' --job-server=…'
You shouldn't set MAKEFLAGS at all. Why do you want to? You didn't give any reason to do so.
MAKEFLAGS is intended, really, to be an internal implementation passing arguments from a parent make to a child make. It's not intended, generally, to be modified by a makefile. About the only thing you can usefully do to it is add new flags.
If you just run the recursive make using the $(MAKE) variable rather than hardcoding make, it will Just Work:
recurse:
#$(MAKE) all FOO=bar
or whatever.
Years too late I got your answer if I got it right.
You can construct $(MAKEARGS) manually yourself like:
MAKEARGS := $(strip \
$(foreach v,$(.VARIABLES),\
$(if $(filter command\ line,$(origin $(v))),\
$(v)=$(value $(v)) ,)))
MAKEARGS := assign static
strip cleans leading and trailing whitespaces.
foreach v iterate over all variable names.
origin $(v) check if variable origin is "command line".
$(v)=$(value $(v)) output env assignment string.
Alternatively you can unpick the $(MAKEFLAGS) like:
MAKEARGS := $(wordlist 2,$(words $(MAKEFLAGS)),$(MAKEFLAGS))
MAKEFLAGS := $(firstword $(MAKEFLAGS))
Which can leave you with cleaner code for further recursions IMHO. I say this because I sometimes need to keep apart arguments and flags in certain cases. Especially as you get caught in debugging a recursion djungle.
But for any specific case one should consult the manual about recursive options processing.
Changing the $(MAKEFLAGS) can lead to unwanted malfunction.
Another useful information for the willing user could be that the $(MAKEFLAGS) variable is basically the whole argument list passed to make, not only the flag characters. So $(info MAKEFLAGS = $(MAKEFLAGS)) can give you something like:
MAKEFLAGS = rRw -- VAR=val
Cheers
To check if -B is present in make flags i do :
BB_CLOBBER := $(shell echo $(MAKEFLAGS) | grep wB)
ifeq (,$(BB_CLOBBER))
# also force clobber make if these files are missing
BB_CLOBBER := $(shell (test -e $(bb_gen)/minimal/.config && test -e $(bb_gen)/full/.config) || echo "B")
endif
bb_prepare:
ifneq (,$(BB_CLOBBER))
#rm -rf $(bb_gen)/full
...

functions in makefiles?

I have a slew of makefile targets that do the same thing:
${SOME_FILE}:
${FILES} | ${DIST_DIR}
##cat ${FILES} | \
sed 's/#DATE/'"${DATE}"'/' | \
sed 's/#VERSION/'"${CR_VER}"'/' \
> ${OUT_FILE};
where ${FILES} and ${OUT_FILE} are the only things changing. I'm trying to figure out if it's possible to simplify these targets to something like:
${SOME_FILE}:
compile(${FILES},${OUT_FILE})
Thanks for any insight.
GNU make has this:
http://www.gnu.org/software/make/manual/make.html#Call-Function
To define a multi-line function, you would use this syntax:
http://www.gnu.org/software/make/manual/make.html#Canned-Recipes
Links to docs (like in the accepted answer) are good but good example is better :)
define my_func
$(eval $#_PROTOCOL = "https:")
$(eval $#_HOSTNAME = $(1))
$(eval $#_PORT = $(2))
echo "${$#_PROTOCOL}//${$#_HOSTNAME}:${$#_PORT}/"
endef
my-target:
#$(call my_func,"example.com",8000)
Take into consideration the following:
There are no custom "functions" in Makefile language. So "my_func" is actually a variable that simply contains a text.
That "function" doesn't have its own scope. All the content of that "function" is copied into the recipe as is. All variables in the body will be used after that as a part of the recipe.
Don't use spaces near the commas to prettify param list of "call" function.
Args are passed like $(1), $(2), ... that is not very handy, so re-declare them with meaningful names. This is optional but recommended for bigger "function" bodies.
Variables are declared with $#_ prefix that makes them "local" to the rule (actually not local but prefixed by the target name).
So we have imitation of functions with imitation of local variables but generally this works good.
If you don't want to restrict yourself to GNUmake, your best bet is probably to generate makefile fragments yourself and then include them.

multi-wildcard pattern rules of GNU Make

I want to write something like regex:
SRC:="a.dat.1 a.dat.2"
$(SRC): %.dat.%: (\\1).rlt.(\\2)
dat2rlt $^ $#
so that a.dat.1 and a.dat.2 will give a.rlt.1 and a.rlt.2.
In GNU Make info page, it says "the % can be used only once".
Is there some trick to achieve this in GNU Make?
I'm afraid what you are trying to do is not possible the way you suggest to do it, since - as you already mention - (GNU) make only allows a single stem '%', see http://www.gnu.org/software/make/manual/make.html#Pattern-Rules:
A pattern rule looks like an ordinary rule, except that its target
contains the character ‘%’ (exactly one of them).
Without it, creating such 'multi-dimensional' targets is cumbersome.
One way around this is by rebuilding the name of the dependency in the command (rather than in the dependency list):
SRC := a.dat.1 a.dat.2
all : $(SRC:%=%.dat2rlt)
%.dat2rlt :
dat2rtl $(word 1,$(subst ., ,$*)).rlt.$(word 2,$(subst ., ,$*)) $*
Of course, however, this way you would lose the dependency, it will not rebuild once the rlt has been updated.
The only way I can see to address that is by generating the rules explicitly:
SRC := a.dat.1 a.dat.2
all : $(SRC)
define GEN_RULE
$1.dat.$2 : $1.rlt.$2
dat2rtl $$< $$#
endef
$(foreach src,$(SRC),$(eval $(call GEN_RULE,$(word 1,$(subst ., ,$(src))),$(word 3,$(subst ., ,$(src))))))
Using named variables, we can write more readable code (based on answer of Paljas):
letters:=a b c
numbers:=1 2 3 4
define GEN_RULE
$(letter).dat.$(number) : $(letter).rlt.$(number)
./rlt2dat $$< $$#
endef
$(foreach number,$(numbers), \
$(foreach letter,$(letters), \
$(eval $(GEN_RULE)) \
) \
)
We can generate SRC in a similar way. Note that using that method SRC will contain all the combinations. That may or may not be beneficial.
Building on the answer of Erzsébet Frigó, you might additionally choose to:
in the inner loop, eval not the macro itself but the result of calling it
name the macro after program you're calling, dat2rtl
in combination, allowing you to
refer to the program name using make's ${0}
define a target, ${0}s (expanding to dat2rts - note the pluralization) with preconditions of all combinations of letters and numbers on which dat2r2 was called
Like this:
letters:=a b c
numbers:=1 2 3 4
define rlt2dat
${0}s::$(letter).dat.$(number)
$(letter).dat.$(number): $(letter).rlt.$(number)
./${0} $$< $$#
endef
$(foreach number,$(numbers), \
$(foreach letter,$(letters), \
$(eval $(call rlt2dat))))
allowing you to build all rlt2dat targets as:
make rlt2dats
For the limited example you gave, you can use a pattern with one %.
SRC := a.dat.1 a.dat.2
${SRC}: a.dat.%: a.rlt.%
dat2rlt $^ $#
$* in the recipe will expand to whatever the % matched.
Note that the "s around your original macro are definitely wrong.
Have a look at .SECONDEXPANSION in the manual for more complicated stuff (or over here).

Resources