Linux操作系统从入门到实战(九)Linux开发工具(中)自动化构建-make/Makefile知识讲解

Linux操作系统从入门到实战(九)Linux开发工具(中)自动化构建-make/Makefile

  • 前言
  • 一、 make/Makefile是什么?
    • 1. 我们先想个问题:手动编译代码有多麻烦?
    • 2. 为了解决麻烦,才有了自动化工具
    • 3. 什么是 Makefile ?
    • 4. 什么是 make ?
  • 二、如何使用 make/Makefile
    • 1. 如何创建第一个Makefile?
      • (1) 创建源文件
      • (2) 创建Makefile文件
      • (3) 编写Makefile规则
      • (4) 执行make命令
    • 2. 依赖关系与命令
      • (1) 依赖关系
      • (2) make的执行逻辑
      • (3) 为什么需要依赖关系?
    • 3. 如何清理编译结果?
      • (1) 添加clean目标
      • (2) 执行清理命令
      • (3) .PHONY 标签的作用
    • 4. Makefile的执行规则
      • (1) 默认执行第一个目标
      • (2) 如何执行其他目标?
      • (3) 多个目标的执行顺序
    • 5. 常见错误与注意事项
      • (1) 命令行必须以Tab键开头
      • (2) 文件名大小写敏感
  • 三、伪目标是什么,为什么伪目标总被执行?
    • 1. make如何判断是否需要重新编译?
    • 2. 什么是伪目标(.PHONY)?
      • (1)定义:
      • (2) 常见用途:
    • 3. 为什么伪目标总是被执行?
      • (1)核心原因:
      • (2) 对比实验:
    • 4. 为什么需要伪目标?
      • (1) 避免与文件冲突
      • (2) 强制执行命令
    • 5. 常见伪目标示例
      • 1. clean目标(最常见)
      • 2. all目标(批量编译多个程序)
      • 3. install目标(安装程序到系统)


前言

  • 前面的博客里我们讲解了vim编译,g++/gcc编译的步骤和动静态链接与库的相关知识
  • 接下来我们继续讲解Linux开发工具自动化构建-make/Makefile

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Linux知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12879535.html?spm=1001.2014.3001.5482


一、 make/Makefile是什么?

1. 我们先想个问题:手动编译代码有多麻烦?

  • 假设你写了一个小项目,里面有好几个 .c 源文件(比如 a.cb.cmain.c)。
  • 要让它们变成能运行的程序,得用 gcc 编译,比如:
    gcc a.c b.c main.c -o myprogram

这看起来简单,但如果项目变大呢?

  • 假设有 100 个源文件,每次都手动敲这串命令,累不说,还容易输错;
    在这里插入图片描述

  • 如果只改了 a.c,手动编译时还得重新编译所有文件,浪费时间

  • 不同文件有依赖关系(比如 main.c 要用 a.c 的结果),手动编译得记清顺序,错一步就失败

2. 为了解决麻烦,才有了自动化工具

就像做复杂的菜时,你需要一份「步骤清单」(先切菜、再炒肉、最后炖),再找个「帮手」按清单一步步做。

在编程里,「步骤清单」就是 Makefile,「帮手」就是 make

3. 什么是 Makefile ?

Makefile 是一个我们自己创建的文件(名字就叫 Makefile,没有后缀),里面写的是「编译规则」

比如在一个 Makefile 里,你可以在里面写下:

现在看一下代码,后面会详细讲

# 规则1:最终要生成的程序叫 myprogram,它依赖 a.o、b.o、main.o
myprogram: a.o b.o main.ogcc a.o b.o main.o -o myprogram  # 生成 myprogram 的命令# 规则2:a.o 依赖 a.c
a.o: a.cgcc -c a.c  # 把 a.c 编译成 a.o(中间文件)# 规则3:b.o 依赖 b.c
b.o: b.cgcc -c b.c# 规则4:main.o 依赖 main.c
main.o: main.cgcc -c main.c

简单说,Makefile 就像一份「菜谱」:

  • 明确最终要做什么(比如 myprogram 这个程序);
  • 明确需要哪些「原材料」(比如 a.o 这些中间文件);
  • 明确每一步怎么做(比如用什么命令编译,先编译哪个、后编译哪个)。

4. 什么是 make ?

make 是 Linux 自带的一个命令工具(就像 lscd 一样,输入 make 就能运行)。

  • 它的作用很单纯:Makefile 里的规则,然后自动执行命令

比如刚才写好了 Makefile,你在终端敲一句 make,它就会:

  1. 先看最终要生成 myprogram,发现需要 a.ob.omain.o
  2. 检查这些 .o 文件有没有,如果没有,就按规则编译 a.c 生成 a.o,以此类推;
  3. 最后把所有 .o 文件拼起来,生成 myprogram

如果之后我们只改了 a.c,再敲 make 时,它会聪明地只重新编译 a.omyprogram,其他没改的文件不碰——省时间!

二、如何使用 make/Makefile

1. 如何创建第一个Makefile?

(1) 创建源文件

首先,创建一个简单的C语言程序code.c
在这里插入图片描述

// code.c
#include <stdio.h>
int main() {printf("Hello, Makefile!\n");return 0;
}

在这里插入图片描述

(2) 创建Makefile文件

在相同目录下创建Makefile文件(注意大小写和文件名):

touch Makefile
vim Makefile

在这里插入图片描述

(3) 编写Makefile规则

Makefile中写入以下内容:

# 目标: 依赖文件
code: code.cgcc -o code code.c  # 注意这行必须以Tab键开头

在这里插入图片描述

(4) 执行make命令

在终端输入make,它会自动读取Makefile并执行编译:

在这里插入图片描述

$ make
gcc -o code code.c

此时,当前目录下会生成可执行文件code,运行它:

$ ./code

在这里插入图片描述

2. 依赖关系与命令

(1) 依赖关系

在Makefile中,每行规则的基本格式是:

目标文件: 依赖文件列表命令1命令2...
  • 目标文件:要生成的文件(如code
  • 依赖文件:生成目标所需要的文件(如code.c
  • 命令:生成目标的具体操作(如gcc -o code code.c

(2) make的执行逻辑

当你执行make时,它会:

  1. 检查目标文件是否存在
  2. 如果不存在,或依赖文件比目标文件更新(即依赖文件被修改过)
  3. 则执行对应的命令来生成/更新目标文件

(3) 为什么需要依赖关系?

假设你修改了code.c,再次执行make时:

$ make
make: 'code' is up to date.

make会自动判断:由于code已存在且code.c未修改,因此无需重新编译——这就是Makefile智能编译能力,大大节省时间!

在这里插入图片描述

3. 如何清理编译结果?

(1) 添加clean目标

Makefile中新增一个clean目标:

code: code.cgcc -o code code.c.PHONY: clean
clean:rm -f code  # 删除生成的可执行文件

在这里插入图片描述

(2) 执行清理命令

当需要删除编译结果时,执行:

$ make clean
rm -f code

在这里插入图片描述

(3) .PHONY 标签的作用

.PHONY用于声明clean是一个伪目标(即它不是真正的文件名),防止目录中真的存在名为clean的文件导致冲突。

4. Makefile的执行规则

(1) 默认执行第一个目标

当你直接输入make时,它会执行Makefile中的第一个目标(如上面的code)。

(2) 如何执行其他目标?

通过指定目标名来执行特定规则,例如:

$ make clean    # 只执行clean目标下的命令
$ make code     # 只执行code目标下的命令(等同于直接make)

(3) 多个目标的执行顺序

Makefile会按照依赖关系自动处理执行顺序。例如:

all: program1 program2program1: file1.cgcc -o program1 file1.cprogram2: file2.cgcc -o program2 file2.c

执行make all时,会先编译program1,再编译program2

5. 常见错误与注意事项

(1) 命令行必须以Tab键开头

在Makefile中,命令行必须以Tab键开头,否则会报错:

# 错误示例(使用空格缩进)
code: code.cgcc -o code code.c  # 错误!会提示"*** missing separator.  Stop."# 正确示例(使用Tab键缩进)
code: code.cgcc -o code code.c

(2) 文件名大小写敏感

Makefilemakefile是不同的文件,GNU make默认优先读取GNUmakefile,然后是makefile,最后是Makefile。建议统一使用Makefile

三、伪目标是什么,为什么伪目标总被执行?

1. make如何判断是否需要重新编译?

当我们执行make时,它会检查两件事:

  • 目标文件(如code)是否存在
  • 依赖文件(如code.c)的修改时间是否比目标文件更新

如果目标文件不存在,或依赖文件被修改过(修改时间比目标文件晚),make就会执行命令重新生成目标文件。

举个例子

# Makefile
code: code.cgcc -o code code.c
  • 第一次执行make:生成code文件
  • 第二次执行makemake发现code已存在,且code.c没修改,==“code”已是最新 ==
    在这里插入图片描述
$ make
gcc -o code code.c  # 第一次执行,生成code
$ make
make: “code”已是最新  

2. 什么是伪目标(.PHONY)?

(1)定义:

伪目标是用.PHONY声明的目标,它不代表一个真实的文件,而是一个动作名称

(2) 常见用途:

  • 清理编译结果(如clean目标)
  • 执行测试(如test目标)
  • 批量操作(如all目标)

示例:

.PHONY: clean  # 声明clean是伪目标
clean:rm -f code  # 删除生成的可执行文件

3. 为什么伪目标总是被执行?

(1)核心原因:

伪目标不对应真实文件,因此make无法检查它的修改时间
当你执行make 伪目标名时,make会直接执行对应的命令,而不做任何检查。

(2) 对比实验:

情况1:普通目标(无.PHONY)

hello:echo "Hello, World!"

执行效果:

$ make hello
echo "Hello, World!"
Hello, World!
$ make hello
make: 'hello' is up to date.  # 第二次不会执行,因为默认认为hello是文件且已存在

情况2:伪目标(有.PHONY)

.PHONY: hello
hello:echo "Hello, World!"

执行效果:

$ make hello
echo "Hello, World!"
Hello, World!
$ make hello
echo "Hello, World!"  # 每次都会执行!因为hello是伪目标
Hello, World!

4. 为什么需要伪目标?

(1) 避免与文件冲突

如果目录中真的有一个名为clean的文件,会发生什么?

# 错误示例:没有.PHONY的clean目标
clean:rm -f code

此时执行make cleanmake会认为:“clean文件已存在,无需执行任何命令”——这显然不是你想要的!

(2) 强制执行命令

对于cleantest这类目标,你总是希望它们无条件执行而不是根据文件时间判断

5. 常见伪目标示例

1. clean目标(最常见)

.PHONY: clean
clean:rm -f *.o       # 删除所有.o文件rm -f executable  # 删除可执行文件

2. all目标(批量编译多个程序)

.PHONY: all
all: program1 program2  # 先编译program1,再编译program2program1: file1.cgcc -o program1 file1.cprogram2: file2.cgcc -o program2 file2.c

3. install目标(安装程序到系统)

.PHONY: install
install:cp program /usr/bin/  # 复制程序到系统目录

以上就是这篇博客的全部内容,下一篇我们将继续探索Linux的更多精彩内容。

我的个人主页
欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Linux知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12879535.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述

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

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

相关文章

开源b2b2c商城源码 支持多端适用 含完整代码包和图文搭建教程

在电商行业蓬勃发展的当下&#xff0c;b2b2c商城系统成为众多企业拓展业务版图的有力工具。这种支持自营与商家入驻并存的系统&#xff0c;含丰富平台商品种类&#xff0c;能通过多元化运营提升平台竞争力。本文分享一个开源b2b2c商城源码的相关知识&#xff0c;并详细介绍其搭…

Vue3入门-指令补充

&#x1f3e0;个人主页&#xff1a;Yui_ &#x1f351;操作环境&#xff1a;vscode\node.js &#x1f680;所属专栏&#xff1a;Vue3 文章目录1. 指令修饰符1.1 按键修饰符1.2 事件修饰符1.3 v-model修饰符2. v-model用在其他表单元素上3. 样式绑定3.1 操作class4. 操作style5.…

UDP类型套接字

理解UDP协议&#xff1a;互联网世界的"明信片"通信 UDP是什么&#xff1f;为什么需要它&#xff1f; 想象一下&#xff0c;你正在给朋友寄送两种不同的东西&#xff1a;一份重要的合同文件和一叠度假时的风景明信片。对于合同文件&#xff0c;你会选择挂号信&#xf…

redis快速入门教程

更新中基本概念安装centOS安装redis&#xff1a;yum install redis -y启动&#xff1a;systemctl start redis设置开机启动&#xff1a;systemctl enable redis检查运行状态&#xff1a;systemctl status redis远程访问编辑配置文件 vi /etc/redis.conf在其中修改为bind 0.0.0.…

UDP和TCP的主要区别是什么

UDP&#xff08;用户数据报协议&#xff09;和 TCP&#xff08;传输控制协议&#xff09;是互联网传输层的两大核心协议&#xff0c;主要区别体现在​​连接方式、可靠性、传输效率、头部开销​​及​​适用场景​​上。以下是具体对比&#xff1a;​​一、核心区别对比表​​​…

ASP .NET Core 8结合JWT轻松实现身份验证和授权

身份验证和授权是每一个后端服务必不可少的&#xff0c;可以实现对非法请求进行拦截&#xff0c;能够有效保护数据的安全性。 JSON Web Token&#xff08;JWT&#xff09;是一项开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方法&#xff…

5G时代的智慧灯杆:塔能“一杆多用”方案如何激活城市新基建?

在《5G应用“扬帆”行动计划》持续推进的进程之中&#xff0c;智慧杆已然成为了5G基站部署环节极为重要的载体&#xff0c;并且被明确地归入到新型基础设施建设的重点范畴之内。相关政策提出&#xff0c;要在2025年达成重点区域5G网络全面且深度覆盖的目标&#xff0c;与此同时…

护照阅读器:国外证件识别的 OCR “解码师”

国外证件版式多样、语种繁杂&#xff0c;人工识别不仅耗时&#xff0c;还易因翻译误差、格式不熟悉导致信息错漏。尤其在跨境业务场景中&#xff0c;传统识别方式严重影响效率与准确性。护照阅读器搭载的 OCR 技术成为破局关键。它能精准提取国外护照、驾照等证件上的多语种文字…

Linux部署Python服务

1、创建项目目录与虚拟环境#确保安装 Python 和 python3-venv 工具 sudo apt update sudo apt install python3 python3-pip python3-venvmkdir myproject cd myproject python3 -m venv venv # 创建虚拟环境#Linux source venv/bin/activate # 激活虚拟环境#Windowds venv\S…

【Python办公】使用Python和Tkinter构建Excel数据导入MySQL工具(GUI版)

目录 专栏导读前言项目概述技术栈环境准备核心代码实现1. 导入必要的库2. 主应用类设计3. 用户界面设计数据库配置区域数据库选择区域4. 数据库连接功能测试连接获取数据库列表5. 数据导入功能关键技术点解析1. SQLAlchemy 2.x 兼容性2. MySQL 8.0 认证问题3. 避免启动时连接错…

华为OD机试_2025 B卷_猜数字(Python,100分)(附详细解题思路)

题目描述 一个人设定一组四码的数字作为谜底&#xff0c;另一方猜。 每猜一个数&#xff0c;出数者就要根据这个数字给出提示&#xff0c;提示以XAYB形式呈现&#xff0c;直到猜中位置。 其中X表示位置正确的数的个数&#xff08;数字正确且位置正确&#xff09;&#xff0c;而…

【网络安全】理解安全事件的“三分法”流程:应对警报的第一道防线

1. 简介 在网络安全领域&#xff0c;每天都会产生大量安全警报。作为一名安全分析师&#xff0c;识别、评估并优先处理这些警报的能力至关重要。三分法&#xff08;Triage&#xff09; 是确保安全团队高效响应安全事件的核心流程&#xff0c;它能够帮助我们合理分配资源、集中精…

AI大模型计数能力的深度剖析:从理论缺陷到技术改进

AI大模型计数能力的深度剖析&#xff1a;从理论缺陷到技术改进 AI大模型在计数任务上表现出明显的局限性&#xff0c;这不仅反映了模型架构的核心缺陷&#xff0c;也揭示了当前深度学习技术在处理结构化信息时的本质挑战。通过对文本计数、图像计数以及相关技术改进方向的全面分…

[C语言初阶]结构体初阶

目录一、结构体的声明二、结构体的定义和初始化三、结构体成员访问四、结构体传参五、函数调用的参数压栈&#xff08;了解&#xff09;在C语言中&#xff0c;我们知道数组是一组相同类型元素的集合&#xff0c;而结构体则更为灵活&#xff0c;它允许我们将不同类型的数据组合在…

LVS(Linux Virtual Server)集群技术详解

一.集群和分布式: 集群&#xff1a;同一个业务系统&#xff0c;部署在多台服务器上&#xff0c;集群中&#xff0c;每一台服务器实现的功能没有差别&#xff0c;数据和代码都是一样的 分布式&#xff1a;一个业务被拆成多个子业务&#xff0c;或者本身就是不同的业务&#…

leetcode_27 移除元素

1. 题意 给定一个数组&#xff0c;把不等于val的元素全部移动到数组的前面来。 不需要考虑值为val里的元素。 2. 题解 2.1 同向双指针 我们利用双指针&#xff0c;慢指针指向下一个插入的位置。而快指针不断向前找到首个不为val的值&#xff0c;找到后将快指针位置值赋给慢…

Linux-Ubuntu下的git安装与配置

一、安装git1.打开终端&#xff0c;运行以下命令&#xff08;需要联网&#xff09;sudo apt-get update sudo apt-get install git2.验证安装安装完成之后&#xff0c;通过运行以下命令验证git是否已经正确安装&#xff1a;git --version二、配置git2.1.配置用户名及邮箱地址在…

2D和3D激光slam的点云去运动畸变

在使用激光雷达设备采集点云的时候&#xff0c;我们都知道&#xff0c;激光雷达是边运动边采集的&#xff0c;每一个点云采集时的激光雷达的中心和姿态都是不一样的&#xff0c;如果不加以矫正&#xff0c;那么这一帧数据就会出现问题&#xff0c;比如采集一个平面的结构的时候…

Java 热门面试题 200 道(Markdown表格版)【简化版】

Java 热门面试题 200 道(Markdown表格版)【简化版】 Java与数据库核心面试题摘要 本文精选200道Java与数据库高频面试题,重点涵盖: Java集合: HashMap原理(数组+链表/红黑树)、ConcurrentHashMap分段锁优化、红黑树改进目的(解决哈希冲突性能问题) MySQL索引: 最左前…

OpenCV探索之旅:多尺度视觉与形状的灵魂--图像金字塔与轮廓分析

在我们学会用Canny算法勾勒处世界的轮廓之后&#xff0c;一个更深层次的问题摆在了面前&#xff1a;这些由像素组成的线条&#xff0c;如何才能被赋予“生命”&#xff0c;成为我们能够理解和分析的“形状”&#xff1f;如果一个物体在图像中时大时小&#xff0c;我们又该如何稳…