make 和 Makefile自动化构建工具

目录

一. 介绍 make 和 Makefile

1.make 和 makefile事什么?

2. make 和 makefile的作用

二. make 和 makefile的使用

1. 查看 makefile 编写

makefile 生成方案

makefile 清理方案

2. make 的使用 

三. 再次理解 makefile 编写

1. make 的时候不回显 

2. 特殊符号

3.  .PHONY

四. 深度理解 make 编译原理 

五. 文件的三个时间

1. ACCESS

2. MODIFY 

3. CHANGE

4.解释 make 识别文件是否被修改

5. 手动修改文件时间


一. 介绍 make 和 Makefile

1.make 和 makefile事什么?

首先说明一下 make 事一条指令,而 makefile 事一个当前目录下的一个文件

2. make 和 makefile的作用

make 和 makefile是一个自动化构建工具,因为在我们的项目中我们需要经常去编译,如果一直使用 gcc/g++ 命令编译时比较麻烦的,所以我们就需要一个自动化构建工具,而makefile文件里面就写的是如何编译,以及 make 和 makefile可以进行自动化推导编译

二. make 和 makefile的使用

1. 查看 makefile 编写

注:makefile/Makefile 都是可以的,首字母大小写都可以

makefile 生成方案

我们现在有一个 mycode.c 的文件,我们要用makefile去写编译他的内容

[lxy@hecs-165234 test8]$ touch makefile
[lxy@hecs-165234 test8]$ vim makefile
[lxy@hecs-165234 test8]$ cat makefile
mycode:mycode.c
        gcc -o mycode mycode.c

我们的下面的两行就是我们的 makefile 编辑 mycode.c 文件的内容,我们介绍一下里面的内容

1. 第一行的 mycode:mycode.c 就是依赖关系

2. 第二行的 gcc -o mycode mycode.c 就是依赖方法

我们看一下是否可以对 mycode.c 文件进行编译,在这之前我们先编写 mycode.c 文件,在 mycode.c 文件里面我们写 hello world

[lxy@hecs-165234 test8]$ vim mycode.c
[lxy@hecs-165234 test8]$ cat mycode.c
#include<stdio.h>

int main()
{
  printf("Hello World\n");
  printf("Hello World\n");
  printf("Hello World\n");
  printf("Hello World\n");
  printf("Hello World\n");
  return 0;
}
[lxy@hecs-165234 test8]$ make //make 就是make 指令的简单使用,后面还回介绍
gcc -o mycode mycode.c
[lxy@hecs-165234 test8]$ ll
total 20
-rw-rw-r-- 1 lxy lxy   42 Jul  3 17:15 makefile
-rwxrwxr-x 1 lxy lxy 8360 Jul  3 17:20 mycode
-rw-rw-r-- 1 lxy lxy  181 Jul  3 17:20 mycode.c
[lxy@hecs-165234 test8]$ ./mycode
Hello World
Hello World
Hello World
Hello World
Hello World

 我们看到是没有问题的,并且也运行出来了

下面回答一下什么是依赖关系和依赖方法

1. 依赖关系:我们知道我们想要编译 mycode.c 文件,然后重命名为 mycode,那么就是我们的 mycode 文件的生成需要依赖于 mycode.c 文件,上面这个就是我们的依赖关系

2. 依赖方法:依赖方法就是更具依赖关系,看如何能让我们的 mycode.c 文件生成 mycode 文件,如果是我们的C语言的话,那么我们的依赖方法就是使用 gcc  编译生成,如果是我们的 C++的话,那么我们就要使用 g++ 编译

makefile 清理方案

既然我们的 makefile 可以编写生成方案的指令,那么当然也可以编写清理方案的指令

[lxy@hecs-165234 test8]$ cat makefile
mycode:mycode.c
        gcc -o mycode mycode.c
clean:
        rm -rf mycode

[lxy@hecs-165234 test8]$ make clean
rm -rf mycode

我们的 makefile 里面添加了两行代码,其中 clean: 就是依赖关系,只是这里的 clean 并不需要依赖任何文件,而我们的依赖方法就是 删除掉之前的生成方案

2. make 的使用 

我们看到,我们在生成解决方案的时候只是使用了 make, 但是我们在清理解决方案的时候还加了 make clean ,那么为什么这样,下面我们做实验看一下

1. 我们尝试使用 make mycode 我们看可不可以

[lxy@hecs-165234 test8]$ make mycode
gcc -o mycode mycode.c
[lxy@hecs-165234 test8]$ ll
total 20
-rw-rw-r-- 1 lxy lxy   64 Jul  3 18:13 makefile
-rwxrwxr-x 1 lxy lxy 8360 Jul  3 18:18 mycode
-rw-rw-r-- 1 lxy lxy  181 Jul  3 17:20 mycode.c

