Makefile学习笔记_05_常用函数_shell_subst_patsubst_foreach_dir

Makefile学习笔记_05_常用函数_shell_subst_patsubst_foreach_dir

目录

说明

自学B站某课程的笔记,欢迎小伙伴们共同讨论,若有理解不对的地方也欢迎指出。
https://www.bilibili.com/video/BV1EM41177s1/spm_id_from=333.999.0.0
开发环境:Visual Studio Code + gcc

函数调用语法

$(函数名, 函数参数) 圆括号
${函数名, 函数参数} 花括号
Note: 参数间以逗号 , 分隔,函数名和参数之间以“空格”分隔

shell 函数

语法

$(shell <command> <arguments>)

调用 shell 命令 command,并返回 shell 命令 command 的执行结果。

示例

通过shell指令找到src文件夹下的所有.cpp文件

cpp_srcs := $(shell find src -name "*.cpp") 

debug:
	@echo $(cpp_srcs)
	
.PHONY: debug  

通过shell指令获取计算机架构

HOST_ARCH := $(shell uname -m)

debug:
	@echo $(HOST_ARCH)

.PHONY: debug
#我运行make debug输出了x86_64 

subst 函数

字符串替换函数

语法

$(subst <a>,<b>,<text>)

把字符串text中的a替换成b

示例

# 找到src文件夹下的所有.cpp文件
cpp_srcs := $(shell find src -name "*.cpp")

# 把上一行找到的.cpp文件中的src/换成objs/
cpp_objs_1 := $(subst src/,objs/, $(cpp_srcs))

# 再把名字中的.cpp后缀换成.o后缀
cpp_objs_2 := $(subst .cpp,.o, $(cpp_objs_1)) 

debug:
	@echo $(cpp_srcs)
	@echo $(cpp_objs_1)
	@echo $(cpp_objs_2)

.PHONY: debug

输出结果如下:
在这里插入图片描述

patsubst 函数

模式字符串替换函数。

语法

$(patsubst <pattern_1>,<pattern_2>,<text>)
在字符串text中,按照模式1找到相应文件,并替换成模式2的形式。

通配符 %表示任意长度的字串,函数返回被替换过后的字符串。

示例

在上面关于使用subst函数的示例中,我们把src/替换成objs/,再把.cpp替换成.o一共分了2步完成,分别是以下2行代码。

# 把上一行找到的.cpp文件中的src/换成objs/
cpp_objs_1 := $(subst src/,objs/, $(cpp_srcs))

# 再把名字中的.cpp后缀换成.o后缀
cpp_objs_2 := $(subst .cpp,.o, $(cpp_objs_1)) 

若使用patsubst函数,则可以以模式的方式,将这2步合并为1步完成。

# 以src/%.cpp的模式进行文件寻找,以objs/%.o的模式进行字符替换
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))

完整代码如下:

# 找到src文件夹下的所有.cpp文件
cpp_srcs := $(shell find src -name "*.cpp")

# 以src/%.cpp的模式进行文件寻找,以objs/%.o的模式进行字符替换
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))

debug:
	@echo $(cpp_srcs)
	@echo $(cpp_objs)
	
.PHONY: debug 

输出结果显示如下。
在这里插入图片描述

foreach 函数

循环函数。

语法

$(foreach <var>,<list>,<text>)

把字符串<list>中的元素逐一取出来,执行<text>包含的表达式,并把所有字符串所组成的整个字符串(以空格分隔)返回。

示例

我现在有3行字符串

include_paths := /aaa/bbb \
				/aaa/ccc \
				/aaa/ddd

我想在每行字符串的前面都加上一个-I,操作代码如下:

include_paths := /aaa/bbb \
				/aaa/ccc \
				/aaa/ddd

include_paths :=$(foreach item,$(include_paths),-I$(item))

debug:
	@echo $(include_paths)

.PHONY: debug

操作逻辑如图所示:
在这里插入图片描述
如果不用循环函数foreach,还可以使用通配符达到同样的效果,代码如下:

include_paths := /aaa/bbb \
				/aaa/ccc \
				/aaa/ddd

I_flag := $(include_paths:%=-I%)

debug:
	@echo $(I_flag)

.PHONY: debug

操作结果如下图所示。
在这里插入图片描述

dir函数

取目录函数。

语法

$(dir <names...>)

从文件名序列中取出目录部分并返回。目录部分是指最后一个反斜杠(“/”)之前
的部分。如果没有反斜杠,那么返回“./”。

示例

# 找到src文件夹下的所有.cpp文件
cpp_srcs := $(shell find src -name "*.cpp")

# 以src/%.cpp的模式进行文件寻找,以objs/%.o的模式进行字符替换
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))

objs/%.o : src/%.cpp
	@mkdir -p $(dir $@)
	@g++ -c $^ -o $@

compile : $(cpp_objs)

debug:
	@echo $(cpp_srcs)
	@echo $(cpp_objs)
	
.PHONY: debug compile

这里的代码与本文前面的部分差别不大,关键在下面代码:

objs/%.o : src/%.cpp    #目标文件是objs下的所有.o文件,依赖项是src下的所有.cpp文件      
	@g++ -c $^ -o $@    #命令 编译依赖文件都编译成.o文件

但是如果这个objs文件夹不存在,则会报错。在命令窗口使用make compile代码,则会显示如下错误。
在这里插入图片描述
显示目录没有objs这个文件夹。检查以下当前目录,嗯,确实没有。
在这里插入图片描述
因此,在执行这个命令前,我们要先创建一个objs文件夹。

objs/%.o : src/%.cpp
	@mkdir -p $(dir $@)    #mkdir表示创建文件夹,加上-p则如果存在这个文件夹也不会报错
	@g++ -c $^ -o $@       #$(dir $@)中的@指的是目标文件objs/%.o,dir函数取出目标文件的父目录。

在此基础上,我们再使用make compile命令,则可以成功编译,结果如下。
在这里插入图片描述
可以看到,我们创建了objs文件夹,并将src中的main.cpp文件编译成main.o文件导出在objs文件夹中。

备注

这个课程里对Makefile常用函数的讲解还包括以下3个函数:
notdirfilterbasename
但是讲课老师对于这几个函数的操作涉及到一些文件,我是远程在别人的服务器上跑的代码,没有这些文件,如果要写进博客,自己再去创建很多静态库、动态库,工作量有点大,这里就不进行讲解了,小伙伴们如果有兴趣,可以自己另外查找这3个函数的具体用法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值