Makefile: what syntax is this: $(#:foobar_%=%)? - makefile

I have the following Makefile snippet, which I don't quite understand. In particular, what is the meaning of $(#:foobar_%=%)? Thanks.
foobar_test:
#echo $(#:foobar_%=%) # will print test

That is a Substitution Reference:
Another type of substitution reference lets you use the full power of the patsubst function. It has the same form ‘$(var:a=b)’ described above, except that now a must contain a single ‘%’ character. This case is equivalent to ‘$(patsubst a,b,$(var))’. See Functions for String Substitution and Analysis, for a description of the patsubst function.
For example:
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
sets ‘bar’ to ‘a.c b.c c.c’.

Related

Makefile, applying a function to a list

In a Makefile, I am trying to populate lists by transforming items from an initial list.
As in my real code, those transformations are non-trivial, I try to use a define... endef construct, to apply to each element of the initial list, containing the logic of what I want to accomplish. Then, I apply this "function" using a foreach containing a eval and call.
But something weird happens: it seems that the last element of the list is not treated by the "function".
Here is a MWE Makefile:
libraries :=
define Function
libName = lib$(1)
libraries += $(libName)
# [...more things...]
endef
libs = a b c
$(foreach lib,$(libs),$(eval $(call Function,$(lib))))
all:
$(foreach lib,$(libs),$(lib))
#echo $(libraries)
And the result of running the command make:
a b c
liba libb
I expected the second line to have an extra item libc at its end...
What did I do wrong? What did I misunderstood?
You missed the fact that the argument you provide is expanded twice: first by call, then again as part of the eval.
You can get a better idea of what is happening with eval by replacing it with info:
$(foreach lib,$(libs),$(info $(call Function,$(lib))))
This will show you the text that eval is evaluating. You'll see that here:
libraries += $(libName)
libName is being evaluated by call, before eval sees it. So it expands to the previous run's setting of libName (or the empty string in the first run).
You need to examine your define and for every variable that is a call parameter like $(1) you use it like this, so call expands it, and for every other variable or function reference you probably want to escape it with $$ so that call doesn't expand it and it's left to eval to expand:
define Function
libName = lib$(1)
libraries += $$(libName)
# [...more things...]
endef

How can I pass and return a value from user defined function in MAKEFILE?

I would like create a function that takes a list as an argument, performs some operation and returns a list(or a scalar value). I would like to define the function using 'define'. The function:
1) Performs an operation on the input list
2) Checks if the resultant list is empty, if the list is empty raise an error.
3) Otherwise return the resultant list
This is easily possible in languages like C/C++. I am facing issues when I try to do this in MAKEFILE.
a) Can you point me to examples or post an example here?.
b) How does the MAKEFILE function returns value?
I checked the makefile documentation and few other places on the web but could not find anything useful. This would give me an idea on starting with functions. Thank you for your help!
define myfuntest
fnames := $(filter %pattern, $(1))
ifneq ($(fnames),)
$(error this is an error)
endif
endef
Caller function is something like:
abc := Documents Downloads
return_value := $(call mytestfun,$(abc))
I want 'fnames' to be returned in 'return_value'
User-defined macros must be a single "expression". The returned value is the result of expanding the expression. You definitely cannot use ifneq or variable assignments or other similar things in a user-defined macro.
You can create a makefile piece which is used alongside call, but it can only be used with eval, and that means it's a separate section of makefile, not really a "function" as normally defined.
So, if you can construct your user-defined macro with just make functions such that the result of the expansion is the result you want then you can do it as a macro; for example:
myfuntest = $(or $(filter %pattern,$(1)),$(error this is an error))
results := $(call myfuntest,foo barpattern biz baz)
If the result of the filter will either be a list of matching words and that will be assigned to results, or else it will run the error function.
However, if your function is more complex and cannot be expressed in an expression format, you will have to use eval, and pass in the name of the variable to be assigned, like this:
define myfuntest
... compute fnames from $(2) ...
$(1) := $$(fnames)
endef
You must be very careful with $ vs. $$, as always when using eval and call together. You then invoke this like:
$(eval $(call myfuntest,return_value,$(abc)))

What does two percent % symbols mean in this Makefile sentence?

