Linux | 自动化构建 —— make / Makefile

news2025/3/18 13:05:26

文章目录

  • 自动化构建-make/Makefile
      • 一、`make` 工具概述
      • 二、`Makefile` 基本结构
      • 三、 `Makefile`和`make`的基本使用
        • 3.1最基本的gcc编译:
        • 3.2make执行Makefile文件
        • 3.3`.PHONY`伪目标
      • 四、Makefile拓展
        • 4.1直接根据文件名编写Makefile
        • 4.2变量的使用
        • 4.3Makefile的适度扩展语法(更通用使用)

自动化构建-make/Makefile

一、make 工具概述

  • make 是一个自动化构建工具,用于自动化编译和构建程序。它根据文件的修改时间和依赖关系,只重新编译那些需要更新的文件,从而节省编译时间,提高开发效率。
  • make 通过读取 Makefile 文件中的规则和指令来确定如何编译和构建程序。

二、Makefile 基本结构

  • Makefile 是一个文本文件,通常位于项目的根目录,包含了一系列的规则,其基本结构如下:
目标: 依赖
    命令(依赖方法)
  • 目标(Target):是 make 要生成的文件或要执行的操作,例如可执行文件、目标文件或自定义的伪目标(如 clean)。
  • 依赖(Dependencies):是生成目标所需的文件或其他目标,例如源文件、头文件或其他库文件。
  • 依赖关系:由目标文件和依赖文件组成的依赖关系
  • 命令(Commands):也是依赖方法,是 make 执行的操作,通常是编译命令或其他构建操作。注意,命令行必须以制表符(Tab)开头,而不能是空格。

三、 Makefilemake的基本使用

3.1最基本的gcc编译:
test:test.c
	gcc test.c -o test

假设当前目录下有一个test.c文件,使用make进行自动化构建

1.在当前目录下执行vim Makefile新建并编辑Makefile文件

2.在Makefile文件中执行:

test:test.c //此处格式为”编译出来的可执行程序名“ :”依赖文件“

gcc test.c -o test //依赖方法,此处格式为Tab + gcc编译命令,必须以制表符(Tab)开头

3.wq保存并退出回到刚才的目录

4.执行make命令构建出可执行文件test

5.执行./make命令运行可执行文件

3.2make执行Makefile文件
test:test.c
	gcc test.c -o test

.PHONY:clean
clean:
	rm -f mytest
  • make会自顶向下扫描Makefile我呢见,默认形成第一个目标文件,如果想指定形成,就是用make + 指定的目标名称,例如下面将第一部分和第二部分颠倒过来:
.PHONY:clean
clean:
	rm -f mytest

test:test.c
	gcc test.c -o test

在这里插入图片描述

然后执行make,会发现执行的是rm -f test1;

在这里插入图片描述

这时候如果想要执行test1,就需要指定执行:

在这里插入图片描述

3.3.PHONY伪目标

概念

  • 伪目标是 Makefile 中不代表实际文件的目标,而是代表一个操作或一系列操作。

  • 通常,make 会根据文件的时间戳来判断是否需要重新构建目标。但对于伪目标,make 不会检查文件是否存在,而是直接执行相应的命令。

例如下面的Makefile:

test1:test1.c
    gcc test1.c -o test1

.PHONY:clean
clean:
    rm -f test1;

在这里插入图片描述

当执行make命令的时候,只有第一次能够被执行,而make clean可以一直执行,因为Makefile中使用.PHONY修饰了clean,执行make clean的时候不会判断是否需要重构目标,而是直接执行相应命令。而对于编译,由于编译文件可能会消耗很多的资源,所以一般不使用PHONY修饰,避免资源的浪费

使用PHONY的好处

  • 避免命名冲突
    • 假设你有一个名为 clean 的文件和一个 clean 伪目标。如果不使用 .PHONY,当 clean 文件存在时,make clean 会认为 clean 已经是最新的,不会执行 clean 目标的命令。使用 .PHONY 可以避免这种情况。
    • 例如:
.PHONY: clean

clean:
    rm -f main.o main

这里,即使存在名为 clean 的文件,make clean 仍会执行 rm -f main.o main 命令。

  • 明确表示操作
    • 对于一些操作,如 allinstalltest 等,它们不代表生成文件,而是执行一系列操作,使用 .PHONY 可以明确表示它们是操作而不是文件生成目标。

