手搓OS-Makefile

我们在生活中常常会遇到这样的问题:为了查看修改后的代码效果,一遍又一遍的编译,敲一行又一行的命令,现在让Makefile解放你的双手。(误)

关于C语言

在之前关于bare metal的学习中,我们已经基本理解C语言编译运行的原理,也就是编译库+编译源文件,链接形成一个可执行文件。

罗列出编译静态库与动态库的方式:

1
2
3
4
5
# 静态库
gcc -r [name.a] [.o] [.o]
# 链接为可执行文件
gcc [.c] [.a] -o [自定义输出文件名]
gcc [.c] -o [自定义输出文件名] -l[库名] -L[库所在路径]
1
2
3
4
5
# 动态库
gcc -c -fpic [.c/.cpp][.c/.cpp]...
gcc -shared [.o][.o]... -o [lib自定义库名.so]
# 上面两条合并也是可以的
gcc [.c/.cpp] -o [自定义可执行文件名] -l[库名] -L[库路径] -Wl,-rpath=[库路径]

记不住对吧,我也是(),不过记不住也问题不大,多写写就记住了。

Makefile

格式

1
2
targets:prerequisties
command

targets:草率一点,就是make指令后的一个标志,代表了下面一串命令执行后的结果

prerequisite:依赖,需要的文件,或者需要事先执行的targets

command:命令

我们扔掉脑子,开玩儿:

1
2
hello: 
@echo "hello world"

1
2
bye:
sudo rm -rf /*

删库一念起,顿觉天地宽

运行规则

  1. make在当前目录下查找Makefile文件
  2. 找到文件中的第一个target文件作为最终目标
  3. 根据不同情况来执行command(这儿理不理解的吧,道理上还是要减少不必要的编译)

.PHONY

当文件夹中有文件或文件夹有与target重名的问题,采用这样一条

代码来声明运行的是target:

1
.PHONY:hello

这样我们就学完了大概makefile是怎么玩儿的了,接下来需要一点点细节……

小细节

下面其实就和大多数编程语言差不了多少了,但是依旧是很有用的

变量

在makefile中变量只能是字符串,这个也是挺好理解的吧,毕竟在Makefile中变量实际上都是一些文件什么的

定义

1
file :=src/main.c

引用:用${}$()

1
2
3
4
5
6
cp :=src/main.c
obj :=objs/main.o

$(obj):${cp}
@gcc -o ${obj} $(cp)
compile : ${obj}

使用变量还有一些高阶方法,后边再说,先说赋值

赋值

赋值符号 含义
:= 简单赋值,没啥含义,通用赋值
= 递归赋值,可能会影响多个值,不受赋值顺序影响
?= 条件赋值,空的才赋值
+= 追加赋值,用空格隔开,加一个变量
1
2
3
4
5
6
7
x = foo
y = $(x)b
x = new

test :
@echo "x => $(x)"
@echo "y => $(y)"

自动变量

  • $@:target的完整名称
  • $<:第一个依赖文件名称
  • $^:所有依赖文件
有用的小符号
符号 含义
\ 换号符,在换行的结尾加上
* 通配符,表示任意字符串,用于文件名
% 通配符,表示任意字符串,用于匹配字符串用于变量
函数

shell:shell命令

1
$(shell <command>)

subst:字符串替换

1
$(subst <from>,<to>,<text>)

patsubst:模式匹配替换

1
$(patsubst <pattern>,<replacement>,<text>)

剩下的常用的函数就参考链接吧(,只有一点细节

模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.PHONLY :all cl cla
src = $(wildcard ./*.c)
targetc = $(patsubst %.c, % ,$(src))
objc = $(patsubst %.c, %.o, $(src))

#srcpp = $(wildcard ./*.cpp)
#targetcpp = $(patsubst %.cpp, %, $(srcpp))
#objcpp = $(patsubst %.o, %.cpp, $(srcpp))

CC = gcc
#PP = g++

CFLAGS = -g -Wall
CPPFLAGS = -I ./

ifeq ($(findstring .c, $(src)), .c)
all:$(targetc)
$(targetc):%:%.o
$(CC) $< -o $@
$(objc):%.o:%.c
$(CC) -c $<
endif

cl:
rm -rf $(objc)
cla:
rm -rf $(objc)
rm -rf $(targetc)
rm -rf a.out

参考链接

GNC-Tutorial/3.Makefile-Tutorial/4.Functions.md at main · WohimLee/GNC-Tutorial (github.com)

https://blog.csdn.net/qq_43630810/article/details/105942231