Dynamic Prerequisite Makefile Recipe – First Silicon Designs

Dynamic Prerequisite Makefile Recipe

Dynamically generate a GNU Make prerequisite only if it would be different.

In a flexible, dynamic build system, there will be target prerequisites that are also Make targets with recipes. This is often true when using Make for building things other than compiled software programs. Although Make understands a few software-specific situations (for example, included header files), convincing Make to do this in a general way is not exactly straightforward. By “general”, we mean it supports the case in which a user may trigger rebuilding of the intermediate target by changing a variable on the Make command line. We don’t want to always build the intermediate target, because it would necessarily trigger rebuilding of downstream targets (which may be expensive). Instead, we want to rebuild the intermediate target only if it would be different than the existing (previous) version. In this article we present one technique for generalizing this intermediate target behavior.

Note that this technique requires a two pass, or recursive, Makefile. In the first pass, prerequisite files are created, and in the second pass they are used for the final, “real” Make target(s). An example use of the function is presented later.

Defining the Dynamic Prerequisite Function

This is a case in which we’ll need to generate Make rules dynamically. As we discuss in another article, we’ll have to create a Make function (multiple line variable). Our function will accept four parameters instead of one, to facilitate its use in a complex build system. Here is the skeleton:

# parameter 1 is a namespace, to allow multiple instances to be created
# parameter 2 is a category name, to allow multiple targets per namespace
# parameter 3 is the target file name with path if appropriate (safer)
# parameter 4 is the variable *name* which contains the file generator command
define gen_file_if_different =
. . . endef

This function, when called using $(call ...), will create three target rules:

  • A target for the experimental, temporary, “test” file, which will always be generated
  • A target that creates an initial version of the intermediate target file
  • A psuedo-target used by pass 1 where the update decision is made

The code for these targets is shown below.