Make: Sorting and Searching


return the full path each time it finds the requested file. Each found file (and path) will be returned in the same order as the paths in the first argument.

which-dirs = $(wildcard $(addsuffix /$2,$1))

It works by adding the name of the file to search for to each element of the path using $(addsuffix). Since $(wildcard) works even if there are no wild card characters present (in which case it acts as a 'file exists' function, returning the name of the file if it is present, or an empty string if not) and $(wildcard) can accept a list of files to look for in which case it searches for each.

A simple use of which-dirs would be to search the PATH for a particular executable. Here's what happens on my machine looking for emacs on the path:

$(warning $(call which-dirs,$(subst :, ,$(PATH)),emacs))

and it outputs:

Makefile:2: /usr/bin/emacs /usr/bin/X11/emacs

Notice that since PATH is a :-separated list I first turned it into a space-separated list for which-dirs by writing $(subst :, ,$(PATH)) .

If I wanted to know the first place that emacs is found on the path I'd just take the first element of the list returned by which-dirs using the GNU Make built-in function $(firstword):

$(warning $(firstword $(call which-dirs,$(subst :, ,$(PATH)),emacs)))

Searching for a list member

That's enough file searching. How about searching to see if a list contains a specific member? GNU Make provides two functions that can be used for that purpose: $(filter) and $(filter-out).

To see if a list contains a specific string the $(filter) function is used. If the string is present in the list then $(filter) returns the string found, if it is not present the the function returns an empty string.

For example, to search the list a b dog c for the word dog and the word cat you can do:

LIST := a b dog c

$(warning $(filter dog,$(LIST)))

$(warning $(filter cat,$(LIST)))

and the output will look like:

Makefile:3: dog


because there is a dog, but no cat.

$(filter) also supports wild cards; well one wild card: %. So to find whether the same list contains any word starting with d you use the pattern d%:

LIST := a b dog c

$(warning $(filter d%,$(LIST)))

and you'll get the following output:

Makefile:3: dog

$(filter-out) performs the opposite of $(filter): it will return an empty string if the pattern is present, and a non-empty string if it is not. For example, to see if the same list does not contain the word cat you use $(filter-out):

LIST := a b dog c

$(warning $(filter-out cat,$(LIST)))

and you'll get the following output:

Makefile:3: a b dog c

Notice that the output here is actually the entire list (because of the way $(filter-out) works). From GNU Make's perspective any non-empty string is 'true' and the empty string is 'false'. The output of both $(filter) and $(filter-out) can be used directly with ifndef or $(if) as a truth-value.

Searching for a sub-string

Lastly, if you are dealing with a string and not a list, you may need to search for a substring. GNU Make has a built-in function $(findstring) for that purpose.

For example, to see if the substring ' og c ' appears in the string ' a b dog c ' do the following:

STRING := a b dog c

$(warning $(findstring og c,$(STRING)))

which will output

Makefile:3: og c

If the string had not been present the function would have returned an empty string. Notice how $(findstring) is treating the same text

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.