Programming Utilities Guide

More about Macros

Macro definitions can appear on any line in a makefile; they can be used to abbreviate long target lists or expressions, or as shorthand to replace long strings that would otherwise have to be repeated.

You can even use macros to derive lists of object files from a list of source files. Macro names are allocated as the makefile is read in; the value a particular macro reference takes depends upon the most recent value assigned.


Note -

Macro evaluation is more complicated than described here. Refer to ...


With the exception of conditional and dynamic macros, make assigns values in the order the definitions appear.

Embedded Macro References

Macro references can be embedded within other references (not supported in previous versions of make)..

$(CPPFLAGS$(TARGET_ARCH))

Note -

The += assignment appends the indicated string to any previous value for the macro.


In which case they are expanded from innermost to outermost. With the following definitions, make will supply the correct symbol definition for (for example) a Sun-4 system.

CPPFLAGS-sun4 = -DSUN4 
CPPFLAGS += $(CPPFLAGS-$(TARGET_ARCH))

Suffix Replacement in Macro References

make provides a mechanism for replacing suffixes of words that occur in the value of the referred-to macro. Although conventional suffixes start with dots, a suffix can consist of any string of characters. A reference of the form:

$(macro:old-suffix=new-suffix)

is a suffix replacement macro reference. You can use such a reference to express the list of object files in terms of the list of sources:

OBJECTS= $(SOURCES:.c=.o)

In this case, make replaces all occurrences of the .c suffix in words within the value with the .o suffix. The substitution is not applied to words that do not end in the suffix given. The following makefile:

SOURCES= main.c data.c moon 
OBJECTS= $(SOURCES:.c=.o) 

all: 
         @echo $(OBJECTS)

offers a simple illustration:

$ make 
main.o data.o moon

Using lint with make

For easier debugging and maintenance of your C programs use the lint tool. lint also checks for C constructs that are not considered portable across machine architectures. It can be a real help in writing portable C programs.

lint, the C program verifier, is an important tool for forestalling the kinds of bugs that are most difficult and tedious to track down. These include uninitialized pointers, parameter-count mismatches in function calls, and non-portable uses of C constructs. As with the clean target, lint is a target name used by convention; it is usually a good practice to include it in makefiles that build C programs. lint produces output files that have been preprocessed through cpp and its own first (parsing) pass. These files characteristically end in the .ln suffix and can also be derived from the list of sources through suffix replacement (this might not be true for older versions of lint):

LINTFILES= $(SOURCES:.c=.ln)

A target entry for the lint target might appear as:

lint: $(LINTFILES) 
         $(LINT.c) $(LINTFILES) 
$(LINTFILES): 
        	$(LINT.c) $@ -i

There is an implicit rule for building each .ln file from its corresponding .c file, so there is no need for target entries for the .ln files. As sources change, the .ln files are updated whenever you run

make lint

Since the LINT.c predefined macro includes a reference to the LINTFLAGS macro, it is a good idea to specify the lint options to use by default (none in this case). Since lint entails the use of cpp, it is a good idea to use CPPFLAGS, rather than CFLAGS for compilation preprocessing options (such as -I). The LINT.c macro does not include a reference to CFLAGS.

Also, when you run make clean, you will want to get rid of any .ln files produced by this target. It is not difficult to add another such macro reference to a clean target.