注: 以下内容来自朱老师物联网大讲堂课件
1. 为什么需要Makefile
工程项目中c文件太多管理不方便,因此用Makefile来做项目管理,方便编译链接过程。
在一个正式的软件项目中,由很多个.c和.h文件构成,此时如果直接在命令行编译,就会像这样:gcc a.c b.c c.c d.c e.c f.c g.c -o exe 每次编译都要输入一堆东西很麻烦,这个问题严重影响工作效率,所以我们就使用Makefile来进行管理
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
2. 一个简单的Makefile示例
2.1 Makefile中的一些基本概念
目标:目标定格写(如上例:led.bin),后面是冒号(冒号后面是依赖),目标就是我们要去make xxx的那个xxx,就是我们最终要生成的东西。
依赖:依赖是用来产生目标的原材料,也就是(目标:)后面的部分。
命令:命令前面一定是Tab,不能是空格,也不能说多个空格。命令就是要生成那个目标需要做的动作。
Makefile中的注释用#
Makefile中注释使用#,和shell一样。
2.2 Makefile的基本工作原理
其一,当我们执行 make xx 的时候,Makefile会自动执行xx这个目标下面的命令语句。
其二,当我们make xx的时候,是否执行命令是取决于依赖的。依赖如果成立就会执行命令,否则不执行。
其三,我们直接执行make 和make 第一个目标 效果是一样的。(第一个目标其实就是默认目标)
make的依赖性决定了make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
2.3 Makefile的执行过程
在默认的方式下,也就是我们只输入make命令。那么,
- make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“led.bin”这个文件,并把这个文件作为最终的目标文件。
- 如果led.bin文件不存在,或是led.bin所依赖的后面的 .o 文件的文件修改时间要比led.bin这个文件新,那么,他就会执行后面所定义的命令来生成led.bin这个文件。
- 如果led.bin所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
- 当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件声明make的终极任务,也就是执行文件led.bin了。
3.一个稍微复杂的Makefile示例
CC = arm-linux-gcc
LD = arm-linux-ld
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
AR = arm-linux-ar
INCDIR := $(shell pwd)
# C预处理器的flag,flag就是编译器可选的选项
CPPFLAGS := -nostdlib -nostdinc -I$(INCDIR)/include
# C编译器的flag
CFLAGS := -Wall -O2 -fno-builtin
#导出这些变量到全局,其实就是给子文件夹下面的Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS
objs := start.o sdram_init.o led.o uart.o main.o
objs += lib/libc.a
uart.bin: $(objs