Learning GNU Make Functions with Arithmetic


Gte will return a non-empty string if either of gt or eq do. The eq function is a bit of a mind bender. It works out the number of elements in its two elements and then treats one of them as a pattern and the other as a list and uses $(filter) to decide whether they are the same. Here's an example where they are equal:

    $(call eq,$(five),$(five)) 
=> $(call eq,x x x x x,x x x x x)
=> $(filter $(words x x x x x),$(words x x x x x))
=> $(filter 5,5)
=> 5

And here's what happens when they are not:

    $(call eq,$(five),$(six)) 
=> $(call eq,x x x x x,x x x x x x)
=> $(filter $(words x x x x x),$(words x x x x x x))
=> $(filter 5,6)

So the $(filter) function acts as a kind of “string equality” operator; the two strings in our case are the lengths of the two number strings. The gt function is implemented in a similar way: it returns a non-empty string if the length of the first number string is not equal to the maximum of the two number strings. Here's an example:

    $(call gt,$(six),$(five))
=> $(call gt,x x x x x x,x x x x x)
=> $(filter-out $(words x x x x x),
$(words $(call max,x x x x x x,x x x x x)))
=> $(filter-out $(words x x x x x),$(words x x x x x x))
=> $(filter-out 5,6)
=> 6

And another when the first number is less than the second:

    $(call gt,$(five),$(six))
=> $(call gt,x x x x x,x x x x x)
=> $(filter-out $(words x x x x x x),
$(words $(call max,x x x x x x,x x x x x)))
=> $(filter-out $(words x x x x x x),$(words x x x x x x))
=> $(filter-out 6,6)

Similarly, it's possible to define “not equal” (ne), “less than” (lt) and “less than or equal” (lte) operators:

    lt = $(filter-out $(words $1),$(words $(call max,$1,$2)))
ne = $(filter-out $(words $1),$(words $2))
lte = $(call lt,$1,$2)$(call eq,$1,$2)

Just three more functions to define and we've got a pretty powerful package: multiply, divide and encode. The first two are clear, the last as a way to create a number string of x's from a integer; we'll leave that to last and then implement a simple calculator in GNU Make.

Multiplication uses the $(foreach VAR,LIST,DO) function. It sets that variable named VAR to each element of LIST and does whatever DO says. So multiplication is easy to implement:

    multiply = $(foreach a,$1,$2)

It just strings together its second argument for however many x's there are in the first. For example,

    $(call multiply,$(two),$(three))
=> $(call multiply,x x,x x x)
=> $(foreach a,x x,x x x)
=> x x x x x x

Division is the most complex function of the lot because it uses recursion:

    divide = $(if $(call gte,$1,$2),                            \
x $(call divide,$(call subtract,$1,$2),$2),)

If its first argument is less than its second then division returns 0 because the ELSE part of the $(if) is empty (see the ,) at the end). If division is possible then divide works by repeated subtraction of the second argument from the first using the subtract function. Each time it subtracts it adds an x and calls divide again. Here's an example:

    $(call divide,$(three),$(two))
=> $(call divide,x x x,x x)
=> $(if $(call gte,x x x,x x),
x $(call divide,$(call subtract,x x x,x x),x x),)

(gte returns a non-empty string so that recursion happens)

        => x $(call divide,$(call subtract,x x x,x x),x x)
=> x $(call divide,x,x x)
=> x $(if $(call gte,x,x x),
x $(call divide,$(call subtract,x,x x),x x),)

(gte returns an empty string so no more recursion)

        => x

About the author

AgileConnection is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.