How to extract a pattern from a makefile string variable - makefile

In a Makefile, I have a variable DPDK_CUSTOM_REPO_VERSION which is defined as follows:
DPDK_CUSTOM_REPO_VERSION="dpdk-19.08-devel"
How to Extract 19.08 from above string into another variable DPDK_VERSION?

The string processing abilities of the make-command are somewhat limited, but you can try the following:
Replace all occurrences of - with space:
$(subst -, ,$(DPDK_CUSTOM_REPO_VERSION)
resulting in dpdk 19.08 devel and take the second word:
$(word 2, $(subst -, ,$(DPDK_CUSTOM_REPO_VERSION)))
This should yield the correct result, if the pattern doesn't change significantly.
Put it together to:
DPDK_CUSTOM_REPO_VERSION="dpdk-19.08-devel"
DPDK_VERSION=$(word 2,$(subst -, ,$(DPDK_CUSTOM_REPO_VERSION)))
test:
echo $(DPDK_VERSION)

Related

Replacing a string with underscore character in GNU Make

We are facing a slightly weird problem in GNU Make.
In one of the part Makefile, we try to modify a string in order to get right filename.
So "dummy_1_.pl" is to converted to "dummy_1.pl".
We tried to use following way :-
MY_STRING := dummy_1_.pl
UNDPL := _.pl
DPL := .pl
$(subst $(UNDPL), $(DPL), $(MY_STRING) )
Surprisingly it doesn't work. We can replace ".", "pl", ".pl" etc all this way. However just "" or "." or "_.pl" etc replacement strings starting with an underscore doesn't seem to work.
Is underscore a special character in Make. Are we missing something basic here... We are at GNU Make 3.81
Any help/thought is highly appreciated. Thanks in advance!.
EDIT :-
The problem was posted in short for focused discussion. It seems, the details are necessary. This applies to a pattern rule as below. There's a OUT_V_FILES target that contains *blah_cpu.v *foo_gpu.v etc various target files. (The special string "cpu", "gpu" etc are part of a list.) We want to derive blah.pl, foo.pl respectively as input file for the rule.
DEVICES := cpu gpu memc dram
MY_STRING := $$(foreach dev,$(DEVICES),$$(subst $$(dev),$(NOTHING),$$(notdir %.pl)))
NOTHING :=
UDOT := _.
DOT := .
$(OUT_V_FILES) : %.v : $(subst $(UDOT),$(DOT),S(MY_STRING)) Makefile
#Body of rule+++++++++
There are two problems here. 1) you never assign the result of the $(subst ... invocation and 2) you have to be aware that whitespace is significant within the context of string manipulation functions. With that in mind your makefile code should be something like...
MY_STRING := $(subst $(UNDPL),$(DPL),$(MY_STRING))
In your updated example, it looks like you have some issues when setting MY_STRING. If you correct it to have the proper filename(s), you get:
MY_STRING := $$(foreach dev,$(DEVICES),$$(subst $$(dev),$(NOTHING),$$(notdir %.pl)))
$(info 1. MY_STRING=$(MY_STRING))
MY_STRING := dummy_1_.pl
$(info 2. MY_STRING=$(MY_STRING))
NOTHING :=
UDOT := _.
DOT := .
MY_NEW_STRING=$(subst $(UDOT),$(DOT),$(MY_STRING))
$(info MY_NEW_STRING=$(MY_NEW_STRING))
gives
1. MY_STRING=$(foreach dev,cpu gpu memc,$(subst $(dev),,$(notdir %.pl)))
2. MY_STRING=dummy_1_.pl
MY_NEW_STRING=dummy_1.pl

Why do I need eval to set variable in makefile function?