多个伪目标

四、Makefile拓展

4.1直接根据文件名编写Makefile
  • 假设你有一个简单的 C 项目,包含以下文件:

    • main.c

    • func.c

    • func.h

一个简单的 Makefile 可以如下:

# 最终的可执行文件
all: main

# 生成可执行文件 main
main: main.o func.o
    gcc main.o func.o -o main

# 编译 main.c 生成 main.o
main.o: main.c func.h
    gcc -c main.c -o main.o

# 编译 func.c 生成 func.o
func.o: func.c func.h
    gcc -c func.c -o func.o

# 清理生成的文件
clean:
    rm -f main.o func.o main
  • 解释
    • all: mainall 是一个伪目标,它依赖于 main,通常作为默认目标,当你只输入 make 时会执行该目标。
    • main: main.o func.omain 目标依赖于 main.ofunc.o,当 main.ofunc.o 发生变化或不存在时,make 将执行 gcc main.o func.o -o main 来生成 main 可执行文件。
    • main.o: main.c func.hmain.o 目标依赖于 main.cfunc.h,当 main.cfunc.h 发生变化或 main.o 不存在时,将执行 gcc -c main.c -o main.o 来编译 main.c 生成 main.o 目标文件。
    • func.o: func.c func.h:与 main.o 的情况类似,编译 func.c 生成 func.o
    • clean:这是一个伪目标,用于清理生成的文件,当你输入 make clean 时,将执行 rm -f main.o func.o main 命令。

4.2变量的使用
  • 可以在 Makefile 中使用变量来避免重复输入,提高可维护性。例如:
# 定义最终的可执行文件名
BIN=test1
# 定义源文件名
SRC=test1.c
# 定义目标文件名
OBJ=test1.o
# 定义编译器为 gcc
cc=gcc
# 定义删除命令为 rm -f
RM=rm -f

# 定义构建最终可执行文件的规则,依赖于目标文件
$(BIN):$(OBJ)
    # 使用 gcc 编译器将目标文件链接为可执行文件
    $(cc) $(OBJ) -o $(BIN)

# 定义生成目标文件的规则,依赖于源文件
$(OBJ):$(SRC)
    # 使用 gcc 编译器将源文件编译为目标文件,-c 选项表示只编译不链接
    $(cc) -c $(SRC) -o $(OBJ)

# 声明 clean 为伪目标
.PHONY:clean
clean:
    # 清理生成的可执行文件和目标文件
    $(RM) $(BIN) $(OBJ)

解释说明

  • 这个 Makefile 主要用于自动化构建一个 C 语言程序。
    • BIN=test1:将最终要生成的可执行文件的名称存储在 BIN 变量中,这里命名为 test1
    • SRC=test1.c:存储源文件的名称,这里是 test1.c
    • OBJ=test1.o:存储目标文件的名称,这里是 test1.o
    • cc=gcc:指定使用 gcc 编译器。
    • RM=rm -f:指定删除文件的命令,使用 rm -f 可以强制删除文件而不提示。
    • $(BIN):$(OBJ):定义 test1 可执行文件的构建规则,它依赖于 test1.o 目标文件。这意味着如果 test1.o 不存在或者比 test1 新,将执行下面的编译命令。
    • $(cc) $(OBJ) -o $(BIN):使用 gcc 编译器将 test1.o 目标文件链接为 test1 可执行文件。
    • $(OBJ):$(SRC):定义 test1.o 目标文件的构建规则,它依赖于 test1.c 源文件。如果 test1.c 不存在或者比 test1.o 新,将执行下面的编译命令。
    • $(cc) -c $(SRC) -o $(OBJ):使用 gcc 编译器将 test1.c 编译为 test1.o 目标文件,-c 选项表示只进行编译而不进行链接操作。
    • .PHONY:clean:声明 clean 为伪目标,即它不代表实际的文件,而是代表一个操作。
    • clean::定义 clean 目标,当执行 make clean 时,将执行下面的命令。
    • $(RM) $(BIN) $(OBJ):使用 rm -f 命令删除 test1 可执行文件和 test1.o 目标文件。

使用此 Makefile 时,你可以:

  • 输入 make 来编译并生成 test1 可执行文件。
  • 输入 make clean 来删除 test1 可执行文件和 test1.o 目标文件。

请注意,使用此 Makefile 时要确保命令行以制表符(Tab)开头,而不是空格,因为 make 要求命令行必须以制表符作为缩进。并且确保 test1.c 文件存在于当前目录中,否则可能会导致编译错误。


4.3Makefile的适度扩展语法(更通用使用)

当有多个文件需要编译的时候,一个个输入很复杂,可以有下面的做法:

  • 创建多个.c文件用作示范,touch test{2..10}.c,创建test2.c test3.c … test10.c
  • 打开Makefile进行编写
BIN=test1
SRC=$(shell ls *.c)

OBJ=test.o
cc=gcc
RM=rm -f


.PHONY:test
test:
    echo $(BIN)
    echo $(SRC)
#使用echo进行测试,更直观一点

关于SRC=$(shell ls *.c)

  • 将当前目录下所有以.c结尾的文件的名称存储在变量SRC中
  • shell是make的一个内置函数,允许在Makefile中调用系统的shell命令,语法为$(shell ),其中,是要执行的shell命令
  • *.c是一个通配符表达式,用于匹配所有文件名以.c结尾的文件。所以ls *.c会调用系统的ls命令列出当前目录下的.c源文件。
  • 当 make 执行到 SRC=$(shell ls *.c) 时,它会调用 shell 函数,进而调用 ls *.c 命令,将该命令的执行结果存储在 SRC 变量中。例如,如果当前目录下有 file1.c、file2.c 和 file3.c,那么 SRC 的值将是 file1.c file2.c file3.c(多个文件名之间以空格分隔)。

执行make后会发现结果如下,多打印了一遍,这是由于echo回显导致的

在这里插入图片描述

  • Makefile 的上下文中,回显(Echo)是指将命令行的内容输出到标准输出(通常是终端)的现象。当 make 执行一个命令时,它会默认将该命令的文本输出显示出来,然后再显示该命令执行的结果。这是 make 的默认行为,主要目的是为了让你看到正在执行的命令,以便你可以跟踪构建过程和进行调试。

  • 这里的 echo test1echo test10.c test1.c test2.c test3.c test4.c test5.c test6.c test7.c test8.c test9.c 就是回显的内容,它们是 make 在执行 echo 命令之前将该命令本身输出到终端的结果。

  • Makefile 中,在命令前面添加 @ 符号可以抑制该命令的回显。例如,将 echo $(BIN) 改为 @echo $(BIN)make 就不会将 @echo $(BIN) 这一命令本身输出到终端,而只输出该命令的执行结果。这样可以使输出更简洁,只关注命令的结果,而不是命令的执行过程。

可在echo前加上@符号抑制该命令的回显

较为完整的基本的Makefile文件如下( $< $@ 等内容看下面模式规则部分):

BIN=test1
#SRC=$(shell ls *.c) 采用shell命令行方式,获取当前所有.c文件名
SRC=$(wildcard *.c) #或者使用wildcard函数,获取当前多有.c文件
#OBJ=test.o          
OBJ=$(SRC:.c=.o)    #将SRC的所有同名.c替换成为.o形成目标文件
cc=gcc
RM=rm -f

$(BIN):$(OBJ)
    #gcc $(OBJ) -o $(BIN)
    @$(cc) $^ -o $@ 
                    #$^表示规则中的所有依赖项链表
                    #$@表示规则中的目标,执行make时会被替换为当前正在构建的目标名称%.o:%.c   
                    #% 是通配符,表示匹配内容,例如%.c就是匹配.c结尾的文件    
	@$(cc) -c $<        
                    #< 的意思是将上面展开的.c文件逐个交给对应的命令,在这里是将.c文件处理成.o文件
.PHONY:clean
clean:
    @$(RM) $(OBJ) $(BIN)

模式规则

  • 对于多个相似的编译规则,可以使用模式规则来简化 Makefile。例如:
# 定义变量
CC = gcc
CFLAGS = -c
OBJS = main.o func.o

# 最终的可执行文件
all: main

# 生成可执行文件 main
main: $(OBJS)
    $(CC) $(OBJS) -o main

# 编译.c 文件生成.o 文件的模式规则
%.o: %.c %.h
    $(CC) $(CFLAGS) $< -o $@

# 清理生成的文件
clean:
    rm -f $(OBJS) main
  • 解释
    • %.o: %.c %.h:这是一个模式规则,% 是通配符,表示任何匹配的文件。当 make 需要生成 .o 文件时,会根据该规则查找相应的 .c.h 文件,并使用 $(CC) $(CFLAGS) $< -o $@ 命令进行编译。
    • $<:表示第一个依赖文件,即 .c 文件。
    • $@:表示目标文件,即 .o 文件。

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

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

相关文章

【个人开发】macbook m1 Lora微调qwen大模型

本项目参考网上各类教程整理而成&#xff0c;为个人学习记录。 项目github源码地址&#xff1a;Lora微调大模型 项目中微调模型为&#xff1a;qwen/Qwen1.5-4B-Chat。 去年新发布的Qwen/Qwen2.5-3B-Instruct同样也适用。 微调步骤 step0: 环境准备 conda create --name fin…

电脑开机提示按f1原因分析及终极解决方法来了

经常有网友问到一个问题&#xff0c;我电脑开机后提示按f1怎么解决&#xff1f;不管理是台式电脑&#xff0c;还是笔记本&#xff0c;都有可能会遇到开机需要按F1&#xff0c;才能进入系统的问题&#xff0c;引起这个问题的原因比较多&#xff0c;今天小编在这里给大家列举了比…

2025华为OD机试真题最新题库 (B+C+D+E卷) + 在线OJ在线刷题使用说明(C++、Java、Python合集)(正在更新E卷,目前已收录581道)

2024年8月份&#xff0c;华为已经开始使用E卷题库&#xff0c;题目和往期一样&#xff0c;旧题加新题的组合&#xff0c;有题目第一时间更新&#xff0c;大家可以跟着继续学习&#xff0c;目前使用复用题较多&#xff0c;可在OJ上直接找到对应的E卷学习&#xff0c;可以放心学习…

Qt+海康虚拟相机的调试

做机器视觉项目的时候&#xff0c;在没有相机或需要把现场采集的图片在本地跑一下做测试时&#xff0c;可以使用海康的虚拟相机调试。以下是设置步骤&#xff1a; 1.安装好海康MVS软件&#xff0c;在菜单栏->工具选择虚拟相机工具&#xff0c;如下图&#xff1a; 2.打开虚拟…

《Origin画百图》之边际分布曲线图

《Origin画百图》第六集——边际分布曲线图 入门操作可看《30秒&#xff0c;带你入门Origin》 边际分布曲线图&#xff0c;其中包含散点图形&#xff0c;而在图的边际有着分布曲线图。在比较数据以查看多个变量之间是否存在关系时非常有用。 1.数据准备&#xff1a;为多列XY数…

如何提升自己的能力

提高自身能力是一个长期且综合的过程&#xff0c;需要从多个方面进行努力和持续的学习&#xff0c;以下是一些有效的方法&#xff1a; 明确目标与规划 确定目标&#xff1a;首先要明确自己想要提高哪些方面的能力&#xff0c;例如沟通能力、领导力、专业技能等&#xff0c;并根…

Vim跳转文件及文件行结束符EOL

跳转文件 gf 从当前窗口打开那个文件的内容&#xff0c;操作方式&#xff1a;让光标停在文件名上&#xff0c;输入gf。 Ctrlo 从打开的文件返回之前的窗口 Ctrlwf 可以在分割的窗口打开跳转的文件&#xff0c;不过在我的实验不是次次都成功。 统一行尾格式 文本文件里存放的…

Termux安装ssh实现电脑ssh

Termux下载 点击下载 在 Termux 中安装并使用 SSH&#xff0c;按照以下步骤操作&#xff1a; 1. 更新软件包列表 pkg update && pkg upgrade2. 安装 OpenSSH pkg install openssh3. 设置 SSH 密码&#xff08;必须&#xff0c;否则无法使用 SSH 服务器&#xff09…

DeepSeek大模型介绍、本地化部署与使用!【AI大模型】

一、DeepSeek 是什么&#xff1f; 1.技术定位 专注大模型与AGI研究&#xff0c;开发高性能基座模型&#xff08;如 DeepSeek LLM 系列&#xff09;&#xff0c;支持长文本、多模态、代码生成等复杂任务。 提供开源模型&#xff08;如 DeepSeek-MoE、DeepSeek-V2&#xff09;…

Axios 的原理

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Gitlab中如何进行仓库迁移

需求&#xff1a;之前有一个自己维护的新仓库A&#xff0c;现在需要将这个仓库提交并覆盖另一个旧的仓库B&#xff0c;需要保留A中所有的commit信息。 1.方法一&#xff1a;将原有仓库A导出后再导入到新的仓库B中 适用场景&#xff1a;新的仓库B是一个待建仓库&#xff0c;相当…

Centos挂载镜像制作本地yum源,并补装图形界面

内网环境centos7.9安装图形页面内网环境制作本地yum源 上传镜像到服务器目录 创建目录并挂载镜像 #创建目录 cd /mnt/ mkdir iso#挂载 mount -o loop ./CentOS-7-x86_64-DVD-2009.iso ./iso #前面镜像所在目录&#xff0c;后面所挂载得目录#检查 [rootlocalhost mnt]# df -h…

Thread类以及常见方法

Thread类是JVM用来管理线程的一个类&#xff0c;每个线程都有一个唯一的Thread对象与之关联。 多一个线程&#xff0c;就多一条执行流&#xff0c;每个执行流也要一个对象来描述&#xff0c;而Thread类的对象就是用来描述一个线程的执行流&#xff0c;JVM 会将这些 Thread 对象…

【蓝桥杯—单片机】第十一届省赛真题代码题解题笔记 | 省赛 | 真题 | 代码题 | 刷题 | 笔记

第十一届省赛真题代码部分 前言赛题代码思路笔记竞赛板配置内部振荡器频率设定键盘工作模式跳线扩展方式跳线 建立模板明确设计要求和初始状态显示功能部分数据界面第一部分第二部分第三部分调试时发现的问题 参数设置界面第一部分第二部分和第四部分第三部分和第五部分 按键功…

CLion2024.3.2版中引入vector头文件报错

报错如下&#xff1a; 在MacBook端的CLion中引入#include <vector>报 vector file not found&#xff08;引入map、set等也看参考此方案&#xff09;&#xff0c;首先可以在Settings -> Build,Execution,Deployment -> Toolchains中修改C compiler和C compiler的路…

自动化测试工具:selenium

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Selenium是一个用于Web应用程序测试的工具。是一个开源的Web的自动化测试工具&#xff0c;最初是为网站自动化测试而开发的&#xff0c;类型像我们玩游戏用的按键…

MR30分布式IO模块:驱动智能制造工厂的工业互联与高效控制新范式

在工业4.0与智能制造浪潮的推动下&#xff0c;传统制造业正经历着从“机械驱动”向“数据驱动”的深刻转型。作为工业数据连接领域的领军者&#xff0c;明达技术凭借其自主研发的MR30分布式IO模块&#xff0c;以创新的技术架构与卓越的性能表现&#xff0c;为全球制造企业构建了…

计算机领域QPM、TPM分别是什么并发指标,还有其他类似指标吗?

在计算机领域&#xff0c;QPM和TPM是两种不同的并发指标&#xff0c;它们分别用于衡量系统处理请求的能力和吞吐量。 QPM&#xff08;每分钟请求数&#xff09; QPM&#xff08;Query Per Minute&#xff09;表示每分钟系统能够处理的请求数量。它通常用于衡量系统在单位时间…

Python----Python高级(并发编程:协程Coroutines,事件循环,Task对象,协程间通信,协程同步,将协程分布到线程池/进程池中)

一、协程 1.1、协程 协程&#xff0c;Coroutines&#xff0c;也叫作纤程(Fiber) 协程&#xff0c;全称是“协同程序”&#xff0c;用来实现任务协作。是一种在线程中&#xff0c;比线程更加轻量级的存在&#xff0c;由程序员自己写程序来管理。 当出现IO阻塞时&#xff0c;…

DeepSeek使用技巧大全(含本地部署教程)

在人工智能技术日新月异的今天&#xff0c;DeepSeek 作为一款极具创新性和实用性的 AI&#xff0c;在众多同类产品中崭露头角&#xff0c;凭借其卓越的性能和丰富的功能&#xff0c;吸引了大量用户的关注。 DeepSeek 是一款由国内顶尖团队研发的人工智能&#xff0c;它基于先进…