Linux中makefile

2023-11-05

 

第一个版本的makefile

Makefile的依赖是从上至下的,换句话说就是目标文件是第一句里的目标如果不满足执行依赖,就会继续向下执行如果满足了生成目标的依赖,就不会再继续向下执行了

Make会自动寻找依赖条件所用到的文件,

 其中,我们可以在中makefile文件中一次执行多个文件,执行命令是make,文件名可以是makefile或是Makefile,必须是这个名字,因为make与之匹配,

在其中我们可以

Makefile是一个脚本文件,该文件存放的是shell命令,既然是脚本文件,就要遵守makefile制定的规则(显示规则)。所以最开始的makefile可以是这样的

前面的hello是所需生成的目标文件,后面的hello.c是生成目标文件所需的依赖文件, 

 

为了将编译的整个过程体现出来,Makefile中的内容可以如下

执行Make指令之后的文件如下 

 

但是hello.i hello.s这些文件都是我们不需要的,所以不需要这么多步骤,hello依赖于hello.o,hello.o依赖于hello.c。所以改写makefile的内容

 

执行Make指令之后的文件如下所示

 

 以上是对单个文件进行编写的makefile,如果是多文件编程的话,应该怎么编写makefile文件?假设文件有add.c mul.c div.c main.c四个文件

Main.c 

 Add.c

Mul.c 

div.c

 对于这四个文件,makefile文件中可以这样写

 

 执行make指令后是这样的

但是这样的makefile是存在问题的,当我修改其中的一个文件后,其他三个文件就必须跟着一起重新编译,效率太低。比如改写add.c文件

 

 

其他三个文件也一起被编译了一遍。

总共有四个文件,需要生成main可执行文件,main依赖于add.o、mul.o、div.o,这三个文件又分别依赖于各自的.c文件,所以makefile可以改写成这样

执行make指令后

 

 此时去修改其中任一个文件,其他文件不会被重新编译,比如修改add.c

修改完之后再重新make一下,发现其他文件并没有被重新编译,只执行了 编译add.c和链接.o文件这两个动作 

为什么会仅执行这两个动作呢?

Makefile的检测原理:

文件有一个属性叫做“修改时间”,当文件被修改后,这个属性就会发生改变。Make就是通过检测这个属性判断哪些文件有没有被修改过。

如果出现目标文件的“修改时间”比依赖文件的“修改时间“更早的话,比如 16:40 早于 16:41。这样的话,make就会重新执行这条规则(重新编译);

Add.o依赖于add.c。add.c 是依赖文件,add.o是目标文件,add.c一被修改,时间就比add.o更晚。所以gcc -c add.c -o add.o 这条规则会重新被执行。一执行后,add.o的时间就比main的时间更晚,所以gcc main.o add.o mul.o div.o 这条规则也会被执行。

关于makefile中的变量

变量的定义:

变量名 = 目标名 等价于 替换功能

变量的使用:

$(变量名)

关于makefile指定最终生成目标问题

Makefile默认将第一条目标视作最终目标,一旦最终目标生成后,其他指令不会继续执行,当将main: add.o mul.o div.o 移到最后时

再去执行make指令,仅仅会生成一个main.o文件,其他文件不会被生成。 

再将mul.o:mul.c放在第一条目标验证一下 

执行make指令后,只生成了mul.o

 

所以可以通过ALL:(最终目标)去指定一个最终目标,ALL需要放在第一条语句

执行完make指令后 

Makefile的两个函数和伪目标

src = $(wildcard *.c)

函数名:wildcard

函数功能:找到当前目录下所有后缀为.c的文件,将文件名组成列表,赋值给src

结果: src = add.c div.c mul.c main.c

obj = $(patsubst %.c,%.o, $(src))

函数名:patsubset

函数功能:将参数3($(src))中,包含参数1(%.c)的部分,替换成参数2

$(src)是一个列表,%会依次顺序遍历列表中的.c文件

结果:obj = add.o div.o mul.o main.o

根据这两个函数,所以makefile可以改写成这样

执行make指令后 

关于伪目标的问题

在上面的makefile文件中,每次都需要删除.o文件,很繁琐,所以在makefile文件中加了删除部分

 通过执行make clean指令可以删除多余的.o文件

rm前面的-,代表出错依然执行。

Make clean -n 是模拟删除动作,并未真正删除,看到模拟执行后,确定没有问题,执行删除动作

