1
votes

Using make's ''Remaking Makefiles'' feature I am generating parts of my makefile with include directives (see Makefile: defining rules and prerequisites in recipes). Now I'm stuck with being unable to see how I can express dependencies between included makefiles. They seem to be all evaluated at once.

Consider the following minimal makefile that illustrates my problem:

all:

-include foo.make
-include bar.make

foo.make: Makefile
    echo FOO:=blub bla baz > foo.make

bar.make: Makefile foo.make
    echo BAR:=$(FOO) > bar.make

If I now run make I will get:

$ cat foo.make
FOO:=blub bla baz
$ cat bar.make
BAR:=

Why? Since bar.make depends on foo.make, shouldn't the evaluation of bar.make wait until it successfully included foo.make?

And how do I fix this problem and make sure that bar.make is either re-evaluated later or only evaluated once foo.make exists, is included and can define the variable BAR?

The reason I cannot combine foo.make and bar.make into a single makefile and rule is two-fold:

Firstly, in my real setup, bar.make depends on more intermediate targets which in turn transitively depend on foo.make. So at the time foo.make can be created, the content of bar.make cannot yet be made.

Secondly, in my real setup, foo.make and bar.make do not just define variables but also eval() define/endef blocks. So I have to write:

-include makefile_with_prerequisite_variables
define MYDEF
sometarget-$1: $(TARGET_$1_PREREQUISITES)
    [...]
endf
-include makefile_with_eval_call_statements

The content of makefile_with_prerequisite_variables and makefile_with_eval_call_statements cannot go into a single makefile snippet:

  • If I would put makefile_with_eval_call_statements above MYDEF together with makefile_with_prerequisite_variables then the $eval( $call( MYDEF)) statements in it would not work because MYDEF is only declared afterward.
  • If I would put makefile_with_prerequisite_variables below MYDEF together with makefile_with_eval_call_statements then the recipes defined in MYDEF would not have proper prerequisits because the $(TARGET_$1_PREREQUISITES) variables would then be declared afterward by makefile_with_prerequisite_variables.

In summary, I need to include two different makefiles where one depends upon the other. I do not know how I can express this relationship such that the content of one makefile would only be created after the other makefile is up-to-date and included into the main makefile.

1

1 Answers

1
votes

First, your makefile creation in this simple example can easily be fixed by escaping the value of $(FOO) so that it's not expanded when bar.make is created but rather deferred until it's read in. So:

bar.make: Makefile foo.make
        echo 'BAR:=$$(FOO)' > $@

However, that might not be sufficient in your more complex real-life makefiles.

GNU make works like this: first parse all the makefiles. Then for every included makefile, treat it as a goal and try to build it (e.g., act as if the user invoked make include1.mk include2.mk include3.mk ...). Then at the end of that, if any of the included makefiles was rebuilt, re-exec ourselves and start the entire process over from scratch.

GNU make does NOT work like this: parse makefiles, try to rebuild the first included makefile and if it's rebuilt, re-exec; if it's not rebuilt go on to the next included makefile, etc.

A simple trick you can use if you have to have this type of order is to put the include of bar.make into foo.make:

all:

-include foo.make

foo.make: Makefile
        printf -- '-include bar.make' > $@
        echo FOO:=blub bla baz >> $@

bar.make: Makefile foo.make
        echo 'BAR:=$$(FOO)' > $@

By doing this you ensure that if foo.make doesn't exist, make can't see the include of bar.make and so it won't try to build it. Only after the first re-exec will make see the include of bar.make and try to build it.

One thing: if you get the latest version of GNU make you no longer need to use the -include trick. You can just use include even with generated makefiles.