Linux 进阶:一文搞懂 make 工具与 Makefile 编写

Linux 进阶:一文搞懂 make 工具与 Makefile 编写

🔥个人主页:Cx330🌸

❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》

《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔

🌟心向往之行必能至


🎥Cx330🌸的简介:


目录

前言:

一、先搞懂:make 是什么?Makefile 又是什么?

1.1 背景

1.2 make:Linux 下的自动化构建工具

1.3 Makefile:make 的 “操作手册”

二、最佳实践:先见一下,如何使用

2.1 构建项目

2.2 清理项目

2.3 理解Makefile/make,编译工作的推导过程,依赖关系和依赖方法

2.4 PHONY:伪目标——总被执行

三、ACM时间管理

3.1 重复make,竟然不让我make?

3.2 Access Time(访问时间)

3.3 Modify Time(修改时间)

3.4 Change Time(状态改变时间)

3.5 详解make如何知道code.c是否需要被重新编译 

四、makefile最佳实践和实用语法

4.1 $@与$^

4.2 定义变量

4.3 $<和$^

五、总结:为什么一定要学 Makefile?​


前言:

如果你在 Linux 下编译过 C/C++ 项目,一定遇到过这样的场景:

修改一个文件后,需要手动输入gcc main.c func.c -o app重新编译,文件多了还容易漏写;如果只改了一个小模块,却要重新编译所有文件 —— 既浪费时间又麻烦。

make工具Makefile,就是为解决这个问题而生的自动化构建方案。今天我们就从基础到实战,彻底掌握它们。


一、先搞懂:make 是什么?Makefile 又是什么?

1.1 背景

  • 会不会写 makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
  • 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
  • makefile 带来的好处就是 ——“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • make 是一个命令工具,是一个解释 makefile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:Delphi 的 make,Visual C++ 的 nmake,Linux 下 GNU 的 make。可见,makefile 都成为了一种在工程方面的编译方法。
  • make 是一条命令makefile 是一个文件,两个搭配使用,完成项目自动化构建。

1.2 make:Linux 下的自动化构建工具

make是一个命令行工具,核心能力是:

  • 检查文件的修改时间(对比目标文件与依赖文件)
  • 只重新编译 “被修改过的依赖文件” 对应的目标
  • 按预定规则(写在 Makefile 里)逐步执行构建步骤

简单说:它能帮你 “智能编译”,避免重复劳动。

1.3 Makefile:make 的 “操作手册”

