🔥个人主页: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/64769d	Inode: 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 }

上面的修改即可解决

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