GNU Make user-defined functions can do a lot. Ask Mr. Make takes you on a quick your of the basics.
Here's a very simple GNU Make function: it takes three arguments and makes a 'date' out of them by inserting / between the first and second and second and third arguments:
make_date = $1/$2/$3
The first thing to notice is that make_date is defined just like any other GNU Make macro (you must use = and not := for reasons we'll see below).
To use make_date we $(call) it like this:
today = $(call make_date,19,12,2007)
That will result in today containing 19/12/2007.
The macro uses special macros $1, $2, and $3. These macros contain the argument specified in the $(call). $1 is the first argument, $2 the second and so on.
There's no maximum number of arguments, but if you go above 10 then you need parens: you can't write $10 instead of $(10). There's also no minimum number. Arguments that are missing are just undefined and will typically be treated as an empty string.
The special argument $0 contains the name of the function. In the example above $0 is make_date.
Since functions are just macros with some special automatic macros filled in (if you use the $(origin) function on any of the argument macros ($1 etc.) you'll find that they are classed as automatic just like $@), you can use GNU Make built in functions to build up complex functions.
Here's a function that turns every / into a \ in a path"
unix_to_dos = $(subst /,\,$1)
using the $(subst). Don't be worried about the use of / and \ there. GNU Make does very
little escaping and a literal \ is most of the time just a \.
Some argument handling gotchas
When GNU Make is processing a $(call) it starts by splitting the argument list on commas to set $1 etc. The arguments are expanded so that $1 etc. are completely expanded before they are ever referenced (it's as if GNU Make used := to set them). This means that if an argument has a side-effect (such as calling $(shell)) then that side-effect will always occur as soon as the $(call) is executed, even if the argument was never actually used by the function.
One common problem is that if an argument contains a comma the splitting of
arguments can go wrong. For example, here's a simple function that swaps its two arguments:
swap = $2 $1
If you do $(call swap,first,argument,second) GNU Make doesn't have any way to know that the first argument was meant to be first,argument and swap ends up returning argument first instead of second first,argument.
There are two ways around this. You could simply hide the first argument inside a macro. Since GNU Make doesn't expand the arguments until after splitting a comma inside a macro will not cause any confusion:
FIRST := first,argument
SWAPPED := $(call swap,$(FIRST),second)
The other way to do this is to create a simple macro that just contains a comma and use that instead:
c := ,
SWAPPED := $(call swap,first$cargument,second)
Or even call that macro , and use it (with parens):
, := ,
SWAPPED := $(call swap,first$(,)argument,second)
Calling built-in functions
It's possible to use the $(call) syntax with built in GNU Make functions. For example, you could call $(warning) like this:
This is useful because it means that you can pass any function name as an argument to a user-defined function and $(call) it without needing to know if it's built-in or not.
This gives you the ability to created functions that act on functions. The classic functional programming map function (which applies a function to every member of a list returning the resulting list) can be created like