| 嵌入式系统中Makefile的作用不言而喻,下面我写一下嵌套Makefile的编写。 
 
 
 实验环境】 
 Ubuntu 8.10发行版、gcc等工具 
  我们要创建的目录结构如下: 
 <img id="aimg_br0CS"  class="zoom" file="http://files.chinaaet.com/images/blog/2015/02/09/6272199137489.png"  lazyloadthumb="1" border="0" alt="" />
 
 
 
 一、创建顶层目录 
 我们首先在用户目录下创建一个makefileTest的文件夹: 
 #cd /home/linux/           
 #mkdir makefileTest 
 #cd makefileTest 
   
 创建好需要用到的文件夹 
 #mkdir f1 f2 main obj include 
 进入include文件夹创建一个共用头文件 
 #cd include 
 #vim myinclude.h 
 输入如下内容: 
 #include <stdio.h> 
 保存退出 
 返回顶层目录: 
 #cd .. 
 二、创建顶层Makefile文件 
 #vim Makefile 
 输入以下内容: 
 CC = gcc 
 SUBDIRS = f1 \ 
           f2 \ 
           main \ 
           obj 
   
 OBJS = f1.o f2.o main.o 
 BIN = myapp 
 OBJS_DIR = obj 
 BIN_DIR = bin 
 export CC OBJS BIN OBJS_DIR BIN_DIR 
   
 all : CHECK_DIR $(SUBDIRS) 
 CHECK_DIR : 
     mkdir -p $(BIN_DIR) 
 $(SUBDIRS) : ECHO 
     make -C $@ 
 ECHO: 
     @echo $(SUBDIRS) 
     @echo begin compile 
 CLEAN : 
     @$(RM) $(OBJS_DIR)/*.o 
     @rm -rf $(BIN_DIR) 
   
 三、进入在f1目录下创建makefile 
 #cd  f1 
 #vim f1.c 
 输入如下测试代码: 
 #include “../include/myinclude.h” 
 void print1() 
 { 
    printf(&quot;Message from f1.c...\n&quot;); 
    return; 
 } 
 保存退出。 
 #vim Makefile 
 输入如下内容: 
 ../$(OBJS_DIR)/f1.o: f1.c 
     $(CC) -c $^ -o $@ 
 保存退出。 
 进入f2目录 
 #cd ../f2 
 #vim f2.c 
 输入如下测试代码: 
 #include “../include/myinclude.h” 
 void print2() 
 { 
    printf(&quot;Message from f2.c…\n&quot;); 
    return; 
 } 
 保存退出。 
   
 #vim Makefile 
 输入如下内容: 
 ../$(OBJS_DIR)/f2.o: f2.c 
     $(CC) -c $^ -o $@ 
 保存退出。 
 进入main目录 
 #cd ../main 
 #vim main.c 
 输入如下内容: 
 #include <stdio.h> 
 int main() 
 { 
    print1(); 
    print2(); 
    return 0; 
 }   
 保存退出。 
 #vim Makefile 
 输入如下内容: 
 ../$(OBJS_DIR)/main.o: main.c 
     $(CC) -c $^ -o $@ 
     保存退出。 
 进入obj目录 
 #cd ../obj 
 #vim Makefile 
 输入如下内容: 
 ../$(BIN_DIR)/$(BIN) : $(OBJS) 
     $(CC) -o $@ $^ 
   
 好了,到此准备工作已经完毕,然我们来测试一下写的makefile是否好用。 
 进入顶层Makefile所在目录,即makefileTest目录。 
 #make 
 会出现如下信息: <img id="aimg_vwRR7"  class="zoom" height="22" file="http://files.chinaaet.com/images/blog/2015/02/09/6272938579079.png" border="0" alt="" />
 
 
 
 
 
 
 目录树结构如下: <img id="aimg_bxH0O"  class="zoom" height="22" file="http://files.chinaaet.com/images/blog/2015/02/09/6273536999079.png" border="0" alt="" />
 
 
 
 
 我们看到在bin目录下生成了我们的目标文件myapp,在obj目录下生成了.o的中间文件。 
 让我们运行下myapp看下结果吧。 
 #bin/myapp <img id="aimg_Pq66N"  class="zoom" height="22" file="http://files.chinaaet.com/images/blog/2015/02/09/6274098444532.png" border="0" alt="" />
 
 
 
 
 也可以用如下命令清除中间文件和目标文件,恢复make之前的状态: 
 #make CLEAN <img id="aimg_FGAG3"  class="zoom" height="22" file="http://files.chinaaet.com/images/blog/2015/02/09/6274469419638.png" border="0" alt="" />
 
 
 
 
 我们可以看到已经变为make之前的目录状态了。 
 大功告成。最后给大家解释一下顶层makefile中一些命令的的含义吧。 
 1、我们注意到有一句@echo $(SUBDIRS) 
 @echo其实是一句显示命令 
 通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用“@”字符在命令行前,那么,这个命令将不被make显示出来,最具代表性的例子是,我们用这个功能来像屏幕显示一些信息。如: 
     @echo 正在编译XXX模块...... 
 当make执行时,会输出“正在编译XXX模块......”字串,但不会输出命令,如果没有“@”,那么,make将输出: 
     echo 正在编译XXX模块...... 
     正在编译XXX模块...... 
 如果make执行时,带入make参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile,看看我们书写的命令是执行起来是什么样子的或是什么顺序的。 
 而make参数“-s”或“--slient”则是全面禁止命令的显示。 
 2、@(RM)并不是我们自己定义的变量,那它是从哪里来的呢? 
 通常在清除文件的伪目标所定义的命令中“rm”使用选项“–f”(--force)来防止 
 在缺少删除文件时出错并退出,使“make clean”过程失败。也可以在“rm”之前加 
 上“-”来防止“rm”错误退出,这种方式时 make 会提示错误信息但不会退出。为了 
 不看到这些讨厌的信息,需要使用上述的第一种方式。 
 另外 make存在一个内嵌隐含变量“RM”,它被定义为:“RM = rm –f” 。因此在书 
 写“clean”规则的命令行时可以使用变量“$(RM)”来代替“rm”,这样可以免出现一 
 些不必要的麻烦!这是我们推荐的用法。 
   
 3、make -C $@ 
 这是一句嵌套makefile的语法,在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的Makefile,这有利于让我们的Makefile变得更加地简洁,而不至于把所有的东西全部写在一个Makefile中,这样会很难维护我们的Makefile,这个技术对于我们模块编译和分段编译有着非常大的好处。 
 例如,我们有一个子目录叫subdir,这个目录下有个Makefile文件,来指明了这个目录下文件的编译规则。那么我们总控的Makefile可以这样书写: 
 subsystem: 
             cd subdir && $(MAKE) 
 其等价于: 
 subsystem: 
             $(MAKE) -C subdir 
 定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利于维护。这两个例子的意思都是先进入“subdir”目录,然后执行make命令。 
 4. export CC OBJS BIN OBJS_DIR BIN_DIR 
 我们把这个Makefile叫做“总控Makefile”,总控Makefile的变量可以传递到下级的Makefile中(如果你显示的声明),但是不会覆盖下层的Makefile中所定义的变量,除非指定了“-e”参数。 
 如果你要传递变量到下级Makefile中,那么你可以使用这样的声明: 
 export <variable ...> 
 
 
 
 
 
 
 
 
 
 
 
 ——————————————————————————————————————
 |