但是如果你在当前目录下去创建一个clean文件,当你执行make clean的时候系统就会认为你要执行clean文件,从而干扰原本的执行命令。 

此时可以在makefile文件中的伪目标clean前加上.PHONY:来指定伪目标从而去除干扰: 

此时再次执行make clean看一下效果: 

这时候就算在本文件下有clean文件也不会造成干扰。

在上面的makefile中,各个生成.o的指令还是很繁琐,应该怎么办?

关于makefile3个自动变量和模式规则的问题

3个自动变量

$@ :在规则命令中,表示规则中的目标

$^ :在规则命令中,表示所有的依赖条件 

$<:这个只能使用在规则命令中,表示规则中的第一个依赖条件。如果将该变量使用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则。

所以可以将makefile改写成这个样子,sub,add这些指令中使用$<和$^都能达到效果,但是为了模式规则,所以使用的$<

执行make指令后 

 

上面的makefile不能进行扩展,可扩展性不行。比如,要添加一个乘法函数,就需要在makefile里面增加乘法函数的部分。不科学,所以,模式规则就来了

%.o:%.c

gcc -c $< -o $@

修改makefile,如下

 

 执行make指令

 

 

此时再添加一个乘法函数,无须更改makefile。

扩展:

当文件中存在clean文件时,make失灵

添加一个伪代码 

