How to trim a string in makefile? - makefile

I have this string cccccc:dddddd
I want to get cccccc only
I looked at makefile docs but still confused how to do this with make functions
This doesn't work but I want to do something like match from : to end of line and trim all of that
MY_VAR:=cccccc:dddddd
....
derp:
echo $(subst :.*,"",$(MY_VAR))
:dddddd is not static so I cant just hardcode that in like $(subst :dddddd,"",$(MY_VAR))

You can try something like:
MY_VAR := $(firstword $(subst :, ,$(MY_VAR))
Note this requires that "cccccc" does not contain whitespace.

Related

make/gmake: given a variable starting with multiple ../, create a variable with one less ../

Given a variable, how can I create another variable with the leading repetitions of ../ that the first variable starts with, albeit with one less repetition?
For instance, given ../../../foo/bar, how do I end up with ../../?
I've tried a perl regexp like perl -e '$a = "../../../foo/bar"; $a =~ /^\.\.\/((\.\.\/)+)/; print "$1\n"' but can't figure out the magic incantation of quotes, backslashes, dollar signs, and so on needed to run it within $(shell).
Further I suspect there's a simpler way to do it.
This will remove one ../ at the front: $(patsubst ../%,%,$(ORIGINAL_PATH))
To isolate the first streak of ../ one could go as follows:
space := $(strip) $(strip)#
FIRST_STREAK := $(firstword $(subst $(space)../,../,$(subst ../,../$(space),$(ORIGINAL_PATH))))
Let's write this as a function:
space := $(strip) $(strip)#
UP_PATH = $(patsubst ../%,%,$(firstword $(subst $(space)../,../,$(subst ../,../$(space),$1))))
Test it:
ORIGINAL_PATH := ../../../foo/bar/../baz
$(info $(call UP_PATH,$(ORIGINAL_PATH)))
Output:
../../

subst "/dev/ttyPS1" to \""/dev/ttyPS1\"" in makefile

I'm trying to perform this substitution without any success with the following,
a="/dev/ttyPS1"
b=$(patsubst \"%\",\\\"\"%\\"\",$(a))
c=$(subst \",\\\"\",$(a))
$(info $(a) $(b) $(c))
Output :
$ make
"/dev/ttyPS1" "/dev/ttyPS1" "/dev/ttyPS1"
Desired Output :
$ make
"/dev/ttyPS1" \""/dev/ttyPS1\"" \""/dev/ttyPS1\""
I must be doing something dumb with the escape sequences since it doesn't appear to change at all... I don't have any preference on how I get there (patsubst, subst, or other). Any ideas? Thanks.
You don't need to escape quotes with backslashes in make syntax: quotes are not special to make. Thus your subst of \" never matches because there's no two-character string \" in the string "/dev/ttyPS1".
Try:
a = "/dev/ttyPS1"
b = $(patsubst "%",\""%"\",$(a))
c = $(subst ",\"",$(a))
$(info $(a) $(b) $(c))

Makefile function with multiple statements

[HEADS UP] : There are some similar questions that are already present here on stackoverflow but they seem to not completely resolve my issue. Therefore, I am posting this question.
I am trying to write a makefile function that should set a value to a variable that is passed as argument to the function.
So, I am calling this function as -
RESULT :=
$(eval $(call myfunction,RESULT,value,res1,res2))
here 'res1' and 'res2' are two possible resulting values for RESULT and the argument 'value' will be used for some test condition.
Following is my attempt of the definition of myfunction. But it seems that it is not working.
define myfunction
TEST1 := $(shell test `mybinary` -ge 5 && printf "TEST")
TEST2 := $(findstring $(2),$(SOME_SHELL_ENV))
$(info "$(TEST1)")
$(info "$(TEST2)")
ifneq "$$(or $(TEST1),$(TEST2)" ""
LOCAL_RESULT := true
else
LOCAL_RESULT := false
endif
ifeq($(LOCAL_RESULT),true)
$(1) = $(3)
else
$(1) = $(4)
endif
endef
To me it appears that the local variables TEST1 and TEST2 are not even getting set.
Can somebody tell me why my function is not working correctly and what changes do I have to make to resolve the issues?
Quoting eval manual page:
The eval function is very special: [...] The argument to the eval function is expanded, then the results of that expansion are parsed as makefile syntax.
It’s important to realize that the eval argument is expanded twice; first by the eval function, then the results of that expansion are expanded again when they are parsed as makefile syntax. This means you may need to provide extra levels of escaping for “$” characters when using eval.
This happens after $(call) arguments are substituted, so $1 etc are already expanded by the time $(eval) is called, and need not to be $-escaped.
To make variables expand during the last (parsing) stage of $(eval), escape $s of non-numeric variables by doubling them.
define myfunction
TEST1 := $$(shell test `echo 6` -ge 5 && printf "TEST")
TEST2 := $$(findstring $(2),$$(PATH))
$$(info "$$(TEST1)")
$$(info "$$(TEST2)")
ifneq "$$(or $$(TEST1),$$(TEST2))" ""
LOCAL_RESULT := true
else
LOCAL_RESULT := false
endif
ifeq ($$(LOCAL_RESULT), true)
$(1) = $(3)
else
$(1) = $(4)
endif
endef
$(eval $(call myfunction,RESULT,value,res1,res2))
test:
echo "$(LOCAL_RESULT)"
Plus, you had a missing closing brace in $(or).
It's not clear if res1 and res2 are variable names or values; depending on this, the last two assignments need or need not to look like $(1) := $($(4)).
Try to always use eager assignments: :=, for fewer surprises from lazy variable expansion.

How to concatenate strings in a Makefile?

I have a Makefile that runs pandoc. I want to turn a list of extensions:
PANDOC_EXTENSIONS = \
multiline_tables \
some_other_extension
into a string that looks like:
PANDOC_EXTENSION_LIST = +multiline_tables+some_other_extension
which will then be passed as a command line option to pandoc like this:
pandoc --from$(PANDOC_EXTENSION_LIST) ...
It's trivial in almost any programming language, but I can't figure out how to do this with the patsubst or subst functions, since make doesn't really have lists. Any ideas?
Here:
Makefile
PANDOC_EXTENSIONS = \
multiline_tables \
some_other_extension
$(foreach word,$(PANDOC_EXTENSIONS),$(eval PANDOC_EXTENSION_LIST := $(PANDOC_EXTENSION_LIST)+$(word)))
.PHONY: all
all:
echo $(PANDOC_EXTENSION_LIST)
Which runs like:
$ make
echo +multiline_tables+some_other_extension
+multiline_tables+some_other_extension
As this illustrates, GNU make really does have lists. A sequence of whitespace-separated words is a list.
Based on example in documentation:
empty:=
space:=$(empty) $(empty)
PANDOC_EXTENSIONS = \
multiline_tables \
some_other_extension
all:
#echo +$(subst ${space},+,${PANDOC_EXTENSIONS})
The result:
$ gmake
+multiline_tables+some_other_extension

gnu make: list the values of all variables (or "macros") in a particular run

How can I list the current value of all variables (also called macros) in a Makefile when running make?
E.g. if this is in the Makefile:
CUR-DIR := $(shell /bin/pwd)
LOG-DIR := $(CUR-DIR)/make-logs
Then I would like it to tell me:
CUR-DIR = /home/johv/src/test
LOG-DIR = /home/johv/src/test/make-logs
GNU make provides .VARIABLES
which holds all global variables' names.
However, this includes built-in variables(like MAKEFLAGS).
If you have to exclude built-in variables, some filtering like the following
might be needed.
The following makefile prints user-defined variables(CUR-DIR, LOG-DIR)
using info:
# Place this line at the top of your Makefile
VARS_OLD := $(.VARIABLES)
# Define your variables
CUR-DIR := $(shell pwd)
LOG-DIR := $(CUR-DIR)/make-logs
# Put this at the point where you want to see the variable values
$(foreach v, \
$(filter-out $(VARS_OLD) VARS_OLD,$(.VARIABLES)), \
$(info $(v) = $($(v))))
Thanks to #Ise Wisteria, condensed down, this shows all variables, useful for large projects with multiple makefiles (Buildroot).
$(foreach v, $(.VARIABLES), $(info $(v) = $($(v))))
output: BR2_GCC_TARGET_TUNE = "cortex-a8" ...
If you get an error like: insufficient number of arguments (1) to function 'addprefix' this project had some broken variables... I trimmed the list of variables to show, only with a prefix BR2_
$(foreach v, $(filter BR2_%,$(.VARIABLES)), $(info $(v) = $($(v))))
I ended up doing it like this:
gmake -pn | grep -A1 "^# makefile"| grep -v "^#\|^--" | sort | uniq > makevars.txt
which gives:
CUR-DIR := /home/johv/src/test
LOG-DIR := /home/johv/src/test/make-logs
MAKEFILE_LIST := Makefile
MAKEFLAGS = pn
SHELL = /bin/sh
VARS_OLD := [...]
gmake -pn is really verbose and looks kinda like this:
# environment
GNOME2_PATH = /usr/local:/opt/gnome:/usr:/usr/local:/opt/gnome:/usr
# automatic
#F = $(notdir $#)
# makefile
SHELL = /bin/sh
# default
RM = rm -f
It's also doable without saving all the .VARIABLES and filtering them out.
Moreover, if one of the original .VARIABLES was modified in your makefile, the two most voted answers won't catch it.
Check out $(origin) function. This target filters out and prints all the variables that were defined in a makefile:
print_file_vars:
$(foreach v, $(.VARIABLES), $(if $(filter file,$(origin $(v))), $(info $(v)=$($(v)))))
I get only a few excess variables this way: CURDIR SHELL MAKEFILE_LIST .DEFAULT_GOAL MAKEFLAGS.
One can replace file with environment or command line to print the respective kinds of variables.
There are a lot of good answers here, but you're going to have problems using $($(v)) if some of your variables are of the recursive flavor. This is why you should use $(value $(v)).
This variation cleans this up a little bit, sorts variables by name and makes the output a bit more readable.
dump:
$(foreach v, \
$(shell echo "$(filter-out .VARIABLES,$(.VARIABLES))" | tr ' ' '\n' | sort), \
$(info $(shell printf "%-20s" "$(v)")= $(value $(v))) \
)
Thanks to #kevinf for the great idea. I would suggest a minor change to prevent .VARIABLE itself from printing out in the variable list:
$(foreach v, $(filter-out .VARIABLES,$(.VARIABLES)), $(info $(v) = $($(v))))
Thanks to #kevinf for the foreach solution -- if one wants to export this list as a somewhat machine-readable file, one will have a hard time with uneven quotes or newlines when using echo or printf, since Make isn't able to quote the data correctly -- one needs to use the $(file ...) function to write the data to avoid sh/bash complaining about invalid syntax. For example, use this in your rule -- it prints variable name, definition and expanded value:
$(file > $(MAKEFILE_ENV_FILE),)
$(foreach v, $(.VARIABLES), \
$(file >> $(MAKEFILE_ENV_FILE),$(v)) \
$(file >> $(MAKEFILE_ENV_FILE), := $(value $(v))) \
$(file >> $(MAKEFILE_ENV_FILE), == $($(v))) \
$(file >> $(MAKEFILE_ENV_FILE),) \
)
(This will still not allow to always distinguish malicious variables with double newlines from two variables, for this one now add a sufficiently unique separator infront of each Makefile-generated newline just after each comma inside $(file >> NAME,TEXT))
Set MAKEFILE_ENV_FILE to some filename, e.g.:
MAKEFILE_ENV_FILE := $(abspath $(lastword $(MAKEFILE_LIST))).env

Resources