How to perform text substitution of new lines using Make functions? - makefile

I have a make variable containing a list of files with one file per line and I'd like to join all of them into a single-line space-separated list.
The following excerpt was a naive attempt to do that, without success.
define FILELIST
src/foo.c
src/bar.c
src/frobnicator.c
endef
empty :=
space := $(empty) $(empty)
$(subst \n,$(space),$(FILELIST))

define FILELIST
src/foo.c
src/bar.c
src/frobnicator.c
endef
$(info FILELIST=$(FILELIST))
F1 := $(foreach w, $(FILELIST), $(strip $(w)))
$(info F1=$(F1))
FILELIST := $(strip $(F1))
$(info FILELIST=$(FILELIST))
result:
FILELIST= src/foo.c
src/bar.c
src/frobnicator.c
F1= src/foo.c src/bar.c src/frobnicator.c
FILELIST=src/foo.c src/bar.c src/frobnicator.c

Related

How can I split a string by a delimiter in Makefile?

Here's the code snippet from my Makefile:
%/foo: %/bar.yaml
$(BINARY) generate -g go \
--package-name {COOL_VALUE}
# COOL_VALUE should be the parent folder of a `foo`, e.g., `foo1/foo2/foo -> foo2`
the question is how can I split $# string by / to get the second last element:
E.g.,
make foo1/foo2/foo
> ./binary generate -g go \
--package-name foo2
make foo3/foo
> ./binary generate -g go \
--package-name foo3
My attempts:
I came up with
$(eval package_name := $(word 1,$(subst /, ,$#)))
% pick second last element somehow
If you are really talking about / as a delimiter, then your best bet is to use the filename functions like this:
PARENT = $(notdir $(patsubst %/,%,$(dir $#)))
$(eval package_folders := $(filter-out foo,$(subst /, ,$#)))
$(eval package_name := $(word $(words $(package_folders)), $(package_folders)))
#echo "$(package_name)"

GNU make path substitution (directory flattening)

I have a makefile that gives me the source files in a hierarchy.
SRCS := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*/*.c)
gives me
./src/main.c ./src/add/add.c ./src/sub/sub.c
I want to flatten the object files into a single "obj" directory.
Of course
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.obj)
gives me
./obj/main.obj ./obj/add/add.obj ./obj/sub/sub.obj
instead of desired
./obj/main.obj ./obj/add.obj ./obj/sub.obj
Question: How do I get rid of additional source directory levels?
Never had to use complex substitution so far. My intuitive try with additional "/%" in pattern
# won't work as expected:
OBJS := $(SRCS:$(SRC_DIR)/%/%.c=$(OBJ_DIR)/%.obj)
produces no meaningful result (${OBJS} becomes same as ${SRCS}).
All examples I found so far only have single occurance of "%" in match pattern.
MAK_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
SRC_DIR = $(MAK_DIR)./src
OBJ_DIR = $(MAK_DIR)./obj
# gives: ./src/main.c ./src/add/add.c ./src/sub/sub.c
SRCS := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*/*.c)
# gives: ./obj/main.obj ./obj/add/add.obj ./obj/sub/sub.obj
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.obj)
.PHONY : all
all :
#echo $(SRCS)
#echo $(OBJS)
Just use the notdir function, and also patsubst, more powerful (and that I find easier to understand than the shorthand):
OBJS := $(patsubst %.c,$(OBJ_DIR)/%.obj,$(notdir $(SRCS)))
But it is not the whole story because later on you will probably want to do something like:
$(OBJ_DIR)/%.obj: $(SRC_DIR)/%.c
which will not work any more. Not mentioning the fact that you could have several source files with the same name in different directories. Assuming you do not have such names conflicts you can generate all your dependencies using foreach-eval-call:
MAK_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
SRC_DIR := $(MAK_DIR)./src
OBJ_DIR := $(MAK_DIR)./obj
SRCS := $(shell find $(MAK_DIR) -type f -name '*.c')
OBJS := $(patsubst %.c,$(OBJ_DIR)/%.obj,$(notdir $(SRCS)))
.PHONY: objs
objs: $(OBJS)
# $(1): source file
define DEP_rule
$(1)-obj := $$(patsubst %.c,$$(OBJ_DIR)/%.obj,$$(notdir $(1)))
$(1)-dep := $$(patsubst %.c,$$(OBJ_DIR)/%.d,$$(notdir $(1)))
$$($(1)-obj): $(1) $$($(1)-dep)
endef
$(foreach src,$(SRCS),$(eval $(call DEP_rule,$(src))))
Just remember that the DEP_rule macro gets expanded twice, thus the $$.

Process list of files in makefile with $(notdir ...)

I would like to apply the 'notdir'-function to a list of files I obtain from a wildcard match. While '$(notdir $(wildcard dir/*.tst))' works, I do not manage to first store the list in a variable ('FILES' in the Makefile below) that then is processed by $(notdir ...). Using the variable directly ('$(notdir $(FILES))') results in the wildcard being returned, using value ('$(notdir $(value $(FILES)))') yields an empty result.
.PHONY: show
FILES := dir/*.tst
FILES2 := dir/a.tst dir/b.tst
#NAMES := $(notdir $(FILES))
NAMES1 := $(notdir $(value $(FILES)))
NAMES2 := $(notdir $(FILES2))
NAMES3 := $(notdir $(wildcard dir/*.tst))
show:
#echo "FILES: " $(FILES)
#echo "NAMES1: " $(NAMES1)
#echo "NAMES2: " $(NAMES2)
#echo "NAMES3: " $(NAMES3)
I also tried $(notdir $(eval $$(FILES))), but this results in a "missing separator" error.
What am I missing here? I'd have expected that value would do the job...
Try the following:
FILES := $(wildcard dir/*.tst)
NAMES := $(notdir ${FILES})

How to filter out a file from wildcard match when an environment is not set

I am using gnu make.
I have version like this:
MYLIST := $(filter-out $(if $(filter 1,$(exclude_file1)), file1.c),$(wildcard *.c))
It works well: when I what to filter out "file1.c", I set the environment variable, exclude_file1.
Now I want the opposite: when an environment variable is not set, I want to exclude file1.c.
Could you point me what should be the change?
MYLIST := $(filter-out $(if $(filter undefined,$(origin exclude_file1)),,file1.c),$(wildcard *.c))
or
MYLIST := $(filter-out $(if $(filter-out undefined,$(origin exclude_file1)),file1.c),$(wildcard *.c))
or
MYLIST := $(filter-out $(if ${exclude_file1},,file1.c),$(wildcard *.c))
etc.
One advantage of the first two formulations is that they don't generate a message when the very useful --warn-undefined-variables is in effect.

How do I define a variable which is a sequential list of integers in gmake?

Given a variable MAX, how do I create a variable LIST which contains the integers 1 to $(MAX)?
Using shell or similar is not possible for my context.
Looks good, though you don't need the $eval:
seq = $(if $(filter $1,$(words $2)),$2,$(call seq,$1,$2 $(words $2)))
$(error [$(call seq,10)])
or somesuch. Make will complain warning: undefined variable '2' under --warn, but you can avoid that by using $(value…).
[You probably want $(filter…) rather than $(findstring…)in your solution BTW.]
Here's a clumsy solution using eval:
UPTO = $(eval TEMP += $(words $(2))) \
$(if $(findstring $(1),$(words $(2))),$(TEMP),$(call UPTO,$(1),$(2) x))
SEQUENCE_TO = $(eval TEMP := )$(strip $(call UPTO,$(1),x))
MAX := 50
LIST := $(call SEQUENCE_TO,$(MAX))
Here is a simple recursive solution, I find it somewhat more understandable than the $(words ...) solution although I guess in the end they're not that different. For better or for worse, this is certainly more verbose.
The repeated call to $(wordlist 2,...) is a bit of a wart. Maybe it could be avoided.
count = $(call count0,$1,0 1 2 3 4 5 6 7 8 9)
count0 = $(if $(wordlist $1,$1,$(wordlist 2,1000000,$2)), \
$(wordlist 1,$1,$(wordlist 2,1000000,$2)), \
$(patsubst 0%,%,$(call count0,$1,$(patsubst %,0%,$2) \
$(patsubst %,1%,$2) $(patsubst %,2%,$2) $(patsubst %,3%,$2) \
$(patsubst %,4%,$2) $(patsubst %,5%,$2) $(patsubst %,6%,$2) \
$(patsubst %,7%,$2) $(patsubst %,8%,$2) $(patsubst %,9%,$2))))
.PHONY: nst
nst:
#echo 7: $(call count,7)
#echo 51: $(call count,51)
#echo 111: $(call count,111)

Resources