再使用变量完善一下 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux中makefile 的相关文章

  • Tomcat Intellij Idea:远程部署

    RackSpace 云服务器 Ubuntu 12 04 Intellij Idea 11 1 2 Windows 8 Tomcat 7 0 26 JDK 6 在 Intellij Idea 上 当我尝试在远程 Tomcat 7 服务器上运行
  • 在内核代码中查找函数的最佳方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我开始浏览内核代码 遇到的一件事是如何跟踪函数调用 结构定义等 有没有一种好的方法可以快速跳转到函数定义并退出 我尝试过 Source N
  • 仅使用containerd(不使用Docker)修剪容器镜像

    如果我刚刚containerd安装在 Linux 系统上 即 Docker 是not安装 如何删除未使用的容器映像以节省磁盘空间 Docker 就是这么方便docker system prune https docs docker com
  • 执行命令而不将其保留在历史记录中[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在进行软件开发时 经常需要在命令行命令中包含机密信息 典型示例是将项目部署到服务器的凭据设置为环境变量 当我不想将某些命令存储在命令历史记
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 如何使用 JSch 将多行命令输出存储到变量中

    所以 我有一段很好的代码 我很难理解 它允许我向我的服务器发送命令 并获得一行响应 该代码有效 但我想从服务器返回多行 主要类是 JSch jSch new JSch MyUserInfo ui new MyUserInfo String
  • ALSA:snd_pcm_writei 调用时缓冲区不足

    当运行我最近从灰烬中带回来的旧程序时 我遇到了缓冲区不足的情况 该程序将原始声音文件完全加载到内存中 2100 字节长 525 帧 并准备 ALSA 进行输出 44 1khz 2 通道 有符号 16 位 if err snd pcm set
  • Google BQ:运行参数化查询,其中参数变量是 BQ 表目标

    我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL 此 SQL 脚本将用于多个日期 客户端和 BQ 表目标 因此这需要在我的 BQ API 命令行调用中使用参数 标志 parameter 现在 我已经点击此链接来了解参数化查询 h
  • 如何为 Linux 桌面条目文件指定带有相对路径的图标?

    对于我的一个 Linux 应用程序 我有应用程序二进制文件 一个 launcher sh 脚本 针对 LD LIBRARY PATH 和一个 desktop 文件 所有这些都位于同一文件夹中 我想使用图标的相对路径而不是绝对路径 我试过了
  • 通过 Visual Studio 2017 使用远程调试时 Linux 控制台输出在哪里?

    我的Visual Studio 2017 VS2017 成功连接Linux系统 代码如下 include
  • 在 Linux 上以编程方式设置 DNS 名称服务器

    我希望能够通过我的 C C 程序为 Linux 上的 DNS 名称服务器添加 IP 地址 我在一个带有只读 etc resolv conf 的嵌入式平台上 这意味着我不能简单地将 nameserver xxx xxx xxx xxx 行添加
  • 就分页分段内存而言的程序寿命

    我对 x86 Linux 机器中的分段和分页过程有一个令人困惑的概念 如果有人能澄清从开始到结束所涉及的所有步骤 我们将很高兴 x86 使用分页分段内存技术进行内存管理 任何人都可以解释一下从可执行的 elf 格式文件从硬盘加载到主内存到它
  • GMail 421 4.7.0 稍后重试,关闭连接

    我试图找出为什么它无法使用 GMail 从我的服务器发送邮件 为此 我使用 SwiftMailer 但我可以将问题包含在以下独立代码中
  • 从 Xlib 转换为 xcb

    我目前正在将我的一个应用程序从 Xlib 移植到 libxcb 但在查找有关我有时使用的 XInput2 扩展的信息时遇到了一些麻烦 libxcb 中有 XInput2 实现吗 如果是的话 在哪里可以找到文档 目前我在使用此功能时遇到问题
  • 如何使用waf构建共享库?

    我想使用构建一个共享库waf http code google com p waf 因为它看起来比 GNU 自动工具更容易 更简洁 到目前为止 我实际上有几个与我开始编写的 wscript 有关的问题 VERSION 0 0 1 APPNA
  • 内核的panic()函数是否完全冻结所有其他进程?

    我想确认内核的panic 功能和其他类似kernel halt and machine halt 一旦触发 保证机器完全冻结 那么 所有的内核和用户进程都被冻结了吗 是panic 可以被调度程序中断吗 中断处理程序仍然可以执行吗 用例 如果
  • 如何在 Linux 中使用 C 语言使用共享内存

    我的一个项目有点问题 我一直在试图找到一个有据可查的使用共享内存的例子fork 但没有成功 基本上情况是 当用户启动程序时 我需要在共享内存中存储两个值 当前路径这是一个char and a 文件名这也是char 根据命令参数 启动一个新进
  • 如何查找哪个 Yocto 项目配方填充图像根文件系统上的特定文件

    我经常与 Yocto 项目合作 一个常见的挑战是确定文件为何 或来自什么配方 包含在 rootfs 中 这有望从构建系统的环境 日志和元数据中得出 理想情况下 一组命令将允许将文件链接回源 即配方 我通常的策略是对元数据执行搜索 例如gre
  • 绕过 dev/urandom|random 进行测试

    我想编写一个功能测试用例 用已知的随机数值来测试程序 我已经在单元测试期间用模拟对其进行了测试 但我也希望用于功能测试 当然不是全部 最简单的方法是什么 dev urandom仅覆盖一个进程 有没有办法做类似的事情chroot对于单个文件并
  • 无法显示 Laravel 欢迎页面

    我的服务器位于 DigitalOcean 云上 我正在使用 Ubuntu 和 Apache Web 服务器 我的家用计算机运行的是 Windows 7 我使用 putty 作为终端 遵循所有指示https laracasts com ser

随机推荐

  • CM5501高效四开关降压-升压控制器(升降压芯片)

    CM5501 High Efficiency 4 Switch Buck Boost Controller Description CM5501 is a synchronous 4 switch Buck Boost controller
  • elasticsearch-索引与分片实现原理

    添加索引 我们往 Elasticsearch 添加数据时需要用到 索引 保存相关数据的地方 索引实际上是指向一个或者多个物理 分片 的逻辑命名空间 一个 分片 是一个底层的 工作单元 它仅保存了全部数据中的一部分 在分片内部机制中 我们将详
  • InheritableThreadLocal类详解

    我们在使用ThreadLocal类的时候 可以保证各个线程使用自己的数据 而不相互干扰 但是如果我们有这样的一个需求 就是各个线程相互不干扰的情况下 各个线程的子线程可以访问到当前线程中的值 对于这个子线程来说就是访问父线程 public
  • Scrum那些事 - 什么是Scrum?

    1 什么是Scrum Scrum是敏捷开发方法论里面的一个具体实施框架 Scrum是一个包括了一系列的实践和预定义角色的过程骨架 是一种流程 计划 模式 用于有效率地开发软件 Scrum的框架中包含3种角色 3个产出 5个活动和5种价值观
  • 1.业务层 、服务层、数据层、表现层

    一般说来 业务逻辑层中的模块包含了系统所需要的所有功能上的算法和计算过程 并与数据访问层和表现层交互 抽象的说 业务逻辑层就是处理与业务相关的部分 一般来说 业务层包含一系列的执行与数据的操作 例如 开具发票 添加客户或下订单等 服务层就是
  • 《我的眼睛--图灵识别》第十章:实战演练:文字类识别

    我的眼睛 图灵识别 第十章 实战演练 文字类识别 1 标准数字 标准数字 Standard Numbers 是指10个数字使用的都是同属一种字体 它们的数字没有发生变形 没有扭曲 没有错位 存在有些变色但影响不大 字与字之间的间隔距离一样
  • Elasticsearch的简单入门:(二)ES基础

    Elasticsearch的简单入门 一 ES简介与安装 https blog csdn net kavito article details 88289820 前面我们把环境准备好了 下面继续学习ES的索引操作 2 操作索引 2 1 基本
  • Oracle VM VirtualBox安装Ubuntu虚拟机的过程记录

    一 版本信息 操作系统 Windows 10 家庭版 Oracle VM VirtualBox 版本 6 0 10 r132072 Qt5 6 2 Ubuntu 16 04 6 desktop amd64 二 创建过程 开始新建虚拟机 点击
  • 循环结构程序设计-第4关:C循环-水仙花数

    任务描述 本关任务 求出所有的水仙花数 提示 所谓水仙花数是指一个三位数 其各位数字的立方和等于该数字本身 比如153是一个水仙花数 因为153 1 3 5 3 3 3 注意 本题不需要输入语句 由于网站限制要求一定要有输入输出示例 但同学
  • 力扣每日一题【电话号码的字母组合】

    电话号码的字母组合 b站视频 class Solution public vector
  • ChatGPT将彻底改变人们的工作方式

    来源 企业网D1Net 关注公众号 人工智能学派 加入我们社群 免费领取官方chatGPT账号 自从OpenAI公司推出ChatGPT以来 它以风暴般的速度迅速影响了大量用户的日常工作和生活 并且已经通过医学院考试 软件工程师编码面试 律师
  • gorm记一次“mysql写入 Error 1366 (HY000): Incorrect string value”错误

    记一次 mysql写入 Error 1366 HY000 Incorrect string value 错误 环境go gorm docker mysql 写入数据库的内容为中文时提示Error 1366 HY000 Incorrect s
  • [管理与领导-88]:IT基层管理者 - 扩展技能 - 5 - 职场丛林法则 -2- 在职场丛林中的黑暗森林法则,在没有弄清楚情况前保持低调地调研

    前言 管理者空降到一个新的环境中 对环境中的人和事都不熟悉 此时的管理者不适合新官上任三把火 而应该意识到 环境中处处充满陷阱 危险 冷箭和一双双冷眼旁观的眼睛和暗箭 一 黑暗森林法则 黑暗森林法则 也被称为刘慈欣的科幻小说 三体 系列中提
  • Vue3的emit(‘update:modelValue‘)

    目录 概述 正文 一 v model 在原生 input 上的用法 二 使用v model在组件上实现双向绑定 通过计算属性实现 概述 在Vue3中 子组件可以通过 emit自定义事件来向父组件传递数据 在这种情况下 父组件可以通过监听子组
  • 查看服务器用户所占空间

    查看服务器个人账户所占空间大小 du h max depth 1 wangsx localhost du h max depth 1 0 mozilla 32K config 46G project 3 7G software 0 data
  • Spring中IOC容器

    IOC入门案例思路分析 1 管理什么 Service和Dao 2 如何将管理的对象存放到IOC容器 配置applicationContext xml 第二步 3 将管理的对象存放到IOC容器 如何获取IOC容器 第三步 4 获取到IOC容器
  • Dos环境变量修改

    批处理修改环境变量 修改用户变量 系统变量 全局变量 永久 临时设置环境变量 设置Java环境变量 关于路径问题 在执行批处理命令时 需要用到路径变量 这里先说明路径相关的变量参数 echo 当前盘符 d0 echo 当前盘符和路径 dp0
  • 6.830 / 6.814: Syllabus 2021 - MIT Lab 2 - SimpleDB Operators

    文章目录 1 参考链接 2 SimpleDB Architecture and Implementation Guide 2 1Filter and Join 2 2 Aggregates 2 3HeapFile Mutability 2
  • 在你的 Android 手机上运行 Golang 程序

    在我们日常开发中 运行一个服务 都是在 shell 或 cmd 下执行命令 像是使用 go run main go 直接编译运行 或是 go build 编译生成可执行文件后 以 xxx 方式运行 Go 支持交叉编译生成各平台的可执行文件
  • Linux中makefile

    第一个版本的makefile Makefile的依赖是从上至下的 换句话说就是目标文件是第一句里的目标 如果不满足执行依赖 就会继续向下执行 如果满足了生成目标的依赖 就不会再继续向下执行了 Make会自动寻找依赖条件所用到的文件 其中 我