Skip to content

Commit 2296e69

Browse files
committed
2023-3-10-wumingda_push
1 parent 9d8c44d commit 2296e69

11 files changed

Lines changed: 835 additions & 31 deletions

‎docs/Stage1-LinuxCprogrammers/01-Introduction.md‎

Lines changed: 0 additions & 16 deletions
This file was deleted.

‎docs/Stage1-LinuxCprogrammers/MakeFile/01-Introduction.md‎

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
* 问题反馈交流区 https://github.com/100askTeam/Stage1_D1s-Applications/discussions/
2-
# Makefile简述
3-
## 为什么引入Makefile?
4-
在上一章节的例子中,我们都是在终端执行 gcc 命令来完成源文件的编译。
5-
感觉挺方便的,这是因为工程中的源文件只有一两个,在终端直接执行编译命令,确实快捷方便。
6-
但是现在一些项目工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,如果仍然在终端输入这些命令来编译,那显然不切实际,开发
7-
效率极低。
8-
我们需要一个工具来管理这些编译过程,这就是“make”。make 是一个应用程序,它根据 Makefile 来做事。Makefile 负责管理整个
9-
10-
编译流程:要编译哪些文件?怎么编译这些文件?怎么把它们链接成一个可执行程序。Makefile 定义了一系列的规则来实现这些管理。
11-
## 2.makefie的引入
12-
Makefile 的引入是为了简化我们编译流程,提高我们的开发进度。下面我们用一个例子来说明 Makefile 如何简化我们的编译流程。我们创建一个工程内
13-
容分别 main.c,sub.c,sub.h,add.c,add.h 五个文件。sub.c 负责计算两个数减法运算,add.c 负责计算两个数加法运算,然后编译出可执行文件。其源
14-
文件内容如下:
2+
# 1.Makefile简述
3+
4+
## 1.1 为什么需要Makefile
5+
现在一些项目工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,如果仍然在终端输入这些命令来编译,那显然不切实际,开发效率极低。
6+
我们需要一个工具来管理这些编译过程,这就是“make”。make 是一个应用程序,它根据 Makefile 来做事。Makefile 负责管理整个编译流程:要编译哪些文件?怎么编译这些文件?怎么把它们链接成一个可执行程序。Makefile 定义了一系列的规则来实现这些管理。
7+
8+
## 1.2 makefie的引入
9+
Makefile 的引入是为了简化我们编译流程,提高我们的开发进度。下面我们用一个例子来说明 Makefile 如何简化我们的编译流程。我们创建一个工程内容分别 main.c,sub.c,sub.h,add.c,add.h 五个文件。sub.c 负责计算两个数减法运算,add.c 负责计算两个数加法运算,然后编译出可执行文件。其源文件内容如下:
1510

