The GNU Make Standard Library

$(call seq,$(call lc,$1),$(call lc,$2)) 

This works by lower-casing its two arguments and then calls seq (the string equality function) to see if they are the same. Here it's used to see if the DEBUG variable has been set to yes; if it has then CPPFLAGS gets -DDEBUG added to it.

    CPPFLAGS += $(if $(call ifcase,$(DEBUG),yes),-DDEBUG,)

Example: Finding a program on the pathHere's a little function definition that will search the PATH for an executable.

    findpath = $(call first, $(call map,wildcard, $(call addsuffix,/$1,
$(call split,:,$(PATH)))))

Calling findpath, $(call findpath,cat), will search the PATH for the first cat program. It uses three functions from the GMSL: first, map and split ; and it uses two built-in functions: wildcard and addsuffix.

The call to split breaks the PATH variable into a list separating it at : 's. Then the built-in addsuffix function is called which adds /$1 to each element of the PATH. $1 contains the parameter to findpath, which is the name of the program being searched for.

Then map is called to perform a built-in wildcard in each possible program. With no wildcard characters in the filename wildcard will return the name of the file if it exists or an empty string. Thus map has the affect of finding the location (or locations) of cat on the PATH by testing each file in turn.

Finally, a call to the GMSL function first returns the first element of the list that map returns (the list of all cat programs on the PATH ).

A debugging feature of GMSL is the ability to trace calls to GMSL functions. By setting GMSL_TRACE to 1 GMSL will output each call to a GMSL function with its parameters. Here's an example of searching for cat using the findpath function with tracing turned on:

    Makefile:8: split(':','/home/jgc/bin:/usr/local/bin:/usr/bin:
Makefile:8: map('wildcard',' /home/jgc/bin/gmake /usr/local/bin/gmake 
/usr/X11R6/bin/gmake /bin/gmake /usr/games/gmake 
/opt/gnome/bin/gmake /opt/kde3/bin/gmake
Makefile:8: first(' /usr/bin/gmake') 

Example: Using assertions to check inputsTypically a Makefile is executed specifying a goal for the build (or under the assumption that there's an 'all' target or similar at the start of the Makefile). In addition there are typically environment variables (e.g. debug options, architecture settings, ...) that affect the build. A quick way to check that these have been set correctly is to use GMSL's assert functions.Here's an example that checks that DEBUG has been set to yes or no, that ARCH contains the word Linux, and that we've specified an output directory in the OUTDIR variable and that that directory exists. The assertion functions will generate a fatal error if their first argument is $(false) (i.e. an empty string).

    $(call assert,$(OUTDIR),Must set OUTDIR)
$(call assert_exists,$(OUTDIR),Must set OUTDIR)
$(call assert,$(if $(call seq,$(DEBUG),yes), $(true), 
$(call seq,$(DEBUG),no)), DEBUG must be yes or no)
$(call assert,$(call findstring,Linux,$(ARCH)), ARCH must be Linux)

The first assert checks that $(OUTDIR) has been set to something. If it has a non-empty value then the assertion passed, if not then an error will be generated:

    Makefile:3: *** GNU Make Standard Library: Assertion failure: Must set OUTDIR. Stop.

The second assertion is of the form assert_exists which checks to see if its first argument exists in the file system. In this case it checks to see if the directory pointed to by $(OUTDIR) exists. It doesn't check to see if it's a directory. We can add another assertion for that like this:

    $(call assert,$(wildcard $(OUTDIR)/.*),OUTDIR must be a directory)

That works by looking to see if $(OUTDIR) contains any files starting with a . (such as the usual . and .. ). If not then $(OUTDIR) is not a directory and the call to wildcard will return an empty string causing the assertion to

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.