Skip to content

LV012-变量与shell命令

在Makefile中,变量可以使用shell命令的结果进行赋值。这种功能非常有用,因为它允许我们在Makefile中动态地获取系统信息,如当前目录、文件列表、系统版本等,而无需在命令行中手动指定。

一、基本语法

1. $(shell command)

这是最常用的通过shell命令为变量赋值的方式。语法格式如下:

makefile
variable := $(shell command)

2. 反引号

也可以使用反引号来执行shell命令:

makefile
variable := `command`

二、常用示例

1. 获取文件列表

makefile
# 获取文件列表
SOURCE_FILES := $(shell find . -name "*.c")
HEADER_FILES := $(shell find . -name "*.h")

# 获取目录列表
INC_DIR += $(shell find ./inc ../../include -type d ) 

# 获取静态库和动态库
LD_FLAGS += $(shell find ./lib -type f|grep \.a\$$)
LD_FLAGS += $(shell find ./lib -type f|grep \.so\$$)

其实这里的几个示例还是很常用的,他们其实用的都是find命令的用法。前面几个都很好理解,这里主要看一些后面获取动态库和静态库的命令:

  • find ./lib -type f:在 ./lib 目录下递归查找所有类型为普通文件(file)的文件。
  • grep \.a\$$:使用grep命令筛选出以.a结尾的文件(静态库文件)。这里的正则表达式解释如下:
    • . 是正则表达式中的特殊字符,匹配任意字符。为了匹配字面意思的点号,需要使用反斜杠 \ 进行转义。
    • a 匹配字母 a
    • $$ 是正则表达式中的锚点符号,表示字符串结尾。在Makefile中,因为$是特殊字符,所以需要使用$$来表示字面意思的$
    • 所以 \.a$$ 表示匹配以.a结尾的文件名,例如 libfoo.alibc.a 等。

2. 获取信息

makefile
# 获取当前目录名
CURDIR_NAME := $(shell basename $(CURDIR))

# 获取系统信息
HOST_OS := $(shell uname -s)
CURRENT_USER := $(shell whoami)
CURRENT_DATE := $(shell date +%Y-%m-%d)

# 获取git信息
GIT_COMMIT := $(shell git rev-parse HEAD)
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
GIT_STATUS := $(shell git status --porcelain)

# 检查是否安装了某个命令
CHECK_CMD := $(shell which gcc 2>/dev/null || echo "not found")

# 检查文件是否存在
FILE_EXISTS := $(shell [ -f "config.txt" ] && echo "exists" || echo "missing")

三、注意事项

1. 错误处理

使用shell命令时要注意错误处理:

makefile
# 安全的方式执行可能失败的命令
VERSION := $(shell git describe --tags 2>/dev/null || echo "unknown")

2. 性能考虑

shell命令在makefile解析时执行,如果命令比较耗时,会影响makefile的解析速度。

3. 输出格式

shell命令的输出会被自动处理,多余的空白符会被删除。如果需要保留空格,可以使用以下方式:

makefile
# 保留原始输出格式
RAW_OUTPUT := $(shell command)
# 或者使用管道处理
PROCESSED_OUTPUT := $(shell command | tr '\n' ' ')