Linux开发工具——make/makefile

发布于:2025-04-06 ⋅ 阅读:(22) ⋅ 点赞:(0)

📝前言:
这篇文章我们来讲讲Linux开发工具——make/makefile

🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记C语言入门基础python入门基础C++刷题专栏


一,make/makefile基础介绍

make/Makefile用于自动化构建和管理项目。

make

  • 功能make是一个命令工具,它根据Makefile定义的规则来自动构建和管理项目。它可以自动检测源文件的修改情况,并仅重新编译那些需要更新的目标文件,从而大大提高了编译效率。
  • 工作原理make通过读取Makefile中的规则,分析目标文件和依赖文件之间的关系(简称依赖关系)。然后,它根据文件的时间戳modify时间)来判断哪些文件需要重新编译。如果一个依赖文件的修改时间晚于目标文件,或者目标文件不存在,make就会执行相应的命令来更新目标文件。
  • 使用方法:在项目目录中,只需在命令行中输入make命令,它就会自动查找当前目录下的Makefile,并按照其中的规则进行构建。如果Makefile中有多个目标,make默认构建第一个规则,后面的要指定要构建的特定目标,例如make target_name

Makefile

  • 作用Makefile是一个文本文件,它包含了一系列规则,用于告诉make工具如何构建项目。它定义了项目中的目标文件、依赖文件以及构建目标所需的命令(方法)。
  • 基本结构Makefile由一系列规则组成,每个规则通常包含以下部分:
    • 目标:通常是要构建的文件,如可执行文件、目标文件或库文件。也可以是一个抽象的目标,如clean用于清理生成的文件。
    • 依赖:目标所依赖的文件列表。
    • 命令:用于构建目标的命令。命令必须以Tab键开头。

(也可以认为:规则 = 依赖关系 + 依赖方法


二,具体示例

1. 基础示例

先对前面介绍到的基础的概念和用法做演示。

步骤:

  1. 现在当前目录下创建Makefile文件:touch ./Makefile
  2. 根据需求,编写Makefile
    在这里插入图片描述

解释:

  1. code.exe是目标文件,code.c是源文件(这是一组依赖关系,code.exe依赖code.c
  2. Tab开头,后面写依赖方法(构造目标用的命令)
  3. 一个抽象的目标clean,可以没有所依赖的文件列表
  4. 依赖方法

调用示例:
在这里插入图片描述

  1. make默认调用第一个规则,即code.exe:code.c这一个
  2. make clean,调用clean对应的规则
  3. 为什么连续调用make会失败呢?

因为:make根据文件modify时间戳来判断哪些文件需要重新编译。


1.1 时间戳

那什么是modify时间戳,?
stat查看文件时间属性
在这里插入图片描述

  • Access:访问时间,当文件被查看,如cat的时候会被修改(但有一些系统会优化,即:多次查看后才修改,为了减少磁盘I/O操作)
  • Modify:修改时间,代表文件最后一次被修改的时间,即内容有所改动,Modify就会改变
  • Change:变更时间,当文件属性有变化的时候会改变
  • Birth:诞生时间,创建时的时间

1.2 是否重新编译判断

当源文件的modify时间相比目标文件“旧”,代表没有源文件没有修改,则不重新编译
当源文件的modify时间相比目标文件“新”,代表源文件修改了,则重新编译

在这里插入图片描述
如图:我们在没有执行make之前,只有源文件1,执行完后,有了目标文件1,时间关系如上。此时再执行make就不会再重新编译

如果我们更改了源文件:
在这里插入图片描述
这时候,代表有新内容,目标文件就需要重新编译

那有没有办法让make无视时间戳,让依赖方法总是被执行呢?
有的兄弟,有的。那就是特殊目标声明:.PHONY,将目标标记为伪目标。
在这里插入图片描述

此时,make 不用去检查伪目标对应的文件是否存在、是否更新,而是直接执行命令
在这里插入图片描述


2. 进阶1——依赖链

在这里插入图片描述
在这里插入图片描述
依赖链的结构就像一个栈:

  1. 检查其依赖code.o,发现 code.o 不存在,则依赖方法入栈
  2. 检查 code.o 的依赖 code.s,发现 code.s 不存在,则依赖方法也入栈
  3. 检查 code.i 的依赖 code.c,发现 code.c 存在,则执行code.i的依赖方法
  4. 将栈中依赖方法依次执行

3. 进阶2——变量替换

定义变量
=:递归展开变量(不会在定义变量时立即对右侧的表达式进行求值,而是在使用该变量时才进行求值。这意味着变量的值可能会因为其他变量的改变而改变)
:=:简单展开变量(在定义变量时就对右侧的表达式进行求值,变量的值在定义时就已经确定,后续不会因为其他变量的改变而改变)

引用变量
$(变量名)

示例:
在这里插入图片描述
$@$^
$@指代目标文件,$^指代依赖文件列表
即上面的内容可以改成:
在这里插入图片描述
这里$^会自动对应这个方法的依赖关系中的$(SRC)$@对应$(BIN)


4. 进阶3——多文件

4.1 获取当前目录下的所有文件

在Makefile中执行命令:$(shell 命令)
使用函数:$(函数名 参数1,参数2…)

获取当前目录下所有.c文件后缀的方法:

  1. $(shell ls *.c),回顾:ls这个命令只列出名称
  2. $(wildcard *.c)

在这里插入图片描述输入make运行结果:
在这里插入图片描述

执行的命令不回显

在命令前加:@
在这里插入图片描述
效果:
在这里插入图片描述

4.2 %<

当有多个源文件需要编译成目标文件,且每个源文件的编译命令基本相同时,使用 $< 能避免重复书写源文件名称。

$<被自动替换为当前规则中列出的第一个依赖文件的名称。例如,对于规则 target: dep1 dep2 dep3,在其对应的命令里使用 $<,它就代表 dep1

4.3 模式规则

%:通配符,如%.c:所有以.c结尾的文件

%.o: %.c :这个规则中,%所匹配的内容在目标和依赖中是相同的。(同名)
当 make工具处理这个规则时,会针对每个 .o 文件的构建分别执行一次规则里的命令

错误写法:
在这里插入图片描述
报错:

make: *** No targets.  Stop.

因为:%.o: %.c只是一个模式规则,并没有具体构建目标。具体的构建目标是指在 Makefile 中明确指定要构建的文件,文件名需要是完整且能明确指向一个具体文件的。

正确使用示例:
在这里插入图片描述

额外语法:

  • 命令可以多行,但是也要Tab开头
  • 注释用#符号

理解执行过程:

  1. 具体构建目标:code.exe,依赖所有.o文件,没有.o文件,于是到下一个规则%.o:%.c
  2. %.o:%.c规则中,make会针对每个.o文件分别执行一次命令,此时,每个.o文件变成了这个规则里的具体构建目标

运行结果:
在这里插入图片描述


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!


网站公告

今日签到

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