Search code examples
makefilegnu

GNU make re-evaluation of dependencies


I have a program that depends on a library that is built by a separate makefile. The main makefile does not properly detect that the library has been rebuilt and therefore does not recreate my program.

The main Makefile can be simplified (just using touch to represent the actual compilation) as this. It always calls the sub-make to make sure that libA is up to date without needing to know about its dependecies.

progA: srcA libA
    touch $@

libA: make_libA_if_needed

.PHONY: make_libA_if_needed
make_libA_if_needed:
    make -f Makefile.libA libA

clean:
    rm -f progA libA

The second makefile Makefile.libA can be simplified as this

libA: libsrcA
    touch $@

This works as expected when the libA does not exists or does not need to be rebuilt

jronnber@jronnber-mobl:~/tmp $ touch srcA libsrcA
jronnber@jronnber-mobl:~/tmp $ make
make -f Makefile.libA libA
make[1]: Entering directory '/home/jronnber/tmp'
touch libA
make[1]: Leaving directory '/home/jronnber/tmp'
touch progA
jronnber@jronnber-mobl:~/tmp $ make
make -f Makefile.libA libA
make[1]: Entering directory '/home/jronnber/tmp'
make[1]: 'libA' is up to date.
make[1]: Leaving directory '/home/jronnber/tmp'
jronnber@jronnber-mobl:~/tmp $

However, if I update libsrcA I need to run make twice in order for progA to be rebuilt properly.

jronnber@jronnber-mobl:~/tmp $ touch libsrcA
jronnber@jronnber-mobl:~/tmp $ make
make -f Makefile.libA libA
make[1]: Entering directory '/home/jronnber/tmp'
touch libA
make[1]: Leaving directory '/home/jronnber/tmp'
jronnber@jronnber-mobl:~/tmp $ make
make -f Makefile.libA libA
make[1]: Entering directory '/home/jronnber/tmp'
make[1]: 'libA' is up to date.
make[1]: Leaving directory '/home/jronnber/tmp'
touch progA
jronnber@jronnber-mobl:~/tmp $

Is this a bug in make or can I change my Makefile somehow to detect that libA has been rebuilt by the sub-make in make_libA_if_needed?


Solution

  • This line is not sufficient:

    libA: make_libA_if_needed
    

    GNU Make knows that there is no recipe here and so it didn't run a command to update that target, so it "knows" that the target hasn't been modified. You can add a dummy recipe to the rule so that make realizes that this target might have been updated (even if the recipe is empty, make still considers that it might have been updated).

    So change the above line to this:

    libA: make_libA_if_needed ;
    

    (note the added semicolon). Or if you prefer you could use this:

    libA: make_libA_if_needed
            @: do nothing
    

    or whatever.

    An alternate way to go is to use a FORCE rule instead of .PHONY. .PHONY is a very big stick and tells make to always rebuild the target AND to assume it was out of date. But the FORCE trick ensures the target is rebuilt without assuming it was out of date. That would look like this:

    libA: FORCE
            $(MAKE) -f Makefile.libA $@
    FORCE:
    

    (note you should always use $(MAKE) to invoke sub-makes, never make). In this model you don't need the make_libA_if_needed target.

    Note the actual name of the target FORCE is just a convention; you can call this anything you like. You can also declare it to be .PHONY if you want to be extra safe.