【Linux】Make/Makefile



这个3/4行的语法和1/2行是一样的。也是依赖关系和依赖方法。

make命令扫描makefile文件时,从上向下扫描,默认形成一个目标文件。
指定make clean的时候才回去执行对应的清除。
为什么要给我们的clean.PHONY:clean声明它是伪目标呢?
PHONY类似一种建议性的关键字。
伪目标,表示对应的依赖方法和依赖关系总是被执行。
什么叫不被执行?
我们上面的这组可执行程序没有被修饰,所以我们如果make完又make,是不会执行的。但如果用为目标修饰了,就会发现也可以执行。

所以我们一般可执行程序不用伪目标修饰,因为如果代码没有更新,没有必要再次编译。
默认老代码不作重新编译。
make怎么知道bin和.c的新旧?

Linux下每一个文件有三个相关时间,分别是Access/Modify/Change
文件=内容+属性
cat打印内容,ls打印属性
如果我们只改文件内容,那么Modify时间被修改。
如果我们只改文件属性,那么Change时间被修改。
如果不修改,单纯查看,Access时间被更新。

可以看到,这样我们的Modfiy时间就被改了。
而且文件属性页同步变化了,所以时间也改了:

大小和时间本就是文件的属性,所以基本都会同时修改。

更改这个权限,我们就是只改属性。
如果过于高频因为查看就更新时间,会有很多隐性的成本。所以linux现在查看上若干次才会更新一次Access时间,具体多少次看具体系统。
我们知道,myproc.c的Modify时间应当是要比myroc早的。所以make可以以此为依据判断myproc.c是否被修改过了。
我们曾经说过,touch可以用来改文件时间:

比如带上-a,就可以只改Access时间。
如果什么选项都不带,就会把ACM三个时间全部更新。
所以通过touch更改时间,也能使我们重复使用make。

所以PHONY的作用就是修饰后总是被执行,如果我们用其修饰第一组的代码,我们就可以重复使用make。
在makefile中注释代码我们使用#来注释。


makefile会在自己内部维护一个类似栈结构的东西。
makefile推导规则

从上往下扫描,从下往上执行。
当我们从上往下扫描,一条找不到时就入栈。所以就保证了我们最后找到myproc.c时,从下往上的执行顺序。
当然我们一般不会这么去写整个过程,自己增加难度。
makefile也允许我们去定义变量。所以我们写makefile一般喜欢这样写:


如果改写成这样:

就不会回显命令。


这样,BIN是我们的目标文件,CC是编译器,SRC是源文件,FLAGS是方法。我们将这组变量打印。

$(BIN)就是取它的内容。
所以我们全以变量的形式呈现了。这就是一个基于变量版本的makefile了。
有点像宏。

所以我们也能猜出,这样做的好处也就是替换具体的文件时不用改后面的代码了,只要在变量处稍作修改。

其实,还可以写得更加优雅:

$@代表的是目标文件,$^代表的是依赖的众多文件列表。
我们的依赖方法来源不止一行。
我们可以把默认的显示信息用@关闭,然后写自己的信息:


但我们发现还是将echo回显了,于是我们继续优化:

多文件呢?
而且,我们并不喜欢直接从.c到可执行文件,而是喜欢先从.c到.o,原因以前说过,为了方便去链接C语言库等,所以我们要改写。

LFLAGS的L代表link。OBJ代表.o文件。
.o文件从哪来的?所以我们要再写一组依赖关系和方法。但是一般我们的.c文件和以此生成的.o文件不止一个,为了简写,我们使用%.o:%.c这样来写我们的依赖关系。%就像makefile模式下的通配符;在依赖关系中我们也简写为:$(CC) $(FLAGES) $<,也是gcc -c $<,这里<用来简写所有的.c文件。

我们知道,gcc -c myproc.c -o myproc.o可以帮我们从.c文件编译到.o文件。
然后,gcc -c myproc.c则可以帮我们直接编译出同名.o文件。
这也就是为什么上面我们写成$(CC) $(FLAGS) $<

优化:

这个地方,我们可以SRC=$(shell ls *.c)执行ls *.c的命令,然后把对应所有的源文件放在SRC中。就不用我们一个一个手写要的源文件了。
第二种做法:
makefile天生自带类似函数的东西,可以支持我们这样写:SRC=$(wildcard *.c)
也是类似通配符。

所以我们的OBJ同样也需要这样能够使用类似通配符的效果,来避免一个一个手写。
OBJ=$(SRC:.c=.o)
这就是最终的makefile。
我们这样来创建100个文件:

不用改刚才的makefile文件了,可以直接这样使用make和make clean:


