title: How to write a good and efficient makefile
body: <p>I have following folder structure:</p>
  
  <pre><code>TOPDIR
  |
  ├── a
  │   ├── a.c
  │   ├── a.h
  │   └── a.mk
  ├── b
  │   ├── b.c
  │   ├── b.h
  │   └── b.mk
  ├── c
  │   ├── c.c
  │   ├── c.h
  │   └── c.mk
  ├── include
  │   └── common.h
  ├── root
  │    ├── main.c
  │    └── root.mk
  └── Makefile
  </code></pre>
  
  <p><strong>per-condition</strong></p>
  
  <p>My target is to write main <code>Makefile</code> under <code>TOPDIR</code> and sub-makefile, <code>*.mk</code> in sub folder, the <code>include</code> folder contain some common defines. <code>root</code> folder contain my main file(<code>main</code> function located here). Meanwhile, in <code>main.c</code>, it will call function from <code>a.c</code> and <code>b.c</code>, <code>c.c</code> is driver related, and will be called from <code>a.c</code> and <code>b.c</code></p>
  
  <p><strong>Problem</strong></p>
  
  <p>I wrote sub-makefile like(I use one <code>a.mk</code> for example, others are same, ONLY <code>root.mk</code> has little different):</p>
  
  <pre><code>#MODULE will be modified for each sub folder
  MODULE = a
  LIB = $(MAKE_DIR)/libs/lib$(MODULE).a
  SRCS = $(wildcard *.c)
  OBJS = $(patsubst %.c, %.o, $(SRCS))
  
  #generate lib file from obj file
  $(LIB): $(OBJS)
      @mkdir -p ../libs
      @$(AR) cr $@ $^
      @echo "    Archive    $(notdir $@)"
  
  #compile obj file from source file
  $(OBJS): $(SRCS)
      @$(CC) $(CFLAGS) -c $^
      @echo "    CC        $(OBJS)"
  
  .PHONY: clean
  clean:
      @$(RM) -f $(LIB) $(OBJS)
      @$(RM) -f *.expand
      @echo "    Remove Objects:   $(OBJS)"
      @echo "    Remove Libraries:  $(notdir $(LIB))"
  </code></pre>
  
  <p>I wrote <code>root.mk</code> like:</p>
  
  <pre><code>PROG = ../prog/DEMO
  
  SRCS = $(wildcard *.c)
  OBJS = $(patsubst %.c, %.o, $(SRCS))
  
  #generate finial target file for run
  $(PROG): $(SRCS)
      @mkdir -p ../prog
      @$(CC) $^ $(CFLAGS) -Wl,-Map=$(PROG).map $(LIBS) -o $@
      @echo "    Generate Program $(notdir $(PROG)) from $^"
  
  .PHONY: clean
  clean:
      @$(RM) -f $(OBJS) $(PROG)
      @$(RM) -f *.expand
      @$(RM) -rf ../prog ../libs
      @echo "    Remove Objects:   $(OBJS)"
      @echo "    Remove Libraries:  $(notdir $(PROG))"
  </code></pre>
  
  <p>I wrote main <code>Makefile</code> like:</p>
  
  <pre><code>MAKE_DIR = $(PWD)
  
  ROOT_DIR    := $(MAKE_DIR)/root 
  DRV_DIR     := $(MAKE_DIR)/driver
  INCLUDE_DIR := $(MAKE_DIR)/include
  DEBUG_DIR   := $(MAKE_DIR)/debug
  
  INC_SRCH_PATH := 
  INC_SRCH_PATH += -I$(ROOT_DIR)
  INC_SRCH_PATH += -I$(DRV_DIR) 
  INC_SRCH_PATH += -I$(INCLUDE_DIR)
  INC_SRCH_PATH += -I$(DEBUG_DIR)
  
  LIB_SRCH_PATH :=
  LIB_SRCH_PATH += -L$(MAKE_DIR)/libs
  
  CC = gcc
  LD = ld
  
  #problem happan here, if I change the sequence of LIB, 
  #during the finial link, it will find some function un-referenced, 
  #why can I put liba first?
  LIBS := -lc -lb -la
  
  CFLAGS :=
  CFLAGS += $(INC_SRCH_PATH) $(LIB_SRCH_PATH) 
  CFLAGS += -Wall -O -ggdb
  CFLAGS += -DDEBUG -D_REENTRANT
  
  LDFLAGS :=
  
  export MAKE_DIR CC LD CFLAGS LDFLAGS LIBS LINT INC_SRCH_PATH
  
  all:
      @$(MAKE) -C a -f a.mk
      @$(MAKE) -C b -f b.mk
      @$(MAKE) -C c -f c.mk
      @$(MAKE) -C root -f root.mk
  
  .PHONY: clean
  clean:
      @$(MAKE) -C debug -f debug.mk clean
      @$(MAKE) -C driver -f driver.mk clean
      @$(MAKE) -C mw -f mw.mk clean
      @$(MAKE) -C root -f root.mk clean
  </code></pre>
  
  <p><strong>Question</strong></p>
  
  <ol>
  <li><p>In main <code>Makefile</code>, I define which <code>LIB</code> file I will use, if need move it to <code>root.mk</code> for better?</p></li>
  <li><p>In sub-makefile, I did NOT use <code>-MM</code> to generate depend file, if this cause the problem I can NOT change the sequence of my <code>lib*</code>, which I also described in <code>Makefile</code> comments. </p></li>
  <li><p>Seems my makefile system can NOT detect I update some head file, for example, I first compiled whole code, and then, I modified one head file, when I try to re-compile, none of source is compiled</p></li>
  </ol>
  
  <p>if:</p>
  
  <pre><code>#Automatic dependency magic:
  %.d: src/%.c
     $(CC) -MM -o$@ $&lt;
  
  -include (MYPROG_OBJECTS:%.o=%.d)
  </code></pre>
  
  <p>need add into each sub-makefile?</p>