一、Makefile基本语法
Makefile是一种用于自动化构建和管理项目的工具,它使用一种特定的语法来描述目标(target)和依赖关系(dependencies)。下面是Makefile的基本语法:
-
目标规则(Target Rules):
target: dependencies commands
target
:表示要生成的目标文件或执行的目标操作的名称。dependencies
:表示生成目标所需要的依赖文件或其他目标。commands
:表示生成目标时要执行的命令。
-
变量(Variables):
variable_name = value
variable_name
:变量名。value
:变量的值。
在Makefile中,你可以定义自己的变量,并在规则中使用它们。例如:
CC = gcc CFLAGS = -Wall -O2 target: dependencies $(CC) $(CFLAGS) -o target dependencies
-
通配符(Wildcards):
*.c
在Makefile中,你可以使用通配符来匹配文件。例如,
*.c
表示匹配所有以.c
为扩展名的文件。 -
隐式规则(Implicit Rules):
.c.o: $(CC) $(CFLAGS) -c $<
隐式规则定义了如何将一种类型的文件转换为另一种类型的文件。上述示例中,
.c.o
表示将.c
文件转换为.o
目标文件的规则,$<
表示依赖文件的名称。 -
伪目标(Phony Targets):
.PHONY: target
伪目标是指不对应实际文件的目标,而是表示某个操作或动作。在Makefile中,你可以声明一个目标为伪目标,以告诉Make工具该目标不对应任何实际文件。例如:
.PHONY: clean clean: rm -f *.o
这些是Makefile的基本语法。通过灵活运用这些规则、变量和命令,你可以构建复杂的自动化构建系统来管理项目。
二、实战常见用法
1. ifeq
ifneq
是 Makefile 中的条件判断语句,用于判断两个值是否不相等。它的语法如下:
ifneq (arg1, arg2)
# 条件满足时执行的命令
else
# 条件不满足时执行的命令
endif
其中,arg1
和 arg2
是需要进行比较的值。如果它们不相等,则执行 ifneq
语句块中的命令;否则,执行 else
语句块中的命令(可选)。最后使用 endif
结束整个条件判断块。
以下是一个示例,演示了如何在 Makefile 中使用 ifneq
条件判断语句:
ARCH_TYPE := x86
ifeq ($(ARCH_TYPE), x86)
CC := gcc
else
CC := arm-linux-gcc
endif
target:
$(CC) -o target source.c
在这个示例中,根据 ARCH_TYPE
变量的值来选择不同的编译器。如果 ARCH_TYPE
的值是 “x86”,则将 CC
变量设置为 “gcc”;否则,将 CC
变量设置为 “arm-linux-gcc”。最后,在 target
目标中使用 $(CC)
变量来编译源代码。
通过使用 ifneq
条件判断语句,可以根据不同的条件执行不同的操作,增强了 Makefile 的灵活性和可定制性。
2.Object rules的vpath %.c thirdparty_special
在 Makefile 中,vpath %.c thirdparty_special
是一个 vpath 指令,用于指定 Make 在查找源文件(.c
文件)时的搜索路径。
具体来说,vpath
指令的作用是将指定的文件模式(这里是 %.c
)与指定的搜索路径(这里是 thirdparty_special
)关联起来。这意味着当 Make 在构建目标时需要查找以 .c
结尾的源文件时,它会首先在 thirdparty_special
目录下进行搜索。
这个特性的作用在于,当项目中的源文件分布在多个目录中时,我们可以通过 vpath
指令告诉 Make 在哪些目录下查找特定类型的文件。这样可以使 Make 能够更智能地定位和使用源文件,而无需在每个规则中都指定完整的路径。
总的来说,vpath %.c thirdparty_special
这个指令可以让 Make 在查找 .c
源文件时自动去 thirdparty_special
目录下寻找,提高了 Makefile 的灵活性和可维护性。
三、常用手段
1. 脚本修改文件名
例1:将含"ab_"、"ab_cde_“的文件名替换为"aaa_”
使用 find
命令找到当前目录下所有含有 “ab_” 或 “ab_cde_” 的文件,并使用 sed
命令来进行替换。下面是一个简单的 Shell 脚本示例,实现了这一功能:
#!/bin/bash
# 查找当前目录下所有含有"gc_"或"gc_hal_"文件名的文件,并循环处理
find . -type f -name 'ab_cde_*' -o -name 'ab_*' | while read filename; do
# 将文件名中的"ab_cde_"和"ab_"替换为"aaa_"
newname=$(echo $filename | sed -e 's/ab_cde_/aaa_/' -e 's/ab_/aaa_/')
# 执行重命名操作
mv "$filename" "$newname"
echo "Renamed $filename to $newname"
done
将上述代码保存到一个文件(比如 rename_files.sh
),然后给予执行权限:
chmod +x rename_files.sh
接着在当前目录下执行该脚本即可:
./rename_files.sh
这个脚本会遍历当前目录以及子目录中的所有文件,将文件名中的 “ab_cde_” 和 “ab_” 替换为 “aaa_”。注意转换先后顺序,此处需先将"ab_cde_"转换,否则先产生的"aaa_de"无法达到转换目的。
请注意,在运行脚本之前,请务必做好必要的备份工作,以免意外情况造成文件损坏。
2. 脚本修改文件内容
例1:将含"ab_"、"ab_cde_“的文件内容替换为"aaa_”
上述例请1修改了文件名,则调用处的文件内容也需修改。
使用 sed
命令来修改文件内容中的特定词汇。下面是一个简单的 Shell 脚本示例,实现了将当前目录下所有文件中的 “ab_def_” 和 “ab_” 替换为 “aaa_”:
#!/bin/bash
# 查找当前目录下的所有文件,并循环处理
find . -type f -exec sed -i 's/ab_cde_/aaa_/g; s/ab_/aaa_/g' {} \;
将上述代码保存到一个文件(比如 modify_files.sh
),然后给予执行权限:
chmod +x modify_files.sh
接着在当前目录下执行该脚本即可:
./modify_files.sh
这个脚本会遍历当前目录以及子目录中的所有文件,将文件内容中的 “ab_cde_” 和 “ab_” 替换为 “aaa_”。使用 -i
参数可以直接修改文件内容,而不需要输出到标准输出或者创建新文件。若替换的字符串中含有路径如"abstract/main",需添加转义字符"abstract/main"。
请注意,在运行脚本之前,请务必做好必要的备份工作,以免意外情况造成文件内容丢失或损坏。
3. 打印变量值
在 Makefile 中,你可以使用 $(info ...)
函数来打印变量的值。
以下是使用 $(info ...)
函数打印变量值的示例:
VAR := Hello, World!
all:
@echo $(VAR)
$(info Variable VAR is $(VAR))
在这个示例中,我们定义了一个名为 VAR
的变量,并将其赋值为 “Hello, World!”。然后,在 all
目标中,我们使用 echo
命令来打印变量 VAR
的值,以验证其内容是否正确。接着,在 $(info ...)
函数中,我们打印了变量 VAR
的值,并加上了一些额外的文本信息。
当你执行 make
命令时,Makefile 将会输出以下内容:
Hello, World!
Variable VAR is Hello, World!
通过使用 $(info ...)
函数,你可以在 Makefile 中打印出变量的值,方便调试和确认变量的内容。
4. 使用shell命令
在 Makefile 中,你可以使用 $(shell ...)
函数来执行任意的 Shell 命令,并将其输出作为变量的值。
因此,如果你想在 Makefile 中获取当前工作目录的绝对路径,可以使用 Shell 命令 pwd
并将其输出赋值给一个变量。以下是一个示例:
CUR_DIR := $(shell pwd)
all:
@echo Current directory is $(CUR_DIR)
在这个示例中,我们使用 $(shell ...)
函数调用了 Shell 命令 pwd
,并将其输出赋值给 CUR_DIR
变量。然后在 all
目标中,我们使用 echo
命令将 CUR_DIR
变量的值打印出来。
当你执行 make
命令时,Makefile 将会输出以下内容:
Current directory is /path/to/current/directory
总之,你可以使用 $(shell ...)
函数在 Makefile 中执行任意的 Shell 命令,并将其输出作为变量的值,从而实现获取当前工作目录的绝对路径等操作。