Linux 项目自动化构建工具:make/makefile

news2025/5/16 13:14:32

什么是 make

make 是一个命令,他会在源文件的当前目录下寻找 makefile 或者 Makefile 文件执行这个文件中的代码。

makefile 文件的编写

我们先来见见猪跑,看看 make 怎么用的:
下面是 makefile 文件的内容:
在这里插入图片描述
这是 test.c 中的内容:

#include<stdio.h>
int main()
{
    printf("hello make\n");
    return 0;
}

之前我们想要使用 gcc 编译 test.c 生成 test 可执行文件,你是不是要这样写命令:

gcc -o test test.c

在我们写了上面的 makefile 文件之后,我们就能使用 make 命令来代替啦!
在这里插入图片描述
我们可以看到使用 make 命令之后顺利编译出来了可执行文件,并且能够顺利执行!

makefile 文件的编写

我们再来看 makefile 文件中的代码:
在这里插入图片描述
其中这个冒号前面的部分叫做依赖关系(绿色框框的那个),后面的部分叫做依赖方法(红色框框的那个)。听上去十分高大尚,翻译成白话文就是:依赖关系的形成需要依赖方法中的所有文件。

make 命令会自动扫描 makefile 文件,查看当前目录下是否存在依赖方法中的所有文件,如果已经存在,那么就会执行下一行 Tab 缩进的代码(只能是 Tab 缩进)。那么如果不存在怎么办呢?

我们在讲 C 语言编译链接的时候知道:从 C 语言的源文件到生成功可执行文件是分成很多步骤的:

gcc -E
gcc -S
gcc -C

根据这个原理我们就在 makefile 文件中将那一行编译生成可执行文件的代码分成一步一步来执行。

test:test.o
	gcc test.o -o test
test.o:test.s
	gcc -c test.s -o test.o
test.s:test.i
	gcc -S test.i -o test.s
test.i:test.c
	gcc -E test.c -o test.i

make 命令扫描 makefile 文件时:

  • 发现依赖关系 test 的依赖文件 test.o 在源文件的当前目录不存在,继续向下扫描。
  • 发现依赖关系 test.o 的依赖文件 test.s 在源文件的当前目录不存在,继续向下扫描。
  • 发现依赖关系 test.s 的依赖文件 test.i 在源文件的当前目录不存在,继续向下扫描。
  • 发现依赖关系 test.i 的依赖文件 test.c 在源文件的当前目录已经存在,就会执行 Tab 缩进的代码:gcc -E test.c -o test.i 生成 test.i
  • test.i 依赖文件已经存在啦,就会执行:gcc -S test.i -o test.s 生成 test.s 文件。
  • test.s 依赖文件已经存在啦,就会执行:gcc -c test.s -o test.o 生成 test.o 文件。
  • test.o 依赖文件已经存在啦,就会执行:gcc test.o -o test 生成 test 可执行文件。

在上述过程执行完成之后(使用 make 命令之后),源文件的当前目录下就会生成:test.i test.s test.o test 文件。
在这里插入图片描述
我们可以看到显示出来命令的执行顺序与我们推导的顺序是一样的哈!
综上所述:扫描 makefile 文件的时候,如果源文件的当前目录不存在依赖文件,就会递归似的向下执行,这种行为叫做 make 的自动化推导

清理可执行文件

我们在更改了源文件的代码之后,需要清除可执行文件后重新编译。那么清除可执行文件能否使用 make 命令呢?那肯定是可以的撒!

clean:
	rm -f test

其中,clean 是依赖关系,冒号右侧为空说明表明没有依赖的文件。那么我们应该如何使用这个依赖关系呢?
执行命令:make clean 即可。

make clean

在这里插入图片描述
我们看到顺利运行了呢!

clean 放在 makefile 文件的最开头

如果我们像这样写 makefile 文件会发生什么呢?

clean:
	rm -f test
test:test.c
	gcc -o test test.c

在这里插入图片描述
可以看到我们想要编译文件就需要使用命令:make test,而 make 命令变成了执行:rm -f test
由此可见:make 命令会从上到下扫描 makefile 文件,将扫描到的第一个依赖关系作为 make 命令的默认行为


不推荐将依赖关系 clean 放在 makefile 文件的开头


make 命令编译多个文件

多个源文件生成一个可执行程序

我们写一个代码:在 function.h 中声明一个 Add 函数,在 function.c 中实现 Add 函数,然后在 test.c 中调用 Add 函数。
function.h

#pragma once
int Add(int a, int b);

function.c

int Add(int a, int b)
{
    return a + b;
}

test.c

#include<stdio.h>
#include "function.h"
int main()
{
    int a, b;
    scanf("%d %d", &a, &b);
    printf("a + b 的结果:%d\n", Add(a, b));
    return 0;
}

