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.
Related
I have two lists of files as prerequisites
input_i.xx
config_j.yy
and I need to run all of their combinations. A single one looks like this:
input1_config3.output: input1.xx config3.yy
run_script $^
Also in reality, their names are not numbered, but I already have their stems defined in INPUTS and CONFIGS. With that, I can generate all the targets together
TARGETS:=$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(input)_$(config).output))
But I have difficulty with the prerequisites. It seems I need to
get basename
split on _
add the extensions .xx and .yy
.SECONDEXPANSION
$(TARGETS): $(basename $#)
run_script $^
Can someone show me how to do that? Not sure if this the proper way, maybe a bottom-up way is easier?
make is not really suitable for keeping track of an M x N matrix of results. The fundamental problem is that you can't have two stems in a rule, so you can't say something like
# BROKEN
input%{X}_config%{Y}.output: input%{X}.xx config%{Y}.yy
As a rough approximation, you could use a recursive make rule to set a couple of parameters, and take it from there, but this is rather clumsy.
.PHONY: all
all:
$(MAKE) -$(MAKEFLAGS) X=1 Y=6 input1_config6.output
$(MAKE) -$(MAKEFLAGS) X=1 Y=7 input1_config7.output
$(MAKE) -$(MAKEFLAGS) X=2 Y=6 input2_config6.output
:
input$X_config$Y.output: input$X.xx config$Y.yy
run_script $^
It would be a lot easier if you provided a complete sample example with a complete set of targets and prerequisites and exactly what you wanted to happen.
Using .SECONDEXPANSION might work, but you're not using it correctly; please re-read the documentation. The critical aspect of .SECONDEXPANSION is that you have to escape the variables that you want to avoid expanding until the second pass. In your example you've not escaped anything, so .SECONDEXPANSION isn't actually doing anything at all here. However, as #tripleee points out it's not easy to use multiple variable values in a single target.
To do this more easily you'll probably want to use eval. Something like this:
define DECLARE
$1_$2.output: $1.xx $2.yy
TARGETS += $1_$2.output
endef
TARGETS :=
$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(eval $(call DECLARE,$(input),$(config)))))
$(TARGETS):
run_script $^
I have another solution using include and bash for loop.
include trees.mk
trees.mk:
#for input in $(INPUTS); do \
for config in $(CONFIGS); do \
echo $${input}_$$config.output : $${input}.xx $$config.yy; \
echo -e '\t run_scipt $$^ ';\
done \
done > $#
At the beginning, trees.mk doesn't exist. The double for loops write out the rule to the target using file redirection >$#.
I got this idea from Managing Projects with GNU Make, Third Edition By Robert Mecklenburg, on
page 56
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.
I want to create a makefile to be included in others, kind of as a "library", let's call it library.mak:
TARGET_FILES = a.txt b.txt c.txt d.txt
SRC_FOLDER = somewhere/else
.PHONY: all
all:
for target in ${TARGET_FILES} ; do \
echo -e "\nMaking $${target}:" ;\
${MAKE} ${MFLAGS} --no-print-directory $${target} ;\
done
.PHONY: ${TARGET_FILES}
${TARGET_FILES}:
cp ${SRC_FOLDER}/$# $#
The two rules are there to make all, as well as one specific target, respectively; using a default rule (which is the purpose of library.mak).
In my "user makefile" called Makefile, I want to then do this:
include library.mak
# special handling of c.txt
c.txt:
grep -v 'all except this' ${SRC_FOLDER}/$# > $#
As you can see, the user wants to be able to override the behaviour for some special cases. While this works, it always greets the user with the dreaded warning: overriding recipe for target and warning: ignoring old commands for target messages, even though the behaviour is as intended.
So here's the question: Can this be done in a different way that avoids these warnings, or is there a means to suppress them?
The warning says you overwrite a recipe for an explicit rule. And this is really wrong. It makes sense to use a pattern rule instead, like: %.txt: ${SRC_FOLDER}/%.txt. Then it's ok to have some explicit rule (c.txt: ${SRC_FOLDER}/c.txt) overwriting a recipe. Of course, it's not 100% the same, but, I think that should not be a problem. Anyway, putting an explicit rule into a reusable file is a crime.
Next, you constantly use "phonies" and rules w/o prerequisites even when you definitely should have them. This is bad. You're trying to make "make" work as a non-branching shell script. That's not only inefficient but also is a misuse. Basically, make can be viewed as "shell extension" capable of "branching on file timestamps in a sophisticated way". If you don't need it, don't use make at all.
Next, I see absolutely no reason to go into recursive make. Whatever, you're going to do, I believe, you can do without it. And even if you really need recursion, then write simply $(MAKE). $(MFLAGS) shoud not be used anymore (read this).
P.S. There's yet another (more flexible) option to define parameterized variables (macros). For example:
define nl :=
endef
define myrule.text
$1: $2/$1
#cp $$< $$#
endef
myrule = $(eval $(foreach foo$0,$1,$(call myrule.text,$(foo$0),$2)$(nl)))
...
# user makefile
# for everything except c.txt call predefined macro
$(call myrule,$(filter-out c.txt,$(TARGET_FILES)),$(SRC_FOLDER))
# for c.txt only
c.txt: $(SRC_FOLDER)/c.txt
grep -v 'all except this' $< >$#
But as you see, it's a bit of a "cryptic" stuff, and I don't feel like recommending it for a beginner.
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
...
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).