前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux内核的Makefile中cmd-check是如何检查前后两次执行的命令是一致的?

Linux内核的Makefile中cmd-check是如何检查前后两次执行的命令是一致的?

作者头像
KINGYT
发布2020-02-17 18:19:36
1.5K0
发布2020-02-17 18:19:36
举报

Linux内核的构建工具用的是GNU Make,在其相关的Makefile中,有一个变量叫做cmd-check,其定义如下:

代码语言:javascript
复制
# Check if both commands are the same including their order. Result is empty
# string if equal. User may override this check using make KBUILD_NOCMDDEP=1
cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
                         $(subst $(space),$(space_escape),$(strip $(cmd_$1))))

它在if_changed等相关命令中会被用到:

代码语言:javascript
复制
# Execute command if command has changed or prerequisite(s) are updated.
if_changed = $(if $(newer-prereqs)$(cmd-check),                              \
        $(cmd);                                                              \
        printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)

再来看下if_changed命令的具体使用场景:

代码语言:javascript
复制
# Final link of vmlinux with optional arch pass after final link
cmd_link-vmlinux =                                                 \
        $(CONFIG_SHELL) $< $(LD) $(KBUILD_LDFLAGS) $(LDFLAGS_vmlinux) ;    \
        $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)

vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) FORCE
        +$(call if_changed,link-vmlinux)

在该段内容中,定义了一个名为vmlinux的target,在它的recipe中,通过call指令调用了if_changed命令,传递的参数为link-vmlinux。

在if_changed命令中,如果$(newer-prereqs)$(cmd-check)部分展开后的结果不为空,则执行后面$(cmd)指向的命令,并将该命令用printf输出到特定的文件中。

对于vmlinux这个target来说,$(cmd)最终指向的就是上面cmd_link-vmlinux变量对应的命令,而printf输出的最终文件名为.vmlinux.cmd,内容为cmd_vmlinux := cmd_link-vmlinux变量对应的命令。

在if_changed的命令中,$(newer-prereqs)表示的是,是否有prerequisites比vmlinux这个target还新,$(cmd-check)表示的是,$(cmd_$@)是否和$(cmd_$1)相同。

对于vmlinux来说,$(cmd_$@)展开后的结果是cmd_vmlinux,$(cmd_$1)展开后的结果是cmd_link-vmlinux。

cmd_link-vmlinux在Makefile中是有明确定义的,但cmd_vmlinux在Makefile中却没法找到明确定义的地方,这个也是初次研究linux内核的Makefile的同学会感到困惑的地方。

为什么我找遍了所有相关的Makefile,就是没找到cmd_vmlinux的定义呢?

我们再来仔细想下,cmd-check的意图是什么?

是为了比较这次执行的命令和上次执行的命令是否相同。

如果两次命令相同,且$(newer-prereqs)结果为空,则此时if_changed后面的构建命令就不用执行了,因为在这两次构建过程中,不管是prerequisites还是构建命令,都没有发生任何变化。

这次的构建命令很容易获取,比如上面的cmd_link-vmlinux,是直接在Makefile中定义的,那上次的构建命令怎么获取呢?

对,肯定是保存到哪个文件里了。

再来回忆下if_changed命令,看下其中的printf部分,这不正是用来保存该次执行命令到特定文件的嘛。

知道了上次执行的命令被保存到了哪里,我们再来看下Makefile是如何使用它们的。

首先看下linux内核根目录里的Makefile,其中有如下定义:

代码语言:javascript
复制
targets := vmlinux

再来看下该变量是如何被使用的:

代码语言:javascript
复制
# read saved command lines for existing targets
existing-targets := $(wildcard $(sort $(targets)))

-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)

看到没,最后是用了make的inlcude指令,将.vmlinux.cmd文件内容当作Makefile内容格式被读了进来。

而.vmlinux.cmd文件中的内容我们前文也提到了,就是cmd_vmlinux := cmd_link-vmlinux对应的命令。

这样,cmd-check中的$(cmd_$@)部分指向的内容我们也找到了。

我们来实际操作看下,先来构建vmlinux:

代码语言:javascript
复制
$ make mrproper defconfig vmlinux

看下该过程生成的文件.vmlinux.cmd文件:

代码语言:javascript
复制
cmd_vmlinux := sh scripts/link-vmlinux.sh ld -m elf_x86_64  -z max-page-size=0x200000 --emit-relocs --discard-none --build-id ;  true

该文件里的内容和我们上文分析的是一样的。

cmd-check里的命令比较逻辑,相对来说还是比较绕的,如果正在研究linux内核的同学恰巧遇到了这个问题,希望本文能对你有所帮助。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux内核及JVM底层相关技术研究 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档