Makefile还有其他语法,日后可以再学。
相关文章:
【Linux】Make/Makefile
这个3/4行的语法和1/2行是一样的。也是依赖关系和依赖方法。 make命令扫描makefile文件时,从上向下扫描,默认形成一个目标文件。 指定make clean的时候才回去执行对应的清除。 为什么要给我们的clean.PHONY:clean声明它是伪目标呢? PHONY类…...
C++练级计划->《多态》虚函数表,菱形继承多态
目录 什么是多态? 多态的条件 虚函数: 虚函数的重写: 协变 析构函数的重写 C11 final 和 override final: override: 总结: 三重对比:重载重写重定义对比 抽象类 多态的原理 虚函数…...
OkHttp3 - 2. OkHttp的核心组件与架构
1 OkHttp的工作原理 OkHttp3 的核心设计遵循以下原则: 请求与响应的分离:通过 Request 和 Response 对象解耦请求构建与结果处理。异步与同步支持:使用 Call 对象管理请求,可以同步或异步执行。高效连接复用:通过连接…...
异或操作解决一些问题
前提: 异或操作符合交换律,结合律(因为其根本上来抽象理解,就是查看所有项二进制数相同位是否有奇数个1,对运算结果二进制数而言,没有该位为0,有该位为1,与顺序无关)。 …...
操作系统之输入输出
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
Centos 安装 Node.js 和 npm
方法2:使用 NVM(Node Version Manager)安装 安装 NVM curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash 重新加载配置 source ~/.bashrc 安装最新的 LTS 版本的 Node.js nvm install --lts 验证安装…...
C语言——指针初阶(一)
目录 一.什么是指针??? 指针是什么? 指针变量: 总结: 总结: 二.指针和指针类型 指针-整数: 总结: 指针的解引用 总结: 三.野指针 如何规避野指针 往期…...
React Native 原生开发指南
写在前面 React Native (RN) 是一个用于构建跨平台移动应用的框架。它允许开发者使用 JavaScript 和 React 来编写应用程序,并将其转换为原生代码。虽然 RN 提供了许多内置的组件和 API,但有时候你可能需要访问原生平台的特定功能或性能优化。为此&…...
【前端】JavaScript中的柯里化(Currying)详解及实现
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯什么是柯里化?💯柯里化的特点💯柯里化的简单示例💯通用的柯里化实现💯柯里化让代码更易读的原因💯…...
解决 docker 部署 vsftpd 速度慢问题
解决 docker 部署 vsftpd 速度慢问题 Docker 部署 ftp version: 3.8services:ftps:image: fauria/vsftpdcontainer_name: my-ftpsenvironment:- FTP_USERyourusername- FTP_PASSyourpassword- PASV_ADDRESS192.168.0.123 # 使用环境变量或直接指定IP地址- PASV_MIN_PORT4900…...
Java基础夯实——2.9 多线程如何共享数据
在 Java 多线程编程中,共享数据通过以下几种方式实现: 1. 使用共享对象 多个线程可以通过引用同一个对象来实现数据共享。例如: class SharedData {private int count;public synchronized void increment() {count;}public synchronized …...
【Leetcode Top 100】234. 回文链表
问题背景 给你一个单链表的头节点 h e a d head head,请你判断该链表是否为 回文链表(回文 序列是向前和向后读都相同的序列)。如果是,返回 t r u e true true;否则,返回 f a l s e false false。 数据…...
GitLab指定用户分配合并权限
进入项目 -》 Project Settings Repository -》展开 Protected branches -》 添加要保护的分支,设置角色 管理用户角色权限 查看到不同用户的角色,一般设置Developer只有Merger Request权限,Maintainer还有Merge审批权限 GitLab 中的权限…...
五,[GXYCTF2019]Ping Ping Ping1
进入靶场,有提示 我们在url试着输入本地IP,返回了ping命令 既然要在url处传参,那就用postman,再输入ip127.0.0.1 & ls,试着列出目录内容 ok,好像是个脏话,它过滤了空格 试着穿越又看到了脏话࿰…...
基于STM32的智能无人机自主飞行与目标识别系统设计
目录 引言系统需求分析 2.1 功能需求 2.2 硬件需求 2.3 软件需求系统设计 3.1 总体架构 3.2 各模块设计系统实现 4.1 硬件实现 4.2 软件实现系统调试与优化总结与展望 1. 引言 随着无人机技术的快速发展,无人机在军事侦察、环境监测、物流配送等领域的应用逐渐增多…...
C 语言数组与函数:核心要点深度剖析与高效编程秘籍
我的个人主页 我的专栏:C语言,希望能帮助到大家!!!点赞❤ 收藏❤ 目录 引言数组基础 2.1 数组的定义与初始化 2.2 一维数组的基本操作 2.3 二维数组及其应用 2.4 数组与指针的关系函数基础 3.1 函数的定义与调用 3.2…...
汽车轮毂结构分析有哪些?国产3D仿真分析实现静力学+模态分析
本文为CAD芯智库原创,未经允许请勿复制、转载! 之前分享了如何通过国产三维CAD软件如何实现「汽车/汽配行业产品设计」,兼容NX(UG)、Creo(Proe),轻松降低企业上下游图纸交互成本等。…...
解决jupyter notebook 新建或打开.ipynb 报500 : Internal Server Error(涉及jinja2兼容性问题)
报错: [E 10:09:52.362 NotebookApp] 500 GET /notebooks/Untitled16.ipynb?kernel_namepyt hon3 (::1) 93.000000ms refererhttp://localhost:8888/tree ...... 重点是: from .exporters import * File "C:\ProgramData\Anaconda3\lib\site-p…...
【若依ruoyi Vue前端线上个人服务器部署】以及常见报错问题解决
提示:【若依ruoyi Vue前端线上个人服务器部署】以及常见报错问题解决 文章目录 前言一、若依ruoyi Vue前端部署常见两种错误1、404问题2、找不到….模块 二、使用步骤(正式开始)1.修改vue.config.js中的publicPath属性。2.修改router/index.j…...
Python学习第十天--处理CSV文件和JSON数据
CSV:简化的电子表格,被保存为纯文本文件 JSON:是一种数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,以JavaScript源代码的形式将信息保存在纯文本文件中 一、csv模块 CSV文件中的每行代表电…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
