3. Makefile基础
说实话,我刚开始做嵌入式开发那会儿,对Makefile是有点抵触的。觉得不就是编译个代码嘛,IDE点一下按钮不就完了?直到有一次,我接手一个老项目,光源文件就两百多个,手动编译一次要半小时,还经常漏掉某个依赖文件没更新……嗯,从那以后,我老老实实把Makefile学了一遍。
今天我们就来聊聊Makefile。说白了,它就是一个自动化编译的脚本。你告诉它“我要生成什么”、“依赖哪些文件”、“用什么命令”,剩下的它帮你搞定。
3.1 Makefile的作用
Makefile的核心作用就三个:
- 自动化编译:一条make命令,搞定所有编译链接
- 增量编译:只重新编译修改过的文件,节省时间
- 依赖管理:自动检查头文件、库文件的变更
我在项目中遇到过最典型的场景:一个固件工程,有驱动层、中间件、应用层,每次改一个.c文件,如果全量编译要等3分钟。用Makefile之后,改哪里编译哪里,基本秒级完成。你想想看,一天改几十次代码,省下来的时间够喝好几杯咖啡了。
3.2 基本语法:目标、依赖与命令
Makefile的基本语法其实很简单,就三要素:
目标(target): 依赖(dependencies)
命令(commands)
举个例子:
main.o: main.c
gcc -c main.c -o main.o
这里:
- 目标:main.o,我们要生成的文件
- 依赖:main.c,生成目标需要的源文件
- 命令:gcc -c main.c -o main.o,具体怎么生成
注意!命令前面必须是一个Tab键,不能是空格。我刚开始学的时候,就因为这个问题折腾了半小时,死活报错。后来才发现是编辑器把Tab自动转成空格了……
3.3 变量定义与使用
写Makefile最怕什么?重复。比如你有一堆.c文件要编译,每个都写一遍gcc命令,那还不如手动编译呢。这时候变量就派上用场了。
变量定义很简单:
CC = gcc
CFLAGS = -Wall -O2
TARGET = myapp
使用变量用$(变量名):
$(CC) $(CFLAGS) -o $(TARGET) main.c
我个人习惯把编译器、编译选项、目标文件都定义成变量,这样后期改起来特别方便。比如换编译器,只需要改CC那一行就行。
常用的变量类型:
| 变量名 | 含义 | 示例 |
|---|---|---|
| CC | C编译器 | gcc, arm-none-eabi-gcc |
| CFLAGS | 编译选项 | -Wall -O2 -I./include |
| LDFLAGS | 链接选项 | -lm -lpthread |
| OBJS | 目标文件列表 | main.o utils.o |
| TARGET | 最终生成的可执行文件 | myapp.elf |
3.4 第一个Makefile示例
光说不练假把式。我们写一个完整的Makefile,编译一个简单的C程序。
假设我们有三个文件:
// main.c
#include <stdio.h>
#include "utils.h"
int main() {
printf("Hello Makefile!\n");
print_utils();
return 0;
}
// utils.h
void print_utils();
// utils.c
#include <stdio.h>
#include "utils.h"
void print_utils() {
printf("This is utils.\n");
}
对应的Makefile:
# 变量定义
CC = gcc
CFLAGS = -Wall -O2
TARGET = myapp
OBJS = main.o utils.o
# 默认目标
all: $(TARGET)
# 链接生成最终目标
$(TARGET): $(OBJS)
$(CC) $(OBJS) -o $(TARGET)
# 编译main.o
main.o: main.c utils.h
$(CC) $(CFLAGS) -c main.c -o main.o
# 编译utils.o
utils.o: utils.c utils.h
$(CC) $(CFLAGS) -c utils.c -o utils.o
# 清理
clean:
rm -f $(OBJS) $(TARGET)
# 伪目标
.PHONY: all clean
使用方法:
make或make all:编译整个工程make clean:清理生成的文件
.PHONY 告诉make,all和clean不是真正的文件,而是伪目标。如果不加这个,万一当前目录下有个叫clean的文件,make clean就会认为目标已经是最新的,什么都不做。
3.5 知识体系总览
下面这张图,是我自己总结的Makefile核心知识结构,你看一眼就能明白整体脉络:
好了,Makefile的基础就这些。说白了,它就是一套规则,告诉编译器怎么干活。你掌握了目标、依赖、命令和变量这四个核心概念,大部分工程的Makefile你都能看懂、能修改。
记住一点:Makefile不是写出来就完事的,它是给你自己看的。所以变量命名要清晰,注释要写明白。我见过太多人写Makefile不写注释,三个月后自己都看不懂了……
可可精品资料库