Can I call a user defined function outside of a target - makefile

I want to know the following:
Q1: Can I call a user-defined function outside of a target?
Q2: Would the changes happen inside like exporting a variable would take effect?
DOT_ENV_FILE ?= $(CURDIR)/.env
define importEnvFile
VARS = $(shell sed -ne 's/ *\#.*$$//; /./ s/=/?=/ p' ${1})
$(foreach v,${VARS},$(eval export ${v}))
endef
$(call importEnvFile,$(DOT_ENV_FILE))

A1: Yes, if you use the eval function:
define defThings
SKY := blue
endef
$(eval $(call defThings))
$(info sky is $(SKY))
A2: Yes:
makefile:
define defThings
export SKY := blue
endef
$(eval $(call defThings))
delegate:
$(MAKE) -f Makefile.other
Makefile.other:
report:
#echo sub-make reports sky is $(SKY)
The other complications of reading and parsing a file and iterating over a list can wait until you have this much working. When you implement a new functionality, keep it as simple as possible until you have it working.

Related

Make $* check for string

I am trying to check if $* matches hello . But the following is not working
build: build-hello
build-%:
ifeq ($*, hello)
echo Hello
else
echo World
endif
The conditions in the ifeq's are processed at makefile read time -- when $* is still blank. There's a couple of workarounds to this: First, you could do a build-hello: rule, which would override the build-% rule for build-hello. If, on the other hand you wanted to minimize rules, you could use the $(if) function as so:
build-%:
#echo $(if $(filter $*,hello),Hello,World)
Or, you could just use shell logic to accomplish this as well.

How to make conditional expansion without subshell?

I wrote following function in GNU Make, that checks whether first argument belongs is found in some list, and expands to second or third argument accordingly:
FLAGS := foo bar
use = $(shell { echo $(FLAGS) | grep -qw $(1) ; } && echo $(2) || echo $(3))
all:
» $(info $(call use, foo, have-foo, no-foo))
» $(info $(call use, baz, have-baz, no-baz))
It behaves as I want:
$ make all
have-foo
no-baz
make: 'all' is up to date.
Is there any way to implement same functionality only with GNU Make,
without subshell?
Is there any way to add more syntax sugar at call sites?
I need it work on GNU Make built without Guile support.
I'm not sure I fully understand but why not this?
use = $(if $(filter $1,$(FLAGS)),$2,$3)
??
While MadScientists answer may be all you need, it looks like you are doing the configuration management in make. While this is IMO the place where it should happen, the heritage has prevented make from becoming a full-flegded tool for that purpose. However, there is a library which helps in this case: The GNUmake Table Toolkit lets you select from a table those lines which fulfill certain freely defined condition (read the documentation to select).
include gmtt/gmtt.mk
# original definition of the flag table
define FLAG-TABLE
2
foo have-foo-1
foo have-foo-2
bar have-bar-1
endef
# GNUmake even allows to write an addendum to a define:
define FLAG-TABLE +=
bar have-bar-2
foo have-foo-3
endef
# the $1 is where the parameter of the call to MY-SELECTION is placed; the $$1 is
# where the first column of the table is put before calling `str-eq`
MY-SELECTION = $(call select,2,$(FLAG-TABLE),$$(call str-eq,$$1,$1))
$(info $(FLAG-TABLE))
$(info ------------------)
$(info $(call MY-SELECTION,foo))
$(info ------------------)
$(info $(call MY-SELECTION,bar))
Output:
$ make
2
foo have-foo-1
foo have-foo-2
bar have-bar-1
bar have-bar-2
foo have-foo-3
------------------
have-foo-1 have-foo-2 have-foo-3
------------------
have-bar-1 have-bar-2

Makefile for many LaTeX files and dependencies in increasing order

I have the following question on writing a reasonable Makefile for compiling a lot of LaTeX exercise sheets for my lectures. The exercises are organised in files file1.tex, file2.tex, ... fileXXX.tex where XXX is the total number (varies from course to course). Now the catch is that I use crossrefs from later files to earlier ones: the dependence of fileY.tex is on all the aux-files of the files fileZ.tex with Z < Y: so those have to be generated before.
So instead of hardcoding all the XXX files with their dependencies into a Makefile I'm looking for a more efficient way to do that. It would be somehow nice to specify just the total number XXX of files.
Like this?
N := 100 # can override on the command line, etc.
SRCS := $(foreach n,$(shell seq $(N)),file$(n).tex)
define dep
$(call dep-rec,$1,,)
endef
# $(call dep-rec,.tex files,accumulated aux files)
define dep-rec
$(if $1,$(eval $(word 1,$1): $2)$(call dep-rec,$(wordlist 2,$(words $1),$1),$2 $(call aux-files-of,$(word 1,$1))))
endef
# return the aux files of $1 (which is a .tex file) -- define as appropriate
define aux-files-of
$(basename $1).aux
endef
$(call dep,$(SRCS))

Makefile target-based dependencies with a wildcard (compact)

I would like to apply the following code in a more compact way:
hello1:
#echo "Hello1"
hello2:
#echo "Hello2"
hello3:
#echo "Hello3"
hello_all: hello1 hello2 hello3
Is there a way of coding hello_all dependencies with a wildcard, e.g. hello* or something?
If your targets are very similar, go with #TimF's solution as it avoids repetition. If they are different and can't be generalized, you can do this with a small helper:
hello-add = $(eval HELLO_TARGETS += $1)$1
$(call hello-add,hello1):
#echo "Hello1"
$(call hello-add,hello2):
#echo "Hello2"
$(call hello-add,hello3):
#echo "Hello3"
hello_all: $(HELLO_TARGETS)
hello-add accepts an argument, adds it to the HELLO_TARGETS variable, and expands to exactly that argument (because eval expands to empty). It behaves like:
HELLO_TARGETS += hello1
hello1:
...
But avoids having to write the target name twice.
I don't think there's a native way to do it. Find below a solution specific to your usecase. I think however that it cannot easily be used in a generic way.
# The number list that will be used to generate the targets
NUMBERS = 1 2 3 4
# Function that will expand to a custom helloX target, with X the number given as parameter
# Note the strip that removes the spaces in the parameter
define createHelloTargets
HELLO_TARGETS += hello$(strip $(1))
hello$(strip $(1)):
#echo Hello$(strip $(1))
endef
# Generate one Hello target for each number in NUMBERS
$(foreach nb, $(NUMBERS), $(eval $(call createHelloTargets, $(nb))))
all: $(HELLO_TARGETS)
This will output :
Hello1
Hello2
Hello3
Hello4
The advantage is that you don't have to write each target, just fill the NUMBERS var and it does the trick.
Basically, this Makefile will create for each number X in NUMBERS a target that looks like this :
helloX:
#echo HelloX
It will also add helloX to HELLO_TARGETS which is a list of all the existing helloX targets. This list is expanded in the all target prerequisites.

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