Makefile : chains of implicit rules examples

chains of implicit rules examples
the source code:

///////////////////////////////////////////////////////////////////
//main.e:
#include "fun1.h"
#include "fun2.h"

int main()
{
    fun1();
    fun2();
    printf("mainn");
}

///////////////////////////////////////////////////////////////////
//fun1.h
void fun1();

///////////////////////////////////////////////////////////////////
//fun2.h
void fun2();

///////////////////////////////////////////////////////////////////
//fun1.e
#include <stdio.h>
#include "fun1.h"

void fun1()
{
    printf("fun1n");
}

///////////////////////////////////////////////////////////////////
//fun2.e
#include <stdio.h>
#include "fun2.h"

void fun2()
{
    printf("fun2n");
}

###################################################################
##Makefile
all : main

.SUFFIXES:

%c : %e
    cp $< $@

%.o: %.c
    @sleep 1
    $(CC) -MD -c -o $@ $(CFLAGS) $<

OBJS = fun1.o fun2.o main.o

main : $(OBJS)
    $(CC) -o $@ $^

clean :
    rm -f $(OBJS) $(OBJS:%.o=%) $(OBJS:%.o=%.d) $(OBJS:%.o=%.c) depend

comma := ,
depend: $(wildcard .d)
    if test -f depend; then sed $(patsubst %.d,-e ‘/^%.o/$(comma)/^#/d’,$^) <depend >depend.new; fi; true
    (for file in $^ /dev/null; do (cat $$file; echo ‘#’); done) >>depend.new
    mv -f depend.new depend
    if test "" != "$^"; then rm -f $^; fi; true


# Include the dependency graph (if it exists).
-include depend

note that sleep 1 is added before $(CC), this is to distinguish the file-create time of .d(depend file) and depend(ie: make file "depend" the oldest).

the output :

[jfo@redhat9 test]$ make clean
if test -f depend; then sed <depend >depend.new; fi; true
(for file in /dev/null; do (cat $file; echo ‘#’); done) >>depend.new
mv -f depend.new depend
if test "" != ""; then rm -f ; fi; true
rm -f fun1.o fun2.o main.o fun1 fun2 main fun1.d fun2.d main.d fun1.c fun2.c main.c depend

[jfo@redhat9 test]$ make
if test -f depend; then sed <depend >depend.new; fi; true
(for file in /dev/null; do (cat $file; echo ‘#’); done) >>depend.new
mv -f depend.new depend
if test "" != ""; then rm -f ; fi; true
cp fun1.e fun1.c
cc -MD -c -o fun1.o fun1.c
cp fun2.e fun2.c
cc -MD -c -o fun2.o fun2.c
cp main.e main.c
cc -MD -c -o main.o main.c
cc -o main fun1.o fun2.o main.o
rm fun1.c main.c fun2.c

[jfo@redhat9 test]$ make
if test -f depend; then sed -e ‘/^fun1.o/,/^#/d’ -e ‘/^fun2.o/,/^#/d’ -e ‘/^main.o/,/^#/d’ <depend >depend.new; fi; true
(for file in fun1.d fun2.d main.d /dev/null; do (cat $file; echo ‘#’); done) >>depend.new
mv -f depend.new depend
if test "" != "fun1.d fun2.d main.d"; then rm -f fun1.d fun2.d main.d; fi; true
cp fun1.e fun1.c
cc -MD -c -o fun1.o fun1.c
cp fun2.e fun2.c
cc -MD -c -o fun2.o fun2.c
cp main.e main.c
cc -MD -c -o main.o main.c
cc -o main fun1.o fun2.o main.o

[jfo@redhat9 test]$ make
if test -f depend; then sed -e ‘/^fun1.o/,/^#/d’ -e ‘/^fun2.o/,/^#/d’ -e ‘/^main.o/,/^#/d’ <depend >depend.new; fi; true
(for file in fun1.d fun2.d main.d /dev/null; do (cat $file; echo ‘#’); done) >>depend.new
mv -f depend.new depend
if test "" != "fun1.d fun2.d main.d"; then rm -f fun1.d fun2.d main.d; fi; true
make: Nothing to be done for all'.<br /> <br /> [jfo@redhat9 test]$ make<br /> make: Nothing to be done forall’.

Take note of the last line of the first make command output. This is similar to that of oskit when doing make all' in $(OSKIT_SRC)/kern directory, which output &quot;rm x86_asm.symc trap_asm.symc.o x86_asm.symc.o pc_asm.symc.o pc_asm.symc trap_asm.symc&quot;. But when youmake’ for the second time, file "depend" will contains
all the intermediate files, so implicit rules is not implict any longer. This is the very reason why the "rm …" didn’t appear for the second make.

everytime when a file included is older than prequisites, make will try to regenerate the target file.(just think of a Makefile includes another Makefile, it is reasonable to generate the included Makefile first if it is out of date!)