Programming Utilities Guide

.KEEP_STATE and Hidden Dependencies

When a C source file contains #include directives for interpolating headers, the target depends just as much on those headers as it does on the sources that include them. Because such headers might not be listed explicitly as sources in the compilation command line, they are called hidden dependencies. When .KEEP_STATE is in effect, make receives a report from the various compilers and compilation preprocessors indicating which hidden dependency files were interpolated for each target.

It adds this information to the dependency list in the state file. In subsequent runs, these additional dependencies are processed just like regular dependencies. This feature automatically maintains the hidden dependency list for each target; it ensures that the dependency list for each target is always accurate and up to date. It also eliminates the need for the complicated schemes found in some earlier makefiles to generate complete dependency lists.

A slight inconvenience can arise the first time make processes a target with hidden dependencies, because there is as yet no record of them in the state file. If a header is missing, and make has no record of it, make does not know that it needs to retrieve it from SCCS before compiling the target.

Even though there is an SCCS history file, the current version won't be retrieved because it doesn't yet appear in a dependency list or the state file. When the C preprocessor attempts to interpolate the header, it won't find it; the compilation fails.

Supposing that a #include directive for interpolating the header hidden.h is added to functions.c, and that the file hidden.h is somehow removed before the subsequent make run. The results would be:

$ rm -f hidden.h 
$ make functions 
cc -O -o functions functions.c 
functions.c: 2: Can't find include file hidden.h 
make: Fatal error: Command failed for target `functions'

A simple workaround might be to make sure that the new header is extant before you run make. Or, if the compilation should fail (and assuming the header is under SCCS), you could manually retrieve it from SCCS:

$ sccs get hidden.h 
1.1 
10 lines 
$ make functions 
cc -O -o functions functions.c

In all future cases, should the header turn up missing, make will know to build or retrieve it for you because it will be listed in the state file as a hidden dependency.

Note that with hidden dependency checking, the $? macro includes the names of hidden dependency files. This might cause unexpected behavior in existing makefiles that rely on $?.

.INIT and Hidden Dependencies

The problem with both of these approaches is that the first make in the local directory might fail due to a random condition in some other (include) directory. This might entail forcing someone to monitor a (first) build. To avoid this, you can use the .INIT target to retrieve known hidden dependencies files from SCCS. .INIT is a special target that, along with its dependencies, is built at the start of the make run. To be sure that hidden.h is present, you could add the following line to your makefile

.INIT:     hidden.h