网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
这将把 `value` 追加到名为 `variable` 的变量的末尾。 1. `:=`(覆盖赋值):使用 `:=` 运算符可以将一个值赋给一个变量,并且这个赋值操作会立即生效。例如:
variable := value
这将把 `value` 赋给名为 `variable` 的变量,并且它会立即生效。
=和:=有啥区别
在Makefile中,
=
和:=
是两种不同的赋值操作符,它们在变量赋值时有一些区别。
=
(简单赋值):使用=
运算符进行赋值时,变量的值会在变量被使用时动态地展开。这意味着,如果变量的值在后续的使用中发生了变化,那么这个变化会反映在变量的展开值中。例如:variable = initial_value target: echo $(variable) variable = updated_value
当目标
target
被执行时,$(variable)
的值将是updated_value
,而不是initial_value
。这是因为变量的展开是动态的。2. `:=`(覆盖赋值):使用 `:=` 运算符进行赋值时,变量的值在赋值时就会被展开,并且展开后的值将被固定。这意味着,无论后续对变量的赋值如何变化,变量的展开值都不会受到影响。例如:
variable := initial_value
target:
echo $(variable)
variable := updated_value当目标 `target` 被执行时,`$(variable)` 的值将始终是 `initial_value`,而不会受到后续赋值的影响。这是因为变量的展开是静态的。
总结起来,
=
运算符进行简单赋值,展开值是动态的;而:=
运算符进行覆盖赋值,展开值是静态的。根据具体的需求和使用场景,可以选择适合的赋值操作符来定义变量。
隐含规则
符号 | 含义 |
---|---|
%.o | 任意的.o文件 |
*.o | 所有的.o文件 |
通配符
符号 | 含义 |
---|---|
$^ | 所有依赖文件 |
$@ | 所有目标文件 |
$< | 所有依赖文件的第一个文件 |
makefile函数
这里只对我用到的做总结,持续更新
dir
在Makefile中,
dir
函数是一个用于提取路径的内置函数。它可以从文件名或文件路径中提取目录部分。
dir
函数的语法如下:dir names...
其中
names
是一个或多个文件名或文件路径。下面是一些示例,说明如何使用
dir
函数:
- 提取文件路径的目录部分:
filepath := /path/to/file.txt dirpath := $(dir $(filepath))
在这个例子中,
$(dir $(filepath))
将返回/path/to/
,即文件路径/path/to/file.txt
的目录部分。
- 提取文件名的目录部分:
filename := myfile.txt dirpath := $(dir $(filename))
在这个例子中,
$(dir $(filename))
将返回空字符串,因为文件名myfile.txt
没有目录部分,它位于当前目录下。
- 处理多个文件名:
files := file1.txt file2.txt file3.txt dirs := $(dir $(files))
在这个例子中,
$(dir $(files))
将返回file1/ file2/ file3/
,即每个文件名的目录部分。
patsubst
在Makefile中,
patsubst
函数是一个用于模式替换的内置函数。它可以根据模式匹配和替换的规则对文本进行替换操作。
patsubst
函数的语法如下:patsubst pattern,replacement,text
其中,
pattern
是要匹配的模式,replacement
是替换的规则,text
是需要进行替换操作的文本。下面是一些示例,说明如何使用
patsubst
函数:
- 替换文件后缀:
files := file1.txt file2.cpp file3.c new_files := $(patsubst %.txt,%.csv,$(files))
在这个例子中,
$(patsubst %.txt,%.csv,$(files))
将把files
列表中以.txt
结尾的文件替换为相应的以.csv
结尾的文件。结果将是file1.csv file2.cpp file3.c
。
- 替换路径中的目录:
files := dir1/file1.txt dir2/file2.txt dir3/file3.txt new_files := $(patsubst dir%,newdir%,$(files))
在这个例子中,
$(patsubst dir%,newdir%,$(files))
将把files
列表中以dir
开头的路径替换为相应的以newdir
开头的路径。结果将是newdir1/file1.txt newdir2/file2.txt newdir3/file3.txt
。
patsubst
函数可用于执行基于模式的替换操作,以生成新的文本。它在Makefile中非常有用,特别是在处理文件名、路径或其他具有规律的文本时。
lastword
在Makefile中,
lastword
是一个用于提取字符串中的最后一个单词的函数。
lastword
函数的语法如下:lastword text
其中,
text
是一个字符串。下面是一个示例,说明如何使用
lastword
函数:variable := This is a sentence last := $(lastword $(variable))
在这个例子中,
$(lastword $(variable))
将返回字符串This is a sentence
中的最后一个单词,即sentence
。该值将被赋给变量last
。
lastword
函数在Makefile中非常有用,特别是在需要提取字符串中最后一个单词的场景下。它可以帮助您对字符串进行处理和操作。请注意,lastword
函数将字符串以空格作为分隔符,因此如果字符串中包含多个单词,它将提取最后一个单词。
wildcard
1、wildcard —— 获取指定格式的文件列表
原型(不同格式之间使用空格隔开)$(wildcard <pattern…>)
示例:获取当前目录下所有的 .cpp 文件和 test目录下所有的 .cpp 文件$(wildcard *.cpp test/*.cpp)
findstring
findstring
函数用于在给定的字符串中搜索指定的子字符串,返回子字符串在字符串中的位置。
strip
函数strip
函数对BACKSLASH
进行处理,去除可能存在的空白字符。
在makefile中,
subst
是一个字符串替换函数,用于替换字符串中的指定子串。语法如下:
$(subst from,to,text)
其中,
from
表示要替换的子串,to
表示替换后的子串,text
表示要进行替换操作的原始字符串。
subst
函数会在text
字符串中查找所有与from
子串匹配的内容,并将其替换为to
子串。
举个案例分析
cur_dir := $(dir $(lastword $(MAKEFILE_LIST)))
obj-y := $(patsubst ( c u r _ d i r ) (cur\_dir)%,%, (cur_dir)(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.s))
这两句话什么意思呢?
cur\_dir := $(dir $(lastword $(MAKEFILE\_LIST)))
这行代码的作用是将当前Makefile所在的目录路径赋值给变量cur\_dir
。obj-y := $(patsubst ( c u r _ d i r ) (cur\_dir)%,%, (cur_dir)(wildcard $(cur_dir)*.c $(cur_dir)*.cpp $(cur_dir)*.s))
这个代码片段是一个Makefile规则,用于将指定目录(cur_dir)下的所有以.c、.cpp和.S为扩展名的文件添加到目标列表(obj-y)中。
具体解释如下:
wildcard $(cur\_dir)\*.c $(cur\_dir)\*.cpp $(cur\_dir)\*.S
:使用wildcard函数获取指定目录下所有以.c、.cpp和.S为扩展名的文件路径列表。$(patsubst $(cur\_dir)%,%,$(wildcard $(cur\_dir)\*.c $(cur\_dir)\*.cpp $(cur\_dir)\*.S))
:使用patsubst函数对文件路径列表进行模式替换,将路径中的$(cur_dir)部分替换为空字符串,得到相对于当前目录的文件路径列表。obj-y := $(patsubst $(cur\_dir)%,%,$(wildcard $(cur\_dir)\*.c $(cur\_dir)\*.cpp $(cur\_dir)\*.S))
:将替换后的文件路径列表赋值给目标变量obj-y。这个规则常用于构建系统中,用于自动化地将指定目录下的源文件添加到编译目标中。
假设当前目录(cur_dir)下有以下文件:
- main.c
- utils.cpp
- startup.S
应用上述Makefile规则后,以下是变量obj-y的值:
obj-y := main.c utils.cpp startup.S
该规则将这三个文件添加到目标变量obj-y中,以供后续构建过程使用。这意味着在编译过程中,这些文件将被编译为目标文件,并最终链接到可执行文件中。
obj-y := $(obj-y:.c=.o)
obj-y := $(obj-y:.cpp=.o)
obj-y := $(obj-y:.S=.o)
$(obj-y:.c=.o)
是一个Makefile中的字符串替换表达式,用于将目标变量obj-y
中所有以.c
为扩展名的文件替换为以.o
为扩展名的文件。
特殊变量
MAKEFILE_LIST
MAKEFILE_LIST
是一个特殊变量,在Makefile中用于表示当前被解析的 Makefile 文件列表。
MAKEFILE_LIST
是一个包含了正在被处理的 Makefile 文件名的列表,按照它们被解析的顺序排列。列表中的第一个元素是顶层的 Makefile 文件,后续元素是被包含或递归调用的其他 Makefile 文件。您可以使用
$(MAKEFILE_LIST)
来引用MAKEFILE_LIST
变量的值。以下是一个示例,展示如何使用
MAKEFILE_LIST
:# Makefile1 include Makefile2 target: @echo "Current Makefile: $(lastword $(MAKEFILE_LIST))" # Makefile2 include Makefile3 # Makefile3 target: @echo "Current Makefile: $(lastword $(MAKEFILE_LIST))"
在这个示例中,假设您运行
make target
命令。Makefile1 通过include
包含了 Makefile2,然后 Makefile2 又通过include
包含了 Makefile3。当执行
make target
时,输出将会是:Current Makefile: Makefile3 Current Makefile: Makefile1
这是因为
MAKEFILE_LIST
变量存储了当前正在被解析的 Makefile 文件列表,按照它们被解析的顺序排列。因此,在 Makefile3 中,$(lastword $(MAKEFILE_LIST))
获取到的就是 Makefile3 的文件名;而在 Makefile1 中,$(lastword $(MAKEFILE_LIST))
获取到的是 Makefile1 的文件名。通过使用
MAKEFILE_LIST
,您可以在 Makefile 中了解当前正在处理的文件是哪个,以便进行相应的操作和判断。
条件语句
条件语句的语法如下:
ifeq (condition, value) # 条件为真时执行的代码 else # 条件为假时执行的代码 endif
举个例子
ifeq ($(IBRT),1)
在这个示例中,
ifeq ($(IBRT),1)
表示如果变量IBRT
的值等于1
,则执行其后的代码块。如果条件为真,则会执行ifeq
和else
之间的代码块。如果条件为假,则会执行else
和endif
之间的代码块。
编译器选项
-I
在编译器中,-I
是一个选项,用于指定包含文件的搜索路径。它告诉编译器在指定的路径中查找头文件。
-D
在编译器中,
-D
是一个选项,用于定义预处理器宏(Preprocessor Macro)。它可以在编译过程中设置宏定义,使得在源代码中可以使用这些宏。例如,假设需要定义一个名为
DEBUG_MODE
的宏,并在源代码中根据该宏执行不同的操作。可以使用-D
选项设置该宏的定义。以下是一个示例:gcc -DDEBUG_MODE source.c
在这个命令中,
-DDEBUG_MODE
告诉编译器在预处理阶段定义了DEBUG_MODE
宏。源代码文件source.c
中可以使用#ifdef
和#ifndef
等条件编译指令来检查并根据宏的定义执行不同的代码。在Makefile中,通过在
subdir-ccflags-y
变量中使用-D
选项,可以设置预处理器宏的定义。例如:subdir-ccflags-y += -DDEBUG_MODE
这样,在执行编译操作时,编译器将使用
-DDEBUG_MODE
选项来设置DEBUG_MODE
宏的定义。这样做可以在源代码中使用条件编译指令来根据宏的定义执行不同的代码逻辑。
makefile Platform and shell detection
# 检测操作系统平台
ifeq ($(OS),Windows_NT)
# Windows平台
PLATFORM = Windows
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
# Linux平台
PLATFORM = Linux
endif
ifeq ($(UNAME_S),Darwin)
# macOS平台
PLATFORM = macOS
endif
endif
# 打印检测到的平台
$(info Detected platform: $(PLATFORM))
# 检测Shell类型
SHELL_TYPE := $(shell echo $$0)
ifeq ($(findstring bash,$(SHELL_TYPE)),bash)
# Bash Shell
SHELL_NAME = Bash
else ifeq ($(findstring zsh,$(SHELL_TYPE)),zsh)
# Zsh Shell
SHELL_NAME = Zsh
else ifeq ($(findstring fish,$(SHELL_TYPE)),fish)
# Fish Shell
SHELL_NAME = Fish
else
# 其他Shell
SHELL_NAME = Unknown
endif
# 打印检测到的Shell类型
$(info Detected shell: $(SHELL_NAME))
$(call)
是Makefile中的一个内置函数,用于调用自定义函数或预定义的函数。
Unix-style Shell(类Unix Shell)是一种命令行解释器,为用户提供与操作系统交互的接口。它是类Unix操作系统中的一部分,如Linux、macOS等。
Unix-style Shell 提供了一个命令行界面,用户可以在其中输入命令并与操作系统进行交互。用户可以执行各种命令,操作文件和目录,管理进程,配置系统等。
常见的Unix-style Shell 包括:
- Bourne Shell(sh):是早期Unix系统上最基本和常见的Shell。它是许多其他Shell的基础。
- Bourne-Again Shell(bash):是Bourne Shell的增强版本,为许多现代Unix-like系统的默认Shell。它提供了更多功能和改进的用户体验。
- C Shell(csh):以C语言的语法为基础,提供了一些额外的功能和语法糖。
- Korn Shell(ksh):融合了Bourne Shell和C Shell的特性,并提供了更多的功能,包括命令行编辑和命令历史等。
- Z Shell(zsh):是一种功能强大的Shell,具有高级的自动补全、主题和插件系统等特性。
在Makefile中,SHELL
是一个特殊的变量,用于指定用于执行命令的默认Shell解释器。
当我们在Makefile中添加
MAKEFLAGS += -rR
,禁用了Make的内置规则和推导规则后,我们可以更加灵活地自定义构建过程。(有待补充)
在Makefile中,
quiet
变量的值是根据是否启用静默模式来确定的。如果启用了静默模式(通过make
命令中的-s
参数),quiet
变量的值将为silent\_
,否则将为空字符串。
quiet
变量通常用于控制构建规则中命令的输出行为。通过在命令前面添加$(quiet)
,可以根据静默模式的状态来决定是否显示命令。例如,假设我们有以下的Makefile:
# Makefile quiet = @ all: $(quiet)echo "Building target..." $(quiet)gcc -o program main.c $(quiet)echo "Build completed." clean: $(quiet)echo "Cleaning target..." $(quiet)rm program
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
令。
例如,假设我们有以下的Makefile:
# Makefile quiet = @ all: $(quiet)echo "Building target..." $(quiet)gcc -o program main.c $(quiet)echo "Build completed." clean: $(quiet)echo "Cleaning target..." $(quiet)rm program
[外链图片转存中…(img-EdBoNYnf-1715604631157)]
[外链图片转存中…(img-oQnXElGt-1715604631158)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!