Dynamic Prerequisite Makefile Recipe – First Silicon Designs

Dynamic Prerequisite Makefile Recipe

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

Rules for the Downstream Target

We now have all the pieces in place for implementing our downstream target recipe. As mentioned earlier, this technique requires a two-pass make operation. A new variable PREREQS_BUILT is used to define which pass is being performed. Initially it will be undefined, which causes the ‘ifneq‘ test to succeed, and we include the rules to generate the intermediate prereqfile1 file:

ifneq ($(PREREQS_BUILT),1)
$(eval $(call gen_file_if_different,grpA,typeX,prereqfile1,GENPROGRAM))
all : grpA_typeX_FILEGEN
        $(MAKE) --no-print-directory -f $(THIS_MAKEFILE) \
                PREREQS_BUILT=1 $(MAKECMDGOALS)
else
all : prereqfile1
        @echo "Must have generated the dependent file!"
        @echo "Executing recipe for $@"
        touch $@
endif

During the initial pass, the downstream target (‘all‘ in this example) lists our function-defined pseudo-target ‘grpA_typeX_FILEGEN‘ as its prerequisite, instead of prereqfile1. If prereqfile1 needs to be updated, it will be, by the function-generated rules. Otherwise it will be left untouched. Then a recursive Make is executed (the second pass) with PREREQS_BUILT=1 defined. On that second pass, the ‘ifneq‘ test will fail, causing the ‘else‘ portion to be used. This portion contains what normally would be the recipe for the downstream target, had we not introduced the dynamic generation capability.

Finally, you’ll see that we explicitly name the makefile in the recursive call during pass one. This is because Make does not pass this along by default. If your makefile is named anything besides “Makefile“, the recursive invocation will fail. The name is not directly available; instead, we have to extract it using the following statement, located prior to any include statements in the makefile:

THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))

In Conclusion

Using Make to build complex systems, as opposed to compiled software programs, is well within reach with a little persistence and cleverness. The rich feature set available with Make allows many higher level functions to be created that enable very flexible use models. In this article, we’ve described a technique to enable a chain of targets to be rebuilt dynamically from any intermediate point, from the command line. We hope you gained some valuable insights here that will accelerate your successful use of Make in challenging build environments. Please contact us with questions or comments. Take a look at our products and services – we can help you create or fine tune your build framework.