makefile学习
makefile
三要素
目标(target)、依赖、命令
生成目标前先检查依赖是否存在,不存在则寻找新的规则生成依赖
更新目标前会检查依赖是否比目标更新,如果更新则更新目标
目标
all:
echo "hello world"
test:
echo "test world"
- all就是目标,echo就是命令,目标的定义叫做规则
- test也是目标
规则
Makefile由若干条规则构成,每条规则指出一个目标文件target若干依赖文件和生成目标的命令
例如要生成m.txt依赖a.txt和b.txt
m.txt: a.txt b.txt
cat a.txt b.txt > m.txt
以#
开头的是注释,Makefile的规则中命令必须以Tab开头不能是空格
当有多条规则时,make执行的是第一条规则,如果依赖不存在则寻找其他规则创建依赖
# 此时有a.txt, b.txt, c.txt 没有m.txt
# 执行make,因为m.txt不存在则会执行cat a.txt b.txt > m.txt
# 再执行cat m.txt c.txt > x.txt
x.txt: m.txt c.txt
cat m.txt c.txt > x.txt
m.txt: a.txt b.txt
cat a.txt b.txt > m.txt
伪目标
如果目标文件存在,则不会执行命令。当存在特殊名称的文件时,make规则会失效
x.txt: m.txt c.txt
cat m.txt c.txt > x.txt
m.txt: a.txt b.txt
cat a.txt b.txt > m.txt
clean:
rm -f m.txt
rm -f x.txt
例如,有一个clean文件, 此时执行make clean则不会执行这个规则,需要定义一个伪目标
# Phony Target
.PHONY: clean
执行多条命令
如果要执行多条命令需要把多条命令用;
分隔,写到一行, 也可以用\
拆成多行便于流量,也可以用&&
cd_ok:
pwd; cd ..; pwd;
cd_ok:
pwd; \
cd ..; \
pwd
cd_ok:
cd .. && pwd
控制打印
默认情况下make会输出执行的每一条命令,如果在前面加上@
则不会打印命令
控制错误
正常情况下make执行命令时会检查每一个命令的返回值,如果返回错误(非0)则中断执行,可以在命令前加上-
忽略错误

# 编译C程序
1. 先将`.c`编译成`.o`
2. 在讲`.o`链接成族中可执行的文件

hello.c
include <stdio.h>
int hello()
{
printf("hello, world!\n");
return 0;
}
hello.h
int hello();
main.c
include <stdio.h>
include "hello.h"
int main()
{
printf("start...\n");
hello();
printf("exit.\n");
return 0;
}
Makefile
.PHONY: clean
world.out: hello.o main.o
cc -o world.out hello.o main.o
hello.o: hello.c
cc -c hello.c -o hello.o
main.o: main.c hello.h
cc -c main.c -o main.o
clean:
rm -f *.o world.out

# 隐式规则
如果不写
main.o: main.c hello.h
cc -c main.c -o main.o
也可以编译,因为make是为了编译c设计的,所以内置一个隐式规则,把.c编译成.o
# 使用变量
变量定义使用:变量名 = 值 或 变量名 := 值,变量名全大写
应用变量名用$(变量名)
TARGET = world.out
OBJS = hello.o main.o
$(TARGET): $(OBJS)
cc -o $(TARGET) $(OBJS)
clean:
rm -f $(OBJS) $(TARGET)

## 自动产生.o
patsubst函数进行模式替换
wildcard 列出当前目录下所有的.c
OBJS = $(patsubst %.c,%.o, $(wildcard *.c))
## 内置变量
$(CC) 替换cc
也可以指定编译器
CC = gcc
## 自动变量
$@ 表示目标文件,$^表示所有依赖文件
world.out: hello.o main.o
cc -o $@ $^
# 模式规则
make可以自动创建`.o`实际上是
$(CC) $(CFLAGS) -c -o $@ $<
能修改的只有变量`$(CC) $(CFLAGS)`, 执行多条命令是隐式规则就不行了
自定义模板规则
%.o: %.c
cc -c -o $@ $<
https://liaoxuefeng.com/books/makefile/prerequisites/index.html