Writing Recursive Makefiles

When writing Makefiles, it makes sense to make them modular. My modular, I mean having a master makefile that calls other Makefiles dynamically. This is done by including the child makefiles, and having the child makefiles add themselves to the parent makefile's execution list. This is better explained in the makefile syntax as showed at the bottom of this page.

Parts of child Makefile

Each child Makefile will have a number of operations:

  1. Source File Download
  2. (Optional) Patch file download
  3. Source Extraction
  4. Source configuration or patch
  5. Source compilation
  6. Source cleanup

Basically, the makefile checks for the existance of the source tarball, and downloads it if it doesn't exist. Then, it extracts the tarball, and either configures the package, or applies a patch file which may contain all of the configurations. Then the source is compiled, and finally, there's an option to remove all of the compiled objects to bring the directory back to its pre-compiled state.

Why?

Sometimes it makes sense to compile a number of thirdparty applications and install them to a specific directory. You may wish to only compile certain components, or configure certain components differently. This can be done by applying different patches etc etc.

Example

I compile and build embedded Linux systems on a daily basis. Sometimes I want to include ppp support, sometimes I don't. So here's the master Makefile, and the ppp makefile used to compile ppp support.

Makefile:

#TOOLCHAIN:=    /home/peterb/cross/toolchain/gcc-3.3.x/toolchain_arm/bin/arm-linux-
TOOLCHAIN:=     arm-linux-
CC:=            $(TOOLCHAIN)gcc
STRIP:=         $(TOOLCHAIN)strip

MAKEFLAGS:=     STRIP=$(STRIP)

include  ppp.mak

.PHONY: list


all:    $(MOD_TARBALL)

clean:  $(MOD_CLEAN)

list:
        @echo $(MOD_TARBALL)

ppp.mak:

# ppp Makefile

PPP_TARBALL=ppp-2.4.1.tar.gz
PPP_MODULE=ppp-2.4.1

MOD_TARBALL+=$(PPP_MODULE)
MOD_CLEAN+=$(PPP_MODULE)_CLEAN

DESTDIR:=/home/peterb/basestation/thirdparty/root

$(PPP_MODULE):  $(PPP_MODULE)/.patched
        DESTDIR=$(DESTDIR) CC=arm-linux-gcc make -C $(PPP_MODULE) CC=$(CC) all install

./$(PPP_MODULE)/.patched:       $(PPP_MODULE)/.extracted
        patch -p0 < dl/$(PPP_MODULE).patch && touch $(PPP_MODULE)/.patched

./$(PPP_MODULE)/.extracted: dl/$(PPP_TARBALL)
        tar zxpvf dl/$(PPP_TARBALL) && touch ./$(PPP_MODULE)/.extracted

dl/$(PPP_TARBALL):
        wget http://locations.of.source/ppp-2.4.1.tar.gz -P dl

$(PPP_MODULE)_CLEAN:
        rm -rf $(PPP_MODULE)
        #rm -rf dl/$(PPP_TARBALL)

So, then I call 'make list', it will output 'ppp-2.4.1' (or any other module that was included at the top of Makefile. And if I call 'make all' then it will compile each string appended to 'MOD_TARBALL' (yes, I know.. confusing name).

Let's follow this path

When running this example, 'make all' will execute $PPP_MODULE, which will call the Makefile under the ppp directory. But first, it must ensure that the '.patched' file exists. This depends upon the '.extracted' file to exist, which requires the tarball to exist.


Click here to return to index