欢迎光临
我们一直在努力

Linux 10:make Makefile自动化编译实战指南及进度条解析

🔥个人主页:Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

       <<Git>><<MySQL>>

🌟心向往之行必能至

目录

一:前言

1.1补充知识

二:理解

2.1引入小故事:加强理解

2.2 伪目标

2.3 make如果知道bin和.c的新旧关系

2.4 继续手动编译过程:加强理解

2.5 适度扩展语法:解决仍存在的多文件繁琐问题

三.实战:利用make makefile制作进度条

3.1  版本一

3.2版本二


一:前言

在上一章我们说过,为了不暴露源码,我们可以先将.c文件编译好再发送给他人,但如果.c文件过多,发送和他人使用也麻烦,这章我们将解决该问题

1.1补充知识

⼀个⼯程中的源⽂件不计数,其按类型、功能、模块分别放在若⼲个⽬录中,makefile定义了⼀

系列的规则来指定,哪些⽂件需要先编译,哪些⽂件需要后编译,哪些⽂件需要重新编译,甚⾄

于进⾏更复杂的功能操作

makefile带来的好处就是⸺“⾃动化编译”,⼀旦写好,只需要⼀个make命令,整个⼯程完全

⾃动编译,极⼤的提⾼了软件开发的效率

make是⼀个命令⼯具,是⼀个解释makefile中指令的命令⼯具

makefile内部包含依赖关系和依赖方式

二:理解

我们先创建一个makefile文件(m大小写都是可以的)和myproc.c文件

myproc.c

#include <stdio.h>
2 int main()
3 {
4 printf("hello Milestone\\n");
5 return 0;
6 }

makefile

1: makefile 
1 myproc:myproc.c
(必须是tab键一下) 2 gcc -o myproc myproc.c
3 .PhONY:clean
4 clean:
(必须是tab键一下) 5 rm -f myproc
6

然后我们再运行make,即可编译成功,再进行输出

[lcb@hcss-ecs-1cde 1]$ make
gcc -o myproc myproc.c
[lcb@hcss-ecs-1cde 1]$ ll
total 32
drwxrwxr-x 2 lcb lcb 4096 Dec 12 22:24 lib
-rw-rw-r– 1 lcb lcb 69 Dec 12 22:06 main.c
-rw-rw-r– 1 lcb lcb 75 Dec 13 08:25 makefile
-rwxrwxr-x 1 lcb lcb 8360 Dec 13 08:25 myproc
-rw-rw-r– 1 lcb lcb 77 Dec 13 08:24 myproc.c
drwxrwxr-x 2 lcb lcb 4096 Dec 12 19:36 test
[lcb@hcss-ecs-1cde 1]$ ./myproc
hello Milestone
[lcb@hcss-ecs-1cde 1]$ make clean
rm -f myproc

注意:项目是要被清理的,所以把clean的目标文件设置为伪目标(后续再讲)

上面的makefile的文件中

依赖关系:

上⾯的⽂件myproc,它依赖myproc.c

依赖方式

gcc -o myproc myproc.c
,就是与之对应的依赖关系

2.1引入小故事:加强理解

月底没生活费了,你打电话给家里人(你和家里人的关系就是依赖关系),问他们寻求支助生活费(这就是依赖方式)

注:依赖关系与依赖方式必须对得上才有用(你不可能打电话问室友的爸爸要生活费)

2.2 伪目标

项目工程是需要被clean的,⼀般我们这种clean的⽬标⽂件,我们将它设置为伪⽬标,⽤ .PHONY 修饰,伪⽬标的特性是,总是被执⾏的

即似乎myproc没有伪目标,就不会总是被执行

