Dynamic Prerequisite Makefile Recipe – First Silicon Designs

Dynamic Prerequisite Makefile Recipe

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

Using the Dynamic Prerequisite Function

Having completed the three rules in our nifty prerequisite-generator function, let’s invoke it to create specific rules. One additional line in our enclosing makefile is all that is necessary:

$(eval $(call gen_file_if_different,grpA,type_X,prereqfile1,GENPROGRAM))

As mentioned in another article, $(eval ...) is required to treat a multiple line chunk of text (such as that returned from our new function) as rule-defining input to Make.

The function can be called many times, as long as the two argument values “grpA” and “type_X” are unique for each call. These two strings form a unique prefix for the pseudo-target name inside the the function definition. That constructed psuedo-target name is then used as a prerequisite of the downstream target during pass one. We’ll examine the downstream target rules shortly. Each of the two values can be any string that is meaningful to your build environment.

The third argument, prereqfile1, is the point of all this Make coding. This is the file that is a proper prerequisite to another Make target. In our desired use model, we want to enable recreating it (differently) “on-the-fly”, using Make command line variable settings. Even so, the file should not be obsoleted if it would be generated identically to the present version. This saves us from a potentially expensive, unnecessary downstream target (re-)construction.

The function call’s final argument, GENPROGRAM, is the name of a variable (not it’s value!). That variable holds the shell command string used for creating the intermediate target file inside the function definition. The contents of GENPROGRAM are evaluated only when the dependency check is performed for the test version of “prereqfile1“, which happens after all the makefiles are parsed. That means GENPROGRAM may be set anywhere in the containing makefile. With the function definition shown above, the command string must be self-contained. No other variable expansion will be performed when executing $(GENPROGRAM) inside the called function rules. Therefore, any command line switches or argument values required by the generator command must be known when GENPROGRAM is assigned a value.

As a trivial example, GENPROGRAM might be defined like this:

GENPROGRAM := echo "This is the life!"

The value can be anything that could be passed as a valid command string on the shell invocation command line (using the ‘-c‘ switch). You can use Unix pipes and control constructs, so long as they are represented in a single line (a semicolon separates individual commands). Although still contrived, the following example shows a 3-command pipe:

GENPROGRAM := grep udp /etc/services | awk '{print $1, $2}' | sed -e 's^/.*^^'

Now let’s put it all together…