我们想要编译 function.h function.c test.c 应该怎么做呢?其实很简单哈!

test:function.c test.c
   gcc -o test test.c function.c
clean:
   rm -f test

如果是多个源文件生成一个可执行程序,只需要在依赖文件中以空格隔开多个源文件即可。如果 .h 文件在源文件的当前目录,依赖文件中是不需要写 .h 文件的!

多个源文件生成多个可执行程序

如果在 makefile 文件的目录下有多个源文件,并且想要将这些个源文件分别编译成可执行文件应该怎么做呢?你可以先想一想🤔,你应该是有能力写出来的。
我们来写这样两个源文件:test1.ctest2.c
test1.c

#include<stdio.h>

int main()
{
   printf("i am test1.c\n");
   return 0;
}

test2.c

#include<stdio.h>

int main()
{
   printf("i am test2.c\n");
   return 0;
}

我们要使用 make 命令讲他们分别编译成:test1test2 两个可执行文件。makefile 文件可以这样写:

All:test1 test2
test1:test1.c
	gcc -o test1 test1.c
test2:test2.c
	gcc -o test2 test2.c
clean:
	rm -f test1 test2

依赖关系:All 依赖于 test1 和 test2make 命令扫描 makefile 文件,发现源文件当前目录不存在 test1 和 test2 那么就会继续向下扫描。当扫描到 test1 和 test2 这两个依赖关系,他们的依赖文件都在源文件的当前目录。可以直接执行他们 Tab 缩进的代码,生成 test1 和 test2,最后完成两个源文件的编译生成两个可执行文件。
在这里插入图片描述

我们可以看到执行 make 命令之后也是顺利生成了 test1test2 两个可执行文件了呢!

make 可以重复编译吗?为什么?

我们还是回到最开始的那个代码:
test.c

#include<stdio.h>
int main()
{
    printf("hello make!\n");
    return 0;
}

makefile

test:test.c
	gcc -o test test.c
clean:
	rm -f test

我们发现在不修改代码的情况下,是不允许二次编译的:
在这里插入图片描述
这是为什么呢?
显然是因为没有这个必要哈,既然你的源文件没有被修改为什么要为你重新编译呢?
那这个是怎么做到的呢?

  • 一般来说,我们都是先有源文件,再有可执行程序。这就意味着源文件的最近修改时间比可执行程序的最近修改时间要早。
  • 因此,我们只需要比较可执行程序的最近修改时间和源文件的最近修改时间,就可以判断源文件是否需要重新被编译啦!

🤔思考:源文件的最近修改时间会和可执行程序的最近修改时间想等吗?这个一般是不会的!😊


那么,这个用来比较的时间哪里来呢?
我们先来学习一个命令吧:这个命令可以查看一个文件的时间状态。

stat 文件

在这里插入图片描述
Access Modify Change 这三个时间称为文件的 ACM 时间。

  • Access:最近访问时间,几乎文件的任何操作之后,这个时间都会发生改变。
  • Modify:当对文件的内容做出修改之后,这个时间就会更新。
  • Change:当对文件的属性做出修改之后,这个时间就会更新。

这就意味着,一旦对文件的内容做出修改,Access Modify Change 时间都会被更新。

因为 Access 时间要被频繁被修改,在实际的实现中 Access 时间的更新是有一定的更新策略(例如:当 Modiify 或者 Change 时间到达一定的次数之后再更新 Access 时间),而不是根据 Access 时间的定义那样,操作一次文件都要更新这个时间。
原因:文件是被存放在磁盘中的,将数据刷新到磁盘的速度是比较慢的,频繁地修改 Access 时间势必会影响操作系统的效率的。

在判断源文件是否需要重新编译,就是根据源文件和可执行程序 Modify 时间的比较结果来判定的!


如何验证呢?
再来学习一个命令吧:

touch 文件名

这个 touch 命令除了能够创建一个普通文件,还有一个功能就是:当这个文件已经存在时,能更新一个文件的 ACM 时间到当前的最新时间。
因此,我们可以更新源文件的 ACM 时间到最新,使得 make 命令可以反复编译一个相同的源文件。
在这里插入图片描述我们看到,第一次可以顺利编译,这很正常。第二次使用 make 编译的时候就不能了!我们在更新源文件的 ACM 时间之后又能使用 make 编译了!由此可以验证就是通过比较源文件与可执行文件的时间来判断是否能使用 make 再次编译的!

如何让一个依赖关系一直被执行

我们上面讲了通过 touch 命令可以使用 make 一直编译。但是,还是不建议这么做,没有修改源文件就不要重复编译,这很好,不是吗!
但是清理可执行文件的依赖关系,我们就有这个需求,让他总是被执行。那么 makefile 文件应该怎么写呢?