我们看到是可以的,而且我们直接使用 make 也是可以调用makefile里面第一个依赖的

2. 我们将 clean放到 makefile 前面,在使用make

[lxy@hecs-165234 test8]$ vim makefile
[lxy@hecs-165234 test8]$ cat makefile
clean:
        rm -rf mycode
mycode:mycode.c
        gcc -o mycode mycode.c
[lxy@hecs-165234 test8]$ make
rm -rf mycode 

我们的实验结果是将 clean 放到前面,然后直接 make 就是使用的是 clean 说明:我们的 make 默认会使用第一个依赖

三. 再次理解 makefile 编写

前面只是 makefile 的简单编写,下面我会说几个比较实用的编写技巧

1. make 的时候不回显 

我们编写的makefile,在 make的时候会回显,如果我们不想回显怎么办?

在依赖方法前面加 @

[lxy@hecs-165234 test8]$ vim makefile
[lxy@hecs-165234 test8]$ cat makefile
clean:
        @rm -rf mycode
mycode:mycode.c
        @gcc -o mycode mycode.c
[lxy@hecs-165234 test8]$ make
[lxy@hecs-165234 test8]$ 

2. 特殊符号

在我们编写makefile的时候,我们有时候需要的依赖关系很多,自己写可能会输入错误,所以我们可以借助两个特殊符号来代替依赖关系中的文件名

$@ $^

[lxy@hecs-165234 test8]$ cat makefile
mycode:mycode.c
        @gcc -o $@ $^

clean:
        @rm -rf mycode
[lxy@hecs-165234 test8]$ make
[lxy@hecs-165234 test8]$ ll
total 20
-rw-rw-r-- 1 lxy lxy   57 Jul  3 18:32 makefile
-rwxrwxr-x 1 lxy lxy 8360 Jul  3 18:32 mycode
-rw-rw-r-- 1 lxy lxy  181 Jul  3 17:20 mycode.c

$@ 代表:依赖关系前面的内容

$^ 代表:依赖关系后面的内容

有了上面两个,makefile 编写起来就相对容易了

3.  .PHONY

我们现在对我们的 mycode.c 文件进行多次 make,我们看可不可以?

