$(wildcard) is GNU Make's 'globbing' function. It's a useful way of getting a list of files inside a Makefile, but it has some unexpected behavior: it doesn't always provide the same answer as running an ls. Read on to find out why, and what to do about it.
$(wildcard) explained$(wildcard) can be used anywhere in a Makefile or rule to get a list of files matching one or more 'glob' style patterns. For example, $(wildcard *.foo) returns a list of files ending in .foo. Recall that a list is a string where list elements are separated by spaces, so $(wildcard *.foo) might return a.foo b.foo c.foo. (If a filename itself contains a space then the returned list may appear incorrect because there's no way to spot the different between the list separator (a space) and then space in a filename.)
$(wildcard) can be called with a list of patterns, so $(wildcard *.foo *.bar) returns all the files ending in .foo or .bar. The $(wildcard) operator supports the following 'globbing' operators: * (match 0 or more characters), ? (match 1 character), and [...] (matches characters  or a range of characters [a-z]).
Another useful feature of $(wildcard) is that if the filename passed to it does not contain a pattern then that file is simply checked for existence. If the file exists then its name is returned, otherwise $(wildcard) returns an empty string. Thus $(wildcard) can be combined with $(if) to create an if-exists function:
if-exists = $(if ($wildcard $1),$2,$3)
which will print a.foo is there if a.foo exists, or a.foo is not there if not.
Some unexpected resultsEach of these examples use two variables for obtaining a list of files ending in .foo in a particular directory: WILDCARD_LIST and LS_LIST return the list of files ending in .foo by calling $(wildcard) and $(shell ls). The variable DIRECTORY holds the directory in which the examples look for files; for the current directory DIRECTORY is left empty.
The starting Makefile looks like this:
WILDCARD_LIST = wildcard returned \'$(wildcard $(DIRECTORY)*.foo)\'
LS_LIST = ls returned \'$(shell ls $(DIRECTORY)*.foo)\'
wildcard returned 'a.foo'
ls returned 'a.foo'
Running this Makefile through make (with just the preexisting a.foo file) results in the following surprising output:
wildcard returned 'a.foo'
ls returned 'a.foo b.foo'
The ls is returning the correct list (since b.foo has been created by the time the all rule runs), but $(wildcard) is not; $(wildcard) appears to be showing the state before b.foo was created. Working with the .foo files in a subdirectory (not in the current working directory) results in different output. Here I've updated the Makefile so that it uses the $(DIRECTORY) variable to specify the subdirectory subdir. Once again there's a single preexisting file subdir/a.foo and the Makefile will create subdir/b.foo.
ls returned 'subdir/a.foo subdir/b.foo'
Here both $(wildcard) and ls return the same results and both show the presence of the two .foo files: subdir/a.foo which existed before make was run and subdir/b.foo that was created by the Makefile. One final Makefile before getting down to an explanation of what's happening. In this Makefile $(warning) is used to print out a list of the .foo files that already exist in the subdirectory: