Linux项目自动化构建工具-make/Makefile (●‘◡‘●)

2023-11-18

目录

1.为什么要使用make

2.makefile的基本语法与变量


1.为什么要使用make

假设我们的执行文件里面包含2个源文件,分别是main.c ,  test.c ,

 如果想要这个程序运行起来,那么就需要先编译:

# 先对源文件进行编译,产生test.o,main.o文件
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ gcc -c test.c  
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ gcc -c main.c

# 将test.o main.o文件进行链接,将生成的可执行程序文件定为mytest
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ gcc test.o main.o -o mytest
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ ./mytest <==> 执行可执行文件 结果如下
hello sjp
hello sjp
hello sjp
hello sjp
hello sjp
hello sjp

编译过程需要进行好多操作,如果有更多的源文件,那么我们就需要输入更多 gcc -c 源文件  的操作,而且如果要对源文件进行重新编译,则上诉的操作需要在操作一遍,光是要找出这些命令就够烦人了,那么有没有一个步骤就完成上面所有操作?make就可以帮我们完成以上所有的操作。

我必须先说明的是make是一条命令。makefile文件

要想使用make这条命令,就需要在当前目录下创建一个makefile或者Makefile文件,内容如下:

1 mytest:main.o test.o
  2   gcc -o mytest main.o test.o # 前面的空格必须以【Tab】键开头
  3 
  4 main.o:main.c
  5   gcc -c main.c                                                                                                                         
  6 test.o:test.c
  7   gcc -c test.c                                                     

当我们执行make指令后,make会去当前目录下去找makefile或Makefile文件,并根据makefile或Makefile中的内容去执行相关的命令