[lxy@hecs-165234 test8]$ make
make: `mycode' is up to date.
[lxy@hecs-165234 test8]$ make
make: `mycode' is up to date.
[lxy@hecs-165234 test8]$ make
make: `mycode' is up to date.

我们多次 make的话,我们看到我们的 make 是不允许继续make的,为什么呢?(这个下面说)

那么我们如何解决这个问题?

.PHONY

.PHONY:.PHONY 后面跟的叫做伪目标,有什么作用?跟在 .PHONY 后面的在执行的时候总是会被执行

[lxy@hecs-165234 test8]$ vim Makefile
[lxy@hecs-165234 test8]$ cat Makefile
.PHONY:mycode
mycode:mycode.c
        gcc -o $@ $^
clean:
        rm -rf mycode

我们在 .PHONY 后面添加伪目标 mycode

下面我们多执行几次 make

[lxy@hecs-165234 test8]$ make
gcc -o mycode mycode.c
[lxy@hecs-165234 test8]$ make
gcc -o mycode mycode.c
[lxy@hecs-165234 test8]$ make
gcc -o mycode mycode.c 

我们看到是可以执行的,但是我们并不建议把 生成解决方案放在 .PHONY 后面,因为这样每一次都会编译,会浪费时间,我们建议把 clean 清理解决方案跟在 .PHONY 后面

四. 深度理解 make 编译原理 

我们现在想要对 mycode.c 文件进行详细编译,也就是将编译的每一步都显示出来(.i 文件, .s 文件,.o 文件)那么我们要怎么编写makefile文件?

[lxy@hecs-165234 test8]$ cat makefile
mycode:mycode.o
        gcc -o mycode mycode.o
mycode.o:mycode.s
        gcc -c mycode.s -o mycode.o
mycode.s:mycode.i
        gcc -S mycode.i -o mycode.s
mycode.i:mycode.c
        gcc -E mycode.c -o mycode.i
clean:
        rm -rf mycode mycode.i mycode.s mycode.o

make


[lxy@hecs-165234 test8]$ make
gcc -E mycode.c -o mycode.i
gcc -S mycode.i -o mycode.s
gcc -c mycode.s -o mycode.o
gcc -o mycode mycode.o

[lxy@hecs-165234 test8]$ ll
total 48
-rw-rw-r-- 1 lxy lxy   235 Jul  3 18:47 makefile
-rwxrwxr-x 1 lxy lxy  8360 Jul  3 18:47 mycode
-rw-rw-r-- 1 lxy lxy   181 Jul  3 18:43 mycode.c
-rw-rw-r-- 1 lxy lxy 16986 Jul  3 18:47 mycode.i
-rw-rw-r-- 1 lxy lxy  1728 Jul  3 18:47 mycode.o
-rw-rw-r-- 1 lxy lxy   565 Jul  3 18:47 mycode.s

 我们看到生成了,我们想要的文件,但是我们发现我们的make后的执行顺序并不是按照我们的 makefile 里面的顺序来的

解释:因为我们的 mycode 需要依赖于我们的 mycode.o,但是我们没有 mycode.o 文件,所以我们需要先获得 .o 文件,以此类推就是这样,而我们的 make 编译就像递归一样,而这就是我们的make的 编译会自动推导

五. 文件的三个时间

我们在上面说,为什么前面连续 make 会make失败

原因:因为我们连续make的话,是比较浪费时间的,所以我们的 make 会根据 源文件和 目标文件的最新修改时间进行对比,如果目标文件比源文件时间要新的话,那么就说明不需要 make 否则需要。

那么我们的 make 是如何得知文件是否被修改的?

解释:在我们的文件中,会有三个时间

ACCESS

MODIFY

CHANGR

指令:stat + 文件名

以 mycode 文件为例

[lxy@hecs-165234 test8]$ stat mycode
  File: ‘mycode’
  Size: 8360          Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1968773     Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/     lxy)   Gid: ( 1000/     lxy)
Access: 2023-07-03 19:03:29.608149503 +0800
Modify: 2023-07-03 19:03:29.608149503 +0800
Change: 2023-07-03 19:03:29.608149503 +0800
 Birth: -

三个时间介绍

1. ACCESS

access 就是我们的文件的左后一次访问时间,不管是我们打开进行查看,还是我们 cat 一下,亦或者是我们对其进行修改,都算访问,但是我们由于需要经常访问,所以我们的 访问时间是一直需要变化的,但是我们的 ACCESS 时间实际是访问几次后才变一次,原因是,由于我们的 ACCESS 算是文件属性,既然是这样,那么说明我们的这些信息是存在磁盘中的,而我们存在磁盘中,如果一直进行访问磁盘无疑是浪费时间的,所以我们的 ACCESS时间是访问几次后变化一次

2. MODIFY 

我们的三个时间里面还有一个时间叫 CHANGE 我们这两个单词的意思都是修改那么有什么不透吗?

这里先说 modify,我们知道我们的文件信息包含两种

1. 文件内容

2.文件属性

而我们这里的 modify 就指的是文件内容,但是我们的文件内容修改了,一般也就待变属性也修改了,因为我们的文件内容一旦修改,大概率我们的 文件大小也就变了,所以我们的文件属性也就自然修改了

3. CHANGE

我们的 CHANGE 代表的文件属性的修改,而我们的文件属性就包含大小以及文件本来的属性之类的,还有就是那些所属组,拥有者等...

我们的文件属性的修改并不一定会修改MODIFY

这就是我们的文件的三个时间

4.解释 make 识别文件是否被修改

既然我们知道我们的文件是有时间的,所以我们的  make 只需要对比源文件和目标文件的新旧,就可以知道源文件是否被修改,而我们的 make 只需要对比 MODIFY 时间就好了

5. 手动修改文件时间

指令:touch

我们的 touch 指令,如果后面的文件名是新的,那么就是创建一个文件,如果是以有的,那么就是修改文件的时间

[lxy@hecs-165234 test8]$ touch mycode.c
[lxy@hecs-165234 test8]$ stat mycode.c
  File: ‘mycode.c’
  Size: 181           Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1968744     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/     lxy)   Gid: ( 1000/     lxy)
Access: 2023-07-03 19:25:06.916600634 +0800
Modify: 2023-07-03 19:25:06.916600634 +0800
Change: 2023-07-03 19:25:06.916600634 +0800
 Birth: -

我们的 mycode.c 已经全部更新为了最新时间,如果我们只想跟新 MODIFY 那么我们带 -m 选项

[lxy@hecs-165234 test8]$ touch -m mycode
[lxy@hecs-165234 test8]$ stat mycode
  File: ‘mycode’
  Size: 8360          Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1968773     Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/     lxy)   Gid: ( 1000/     lxy)
Access: 2023-07-03 19:03:29.608149503 +0800
Modify: 2023-07-03 19:27:37.160520398 +0800
Change: 2023-07-03 19:27:37.160520398 +0800
 Birth: - 

touch 的选项意义

-a     change only the access time

       -c, --no-create
              do not create any files

       -d, --date=STRING
              parse STRING and use it instead of current time

       -f     (ignored)

       -h, --no-dereference
              affect each symbolic link instead of any referenced file (useful only on systems that can change the timestamps of a symlink)

       -m     change only the modification time

       -r, --reference=FILE
              use this file's times instead of current time

       -t STAMP

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Naxx Crazy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值