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)则中断执行,可以在命令前加上-忽略错误

![](https://img2024.cnblogs.com/blog/2305957/202504/2305957-20250423215908367-1319750583.png)

# 编译C程序
1. 先将`.c`编译成`.o`
2. 在讲`.o`链接成族中可执行的文件
![](https://img2024.cnblogs.com/blog/2305957/202504/2305957-20250423220541215-133809338.png)
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


![](https://img2024.cnblogs.com/blog/2305957/202504/2305957-20250423220711814-798587615.png)
# 隐式规则
如果不写

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)

![](https://img2024.cnblogs.com/blog/2305957/202504/2305957-20250423221428970-810493612.png)

## 自动产生.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
posted @ 2025-04-23 22:24  店里最会撒谎白玉汤  阅读(17)  评论(0)    收藏  举报