test:test.c
	gcc -o test test.c
.PHONY:clean
clean:
	rm -f test

makefile 文件中被 .PHONY 修饰的依赖关系就可以被一直执行啦!
你若不信,就可以给可执行文件 test 这个依赖关系加上 .PHONY 修饰,看能不能 make 重复编译(不建议这么做!!!)。

特殊符号

  • $@:表示:依赖关系:依赖方法 中冒号前面的一坨!
  • @^:表示:依赖关系:依赖方法 中冒号后面的一坨!

那么,我们写 makefile 文件就可以这么写啦:

test:test.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f test

在这个 makefile 文件中:$@ 就是 test$^ 就是 test.c

==这才是我们在平时用的最多的 makefile 文件的编写方法啦!==😊

取消回显

我们在使用 make 的时候是不是能看到 make 推导出来的要执行的指令的内容!像这样:
在这里插入图片描述
如果你不想回显命令,只需要在指令前面加上 @ 符号就可以啦!

test:test.c
	@gcc -o $@ $^
.PHONY:clean
clean:
	@rm -f test

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1257708.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AD9510 概要总结】A..

目录 特征FEATURES概述 GENERAL DESCRIPTION功能描述 FUNCTIONAL DESCRIPTIONPLL部分REFIN PLL参考输入—REFINVCO/VCXO时钟输入—CLK2PLL基准分频器—RVCO/VCXO 反馈分频器—N (P, A, B)A 和 B 计数器确定 P、A、B 和 R 的值 鉴频鉴相器&#xff08;PFD&#xff09;和电荷泵消…

国联易安:“主动防御”才能保障数据库安全

随着IT与互联网技术高速发展,政府、金融、电信、教育、医疗等各行业的数据成为了组织机构的核心资产。一旦数据被泄漏,不仅会造成严重经济损失&#xff0c;而且会带来极大负面社会影响。 国联易安国联数据库安全防护系统是一款基于数据库协议分析与控制技术的数据库主动防御系统…

如何编写自己的python包,并在本地进行使用

如何编写自己的python包,并在本地进行使用 一、直接引用 1.创建Python项目pythonProject。 2.并且在此项目下创建pg_message包。 3.pg_message包下默认生成_init_.py文件。 Python中_init_.py是package的标志。init.py 文件的一个主要作用是将文件夹变为一个Python模块,Pyt…

汇编程序:查0~9的平方表获得平方数

查平方表。在数据段中建立一个表格TABLE&#xff0c;存放0~9的平方值。从键盘输入一个十进制数字(0~9)&#xff0c;查表求键入数字的平方值。并把结果显示在CRT屏幕上。能够单步执行程序&#xff0c;认真观察、判断每条指令执行的结果是否正确&#xff0c;对错误结果&#xff0…

【网络安全】-常见的网站攻击方式详解

文章目录 介绍1. SQL 注入攻击攻击原理攻击目的防范措施 2. 跨站脚本攻击&#xff08;XSS&#xff09;攻击原理攻击目的防范措施 3. CSRF 攻击攻击原理攻击目的防范措施 4. 文件上传漏洞攻击原理攻击目的防范措施 5. 点击劫持攻击原理攻击目的防范措施 结论 介绍 在数字时代&a…

工具: OPC-UA学习和模型搭建

本文采用的是open62541 V1.3.8 作为OPC-UA的开发的支持库官网 使用文档说明 git相关 git源码 Release版本 下载最新的git源码或者release版本发布包&#xff0c;之后按照使用文档进行编译可以生成动态库。推荐使用的是release发布包。open62541内部有其他的git库依赖 将动态…

微软重磅更新:Bing Chat全线改名Copilot,用户可免费使用GPT4!(文末附Copilot使用教程)

原创 | 文 BFT机器人 微软在2023年的Ignite大会上宣布了许多新产品和功能。其中最引人注目的是Bing Chat更名为Copilot&#xff0c;Copilot基于最新的OpenAI模型&#xff0c;包括GPT-4和DALL・E 3&#xff0c;为用户提供文本和图像生成功能。也就是说&#xff0c;只要你拥有微…

文件元数据批量修改:mp3音频和mp4视频的元数据如何批量修改

在数字媒体处理和管理的日常工作中&#xff0c;文件元数据的批量修改是一个常见的需求。元数据&#xff0c;或者称为文件信息&#xff0c;可以包括文件的创建日期、修改日期、文件名、文件大小、标签等。在音乐和视频处理领域&#xff0c;例如对mp3音频和mp4视频文件&#xff0…

关于铝镓氮(AlGaN)上p-GaN的高选择性、低损伤蚀刻

