Programming Utilities Guide

Nested make Commands

The solution is to use a nested make command, running in the directory the library resides in, to rebuild it (according to the target entry in the makefile there)


Note -

The MAKE macro, which is set to the value ``make'' by default, overrides the -n option. Any command line in which it is referred to is executed, even though -n might be in effect. Since this macro is used to invoke make, and since the make it invokes inherits -n option from the special MAKEFLAGS macro, make can trace a hierarchy of nested make commands with the -n option.


# First cut entry for target in another directory.  

../lib/libpkg.a:
        	cd ../lib ; $(MAKE) libpkg.a

The library is specified with a path name relative to the current directory. In general, it is better to use relative path names. If the project is moved to a new root directory or machine, so long as its structure remains the same relative to that new root directory, all the target entries will still point to the proper files.

Within the nested make command line, the dynamic macro modifiers F and D come in handy, as does the MAKE predefined macro. If the target being processed is in the form of a pathname, $(@F) indicates the filename part, while $(@D) indicates the directory part. If there are no / characters in the target name, then $(@D) is assigned the dot character (.) as its value.

The target entry can be rewritten as:

# Second cut.  

../lib/libpkg.a:
        	cd $(@D); $(MAKE) $(@F)

Forcing a Nested make Command to Run

Because it has no dependencies, this target runs only when the file named ../lib/libpkg.a is missing. If the file is a library archive protected by .PRECIOUS, this could be a rare occurrence. The current make invocation neither knows nor cares about what that file depends on, nor should it. It is the nested invocation that decides whether and how to rebuild that file.

After all, just because a file is present in the file system does not mean it is up-to-date. This means that you have to force the nested make to run, regardless of the presence of the file, by making it depend on another target with a null rule (and no extant file):

Table 4-14 Target Entry for a Nested make Command
# Reliable target entry for a 
# nested make command.

../lib/libpkg.a:  FORCE
        	cd $(@D); $(MAKE) $(@F) 
FORCE:

In this way, make reliably changes to the correct directory ../lib and builds libpkg.a if necessary, using instructions from the makefile found in that directory. These lines are produced by the nested make run:

$ make ../lib/libpkg.a 
cd ../lib; make libpkg.a 
make libpkg.a 
`libpkg.a' is up to date.

The following makefile uses a nested make command to process local libraries that a program depends on.

Table 4-15 Makefile for C Program with User-Supplied Libraries
# Makefile for a C program with user-supplied 
# libraries and nested make commands. 

CFLAGS= -O 

.KEEP_STATE:

functions: main.o data.o ../lib/libpkg.a 
        	$(LINK.c) -o $@ main.o data.o
         ../lib/libpkg.a -lcurses -ltermlib 
         ../lib/libpkg.a:  FORCE
        	cd $(@D); $(MAKE) $(@F) 
FORCE: 

lint: main.ln data.ln 
        	$(LINT.c) main.ln data.ln 
clean: 
        	rm -f functions main.o data.o main.ln data.ln

When ../lib/libpkg.a is up to date, this makefile produces:

$ make 
cc -O -c main.c 
cc -O -c data.c 
cd ../lib; make libpkg.a 
`libpkg.a' is up to date.  
cc -O -o functions main.o data.o ../lib/libpkg.a -lcurses -l   termlib

The MAKEFLAGS Macro

Like the MAKE macro, MAKEFLAGS is also a special case.


Note -

Do not define MAKEFLAGS in your makefiles.


MAKEFLAGS contains flags (that is, single-character options) for the make command. Unlike other FLAGS macros, the MAKEFLAGS value is a concatenation of flags, without a leading `-'. For instance the string eiknp would be a recognized value for MAKEFLAGS, while -f x.mk or macro=value would not.

If the MAKEFLAGS environment variable is set, make runs with the combination of flags given on the command line and contained in that variable.

The value of MAKEFLAGS is always exported, whether set in the environment or not, and the options it contains are passed to any nested make commands (whether invoked by $(MAKE), make, or /usr/bin/make). This insures that nested make commands are always passed the options which the parent make was invoked.