Repeat element from list - makefile

In a makefile is there any way to specifiy the same element of a list (I think this is the correct term) more than once? For example, having a a list with 3 files A.txt B.txt C.txt, I'd like to create targets based on these elements that would be contained within a directory where the pattern would have to be repeated twice: A/A-rambo B/B-rambo C/C-rambo.
I tried:
TXT = A.txt B.txt C.txt
DIR := $(patsubst %.txt,%,$(TXT))
OUT := $(patsubst %,%/%-rambo,$(DIR))
$(info $(OUT))
but this prints A/%-rambo B/%-rambo C/%-rambo, where the second %is not being replaced.
And so does OUT := $(patsubst %,$(addsuffix /%-rambo,%),$(DIR))

Make cannot handle a pattern rule with two wildcards in the target name, even if they're required to have the same value.
There's more than one way to get the effect you want, none ideal. I'd suggest generating a rule for each txt file:
define template
$(1)/$(1)-rambo: $(1).txt
#echo building $$# from $$^
endef
STEMS := A B C
$(foreach x,$(STEMS),$(eval $(call template,$(x))))

Try:
OUT := $(foreach T,$(TXT),$(T:.txt=)/$(T:.txt=-rambo))

Related

Wildcard only files with pure make

I am seeking for a solution to only match files when wildcarding in make with pure make functions.
Say we have a file structure such as
Makefile
dir1/
file1
file2
dir2/
file3
where we want to obtain file1 and file2 without any hardcoding, i.e. without explicitly removing or adding files or directories, and where every piece of code is written in pure make. It is okay to assume the depth of the directories.
When writing
FILES_DEPTH1 = $(wildcard *)
FILES_DEPTH2 = $(wildcard */*)
FILES_DEPTH3 = $(wildcard */*/*)
these expands to
FILES_DEPTH1 = Makefile dir1
FILES_DEPTH2 = dir1/file1 dir1/file2 dir1/dir2
FILES_DEPTH3 = dir1/dir2/file3
which is not what we want. While one could solve this problem using find as shown here, I am only interested in solutions that only utilizes pure make functions. Does such a solution exist?
Try this:
DIRS := $(patsubst %/.,%,$(wildcard */*/.))
FILES := $(filter-out $(DIRS),$(wildcard */*))
(note, not tested...)

remove patterned prefix from list in gnu make

If I have a list of files:
files := xx_foo1.c yy_foo2.c zz_bar1.c aa_bb_bar2.c
Is there any way of removing everything up to the last underscore from the list to get foo1.c foo2.c bar1.c bar2.c?
I was looking into using patsubst, but I would need two%'s -- one for the first part to be ignored, and one for the last part to be kept.
It can be done but it's a little gross. You want something like this:
final := $(foreach F,$(files),$(word $(words $(subst _, ,$F)),$(subst _, ,$F)))
This says, for each element in files we convert the _ to a space, now we can use our per-word functions to manipulate it: extract the last word in the list of words.
ETA
ReAl points out below that this can be simplified using lastword:
final := $(foreach F,$(files),$(lastword $(subst _, ,$F)))
As I see it you are using the underscore as separating character between hierarchical names. GNUmake is well equipped to work with such a scheme if the character is /: file name functions.
So your example should simply boil down to
$(notdir $(subst _,/,$(files))
Use the external program — sed — and enjoy all its power
files := xx_foo1.c yy_foo2.c zz_bar1.c aa_bb_bar2.c
f := `echo $(files) | sed -e "s/[[:alnum:]]*_//g"`
all:
echo $(f)

code management: generate source files with slight variations of various rules

I have a source file in a declarative language (twolc, actually) that I need to write many variations on: a normative version and many non-normative versions, each with one or more variations from the norm. For example, say the normative file has three rules:
Rule A:
Do something A-ish
Rule B:
Do something B-ish
Rule C:
Do something C-ish
Then one variation might have the exact same rules as the norm for A and C, but a different rule for B, which I will call B-1:
Rule A:
Do something A-ish
Rule B-1:
Do something B-ish, but with a flourish
Rule C:
Do something C-ish
Imagine that you have many different subtle variations on many different rules, and you have my situation. The problem I am worried about is code maintainability. If, later on, I decide that Rule A needs to be refactored somehow, then I will have 50+ files that need to have the exact same rule edited by hand.
My idea is to have separate files for each rule and concatenate them into variations using cat: cat A.twolc B.twolc C.twolc > norm.twolc, cat A.twolc B-1.twolc C.twolc > not-norm.twolc, etc.
Are there any tools designed to manage this kind of problem? Is there a better approach than the one I have in mind? Does my proposed solution have weaknesses I should watch out for?
As you added the makefile tag, here is a GNU-make-based (and Gnu make only) solution:
# Edit this
RULES := A B B-1 C
VARIATIONS := norm not-norm
norm-rules := A B C
not-norm-rules := A B-1 C
# Do not edit below this line
VARIATIONSTWOLC := $(patsubst %,%.twolc,$(VARIATIONS))
all: $(VARIATIONSTWOLC)
define GEN_rules
$(1).twolc: $$(patsubst %,%.twolc,$$($(1)-rules))
cat $$^ > $$#
endef
$(foreach v,$(VARIATIONS),$(eval $(call GEN_rules,$(v))))
clean:
rm -f $(VARIATIONSTWOLC)
patsubst is straightforward. The foreach-eval-call is a bit more tricky. Long story short: it loops over all variations (foreach). For each variation v, it expands (call) GEN_rules by replacing $(1) by $(v) (the current variation) and $$ by $. Each expansion result is then instantiated (eval) as a normal make rule. Example: for v=norm, the GEN_rules expansion produces:
norm.twolc: $(patsubst %,%.twolc,$(norm-rules))
cat $^ > $#
which is in turn expanded as (step-by-step):
step1:
norm.twolc: $(patsubst %,%.twolc,A B C)
cat $^ > $#
step2:
norm.twolc: A.twolc B.twolc C.twolc
cat $^ > $#
step3:
norm.twolc: A.twolc B.twolc C.twolc
cat A.twolc B.twolc C.twolc > norm.twolc
which does what you want: if norm.twolc does not exist or if any of A.twolc, B.twolc, C.twolc is more recent than norm.twolc, the recipe is executed.

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))

Get word before the last word inside GNU makefile

I need to extract the word before the last from $(MAKEFILE_LIST).
So far I could not come up with anything better than this kind of monstrosity:
LIST := a b c
LAST_WORD_INDEX = $(words $(LIST))
BEFORE_LAST := $(word $(shell echo $(LAST_WORD_INDEX) - 1 | bc),$(LIST))
$(info word before last is $(BEFORE_LAST))
When I run it:
word before last is b
make: *** No targets. Stop.
The result is correct, but is there more elegant and sane way to achieve the same?
$(words ${LIST}) will give you the index of the last-but-one word if you prepend an element to LIST.
BEFORE_LAST := $(word $(words ${LIST}),1st ${LIST})
Notice that 1st in there.
I ended up using GMSL library, which makes things quite a bit more coherent:
include gmsl-1.1.6/gmsl
$(lastword $(call chop,$(MAKEFILE_LIST)))

Resources