[lcb@hcss-ecs-1cde 1]$ make
gcc -o myproc myproc.c
[lcb@hcss-ecs-1cde 1]$ make
make: `myproc' is up to date.
[lcb@hcss-ecs-1cde 1]$ make clean
rm -f myproc
[lcb@hcss-ecs-1cde 1]$ make clean
rm -f myproc
[lcb@hcss-ecs-1cde 1]$

上面也确实如此

注:编译器编译时是自上而下,也就是说如果把clean放在最前面,那make执行的就是clean,而不是myproc

同样,如果我们为myproc加上.PHONY呢,事实就是也可以无限次执行

[lcb@hcss-ecs-1cde 1]$ make
gcc -o myproc myproc.c
[lcb@hcss-ecs-1cde 1]$ make
gcc -o myproc myproc.c
[lcb@hcss-ecs-1cde 1]$ make
gcc -o myproc myproc.c
[lcb@hcss-ecs-1cde 1]$

可以如此的原因是:编译器默认老代码不再编译

2.3 make如果知道bin和.c的新旧关系

make通过Modify知道bin和.c的新旧关系

此处就需要回顾前面提到的时间戳及文件组成:内容+属性

Modify:
内容变更,时间更新

Change
:属性变更,时间更新

Access(特殊)
:常指的是⽂件最近⼀次被访问的时间。在
Linux
的早期版本中,每当⽂件被访问时,其atime都会更新。但这种机制会导致⼤量的
IO
操作。具体更新原则,不做过多解释。

[lcb@hcss-ecs-1cde 1]$ stat makefile
File: ‘makefile’
Size: 82 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769dInode: 140743 Links: 1
Access: (0664/-rw-rw-r–) Uid: ( 1000/ lcb) Gid: ( 1000/ lcb)
Access: 2025-12-13 08:37:17.590512411 +0800
Modify: 2025-12-13 08:37:15.249728856 +0800
Change: 2025-12-13 08:37:15.250728764 +0800
Birth: –

注意,如果修改内容,属于也变更(修改内容很有可能会更新大小,大小属于属性)

下面画个图理解

左边的为旧的,右边的为新的

此时如果再进行make执行,由于bin的时间比.c文件新,所以.c为老代码,不再编译

此时如果进行修改,改变.c的时间戳

那么.c文件与myproc相比,就为新了,可进行修改,那么就可以执行文件,进行编译

2.4 继续手动编译过程:加强理解

在上一章我们已经详细讲述了编译过程,此处不再解释,只是给出代码

myproc:myproc.o
gcc myproc.o -o myproc
myproc.o:myproc.s
gcc -c myproc.s -o myproc.o
myproc.s:myproc.i
gcc -S myproc.i -o myproc.s
myproc.i:myproc.c
gcc -E myproc.c -o myproc.i
.PHONY:clean
clean:
rm -f *.i *.s *.o myproc

上面识别过程由上到下压栈,要是符合,再由下到上出栈

2.5 适度扩展语法:解决仍存在的多文件繁琐问题

N=proc.exe
2 CC=gcc
3 SRC=$(wildcard *.c) # 修正:*c → *.c,匹配所有.c文件
4 OBJ=$(SRC:.c=.o) # 从.c文件推导.o文件列表
5 LFLAGS=-o # 链接选项(gcc -o 目标 文件)
6 FLAGS=-c # 编译选项(gcc -c 只编译不链接)
7 RM=rm -rf # 修正:=后去掉空格,补充rm命令(原只写了参数)
8
9 # 2. 链接规则
10 $(BIN):$(OBJ)
11 @$(CC) $(LFLAGS) $@ $^ # $@=proc.exe,$^=所有.o文件
12 @echo "linking … $^ to $@"
13
14 # 3. 编译规则(.c → .o,批量编译)
15 %.o:%.c
16 @$(CC) $(FLAGS) $< -o $@ # 补充-o $@,明确输出.o文件(原缺失会导致编译产物命名异常)
17 @echo "compiling … $< to $@" # 修正拼写:compling
18
19 # 4. 清理伪目标(修正RM变量后可正常删除文件)
20 .PHONY:clean
21 clean:
22 $(RM) $(OBJ) $(BIN)
23
24 # 5. 测试伪目标(修正执行命令,逻辑合理化)
25 .PHONY: test
26 test: $(BIN) # 先确保可执行文件已构建,再执行测试
27 @echo "=== Source files: $(SRC) ==="
28 @echo "=== Object files: $(OBJ) ==="
29 @./$(BIN) # 修正:加./执行当前目录的可执行文件(Windows可直接写$(BIN
~
~
~

注:上面的SRC也可改为 SRC=$(shell *.c)

三.实战:利用make makefile制作进度条

3.1  版本一

makefile

1 SRC =$(wildcard *.c)
2 OBJ=$(SRC:.c=.o)
3 BIN=processbar
4
5 $(BIN) : $(OBJ)
6 gcc -o $@ $^
7 %.o:%.c
8 gcc -c $<
9 .PHONY:clean
10 clean:
11 rm -rf $(OBJ)
12 rm -rf $(BIN)

核心代码 main.c和process.c

1 #include<stdio.h> 1 SRC =$(wildcard *.c)
2 #include "process.h" | 2 OBJ=$(SRC:.c=.o)
3 int main() | 3 BIN=processbar
4 { | 4
5 double total=1024.0; | 5 $(BIN) : $(OBJ)
6 double speed=1.0; | 6 gcc -o $@ $^
7 double current=0.0; | 7 %.o:%.c
8 while(current<=total) | 8 gcc -c $<
9 { | 9 .PHONY:clean
E> 10 Flushprocess(total,current); | 10 clean:
11 current+=speed; | 11 rm -rf $(OBJ)
12 | 12 rm -rf $(BIN)
13 usleep(1000); |~
14 } |~
15 printf("Download %.2fMB done\\n",current); |~
16 //process_v1(); |~
17 return 0; |~
18 }

process.c

2 #include"process.h" | 2 OBJ=$(SRC:.c=.o)
3 #include<string.h> | 3 BIN=processbar
4 #define NUM 101 | 4
5 #define STYLE '=' | 5 $(BIN) : $(OBJ)
6 void process_v1() | 6 gcc -o $@ $^
7 { | 7 %.o:%.c
8 char buffer[NUM]; | 8 gcc -c $<
W> 9 char*LABEL="|/-\\\\"; | 9 .PHONY:clean
10 memset(buffer,0,sizeof(buffer)); | 10 clean:
11 int num=0; | 11 rm -rf $(OBJ)
12 int len=strlen(LABEL); | 12 rm -rf $(BIN)
13 while(num<=100) |~
14 { |~
15 int cur =(num%len); |~
16 printf("[%-100s][%d%%][%c]\\r",buffer,num,LABEL[cur]); |~
17 fflush(stdout); |~
18 usleep(99999); |~
19 buffer[num++]=STYLE; |~
20 } |~
21 printf("\\n"); |~
22 } |~
23 void Flushprocess(double total,double current) |~
24 { |~
25 char buffer[NUM]; |~
26 memset(buffer,0,sizeof(buffer)); |~
W> 27 char *lable="|/-\\\\"; |~
28 int len = strlen(lable); |~
29 static int cnt = 0; |~
30 // 不需要⾃⼰循环,填充# |~
31 int num = (int)(current*100/total); // 11.0 / 1000 |~
32 int i = 0; |~
33 for(; i < num; i++) |~
34 { |~
35 buffer[i] = STYLE; |~
36 } |~
37 double rate = current/total; |~
38 cnt %= len; |~
39 printf("[%-100s][%.1f%%][%c]\\r", buffer, rate*100, lable[cnt]); |~
40 cnt++; |~
41 fflush(stdout); |~
42 } |~
43

但上面代码有所缺陷,即download定义的太多死板,后面更新 上传又要重新传参,因此我们可以使用前面c语言学习的知识,回调函数

3.2版本二

修改的核心代码

#include<stdio.h>
2 #include "process.h"
E> 3 typedef void(*) callback(double total,double current);
4 double total =1024.0;
5 double speed =1.0;
E> 6 void Download(callback cb)
7 {
8 double current =0.0;
9 while(current<total)
10 {
11 cb(total,current)
12 usleep(3000);
13 current+=speed;
14 }
15 printf("\\ndownload%.2fMB done\\n",current);
16 }
17 int main()
18 {
19 Download();
20 return 0;
21 }

上面的修改即可解决

赞(0)
未经允许不得转载:171主机测评 » Linux 10:make Makefile自动化编译实战指南及进度条解析
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址