snifer

【原创】嵌入式系统中嵌套Makefile的编写

0
阅读(2729)

嵌入式系统中Makefile的作用不言而喻,下面我写一下嵌套Makefile的编写。

实验环境】

Ubuntu 8.10发行版、gcc等工具

 我们要创建的目录结构如下:


一、创建顶层目录

我们首先在用户目录下创建一个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("Message from f1.c...\n");

   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("Message from f2.c…\n");

   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

会出现如下信息:


目录树结构如下:

我们看到在bin目录下生成了我们的目标文件myapp,在obj目录下生成了.o的中间文件。

让我们运行下myapp看下结果吧。

#bin/myapp

也可以用如下命令清除中间文件和目标文件,恢复make之前的状态:

#make CLEAN

我们可以看到已经变为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”,这样可以免出现一

些不必要的麻烦!这是我们推荐的用法。

 

3make -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 ...>