[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make 
gcc -c main.c
gcc -c test.c
gcc -o mytest main.o test.o
# 不修改源文件中的任何内容,再执行make指令,则不会再继续对源文件进行编译
[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make 
make: `mytest' is up to date.

我们只写了mytest需要的目标文件,结果make会主动的去判断每个目标文件相关的源代码文件,并直接进行编译,最后在执行链接的操作

编译完成后,如果我们再去修改源文件中的代码,那么make会主动的去判断哪一个源目标文件被修改了,并仅重新编译该文件, 如此这样,可以节省很多的编译时间,某些程序在进行编译操作时,会消耗很多的cpu资源。

例如:我们将test.c中的代码修改了一下,那么我们在执行一次make命令,则只会重新编译更新test.c文件产生test.o文件不会对main.c文件进行重新编译,最后再将main.o和test.o重新链接,

[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make
gcc -c test.c
gcc -o mytest main.o test.o

执行make命令后,没有将main.c重新编译。 

总结make的好处:

  • make可以简化编译所需要执行的命令。
  • 若在编译完成后,修改了某个源文件中的内容,我们再执行make命令,则make只会去编译更新那个被修改的源文件,其它的目标文件不会被修改。
  • 最后可以依照依赖性来更新执行文件

2.makefile的基本语法与变量

基本的makedile规则:

目标:依赖文件列表  

<Tab>依赖方法

第一行 为依赖关系。

例如;

1 mytest:main.o test.o
2   gcc -o mytest main.o test.o # 前面的空格必须以【Tab】键开头
                                         

mytest:main.o test.o 是依赖关系

上面中的第一行中的mytest是目标main.o test.o是依赖文件

gcc -o mytest main.o test.o 是生成mytest文件的方法,也就是依赖方法。

mytest依赖main.o和test.o的链接才能生成mytest

如果我们想要一个命令直接清理掉所有的目标文件(.o文件)与执行文件(.exe文件),那么我可以需要建立clean目标,如下:

  1 mytest:main.o test.o
  2   gcc -o mytest main.o test.o
  3 
  4 main.o:main.c
  5   gcc -c main.c
  6 test.o:test.c
  7   gcc -c test.c
  8 
  9 .PHONY:clean
 10 clean:
 11   rm -f test.o  main.o mytest    

其中.PHONY是修饰clean的,使clean可以一直重复使用,当然.PHONY:clean去掉也是可以的。

当我们要将生成的test.o main.o mytest删掉时,用make clean命令即可。

[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make clean 
rm -f test.o  main.o mytest 

在makefile文件中重复的变量有很多,那么我们是否可以将它们简化呢?

例子;

 1 mytest:main.o test.o
 2   gcc -o mytest main.o test.o

上面的命令可以改成:

  1 mytest:main.o test.o
  2   gcc -o $@ $^ 

$@:表示目标,代表上面的 mytest 

$^:表示依赖文件列表中的所有依赖文件。代表上面的 main.o test.o

当我们执行make,效果是一样的,如下:

[sjp@iZwz97d32td9ocseu9tkn4Z ~]$ make
gcc -c main.c
gcc -c test.c
gcc -o mytest main.o test.o

使用$^好处:

如果是依赖文件列表中有几十个文件甚至更多,那么在依赖方法中直接使用$^可以直接取代依赖文件列表中所有的文件,不需要将所有的依赖文件一 一列出来 所以使用$^是非常方便的。

使用$^和$@的好处:

如果我们修改(删除,添加)依赖关系中的目标或依赖列表中的依赖文件时,我们可以不用修改(删除添加)依赖方法中的文件

make和makefile说完之后,我们还需要解决一个问题。

问题:

我们知道,生成可执行文件有两种方法:

方法一;将源文件进行编译并链接形成可执行文件,没有保存其中的编译产生的目标文件(.o文件)。如下;

gcc main.c test.c -o mytest  直接将main.c和test.c文件编译并链接形成mytest文件,没有保存其中编译产生的目标文件(.o文件)

方法二:将源文文件进行编译产生目标文件,将它保存下来,然后再将目标文件进行链接。

gcc -c test.c

gcc -c main.c

gcc test.o main.o -o mytest

先将test.c main.c 编译产生目标文件(.o文件),然后再将目标文件进行链接。

请问方法二相对于方法一有什么优势?

方法二是将编译生成的目标文件给保存起来,我们生成可执行文件时,将目标文件链接起来,如果我们其中有一个文件修改了代码后,我们只需要

对被修改的源文件进行编译即可,不用再将所有的源文件进行编译。例如:如果有一个项目有100多个源文件,如果我们将它编译链接后

形成可执行程序后,发现功能并没有符合我们的预期,我们在将其中的几个源文件进行修改,那么我们只需要对那几个被修改的源文件再进行编译即可

而方法一由于没有保存相关的目标文件,就需要将所有的源文件进行再一次编译。而将所有的源文件在一次编译可能需要等上几个小时等,所以为了能减少时间,我们在编译的时候需要将其目标文件进行保存。

好啦,今天的分享就到这里了,如果这篇文章帮到你的话,记得给笔者一个赞哦,关注我,我将不断分享知识出来,感谢你的支持。

记得点个赞哦(●'◡'●)。

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

Linux项目自动化构建工具-make/Makefile (●‘◡‘●) 的相关文章

  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • 为什么可以通过ref参数修改readonly字段?

    考虑 class Foo private readonly string value public Foo Bar ref value private void Bar ref string value value hello world
  • 启动时的 Excel 加载项

    我正在使用 Visual C 创建 Microsoft Excel 的加载项 当我第一次创建解决方案时 它包含一个名为 ThisAddIn Startup 的函数 我在这个函数中添加了以下代码 private void ThisAddIn
  • iptables通过注释删除特定规则

    我需要删除一些具有相同评论的规则 例如 我有带有 comment test it 的规则 所以我可以像这样获得它们的列表 sudo iptables t nat L grep test it 但是我怎样才能删除所有带有注释 测试它 的 PR
  • IQueryable 单元或集成测试

    我有一个 Web api 并且公开了一个端点 如下所示 api 假期 name name 这是 Web api 的控制器 get 方法 public IQueryable
  • 在 NaN 情况下 to_string() 可以返回什么

    我使用 VS 2012 遇到了非常令人恼火的行为 有时我的浮点数是 NaN auto dbgHelp std to string myFloat dbgHelp最终包含5008角色 你不能发明这个东西 其中大部分为0 最终结果是 0 INF
  • 如何在 C 中安全地声明 16 位字符串文字?

    我知道已经有一个标准方法 前缀为L wchar t test literal L Test 问题是wchar t不保证是16位 但是对于我的项目 我需要16位wchar t 我还想避免通过的要求 fshort wchar 那么 C 不是 C
  • 在mysql连接字符串中添加应用程序名称/程序名称[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在寻找一种解决方案 在连接字符串中添加应用程序名称或程序名称 以便它在 MySQL Workbench 中的 客户端连接 下可见 SQL
  • 如何按 pandas 中的值对系列进行分组?

    我现在有一只熊猫Series与数据类型Timestamp 我想按日期对其进行分组 并且每组中有许多行具有不同的时间 看似显而易见的方法类似于 grouped s groupby lambda x x date 然而 熊猫的groupby按索
  • 从 wxPython 事件处理程序中调用函数

    我正在努力寻找一种在 wxPython 事件处理函数中使用函数的方法 假设我有一个按钮 单击该按钮时 它会使用事件处理程序运行一个名为 OnRun 的函数 但是 用户忘记单击 OnRun 按钮之前的 RadionButton 我想弹出一个
  • 从迭代器外部将 StopIteration 发送到 for 循环

    有几种方法可以打破一些嵌套循环 他们是 1 使用中断 继续 for x in xrange 10 for y in xrange 10 print x y if x y gt 50 break else continue only exec
  • WPF DataGridTemplateColumn 组合框更新所有行

    我有这个 XAML 它从 ItemSource 是枚举的组合框中选择一个值 我使用的教程是 http www c sharpcorner com uploadfile dpatra combobox in datagrid in wpf h
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • OpenGL:仅获取模板缓冲区而没有深度缓冲区?

    我想获取一个模板缓冲区 但如果可能的话 不要承受附加深度缓冲区的开销 因为我不会使用它 我发现的大多数资源表明 虽然模板缓冲区是可选的 例如 排除它以利于获得更高的深度缓冲区精度 但我还没有看到任何请求并成功获取仅 8 位模板缓冲区的代码
  • 如何创建用于霍夫曼编码和解码的树?

    对于我的作业 我将对霍夫曼树进行编码和解码 我在创建树时遇到问题 并且陷入困境 不要介意打印语句 它们只是让我测试并查看函数运行时的输出是什么 对于第一个 for 循环 我从主块中用于测试的文本文件中获取了所有值和索引 在第二个 for 循
  • Python 相当于 Scala 案例类

    Python 中是否有与 Scala 的 Case Class 等效的东西 就像自动生成分配给字段而无需编写样板的构造函数一样 当前执行此操作的现代方法 从 Python 3 7 开始 是使用数据类 https www python org
  • 没有名为“turtle”的模块

    我正在学习并尝试用Python3制作贪吃蛇游戏 我正在进口海龟 我正在使用 Linux mint 19 PyCharm python37 python3 tk Traceback most recent call last File hom
  • 两种 ODE 求解器之间的差异

    我想知道 两者之间有什么区别ODEINT and solve ivp用于求解微分方程 它们之间有什么优点和缺点 f1 solve ivp f 0 1 y0 y0 is the initial point f2 odeint f y0 0 1
  • 堆栈是向上增长还是向下增长?

    我在 C 中有这段代码 int q 10 int s 5 int a 3 printf Address of a d n int a printf Address of a 1 d n int a 1 printf Address of a
  • 如何在richtextbox中使用多颜色[重复]

    这个问题在这里已经有答案了 我使用 C windows 窗体 并且有 richtextbox 我想将一些文本设置为红色 一些设置为绿色 一些设置为黑色 怎么办呢 附图片 System Windows Forms RichTextBox有一个

随机推荐

  • 【数据库】Sqlite数据库

    1 sqlite数据库简介 SQLite是内嵌在Python中的轻量级 基于磁盘文件袋额数据库管理系统 就是一个文件 不需要安装和配置服务 支持使用SQL语句来访问数据库 该数据库使用C语言开发 支持大多数SQL91标准 支持原子的 一致的
  • c++ 共享内存方法实现windows进程通信

    主要逻辑 1 进程1 2通过读写一块共享内存完成这2个进程间的通信 2 进程互斥锁Mutex作用是实现进程同步 防止进程2一直读 实现进程1写一次进程2读一次 进程1代码 发送数据 include
  • keil新工程编译问题

    1 新建工程 找不到first和last 需要在工程中添加相对应芯片的start XXX swenjian 2 移植操作系统 error L6200E Symbol SysTick Handler multiply defined 这是在操
  • cuda矩阵乘法(简单理解)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 CUDA矩阵乘法 矩阵规模 一 一维并行 1 一维线程并行 thread 2 一维块线程并行 block 3 一维共享A一行程并行 shared 二 二维并行 1 共享存储二
  • 差分 【一维差分和二维差分】

    全文目录 一维差分 差分数组的构建 二维差分 差分矩阵的构建 一维差分 首先来了解一下差分的性质 差分是前缀和的逆运算 如果说前缀和是 S f n 那么差分就是 D f 1 n 也就是说 原数组是差分数组的前缀和 原数组 a i 差分数组
  • 自动化测试系列 —— UI自动化测试

    UI 测试是一种测试类型 也称为用户界面测试 通过该测试 我们检查应用程序的界面是否工作正常或是否存在任何妨碍用户行为且不符合书面规格的 BUG 了解用户将如何在用户和网站之间进行交互以执行 UI 测试至关重要 通过执行 UI 测试 测试人
  • 全球及中国可穿戴医疗设备市场潜力分析与投资动态调研报告2022-2028年

    全球及中国可穿戴医疗设备市场潜力分析与投资动态调研报告2022 2028年 修订日期 2022年2月 出版单位 鸿晟信合研究院 对接人员 周文文 内容分析有删减 了解详情可查看咨询鸿晟信合研究院专员 目录 第一章 可穿戴医疗设备行业相关概述
  • VS2019或者VS2017创建ASP.NET项目

    最近在学 NET Web应用程序开发 做个记录 默认大家的本机的IIS服务已经搭建好了 没有搭建好的自行百度 文章目录 首先是VS的相关配置 然后是项目的创建 发布网站 项目的发布 IIS配置 一 首先是VS的相关配置 首先打开VS2019
  • C# 获取本地主机IP地址

  • 数据库----------唯一约束、默认约束、零填充约束

    目录 1 唯一约束 Unique 1 概念 2 语法 3 添加唯一约束 4 删除唯一约束 2 默认约束 default 1 概念 2 语法 3 添加默认约束 4 删除默认约束 3 零填充约束 zerofill 了解即可 1 概念 2 操作
  • R语言基础

    专注系列化 高质量的R语言教程 推文索引 联系小编 付费合集 本篇总结一些关于工具包的问题 所指的 工具包 对应的英文原文是package s 本篇目录如下 1 工具包简介 2 安装工具包 2 1 CRAN 2 2 GitHub 2 3 离
  • SQL注入——DNSLOG注入

    SQL注入 DNSLOG注入 SQL注入 DNSLOG注入 SQL注入 DNSLOG注入 一 原理 一 原理 当我们遇到盲注漏洞的时候 注入过程没有回显 手工测试会花费大量的时间 如果用sqlmap跑数据的话 实际应用中很可能被目标服务器直
  • 如何在PyCharm中对自己的pySC2 Agent代码进行Debug

    PySC2环境在Win10系统上的部署与安装 请参考 https blog csdn net qq 38962621 article details 112798659 spm 1001 2014 3001 5501 PySC2自定义Age
  • docker单机编排工具docker-compose

    编排工具安装 本文为在linux系统中操作 首先是安装epel源 然后安装python的pip组件 利用pip安装docker compose 在安装完毕后 可以使用查看版本命令以及帮助命令查看所支持的子命令 wget O etc yum
  • CRM管理软件有哪些?这5款好用的CRM软件值得推荐!

    CRM软件最常在销售部门实施 作为销售人员自动化的中心枢纽 包括联系人 客户和机会管理 CRM软件通常与其他企业解决方案 例如ERP系统 营销自动化软件和客户服务软件 分开交付 但通常与其他业务应用程序集成以促进增强和协调的客户体验 目前市
  • 嵌入式常用通讯协议1(UART 、RS232、RS485、SPI、IIC)

    目录 1 常用通讯协议汇总 2 常见的电平信号及其电气特性 2 1 TTL电平 2 2 CMOS电平标准 2 3 RS232标准 2 4 RS485标准 3 UART 通用异步收发器 协议 3 1 UART定义 3 2 UART作用 3 3
  • LeetCode刷题C++

    5 最长回文字符串 给你一个字符串 s 找到 s 中最长的回文子串 划定步长 遍历判断 class Solution public string longestPalindrome string s if s size lt 2 retur
  • Vue 引入G2图表

    安装G2依赖 npm install antv g2 npm install antv data set vue ge 在Vue main js文件中引入G2 import G2 from antv g2 Vue use G2 模板中使用完
  • 深入理解链表:一种动态的线性数据结构

    文章目录 前言 1 概述 2 单向链表 3 单向链表 带哨兵 4 双向链表 带哨兵 5 环形链表 带哨兵 6 结语 前言 链表是我们在日常编程中经常使用的一种数据结构 它相比于数组具有更好的动态性能 但是 对链表的深入理解需要我们掌握其内在
  • Linux项目自动化构建工具-make/Makefile (●‘◡‘●)

    目录 1 为什么要使用make 2 makefile的基本语法与变量 1 为什么要使用make 假设我们的执行文件里面包含2个源文件 分别是main c test c 如果想要这个程序运行起来 那么就需要先编译 先对源文件进行编译 产生te