linux_makefile文件编写,基本规则、工作原理、模式规则,wildcard函数、patsubst函数

article/2025/10/28 8:14:44

接上一篇:linux_GDB调试学习(调试运行、多文件设置断点)_C/C++程序调试

本次来分享linux下的makefile文件的编写,开始上菜:

目录

  • 1.makefile文件的命名规则
  • 2.用途
  • 3.基本规则
  • 3.1.用例一
  • 4.工作原理
    • 4.1.用例二
  • 5.makefile的执行
    • 5.1.用例三
  • 6.makefile的变量
    • 6.1.普通变量
    • 6.2.自动变量
    • 6.3.用例四
  • 7.makefile函数-两个常用函数
    • 7.1.wildcard函数
    • 7.2.patsubst函数
    • 7.3.用例五

使用前请安装make,安装命令:sudo apt install make

1.makefile文件的命名规则

   ①要么第一个字母大写,剩余字母小写,例如:Makefile
   ②要么全部字母小写:makefile

2.用途

   ①项目代码编译管理
   ②节省编译项目的时间
   ③一次编写终身受益

3.基本规则

(1)格式:
目标:依赖
   (tab)命令

(2)解释:

目标 --> 要生成的目标文件
依赖 --> 生成目标文件需要的一些文件
命令 --> 借助依赖文件生成目标文件的手段
tab --> 缩进,在第二行开始

Makefile会把规则中的第一个目标作为终极目标
app:依赖 #指定生成的最终目标为app

3.1.用例一

写该用例前请自己先创建add.c、sub.c、main.c源文件,否则执行makefile的时候会出错。
创建一个makefile文件,在其中添加如下内容:
mycalc:add.c sub.c main.c -o mycalc
   gcc add.c sub.c main.c -o mycalc

#该代码功能:(在makefile文件中用#进行注释)
#执行gcc add.c sub.c main.c -o mycalc命令,生成mycalc可执行文件

4.工作原理

   ①若想生成目标,检查规则中的依赖条件是否存在,
   ②如果不存在,寻找是否有规则用来生成该依赖文件
   ③检查规则中的目标是否需要更新,必须检查它的所有依赖,
   ④依赖中有任意一个被更新,则目标必须更新
   ⑤依赖文件比目标文件时间晚,则需要更新

make怎么知道哪个文件被更新了?
   make根据文件修改的时间来进行对比的,源文件生成的时间<.o生成的时间<最终目标生成的时间,这样就知道哪个文件被修改了,可看用例二。

4.1.用例二

写该用例前请自己先创建main.c、add.c、sub.c、mul.c源文件,否则执行makefile的时候会出错。
创建一个makefile文件,在其中添加如下内容:
app:main.o add.o sub.o mul.o
   gcc main.o add.o sub.o mul.o -o app
main.o:main.c
   gcc -c main.c
add.o:add.c
   gcc -c add.c
mul.o:mul.c
   gcc -c mul.c
sub.o:sub.c
   gcc -c sub.c

在这里插入图片描述

解释说明:
   ①make先检查main.o add.o sub.o mul.o是否存在,若是不存在,则会向下寻找是否有用来生成该依赖条件的文件;
   ②第4行到第14行都是对第一行的依赖条件的生成,make就会去找这些行依赖;
   ③使用该种方法,第一次编译后,若是main.c或者其他某单个文件被修改(make会对比文件修改的时间),只会编译对应的单个文件,就不会全部文件都被编译一次,这样更节省时间。

注意:生成终极目标的规则一定要写在第一行,在这里app就是我们需要生成的终极目标,若是写在其他行,我们的终极目标就变了。

5.makefile的执行

make的执行命令如下:

make				#makefile文件的路径下,终端执行命令:
make +objname		#执行makefile文件中的objname目标

使用方法请看用例三

5.1.用例三

写该用例前请自己先创建main.o、add.c、sub.c、mul.c源文件,否则执行makefile的时候会出错。
创建一个makefile文件,在其中添加如下内容:
app:main.o add.o sub.o mul.o
   gcc main.o add.o sub.o mul.o -o app
main.o:main.c
   gcc -c main.c