I encountered this line of code in Makefile. I have tried so hard to find an explanation but not able to. Can someone pass a hint if you have a clue? In particular, what does symbol %= mean in this Makefile sentence.
ifndef VARA
VARB := $(CURDIR:/Dev/home/ajhome/%=/home/%)
export VARA:= $(VARB)
endif
Appreciate a lot in advance.
That shouldn't be read as a %=, the % and = have different functions. It's a pattern substitution:
$(VARNAME:pattern1=pattern2)
And % is a placeholder in the pattern. This is often used (for example) to get the name of object files from source files, for example
SRCS = foo.c bar.c
OBJS = $(SRCS:%.c=%.o)
# $(OBJS) is foo.o bar.o
In your case, it will take the directory in $(CURDIR) and replace the /Dev/home/ajhome/ at its beginning with /home/. Well, if $(CURDIR) is a list of directories, it will do so for each one of them, but the variable name suggests that there's only one in them, so I'm going with that.

Makefile mysteries: What is wrong with this particular use of pathsubst?

My makefile contains these snippets (among others):
SRC = src
OBJ = obj
DEPS = $(wildcard $(SRC)/*.cpp)
# ...
all : $(BINARIES)
#echo $(pathsubst $(SRC)/%.cpp,$(OBJ)/%.d,$(DEPS))
#echo $(DEPS:$(SRC)/%.cpp=$(OBJ)/%.d)
When I make all, only the second #echo outputs something:
$ make all
obj/sample1.d obj/sample1_U.d
The (gnu make) manual states:
Another type of substitution reference lets you use the full power of the patsubst function. It has the same form ‘$(var:a=b)’ described above, except that now a must contain a single ‘%’ character. This case is equivalent to ‘$(patsubst a,b,$(var))’
From this explanation, I would expect that both #echo statements produce the same output, which they clearly don't. What is wrong with the first form using the explicit pathsubst?
(I am using gnu make 3.81 on OS X.)
Presumably you want patsubst, not pathsubst.

GNU Make: How to call $(wildcard) within $(eval)

I'm trying to create a generic build template for my Makefiles, kind of like they discuss in the eval documentation.
I can't seem to get the wildcard function to work within an eval. The basic code I'm having issues with looks like this.
SRC_DIR = ./src/
PROG_NAME = test
define PROGRAM_template
$(1)_SRC_DIR = $(join $(SRC_DIR), $(1)/)
$(1)_SRC_FILES = $(wildcard $$($(1)_SRC_DIR)*.c)
endef
$(eval $(call PROGRAM_template, $(PROG_NAME)))
all:
#echo $(test_SRC_DIR)
#echo $(test_SRC_FILES)
#echo $(wildcard $(wildcard $(test_SRC_DIR)*.c)
When I run make with this, the output is
./src/test
[correct list of all .c files in ./src/test/]
Basically, the wildcard call within PROGRAM_template is not being eval'd as I expect it. The call results in an empty list.
The join call is being eval'd correctly though.
So, what am I doing wrong? My guess is that
$$($(1)_SRC_DIR)
is not correct, but I can't figure out the right way to do it.
EDIT
Once this was solved, it didn't take long for me to hit another issue with eval.
I posted it as a new question at
Workaround for GNU Make 3.80 eval bug
You need to double escape virtually all of the functions and variables when you use eval. In most cases, the only things that don't need to be double-escaped are function arguments (because the call function will fully expand them). In this case, you technically don't need to double-escape join or SRC_DIR either, but it will simplify your life if you just always double-escape all variables and functions when using eval.
The reason you need the double escapes is that expansion happens twice when using eval. The eval function itself performs expansion, and then expansion is done again when the block is finally parsed as makefile syntax (i.e. when it is actually evaluated).
The way you've got it written, wildcard is invoked on the string literal $( test_SRC_DIR)*.c. If you want, you can see this for yourself by replacing wildcard with info in your version and see what happens.
You need to hold off on actually invoking wildcard until the second expansion, so that it's argument is the result of the expansion of $(test_SRC_DIR).
Try this:
SRC_DIR = ./src/
PROG_NAME = test
define PROGRAM_template
$(1)_SRC_DIR = $$(join $$(SRC_DIR),$(1)/)
$(1)_SRC_FILES = $$(wildcard $$($(1)_SRC_DIR)*.c)
endef
$(eval $(call PROGRAM_template,$(PROG_NAME)))
all:
#echo $(test_SRC_DIR)
#echo $(test_SRC_FILES)
#echo $(wildcard $(test_SRC_DIR)*.c)
EDIT: After posting this, I thought I'd better test it out to make sure it actually works. In doing so, I discovered another problem. You should avoid putting spaces between the comma and argument when calling functions. It causes a literal space character to be prepended to the argument that is passed to the function and leads to unintended results. I've removed the spaces after the commas in the function calls in my version (while this isn't a problem for the call to join, I removed the space there as well just because it's a good habit to get into).

Resources