Makefile 是一个文本文件,没有后缀名,核心作用是定义构建规则—— 告诉 make:

  • 最终要生成的目标文件(比如可执行程序app
  • 生成目标需要依赖哪些文件(比如main.ofunc.o
  • 具体用什么命令生成目标(比如gcc -c main.c

没有 Makefile,make 命令就会报错(不知道该做什么)。


二、最佳实践:先见一下,如何使用

2.1 构建项目

1. 创建Makefile文件

touch Makefile //创建Makefile文件

2. vim编辑Makefile

3. make

2.2 清理项目

如果要清理项目时,可能会不小心将程序搞崩溃,所以这时候就需要Makefile自动化清理

2.3 理解Makefile/make,编译工作的推导过程,依赖关系和依赖方法


我们现在将clean换到前面,我们再make试一试:

我们发现make变成了进行clean的操作,那么我如果想编译code.c呢?—接着往下看:

我们只需在make后面加上目标文件即可!

那么make的逻辑是什么呢?

Makefile、make
默认形成的是从上向下遇到的第一个目标文件!!
且执行一组依赖关系和依赖方法

如图:

思考:make / Makefile:具体是如何形成可执行程序的呢???推导过程又是如何呢?

我们打开vim编辑Makefile

我们make一下:

make 是如何工作的,在默认的方式下,也就是我们只输入 make 命令。那么:

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

清理工程:

2.4 PHONY:伪目标——总被执行


三、ACM时间管理

3.1 重复make,竟然不让我make?

这里我们重复make发现不让我们make了,这里显示的意思是code文件没有进行更新

为什么我没有更新就不让我make呢?

答:gcc编译代码的时候,代码如果没有被编译过,或者曾经被修改过,make+gcc才会进行重新编译!

那么make如何知道code.c是否需要被重新编译呢?

 这里我们补充一个指令:

查看文件时间:stat code.c

3.2 Access Time(访问时间)

  • 缩写:atime
  • 含义:文件内容被读取 / 访问的时间(仅指查看内容,不包含修改)。
  • 触发场景:用 cat/less/more 打开文件查看内容、用 grep 匹配文件内容等。
  • 注意:部分系统为优化性能,会通过 noatime 挂载选项关闭 atime 的自动更新(避免频繁写磁盘)。

3.3 Modify Time(修改时间)

  • 缩写:mtime
  • 含义:文件内容被修改并保存的时间(仅与文件内容变更相关)。
  • 触发场景:用编辑器(如 vim)修改文件内容后保存、用 echo "内容" >> 文件 追加内容等。
  • 关联:mtime 变更时,文件的元数据也会变化,因此 ctime 会同步更新

3.4 Change Time(状态改变时间)

  • 缩写:ctime
  • 含义:文件元数据(非内容)被修改的时间(元数据包括权限、所有者、文件大小、文件名、链接数等)。
  • 触发场景:用 chmod 修改权限、chown 变更所有者、mv 重命名文件、rm 删除文件(删除前会改元数据)等。

3.5 详解make如何知道code.c是否需要被重新编译 

我们再来回顾一下:

文件 = 内容 + 属性

先说结论:文件内容改变影响的是Modify时间,文件属性改变影响的是Change时间

这里我们改变文件属性,来验证哪个时间会变化:

说明:改变文件属性影响的是文件的Change时间,而其他时间不变

我们再来改变文件内容,来验证哪个时间会改变:

这里我们改变code.c的内容来验证一下

从图中发现我们改变内容,ACM时间都改了!!!

在Linux系统中,修改文件内容,文件属性就会因此而变化,这是正常的!!!

我们再来读取一下文件信息,来观察时间变化情况:

先说结论这里读取文件信息会影响的是Access时间

但是你图片上展示的Access、Modify、Change时间都是一样的啊?我怎么知道你改变的是哪个?

说明:

我们读取文件会导致大量IO操作,Linux系统不会傻傻的你用一次就给你更新一下Access时间,这样会导致太大的IO操作,Linux对其进行特殊处理,它有一个策略,就是在你访问7、8次识别出来,他才会更新一下,最后总结一下:Access时间更新最频繁,但是他不是常更新,他有自己的策略,和系统有关

那你还没有给我解决前一个问题啊:make怎么知道我的文件是否需要被重新编译呢?

我们再来make一下:

永远都是先有源文件才有目标可执行文件!所以我们可以来画个图:

code文件时间比源文件时间新,此时我们再make一下看看结果

果然如此,所以我们得到结论:make是如何知道code.c需要被重新编译?

解析:

那么我可执行程序的时间比源文件新,说明源文件没有更新,也就说明Modify时间没有变!,如果源文件比可执行程序文件新,说明我们源文件被改了,Modify时间变了!此时make就知道code.c需要被重新编译了!

答:只要code.c的Modify时间比code可执行程序文件新,就需要重新编译!

那么我们将.PHONY修饰一下gcc编译试一下:

我们再来make一下:

此时我们发现make竟然可以一直执行,那么我想问一下大家知道.PHONY的本质了嘛?

.PHONY的本质:忽略实践对比!

但是我们不建议用.PHONY进行修饰!


四、makefile最佳实践和实用语法

在编译过程中,我们都倾向于将源文件 .c 先编译为 .o 文件

分两步是比较推荐的做法!

4.1 $@与$^

code:code.o gcc -o $@ $^ // $@代表code $^代表code.o code.o:code.c gcc -c code.c .PHONY:clean clean: rm -rf code.o code.exe 

4.2 定义变量

我们再来make一下看是否可以执行

我们可以观察到都是可以执行的!

我们再来打印一下要进行的操作!

有没有发现这样很挫,能不能不让它回显:有的!

我们只需要在前面加上@符号即可,我们再来make一下:

这样他就不会回显出来了!

那么如果不想让gcc -c code.cgcc -o code.exe code.o回显,同样可以在他们前面加上@

查看文件:

4.3 $<和$^

$^ 表示所有的依赖文件

$< 代表第一个依赖文件

如果我们创建了10个文件都进行编译,我们来看一下make结果:

 

我们创建了10个.c文件,但为什么就给我一个.o编译为.exe?

这是因为我们在声明.o文件时只声明一个,那么向编译10个就要全写上嘛?那如果100个那岂不是很麻烦?

那么接下来有两种方法来进行展开:

做法一:

这时候就可以观察到全部展开了!

我们发现没有.o文件啊,这里有个语法make自动识别:

我们再来make一下

这样.o文件也展开了

我们再对Makefile进一步优化:

这样就可以全部删除了

再进行优化:

如果我们创建上1000个.c文件进行编译,我们来看一下它的编译时间:

这里大家可能看不到过程,其实是编译了很长时间的,我们在make一下发现他不让我百衲衣,因为会花费大量时间,我们再来code.c把源文件修改一下,如何发现再make它编译一下就出来了,这是为什么呢?

因为他只编译了被修改的内容!!!

我们之前说到的展开文件还有一个做法也是比较推荐的:


五、总结:为什么一定要学 Makefile?​

  1. 效率提升:只编译修改过的文件,大型项目节省大量时间;​
  2. 统一流程:团队协作时,所有人用同一个 Makefile,避免 “本地能跑,别人跑不了”;​
  3. 进阶基础:后续学习 CMake(生成 Makefile 的工具)、自动化部署,都需要理解 Makefile 的核心逻辑。​

如果你是 Linux 开发新手,建议从 “多文件案例” 开始动手实践,重点注意Tab 键和变量简化这两个细节 —— 上手后会发现,Makefile 其实比想象中简单!


结语:掌握Makefile能显著提升Linux开发效率,特别适合需要管理多文件项目的开发者,讲解了大量实用案例和底层原理分析,帮你彻底理解这个工程化开发必备工具

Read more

Flutter 组件 genkit 的适配 鸿蒙Harmony 深度进阶 - 驾驭模型幻觉审计、实现鸿蒙端多维 RAG 向量对齐与端云协同 AI 指挥中心方案

Flutter 组件 genkit 的适配 鸿蒙Harmony 深度进阶 - 驾驭模型幻觉审计、实现鸿蒙端多维 RAG 向量对齐与端云协同 AI 指挥中心方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 genkit 的适配 鸿蒙Harmony 深度进阶 - 驾驭模型幻觉审计、实现鸿蒙端多维 RAG 向量对齐与端云协同 AI 指挥中心方案 前言 在前文中,我们利用 genkit 实现了基础的 AI 模型流式调用(Streaming)与 Prompt 工程。但在真正的“专业级医疗诊断辅助”、“金融量化分析报告生成”或“大型智能客服矩阵”场景中。简单的模型调用仅仅是起点。面对大模型不可避免的“幻觉(Hallucinations)”问题。面对如何在鸿蒙(OpenHarmony)端实现本地向量库(Vector Store)与云端知识库的实时同步。面对如何在不同算力的设备(从手环到大屏)上分配不同的 AI

By Ne0inhk

10分钟,教你用OpenClaw+Chrome插件生成一份AI每日简报

大家好,我是岳哥。 最近在自己电脑上安装了OpenClaw(原名Clawdbot),越用越上瘾,中午吃饭的时候都还在用手机飞书给它下命令。 花了点时间让它帮我做了一个AI每日简报,可以看下效果。 这个是基于X和Brave Search搜索全网信息源生成的,我个人认为效果还是挺不错的,直接在飞书上就可以看到了。 下面给大家分享一下要如何实现这个功能。 安装OpenClaw和飞书插件 这个前面有详细介绍,包括飞书插件安装失败的解决办法,都有给大家分享,跟着教程操作都可以安装成功的。 具体链接如下: Clawdbot/Moltbot安装教程,接入飞书本地搭建你的AI助理平台 教你如何解决OpenClaw安装飞书插件失败的问题 安装Chrome插件 这个是OpenClaw开发的一个Chrome插件,可以根据你的要求使用Chrome打开你要搜索的信息关键词的相关网页。 这个插件分为三个部分: * 浏览器控制服务(网关或节点):代理/工具调用的API(通过网关) * 本地中继服务器(环回CDP):控制服务器与扩展之间的桥接(默认设置)http://127.0.0.

By Ne0inhk
爆火AI圈的OpenClaw(小龙虾):能干活的本地AI智能体,一文吃透入门到实战

爆火AI圈的OpenClaw(小龙虾):能干活的本地AI智能体,一文吃透入门到实战

🔥个人主页:Cx330🌸 ❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》 《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔 《Git深度解析》:版本管理实战全解 🌟心向往之行必能至 🎥Cx330🌸的简介: 目录 前言: 一、先搞懂:OpenClaw到底是什么?为什么这么火? 1.1 项目核心定位 1.2 爆火的核心原因:踩中AI落地痛点 1.3 OpenClaw vs 传统AI vs 自动化工具 二、OpenClaw核心架构:它是怎么干活的? 三、保姆级部署:全平台一键安装,小白也能搞定 3.1 部署前置准备 3.2 官方一键脚本(新手首选,

By Ne0inhk
出门也能用家里的AI?我用cpolar给OpenClaw开了个“任意门”

出门也能用家里的AI?我用cpolar给OpenClaw开了个“任意门”

前言 在数据安全越来越重要的今天,能本地运行、不泄露隐私的 AI,才是最让人安心的选择。OpenClaw 正是这样一款隐私优先的本地模型,可它最大的遗憾,就是只能在家访问。一旦出门,再安全的 AI 也用不上。这让很多人陷入两难:用在线 AI 担心隐私,用本地 AI 又不够方便。难道安全和便携真的不能兼得吗?当然不是。我在长期使用中找到最佳方案:用 cpolar 内网穿透,给隐私 AI 加上 “随身能力”。它不改变本地运行逻辑,不上传数据,只建立一条加密隧道,让你在外也能安全访问家里的 OpenClaw。既能保证所有对话、文件都存在本地,又能实现随时随地调用,兼顾隐私与便捷。这篇文章就带你实操,让你的隐私 AI 不再受限于局域网,走到哪用到哪。 1 OpenClaw和cpolar是什么? 1.1 OpenClaw:

By Ne0inhk