1611
```c
1712
main.c:
@@ -150,3 +145,4 @@ gcc -o output main.o add.o sub.o
150145
会发现,它重新编译了 add.c,并且重新生成了可执行程序。
151146
通过上述例子,Makefile 将我们上面的三个问题都解决了,无需手工输入复杂的命令,只编译修改过的文件。在一个很庞大的工程中,只有第一次编译时间比较长,第二次编译时会大大缩短时间,节省了我们的开发周期。
152147
下面我们来学习 Makefile 的知识。
148+
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# 2. makefile规则
2+
## 2.1 命名规则
3+
一般来说将 Makefile 文件取名为“Makefile”或“makefile”都可以,惯例是使用首字母大写的“Makefile”。也可以使用其他名字,比如makefile.linux,但你需要用“-f”参数指定,示例如下
4+
5+
```bash
6+
make -f makefile.linux
7+
```
8+
9+
## 2.2 语法规则
10+
基本语法规则:
11+
12+
![image](https://github.com/1WMD1/script_file/blob/master/makefile/png/image-20230310110255519.png)
13+
14+
* target:需要生成的目标文件
15+
* prerequisites:生成该 target 所依赖的一些文件
16+
* command:生成该目标需要执行的命令
17+
18+
19+
20+
三者的关系:target 依赖于 prerequisites 中的文件,其生成规则定义在command 中。举例,比如我们平时要编译一个文件:
21+
22+
```bash
23+
$ gcc main.c -o main
24+
```
25+
26+
换成 Makefile 的书写格式如下:
27+
28+
```makefile
29+
main:main.c
30+
gcc main.c -o main
31+
```
32+
33+
第 1 行表示 main 这个可执行程序依赖于 main.c,第 2 行表示需要用“gcc main.c -o main”这个命令来生成 main。
34+
注意:Makefile 文件里的命令必须要使用 Tab,不能使用空格。
35+
36+
## 2.3 目标生成规则
37+
38+
* 目标生成:
39+
40+
> 检查规则中的依赖文件是否存在。
41+
42+
> 若依赖文件不存在,则寻找是否有规则用来生成该依赖文件。
43+
44+
目标生成流程,如下:
45+
46+
![image](https://github.com/1WMD1/script_file/blob/master/makefile/png/image-20230310111353906.png)
47+
48+
* 目标更新:
49+
50+
> 检查目标的所有依赖,任何一个依赖有更新时,就要重新生成目标。
51+
> 目标文件比依赖文件更新时间晚,则需要更新。
52+
53+
目标更新流程,如下:
54+
55+
![image](https://github.com/1WMD1/script_file/blob/master/makefile/png/image-20230310111817321.png)
56+
57+
我们使用上面的例子,Makefile 内容如下:
58+
59+
```makefile
60+
output: main.o add.o sub.o
61+
gcc -o output main.o add.o sub.o
62+
main.o: main.c
63+
gcc -c main.c
64+
add.o: add.c
65+
gcc -c add.c
66+
sub.o: sub.c
67+
gcc -c sub.c
68+
clean:
69+
rm *.o output
70+
```
71+
72+
编译执行:
73+
74+
```bash
75+
$ make
76+
gcc -c main.c
77+
gcc -c add.c
78+
gcc -c sub.c
79+
gcc -o output main.o add.o sub.o
80+
```
81+
82+
make 命令会检测寻找目标的依赖是否存在,不存在,则会寻找生成依赖的命令。
83+
1.output 依赖于“main.o add.o sub.o”,这三个文件都没有,分别去生成它们。怎么生成?继续寻找规则,发现 main.o 依赖于 main.c,于是使用“gcc -c main.c”来生成;其他两个文件类似处理。
84+
85+
2.现在 output 的依赖文件都有了,但是 output 文件还没有,所以使用“gcc -o output main.o add.o sub.o”来生成 output 文件。当我们修改某一个文件时,比如之修改 add.c 文件,然后重新 make,如下:
86+
87+
```bash
88+
$ make
89+
gcc -c add.c
90+
gcc -o output main.o add.o sub.o
91+
```
92+
93+
make 命令还是根据 Makefile 来检查、执行:
94+
1.output 依赖于“main.o add.o sub.o”,这三个文件都有了,main.o 依赖于 main.c,main.c 没改过,所以不需要重新生成 main.o;
95+
但是 add.o的依赖文件 add.c 被改过,需要重新生成 add.o,使用命令“gcc -c add.c”;sub.o 跟 main.o 类似,也不需要重新生成。
96+
2.现在 output、它的三个依赖文件都有了,但是其中一个依赖文件 add.o 比output 文件新,所以使用“gcc -o output main.o add.o sub.o”来生成output 文件。
97+
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# 3.变量
2+
## 3.1 变量的定义及取值
3+
Makefile 也支持变量定义,变量的定义也让的我们的 Makefile 更加简化,可复用。
4+
变量的定义:一般采用大写字母,赋值方式像 C 语言的赋值方式一样,如下:
5+
6+
```bash
7+
DIR = ./100ask/
8+
```
9+
10+
变量取值:使用括号将变量括起来再加美元符,如下:
11+
12+
```bash
13+
FOO = $(DIR)
14+
```
15+
16+
变量可让 Makefile 简化可复用,上面个的 Makefile 文件,内容如下:
17+
18+
```makefile
19+
output: main.o add.o sub.o
20+
gcc -o output main.o add.o sub.o
21+
main.o: main.c
22+
gcc -c main.c
23+
add.o: add.c
24+
gcc -c add.c
25+
sub.o: sub.c
26+
gcc -c sub.c
27+
clean:
28+
rm *.o output
29+
```
30+
31+
我们可以将其优化,如下:
32+
33+
```makefile
34+
#Makefile 变量定义
35+
OBJ = main.o add.o sub.o
36+
output: $(OBJ)
37+
gcc -o output $(OBJ)
38+
main.o: main.c
39+
gcc -c main.c
40+
add.o: add.c
41+
gcc -c add.c
42+
sub.o: sub.c
43+
gcc -c sub.c
44+
clean:
45+
rm $(OBJ) output
46+
```
47+
48+
我们分析一下上面简化过的 Makefile,第一行是注释,Makefile 的注释采用‘#’,而且不支持像 C 语言中的多行注释。第二行我们定义了变量 OBJ,并赋值字符串”main.o,add.o,sub.o“。其中第三,四,十三行,使用这个变量。这样用到用一个字符串的地方直接调用这个变量,无需重复写一大段字符串。
49+
Makefile 除了使用‘=’进行赋值,还有其他赋值方式,比如‘:=’和‘?=’,接下来我们来对比一下这几种的区别:
50+
51+
赋值符‘=’
52+
我们使用一个例子来说明赋值符‘=’的用法。Makefile 内容如下:
53+
54+
```makefile
55+
PARA = 100
56+
CURPARA = $(PARA)
57+
PARA = ask
58+
59+
print:
60+
@echo $(CURPARA)
61+
```
62+
63+
分析代码:第一行定义变量 PARA,并赋值为“100”,第二行定义变量 CURPARA,并赋值引用变量 PARA,此时 CURPARA 的值和 PARA 的值是一样的,第三行,将变量 PARA 的变量修改为“ask”。第六行输出 CURPARA 的值,echo 前面增加@符号,代表只显示命令的结果,不显示命令本身。
64+
通过命令“make print”执行 Makefile,如下:
65+
66+
```bash
67+
$ make print
68+
ask
69+
```
70+
71+
从结果上看,变量 CURPARA 的值并不是“100”,而是 PARA 的最后一次赋值。使用赋值符“=”设置的变量,它的值在运行时才能确定,这称为“延时变量”。
72+
其实可以理解为在 C 语言中,定义一个指针变量指向一个变量的地址。如下:
73+
74+
```c
75+
01 int a = 10;
76+
02 int *b = &a;
77+
03 a=20;
78+
```
79+
80+
代码分析:我们见上面的 Makefile 的第二行的“=”替换成“:=”,重新编译,如下:
81+
82+
```bash
83+
$ make print
84+
100
85+
```
86+
87+
从结果上看,变量 CURPARA 的值为“100”。使用“:=”设置的变量被称为“即时变量”,在赋值时就确定了它的值。
88+
89+
赋值符‘?=’
90+
91+
我们用两个 Makefile 来说明赋值符“?=”的用法。如下:
92+
93+
```makefile
94+
第一个 Makefile:
95+
PARA = 100
96+
PARA ?= ask
97+
print:
98+
@echo $(PARA)
99+
```
100+
101+
编译结果:
102+
103+
```bash
104+
$ make print
105+
100
106+
```
107+
108+
```makefile
109+
第二个 Makefile:
110+
PARA ?= ask
111+
print:
112+
@echo $(PARA)
113+
```
114+
115+
编译结果:
116+
117+
```bash
118+
$ make print
119+
ask
120+
```
121+
122+
上面的例子说明,使用“?=”给变量设置值时,如果这个变量之前没有被设置过,那么“?=”才会起效果;如果曾经设置过这个变量,那么“?=”不会起效果。赋值符‘+=’
123+
Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进去,此时就要使用到符号“+=”,比如如下:
124+
125+
```makefile
126+
OBJ = main.o add.o
127+
OBJ += sub.o
128+
```
129+
130+
这样的结果是 OBJ 的值为:”main.o,add.o,sub.o“。说明“+=”用作与变量的追加。
131+
132+
## 3.2 系统自带变量
133+
134+
系统自定义了一些变量,通常都是大写,比如 CC,PWD,CLFAG 等等,有些有默认值,有些没有,比如以下几种,如下:
135+
* CPPFLAGS:预处理器需要的选项,如:-l
136+
* CFLAGS:编译的时候使用的参数,-Wall -g -c
137+
* LDFLAGS:链接库使用的选项,-L -l
138+
其中:默认值可以被修改,比如 CC 默认值是 cc,但可以修改为 gcc:CC=gcc使用的例子,如下:
139+
140+
```
141+
OBJ = main.o add.o sub.o
142+
output: $(OBJ)
143+
gcc -o output $(OBJ)
144+
main.o: main.c
145+
gcc -c main.c
146+
add.o: add.c
147+
gcc -c add.c
148+
sub.o: sub.c
149+
gcc -c sub.c
150+
151+
clean:
152+
rm $(OBJ) output
153+
```
154+
155+
使用系统自带变量,如下:
156+
157+
```
158+
CC = gcc
159+
OBJ = main.o add.o sub.o
160+
output: $(OBJ)
161+
$(CC) -o output $(OBJ)
162+
main.o: main.c
163+
$(CC) -c main.c
164+
add.o: add.c
165+
$(CC) -c add.c
166+
sub.o: sub.c
167+
$(CC) -c sub.c
168+
169+
clean:
170+
rm $(OBJ) output
171+
```
172+
173+
在上面例子中,系统变量 CC 不改变默认值,也同样可以编译,修改的目的是为了明确使用 gcc 编译。
174+
175+
## 3.3 自动变量
176+
Makefile 的语法提供一些自动变量,这些变量可以让我们更加快速地完成Makefile 的编写,其中自动变量只能在规则中的命令使用,常用的自动变量如
177+
下:
178+
* $@:规则中的目标
179+
* $<:规则中的第一个依赖文件
180+
* $^:规则中的所有依赖文件
181+
我们上面的例子继续完善,修改为采用自动变量的格式,如下:
182+
183+
```makefile
184+
CC = gcc
185+
OBJ = main.o add.o sub.o
186+
output: $(OBJ)
187+
$(CC) -o $@ $^
188+
main.o: main.c
189+
$(CC) -c $<
190+
add.o: add.c
191+
$(CC) -c $<
192+
sub.o: sub.c
193+
$(CC) -c $<
194+
195+
clean:
196+
rm $(OBJ) output
197+
```
198+
199+
其中:第 4 行$^表示变量 OBJ 的值,即 main.o add.o sub.o,第四,第六,第八行的$<分别表示 main.c add.c sub.c。$@表示 output。

0 commit comments

Comments
 (0)