【Linux开发工具】自动化构建-make/Makefile

发布于:2024-12-21 ⋅ 阅读:(210) ⋅ 点赞:(0)

🔥个人主页🔥:孤寂大仙V
🌈收录专栏🌈:Linux
🌹往期回顾🌹:【Linux开发工具】gcc和g++
🔖流水不争,争的是滔滔不


一、make和Makefile简介

1.1 什么是 make 和 Makefile?

make 是一个自动化构建工具,常用于 C/C++ 项目的编译和管理。它通过读取 Makefile 文件,自动处理文件依赖和编译过程,避免重复编译,提高效率。

2.1 Makefile 简介

Makefile 是一个文本文件,包含了构建规则和依赖关系,告诉 make 如何从源代码生成目标文件。一个简单的 Makefile 包括:

  • 目标(target):编译后生成的文件。
  • 依赖(dependencies):目标文件所依赖的源文件。
  • 命令(commands):如何生成目标的命令。

makefile带来的好处就是⸺“自动化编译”,一旦写好,只需要⼀个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是⼀条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

二、make和Makefile的使用

2.1 简单使用自动化构建

实现代码

#include<stdio.h>
int main()
{
    printf("hbx\n");
    return 0;
}

Makefile文件

code:code.c
        gcc -o code code.c
.PHONY:clean
clean:
        rm -f code

code:code.c 称为依赖关系。 gcc -o code code.c 称为依赖方法

.PHONY:clean
自动化构件中,工程是需要被清理的。
像clean这种,没有被第⼀个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令⸺“make clean”,以此来清除所有的目标文件,以便重编译。
但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。

make命令扫描Makefile文件的时候,从上而下扫描,默认形成第一个目标文件。
在这里插入图片描述

⽂件 = 内容 + 属性
Modify: 内容变更,时间更新
Change:属性变更,时间更新
Access:常指的是文件最近⼀次被访问的时间。在Linux的早期版本中,每当文件被访问时,其atime
都会更新。但这种机制会导致大量的IO操作。具体更新原则,不做过多解释。

对上述总是被执行进行解释:make因为有时间轴这一个概念,make 的时间轴基于文件的修改时间来决定是否需要重新编译和生成目标文件。它通过对比目标文件和依赖文件的时间戳,确保在文件发生变化时,只重新构建受影响的部分,避免重复的编译工作,提高了构建效率。.PHONY 是一个伪目标(phony target)的声明,用来告诉 make 某些目标并不是实际存在的文件,而只是一个命令或操作。这些伪目标不会与文件的修改时间进行比较,因为它们并不是用来生成实际文件的。。

2.2 编译链接过程

在Makefile文件中

code:code.o
        gcc code.o -o code
code.o:code.s
        gcc -c code.s -o code.o
code.s:code.i
        gcc -S code.i -o code.s
code.i :code.c
        gcc -E code.c -o code.i

.PHONY:clean
        re -f *.i *.s *.0 code

编译后
在这里插入图片描述
在这里插入图片描述
只输入make命令:

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第⼀个目标文件(target),在上面的例子中,他会找到 code 这个文件,并把这个文件作为最终的目标文件。
  3. 如果 code文件不存在,或是 code 所依赖的后面的 code.o 文件的文件修改时间要比 code 这个文件新(可以用touch 测试),那么,他就会执行后面所定义的命令来生成code 这个文件。
  4. 如果 code 所依赖的 code.o 文件不存在,那么 make 会在当前文件中找目标为code.o 文件的依赖性,如果找到则再根据那⼀个规则生成 code.o 文件。(这有点像⼀个堆栈的过程)
  5. 当然,你的C文件和H文件是存在的啦,于是 make 会生成 code.o 文件,然后再用 myproc.o 文件声明 make 的终极任务,也就是执行文件 hello 了。
  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第⼀个目标文件。
  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

2.3 扩展语法

Makefile还可以这样写
1

BIN=code
CC =gcc
SRC=code.c
FLAGS=-o
RM=rm -f

$(BIN):$(SRC)
        $(CC) $(FLAGS) $@ $^ 
.PHONY: 
clean:  
        $(RM) $(BIN)

2

BIN=code
SRC=code.c
CC=gcc
FLAGS=-o
RM =rm -f

$(BIN):$(SRC)
        @$(CC) $(FLAGS) $@ $^
        @echo "linking ... $^ to $@"
.PHONY:
clean:
        @$(RM) $(BIN)
        @echo "remove ... $(BIN)"


.PHONY:test
test:
        @echo $(BIN)
        @echo $(CC)
        @echo $(SRC)
        @echo $(FLAGS)
        @echo $(RM)

3

BIN=code
SRC=$(wildcard *.c)//当前目录下所有的.c文件名
OBJ=$(SRC:.c=.o)//把当前目录下的。c文件->。o文件

$(BIN):$(SRC)
        gcc -o $@ $^
%.o:%.c           //根据前面讲的可知中间编译过程很复杂,通过这个简化步骤
        gcc -c $<

.PHONY:
claen:
        rm -f $(OBJ) $(BIN)


三、一个简单的利用自动化构建的程序—进度条

在这里插入图片描述

\r 是 回车符(Carriage Return),通常用来将光标移动到当前行的开头。
还有一个缓冲区问题,先解释一下这个缓冲区的概念,我们打印的数据会存在一个缓冲区中,打印一段话后面跟一个\n就是进行行刷新。但是我们要写的进度条用#表示下载了多少,也就是每下载一点就要有显示。每有一个#就要打印在显示屏上,但是因为有缓冲区这个概念,看似不可行。这时可以用fflush(stdout)来解决这个问题。
在这里插入图片描述
首先要新建,头文件、源文件、main。
main.c

#include"process.h"

double total=1024.0;
double speed=1.0;
double current=0;
void DownLoad()
{
        while(current<=total)
        {
                process_v1(total,current);
                usleep(50000);
                current+=speed;
        }
        printf("\n");
        printf("DownLoad %0.1f MB Done",current);
}
int main()
{
        DownLoad();
        return 0;
}

模拟实现一下下载数据的过程。
process.h

#include<stdio.h>
#include<string.h>
#include<unistd.h>

void process_v1(double total,double current);

函数声明
process.c

#include"process.h"

#define NUM 101
#define STYNE '#'

void process_v1(double total,double current)
{
        char buffer[NUM];
        memset(buffer,0,sizeof(buffer));
        int num=(int)(current*100/total);
        const char* lable ="|/-\\";
        int len=strlen(lable);
        double rate=current/total;
        int i=0;
        static int cnt=0;
        for(i=0;i<num;i++)
        {
                buffer[i]=STYNE;
        }
        cnt%=len;
        printf("[%-100s][%0.1f%%][%c]\r",buffer,rate*100,lable[cnt]);
        cnt++;
        fflush(stdout);
}

开空间,进行计算每下载一点的数据占要下载数据的总量的多少,在利用for循环进行#的转化。比率问题,直接除。还有一个转圈只要程序没执行完就一直转,所以创建一个静态变量,cnt%=len,永远是0-6循环。


网站公告

今日签到

点亮在社区的每一天
去签到