add.o:add.c
   gcc -c add.c
mul.o:mul.c
   gcc -c mul.c
sub.o:sub.c
   gcc -c sub.c
clean:
   rm main.o add.o sub.o mul.o

这个时候,终端执行命令:
make   #是编译.c文件
终端执行命令:
make clean   #就会删除掉main.o add.o sub.o mul.o这四个文件。

问题1:
如果当前目录下有同名clean文件会怎么样?
答:报错:clean已是最新,即不执行clean对应的命令。

解决方案:
添加伪目标声明代码:.PHONY:clean
makefile文件中的代码更改如下:
app:main.o add.o sub.o mul.o
   gcc main.o add.o sub.o mul.o -o app
main.o:main.c
   gcc -c main.c
add.o:add.c
   gcc -c add.c
mul.o:mul.c
   gcc -c mul.c
sub.o:sub.c
   gcc -c sub.c
.PHONY:clean    #伪目标声明
clean:
   rm main.o add.o sub.o mul.o -f    #-f是强制执行这个命令,无论有没有这些.o文件

这样就不会出现上述问题了。

问题2:
   在执行makefile的时候,当你执行完一条命令出错后,就不会在执行剩下的命令了,这时候,我们在命令的前面加入特殊-,表示此条命令出错,make也会继续执行后续的命令。如:“-rm a.o b.o”

6.makefile的变量

6.1.普通变量

变量定义及赋值:obj = a.o b.o c.o
变量取值:fobj = $(obj)

由 Makefile 维护的一些变量,通常格式都是大写
例如:
   CC =cc   #系统变量CC默认为cc,也就是gcc
有些有默认值,有些没有
   CPPFLAGS : 预处理器需要的选项 如:-I
   CFLAGS:编译的时候使用的参数 –Wall –g -c
   LDFLAGS :链接库使用的选项 –L -l

用户可以修改这些变量的默认值
CC = gcc

(请看用例四。)

6.2.自动变量

1、自动变量规则:
   $@    #规则中的目标
   $<    #规则中的第一个依赖条件
   $^    #规则中的所有依赖条件

都是在规则中的命令中使用
2、模式规则
   在规则的目标定义中使用   %
   在规则的依赖条件中使用   %

3、示例:
%.o:%.c
$(CC) –c $< -o $@
   $<   #表示依次取出依赖条件
   $@  #表示依次取出目标值
   %    #表示一个或者多个
   $^    #规则中的所有依赖

如图:
在这里插入图片描述
在这里插入图片描述

(请看用例四。)

6.3.用例四

现将用例三中makefile的代码做如下修改:

obj=main.o add.o sub.o mul.o
target=app
CC = gcc
$(target):$(obj)$(CC) $(obj) -o $(target)
%.o:%.c$(CC) -c $< -o $@
.PHONY:clean		#伪目标声明
clean:rm main.o add.o sub.o mul.o -f

(这样一写是不是就看着简洁很多了~~)
执行的功能效果和用例三是一样的。

7.makefile函数-两个常用函数

   makefile中所有的函数必须都有返回值,在这里介绍两个常用的函数。

7.1.wildcard函数

查找指定目录下指定类型的文件,该函数有一个参数
用法:src = $(wildcard ./src/*.c)
#找到./src 目录下所有后缀为.c的文件,赋给变量src,其中./src/*.c就是该函数的参数了

7.2.patsubst函数

匹配替换,从src中找到所有.c 结尾的文件,并将其替换为.o
用法:
#把src变量中所有后缀为.c的文件替换成.o
   obj = $(patsubst %.c ,%.o ,$(src))

#指定.o 文件存放的路径 ./obj/%.o
   obj = $(patsubst %.c, ./obj/%.o, $(src))

注意:在写目标的时候,也需要加上路径
./obj/%.o:%.c

当然,makefile的函数肯定不止这些,这里只是介绍两个常用的。

7.3.用例五

现将用例四中makefile的代码做如下修改:

target=app
src=$(wildcard ./*.c)
obj=$(patsubst ./%.c, ./%.o, $(src))
CC = gcc
$(target):$(obj)$(CC) $(obj) -o $(target) -I./1
%.o:%.c$(CC) -c $< -o $@
.PHONY:clean		#伪目标声明
clean:rm main.o add.o sub.o mul.o -f

(执行的功能效果和用例四是一样的。)

以上就是本次的分享了,希望对广大网友有帮助。

此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】


http://chatgpt.dhexx.cn/article/3rSeT5tO.shtml

相关文章

makefile wildcard patsubst使用小结

这是当前的目录&#xff1a; objs main.o g_a.o g_b. target : $(objs)gcc -o target $(objs) main.o : g_a.h g_b.hgcc -c main.c g_a.o : g_a.hgcc -c g_a.c g_b.o : g_b.hgcc -c g_b.c.PHONY : cleansrc $(wildcard *.c) obj $(patsubst %.c,%.o,$(src)) #obj $(patsu…

Makefile中patsubst函数使用方法

Makefile中patsubst函数使用方法 patsubst函数用于将文件模式进行替换。 一、作用 替换文件后缀。 二、格式 $(patsubst 原模式&#xff0c; 目标模式&#xff0c; 文件列表) 三、实例 图1 源文件结构 图2 patsubst实例

从零开始学习makefile(5)makefile中patsubst的作用

目录 介绍 text pattern与replacement 返回值 通配符% 示例1 例子2 介绍 patsubst是pattern substitute的缩写。其用法是&#xff1a; $(patsubst pattern,replacement,text) text text是将要被处理的字符串。首先&#xff0c;patsubst以空格为分隔符&#xff0c;将te…

list_for_each_entry和list_for_each_entry_safe

看内核代码都会发现&#xff0c;内核链表的操作常用的二个宏list_for_each_entry和list_for_each_entry_safe 循序渐进&#xff0c;先从最底层的函数container_of函数说起&#xff0c;其内核定义如下&#xff1a; 先看offsetof宏&#xff0c;根据优先级的顺序&#xff0c;最里面…

Map中的entry,entrySet,keySet的区别和用法

Map中的元素是以键值对的形式存在的&#xff0c;即key-value。key是唯一的不能重复&#xff0c;但value可以重复。 Map.keySet(): 这个方法返回的就是map集合中所有键Key的一个Set集合。如Map<Integer&#xff0c;String> 中put(1, “张三”)&#xff0c;put(2, “李四”…

Map.Entry与entrySet与entry,getKey()与entry.getValue()的用法

直接上代码 实体类 Data AllArgsConstructor NoArgsConstructor public class SinglePressureResultDTO {private Integer Times; private Integer SCU_number; private Boolean Intervention; private Long startTime_low; private Long low_time; private Long start…

Map集合的entrySet()方法

之前学习集合的时候要通过迭代器来迭代的时候最难得就是map集合得迭代&#xff0c;一直也不太明白&#xff0c;今天总算搞懂了 首先我们看什么容器才能迭代 根据API我们得知是对所有collection迭代的集合&#xff0c;那么已知的collection容器有哪些 我把常用的标出了&#xf…

keySet()和entrySet()

一、描述 keySet()和entrySet()&#xff0c;是Map集合中的两种取值方法。 与get(Object key)相比&#xff0c;get(Object key)只能返回到指定键所映射的值&#xff0c;不能一次全部取出。而keySet()和entrySet()可以。 Map集合中没有迭代器&#xff0c;Map集合取出键值的原理…

Java高级之HashMap中的entrySet()方法

基本使用 entrySet()方法得到HashMap中各个键值对映射关系的集合。 然后Map.Entry中包含了getKey()和getValue()方法获取键和值。 示例&#xff1a; public class Demo {public static void main(String[] args) {Map<String, String> map new HashMap<>();ma…

KeySet和EntrySet区别

场景&#xff1a; keySet()和entrySet()&#xff0c;是Map集合中的两种取值方法。 与get(Object key)相比&#xff0c;get(Object key)只能返回到指定键所映射的值&#xff0c;不能一次全部取出。而keySet()和entrySet()可以。 Map集合中没有迭代器&#xff0c;Map集合取出键…

Map中entrySet()方法使用

public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。 就是返回一个集合&#xff0c;集合里存放的是对象&#xff0c;创建对象的类有两个属性&#xff0c;分别是 键和值 也即键值对。 其中Entry是属于Map的静态内部类&#x…

glPushMatrix 和glPopMatrix图解 ----求别笑

猜想&#xff1a; openGL在绘制场景时的一般用法是&#xff1a; 首先在函数的开始处用glLoadIdentity()设置当前的矩阵为单位矩阵。 然后在函数中用glPushMatrix()和glPopMatrix()函数进行操作&#xff1a; 根据实践判断&#xff1a; 即这两者是分开的&#xff0c;并不是当前…

OpenGL的glPushMatrix和glPopMatrix矩阵栈顶操作函数详解

OpenGL中图形绘制后&#xff0c;往往需要一系列的变换来达到用户的目的&#xff0c;而这种变换实现的原理是又通过矩阵进行操作的。opengl中的变换一般包括视图变换、模型变换、投影变换等&#xff0c;在每次变换后&#xff0c;opengl将会呈现一种新的状态&#xff08;这也就是…

为什么调用glPushMatrix()和glPopMatrix()

2019独角兽企业重金招聘Python工程师标准>>> 今天忽然感悟到为什么在进行变换之前要用glPushMatrix();这个函数&#xff0c;而在变换完毕后有用glPopMatrix()这两个函数了,赶紧记下来&#xff1a; 我们在变换坐标的时候&#xff0c;使用的是glTranslatef(),glRotaef…

opengl入门记录--glPushMatrix和glPopMatrix原理

glPushMatrix、glPopMatrix操作事实上就相当于栈里的入栈和出栈。 很多人不明确的可能是入的是什么&#xff0c;出的又是什么。 比如你当前的坐标系原点在你电脑屏幕的左上方。如今你调用glPushMatrix&#xff0c;然后再调用一堆平移、旋转代码等等&#xff0c;然后再绘图。那…

OpenGL编程指南9:裁剪平面+glPushMatrix和glPopMatrix矩阵栈顶操作

1.任意裁剪平面 Opengl中&#xff0c;除了视景体的立方体裁剪平面之外&#xff0c;另外还可以额外指定多达6个裁剪平面&#xff0c;对视景体做进一步限制。每一个平面都由平面公式定义&#xff1a;AxByCzD 0.裁剪平面的指定通过函数&#xff1a;glClipPlane(GLenum plane,cons…

使用glPushMatrix和glPopMatrix的原因

转自 百度百科 glPushMatrix 函数将当前矩阵堆栈推送&#xff0c;通过一个&#xff0c;复制当前矩阵。 这就是后 glPushMatrix 的调用堆栈的顶部矩阵是它下面的相同的。 1. 原理讲解 终于明白为什么使用glPushMatrix()和glPopMatrix()的原因了。将本次需要执行的缩放、平移等操…

【已解决】DQN报错:NameError: name ‘glPushMatrix‘ is not defined

1、问题 pycharm在运行DQN平衡杆代码时报错&#xff1a;NameError: name ‘glPushMatrix’ is not defined。 画面只出现一个白色背景。 2、分析 pyglet版本过高&#xff0c;降低版本即可。 pip install pyglet1.5.273、测试 没有报错&#xff0c;运行成功。 参考链接…

opengl glPushMatrix()

OpenGL有三个矩阵堆栈&#xff0c;分别是GL_MODELVIEW&#xff08;模型视图矩阵堆栈&#xff09;、GL_PROJECTION&#xff08;投影矩阵堆栈&#xff09;、GL_TEXTURE&#xff08;纹理矩阵堆栈&#xff09;&#xff0c;用法和普通堆栈一样&#xff1b; 这里我们只讲模型视图矩阵…

解决:nameerror: name ‘glpushmatrix‘ is not defined

在尝试gym的render()时&#xff0c;出现错误&#xff1a; nameerror: name glpushmatrix is not defined最后解决的办法&#xff1a;更换pyglet包的版本 出现错误时的pyglet版本&#xff1a; 然后将版本更换为&#xff1a; 就可以使用env.render()啦&#xff01;