嵌入式系统中嵌套Makefile的编写

2019-07-12 18:49发布

嵌入式系统中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 保存退出 返回顶层目录: #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... ");    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… ");    return; } 保存退出。   #vim Makefile 输入如下内容: ../$(OBJS_DIR)/f2.o: f2.c     $(CC) -c $^ -o $@ 保存退出。 进入main目录 #cd ../main #vim main.c 输入如下内容: #include 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