引言 GaN基高电子迁移率晶体管&#xff08;HEMT&#xff09;由于其高频和低导通电阻的特性&#xff0c;近来在功率开关应用中引起了广泛关注。二维电子气&#xff08;2DEG&#xff09;是由AlGaN/GaN异质结中强烈的自发和压电极化效应引起的&#xff0c;这导致传统器件通常处于…

ICMPv6报文与邻居状态跟踪

ICMPv6报文 ICMPv6(Internet Control Message Protocol for the IPv6)是IPv6的基础协议之一。 在IPv4中,Internet控制报文协议ICMP(Internet Control Message Protocol)向源节点报告关于向目的地传输IP数据包过程中的错误和信息。它为诊断、信息和管理目的定义了一些消息…

抖音本地生活服务商申请入口门槛过高,该怎么办?

近年来&#xff0c;短视频平台的举起让直播带货和本地生活服务行业逐渐兴起&#xff0c;并且以其便捷、高效的特点受到了广大用户的欢迎。很多创业者也加入了本地生活服务商的行列中&#xff0c;但有消息传出&#xff0c;抖音本地生活服务商申请入口可能会关闭&#xff0c;由于…

防雷接地电阻和接地网的区别及其应用

接地是电气工程中的一种重要的安全措施&#xff0c;它可以保护电气设备和人员免受雷击和过电压的危害&#xff0c;也可以提高电气系统的运行稳定性和可靠性。接地的基本原理是将电气设备或人体与大地连接成同一电位&#xff0c;从而消除或减小危险电压。 地凯科技接地的实现方式…

掌握你的Mac,iStat Menus带你了解mac系统状态

iStat Menus for mac是一款强大的mac系统状态监控工具&#xff0c;它能够提供实时的系统信息和性能监测&#xff0c;帮助用户全面了解和管理自己的Mac设备。无论是CPU、内存、网络、硬盘还是传感器数据&#xff0c;iStat Menus都能直观地展示&#xff0c;并且支持自定义布局和样…

组装自己的稳定扩散模型

在本文中&#xff0c;我们将利用 Hugging Face Diffusers 库的组件实现自己的稳定扩散模型&#xff0c;可以像 diffuser.diffuse() 一样简单地生成图像。 在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编…

基于AC6969的蓝牙控制RGB彩灯

程序的实现思路&#xff1a;单片机与手机app之间通过蓝牙实现通讯&#xff0c;通过点击屏幕上的对应色块然后app会把对应的RGB值发送到单片机。然后单片机会对数据进行解析然后把数字量转换为模拟量&#xff0c;然后通过PWM控制IO口输出不同的电压以此来达到控制RGB灯 RGB彩灯原…

运动蓝牙耳机哪个品牌好?什么运动耳机好用?运动蓝牙耳机推荐

​运动耳机作为现代人运动时不可或缺的装备&#xff0c;除了能够提供稳固舒适佩戴体验之外&#xff0c;还带来了高品质音质体验。我们在选择运动耳机时&#xff0c;需要考虑到它们的音质、稳定性、舒适度和耐用性等方面&#xff0c;以确保在运动中获得最佳的体验和效果。下面&a…

ubuntu下载vscode并运行程序

如有帮助点赞收藏关注&#xff01; 如需转载&#xff0c;请注明出处&#xff01; 好久没有在linux下编译c代码了&#xff0c;由于换了酷炫彩灯的电脑。又要重新安装一次喽。做个记录&#xff0c;可以帮助到有需要的人&#xff0c;接下来不要错过每一个步骤。 我们一起手把手运行…

Yolov8训练数据集过程 + 测试测试集 + 继续训练

做自己第一次使用Yolov8训练的记录 1、下载代码 官网的我没找到对应的视频教程&#xff0c;操作起来麻烦&#xff0c;一下这个链接的代码可以有对应bilibili教程&#xff1a;完整且详细的Yolov8复现训练自己的数据集 选择这个下载&#xff1a; 2、安装需要的包&#xff1a; …

桥梁道路结冰传感器守护出行安全的重要工具

随着冬季的到来&#xff0c;气温逐渐降低&#xff0c;路面和桥梁容易结冰&#xff0c;给人们的出行带来安全隐患。为了解决这一问题&#xff0c; WX-JB2H 桥梁道路结冰传感器应运而生。本文将详细介绍桥梁道路结冰传感器的作用、原理及在冬季出行中的重要性。 一、桥梁道路结冰…

JVS-rules规则引擎导出与导入,确保业务连续性的关键

在复杂的系统环境中&#xff0c;规则和配置的迁移、备份及共享成为了确保业务连续性和一致性的关键过程。不同的环境可能需要相同的规则和配置数据&#xff0c;或者我们可能需要备份这些数据以防万一。JVS规则引擎提供了规则的导出与导入功能&#xff0c;使用户能够在多个环境间…