If I have the following at the top of a gnu makefile:
$(if _,a:=1)
$(info a=$a)
Compilation fails (make-3.81: *** No rule to make target '=1', needed by 'a'. Stop., or *** missing separator. Stop. if I exclude the colon). I know I can get around this by using an eval, but I'm not understanding why it's required. Shouldn't this expand to a:=1, be parsed, and set a to 1?
I'm not understanding why it's required
Well, such is the design.
Evaluation procedure always performs a (recursive) expansion (except for "the initial evaluation" where subsequent expansion can be effectively stopped by =, i.e. "lazy assignment"), but expansion procedure never does evaluation, unless it's explicitly told so (basically, $(eval ...) is such an order to switch from expansion to evaluation).
Consider this:
x := 0
y := 1
# z is set to "y<space><equal><space><dollar>x"
z = y = $x
# [0] [1] [y = $x]
$(info [$x] [$y] [$(value z)])
# error as "y = $x" will not be re-evaluated
#$z
# effectively sets y to "0"
$(eval $z)
# [0] [0] [y = $x]
$(info [$x] [$y] [$(value z)])
From make's point of view $(if cond,x=y) does not differ much from $z --- it's expanded but not evaluated. No matter where it stands. Just think anything of a form $(...) to be "data", not "code".
In your case the if function evaluates as its second argument (a:=1) but this is not evaluated in turn as a make variable assignment. With your version of make it becomes a rule. This is probably due to the way make syntactically parses the makefiles. It does not consider that this if statement can be a variable assignment because (before expansion) it looks like none of the valid make variable assignments. So the if statement gets expanded but it is too late for make to consider the result as a variable assignment...
Instead you can use:
a := $(if _,1)
or:
ifneq (_,)
a := 1
endif
or:
$(if _,$(eval a := 1))
or:
$(eval $(if _,a := 1))
The two last forms work because by definition the result of the expansion of the argument of the eval function is processed as plain make statements.

How to filter out a pattern with space in Makefile

I want to filter out a pattern as "-Wl, Bdynamic -lmylib" from a long LDFLAGS list. But filter-out function can only handle space-separated list, is there other method to do this in Makefile?
The only way to do it is by replacing spaces with some other character that you know doesn't appear in the variable value. For example suppose you know that the ^ character never appears in your variable value, then you can do something like this:
# Create a variable containing a space
E :=
S := $E $E
LDFLAGS := $(subst ^,$S,$(subst -Wl^Bdynamic^-lmylib,,$(subst $S,^,$(LDFLAGS))))

How to search for whole words in a Makefile string?

I need a method to search for a substring only if it is a whole word.
Ideally I want a function (say findwstring()) such that the two examples,
$(findwstring a, a b c)
$(findwstring a, angle b c)
should produce the values ‘a’ and ‘’ (the empty string), respectively.
I couldn't find anything here which could help me.
$(filter a, a b c)
Produces 'a'.
$(filter a, angle b c)
Produces ''.
Percent (%) in the search string is considered the wildcard character.
From the docs you linked (actually the function right below findstring), boldface mine:
$(filter pattern…,text)
Returns all whitespace-separated words in text that do match any of the pattern words, removing any words that do not match. The patterns are written using ‘%’, just like the patterns used in the patsubst function above.
The filter function can be used to separate out different types of strings (such as file names) in a variable. For example:
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
says that foo depends of foo.c, bar.c, baz.s and ugh.h but only foo.c, bar.c and baz.s should be specified in the command to the compiler.

Makefile: extract pattern from a full path string

In a Makefile, I can get the full path string by $(CURDIR). The result is like /home/jones/prj/platform/Application_UBUNTU/build_os. How do I extract the UBUNTU from the string?
I use subst to replace '/' as space.
DIR = $(subst /, " ", $(CURDIR))
I get result as home jones prj platform Application_UBUNTU build_os.
Then I try to use filter command but I cannot use % or wildcard to match Application_UBUNTU out. Thanks for help in advance.
Use the penultimateword macro from my answer here.
penultimateword = $(wordlist $(words $1),$(words $1), x $1)
BUILD_OS=$(call penultimateword,$(subst /, ,$(CURDIR)))
BUILD_OS=$(subst _, ,$(BUILD_OS))
BUILD_OS=$(word 2,$(BUILD_OS))
This is obviously sensitive to extra underscores in the path/etc.

Resources