linux内核编译基础知识储备 --- 过渡篇(四)
文章目录
一. 一种makefile中定义函数的方式
The call function is unique in that it can be used to create new parameterized functions. You can write a complex expression as the value of a variable, then use call to expand it with different values.
The syntax of the call function is:
$(call variable,param,param,…)
When make expands this function, it assigns each param to temporary variables $(1), $(2), etc.
一个类似宏定义的定义,当make展开这个函数时,它将每个参数分配给临时变量$ (1)、$ (2)等。还是很抽象是不?不要紧,后续我们会讲到它的相关实例。
二. makefile之if函数
#if 函数的语法是:
$(if <condition>,<then-part> )
或
$(if <condition>,<then-part>,<else-part> )
<condition>参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,<then-part>会被计算,否则<else-part>会被计算
if函数的返回值是,
如果<condition>为真(非空字符串),那个<then-part>会是整个函数的返回值,
如果<condition>为假(空字符串),那么<else-part>会是整个函数的返回值,此时如果<else-part>没有被定义,那么,整个函数返回空字串。
三. MAKE变量
$(MAKE)就是预设的 make 这个命令的名称(或者路径)。
四. $(quiet)
# 顶层Makefile
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
#
# Most importantly: sub-Makefiles should only ever modify files in
# their own directory. If in some directory we have a dependency on
# a file in another dir (which doesn't happen often, but it's often
# unavoidable when linking the built-in.o targets which finally
# turn into vmlinux), we will call a sub make in that other dir, and
# after that we are sure that everything which is in that other dir
# is now up to date.
#
# The only cases where we need to modify files which have global
# effects are thus separated out and done before the recursive
# descending is started. They are now explicitly listed as the
# prepare rule.
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
# that echo $($(quiet)$(cmd)), we now have the possibility to set
# $(quiet) to choose other forms of output instead, e.g.
#
# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
#
# If $(quiet) is empty, the whole command will be printed.
# If it is set to "quiet_", only the short version will be printed.
# If it is set to "silent_", nothing will be printed at all, since
# the variable $(silent_cmd_cc_o_c) doesn't exist.
#
# A simple variant is to prefix commands with $(Q) - that's useful
# for commands that shall be hidden in non-verbose mode.
#
# $(Q)ln $@ :<
#
# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
# If KBUILD_VERBOSE equals 1 then the above command is displayed.
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
这里的Q代表着是否为quiet静默编译,需要在make编译时通过传入V=1来指定。通常情况下我们不会在命令行传入V这个参数,此时走的是else分支(特别指定除外), quiet=quiet_ — 只打印简短的编译信息,Q = @ — 命令不会回显。讲了这么多,不如来个实例看着直观:
4.1 quiet = 空 与 quiet=quiet_ 的区别
(1)执行 sudo make drivers/char/mem.o ,此时 quiet=quiet_
(2)在scripts/Makefile.build中把quiet_cmd_cc_o_c定义成与cmd_cc_o_c一样的形式,模拟quiet = 空的场景,只是为了测试,看不懂不要紧,后面会有对应的讲解,这里只是给出一个直观的图形,免得那么抽象;
# quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ 注释掉
quiet_cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
执行 sudo make drivers/char/mem.o

4.1 有无@的区别
@表示在make时不输出make的信息(类似Windows下的echo off)。就是是否回显命令行,比较简单,这里就不再赘述。
五. echo-cmd 变量
1. echo-cmd 变量的定义
# scripts/Kbuild.include
# echo command.
# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
echo-cmd就是打印出调用的命令。if $ ($ (quiet)cmd_$ (1)) 是判断命令$ (quiet)cmd_$ (1)或者cmd_$(1)是否定义?如果有定义,echo-cmd就会将这个命令打印出来。(例如对于 $(call echo-cmd,checksrc) 就是打印quiet_cmd_checksrc或者cmd_checksrc )。
有一点比较重要的是你或许注意到了末尾括号前有一个分号";" ,这是因为 一般在调用echo-cmd命令后面紧跟一个与之对应的要执行的命令,由于echo也是一条命令,用分号来分割两个命令。比如:
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c)
想想其实也不觉得奇怪,只打印命令肯定不是我们的目的,执行这条命令才是我们的目的!打印只是为了方便编译调试。
2. escsq 函数
转义单引号(在单引号前面加个 \),以便在echo语句中使用。
# scripts/Kbuild.include
squote := '
...
#Escape single quote for use in echo statements
escsq = $(subst $(squote),'\$(squote)',$1)
3. echo-why
通常情况下我们不会在命令行传入V这个参数,因此KBUILD_VERBOSE=0,因此下面这个分支走不到,即echo-why为空。
# scripts/Kbuild.include
ifeq ($(KBUILD_VERBOSE),2)
why = \
$(if $(filter $@, $(PHONY)),- due to target is PHONY, \
$(if $(wildcard $@), \
$(if $(strip $(any-prereq)),- due to: $(any-prereq), \
$(if $(arg-check), \
$(if $(cmd_$@),- due to command line change, \
$(if $(filter $@, $(targets)), \
- due to missing .cmd file, \
- due to $(notdir $@) not in $$(targets) \
) \
) \
) \
), \
- due to target missing \
) \
)
echo-why = $(call escsq, $(strip $(why)))
endif
六. $(call echo-cmd,checksrc)
通过前面的分析, $(call echo-cmd,checksrc)可以展开为:
$(if $(quiet_cmd_checksrc),echo ' $(call escsq,$(quiet_cmd_checksrc))';)
其中quiet_cmd_checksrc变量的定义如下:
# scripts/Makefile.build
# Linus' kernel sanity checking tool
ifneq ($(KBUILD_CHECKSRC),0)
ifeq ($(KBUILD_CHECKSRC),2)
quiet_cmd_force_checksrc = CHECK $<
cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
else
quiet_cmd_checksrc = CHECK $<
cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
endif
endif
一般情况下我们不会在命令行传入C这个参数(定义如下,在顶层Makefile中),因此KBUILD_CHECKSRC = 0,因此下面这个分支走不到,*$ (call echo-cmd,checksrc)为空。参数C定义在顶层Makefile中:
# Call a source code checker (by default, "sparse") as part of the
# C compilation.
#
# Use 'make C=1' to enable checking of only re-compiled files.
# Use 'make C=2' to enable checking of *all* source files, regardless
# of whether they are re-compiled or not.
#
# See the file "Documentation/sparse.txt" for more details, including
# where to get the "sparse" utility.
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
七. $(cmd_modversions)
一般情况下不会定义CONFIG_MODVERSIONS,因此 $(cmd_modversions)为空。
其中 $(cmd_modversions)~变量的定义如下:
# scripts/Makefile.build
ifndef CONFIG_MODVERSIONS
...
else
...
cmd_modversions = \
if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
$(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
> $(@D)/.tmp_$(@F:.o=.ver); \
\
$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
-T $(@D)/.tmp_$(@F:.o=.ver); \
rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
else \
mv -f $(@D)/.tmp_$(@F) $@; \
fi;
endif
八. $(cmd_record_mcount)
一般情况下不会定义CONFIG_FTRACE_MCOUNT_RECORD,因此 $(cmd_record_mcount)为空。 其中 cmd_record_mcount变量的定义如下:
# scripts/Makefile.build
ifdef CONFIG_FTRACE_MCOUNT_RECORD
...
cmd_record_mcount = \
if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then \
$(sub_cmd_record_mcount) \
fi;
endif
九. $(call echo-cmd,record_mcount)
通过前面的分析,call echo-cmd,record_mcount可以展开为:
$(if $(quiet_record_mcount),echo ' $(call escsq,$(quiet_cmd_record_mcount))';)
未定义quiet_record_mcount,因此 $(call echo-cmd,record_mcount)为空。
十.$(call echo-cmd,cc_o_c)
通过前面的分析 , $(call echo-cmd,cc_o_c)可以展开为:
$(if $(quiet_cmd_cc_o_c),echo ' $(call escsq,$(quiet_cmd_cc_o_c))';)
其中quiet_cmd_cc_o_c变量的定义在scripts/Makefile.build中:
# scripts/Makefile.build
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
由于变量quiet_modtag为空,quiet_cmd_cc_o_c又可以展开为
quiet_cmd_cc_o_c = CC $@
就是打印" CC $@ "这么一句话 。
总结
好了,前面巴拉巴拉一大堆,是时候来个总结啦,就好像千里行军总得找个好地方,整顿行囊,这样才能走得更远,更稳。
- echo-cmd 函数: 判断命令$ (quiet)cmd_$ (1)或者cmd_$(1)是否定义如果有定义,echo-cmd就会将这个命令打印出来。且后面紧跟着这条命令的具体执行;
- escsq 函数 : 转义单引号(在单引号前面加个 \),以便在echo语句中使用;
- $(call echo-cmd,cc_o_c) : 命令行未传入V参数值的情况下 展开为echo ’ CC $@’ ;
- $(call echo-cmd,checksrc) : 返回空,不关注;
- $ (call echo-cmd,record_mcount) : 返回空,不关注;
- echo-why 变量 :未定义,不关注;
- cmd_modversions 变量 :未定义,不关注;
- cmd_record_mcount 变量 :未定义,不关注;
linux内核编译基础知识储备 --- 过渡篇(四)的更多相关文章
- 十天学Linux内核之第十天---总结篇(kconfig和Makefile & 讲不出再见)
原文:十天学Linux内核之第十天---总结篇(kconfig和Makefile & 讲不出再见) 非常开心能够和大家一起分享这些,让我受益匪浅,感激之情也溢于言表,,code monkey的 ...
- 1)Linux程序设计入门--基础知识
)Linux程序设计入门--基础知识 Linux下C语言编程基础知识 前言: 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将 会学到以下内容: 源程序编译 Makef ...
- Linux内核编译与安装
2013-04-16 Linux内核介绍 Linux内核是一个用C语言写成的,符合POSIX标准的类Unix操作系统.内核是操作系统中最基本的一部分,提供了众多应用程序访问计算机硬件的机制.L ...
- Linux 内核编译步骤及配置详解
前言 Linux内核是操作系统的核心,也是操作系统最基本的部分. Linux内核的体积结构是单内核的.但是他充分采用了微内核的设计思想.使得虽然是单内核.但工作在模块化的方式下.并且这个模块可以 ...
- Linux内核编译完整过程
Linux内核编译完整过程 通过网上的资料我自己的实际内核编译,我把对Linux内核编译的过程写在这里,也许对其他的Linux爱好者的编译学习有些帮助,其中很大部分是网上的资料,另外就是我在实际编译过 ...
- jQuery学习笔记 - 基础知识扫盲入门篇
jQuery学习笔记 - 基础知识扫盲入门篇 2013-06-16 18:42 by 全新时代, 11 阅读, 0 评论, 收藏, 编辑 1.为什么要使用jQuery? 提供了强大的功能函数解决浏览器 ...
- 运行在TQ2440开发板上以及X86平台上的linux内核编译
一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的“linux-2.6.30.4_20100531.tar.bz2”源码包. 解压(天嵌默认解压到/opt/E ...
- linux内核编译环境配置
linux内核编译环境配置 如果不是编译内核,只需要安装与内核相匹配的kernel-devel开发包即可.即是/lib/modules/`uname -r`/build -> /usr/src/ ...
- linux运维基础知识
linux运维基础知识大全 一,序言 每一个微不足道的知识,也是未来的铺垫.每一份工作的薪资职位,也是曾经努力的结果. 二,服务器 1,运维人员工作职责: 1)保证数据不丢失:2)保证服务器24小时运 ...
- Lab1:Linux内核编译及添加系统调用(详细版)
实验一:Linux内核编译及添加系统调用(HDU) 花了一上午的时间来写这个,良心制作,发现自己刚学的时候没有找到很详细的,就是泛泛的说了下细节地方也没有,于是自己写了这个,有点长,如果你认真的看完了 ...
随机推荐
- GitLab 配置优化
代码库最近换了,使用了 GitLab.这两天观察了下服务器的使用情况,发现 GitLab 很吃内存.直接占用了 30 多个G的内存. 一.发现问题 使用 top 命令查看内存时,发现前几十个都是同一个 ...
- 27-lazy loading(懒加载和预加载)
懒加载 document.getElementById('btn').onclick = function () { // 懒加载:当文件需要使用时才加载 import(/* webpackChunk ...
- 微信小程序搜索不到腾讯服务路线规划插件的解决方法
具体操作如下: 提示:主要内容都是按开发文档来写的 开发文档: 链接: https://lbs.qq.com/miniProgram/plugin/pluginGuide/routePlan 添加插件 ...
- JavaScript封装大全
JavaScript封装大全-持续更新 Ajax封装 // 使用该封装需注意 // Ajax(method(默认GET), url(网址 必传), success(res){(成功时数据处理函数 必传 ...
- PostgreSQL-HA 高可用集群在 Rainbond 上的部署方案
PostgreSQL 是一种流行的开源关系型数据库管理系统.它提供了标准的SQL语言接口用于操作数据库. repmgr 是一个用于 PostgreSQL 数据库复制管理的开源工具.它提供了自动化的复制 ...
- OCR 文字检测(Differentiable Binarization --- DB)
文本检测 基于分割的做法(如蓝色箭头所示): 传统的pipeline使用固定的阈值对于分割后的热力图进行二值化处理 首先,它们设置了固定的阈值,用于将分割网络生成的概率图转换为二进制图像 然后,用一些 ...
- 解决v-html渲染HTML标签展示信息有误问题
后端返回的数据内容为: // html反转义 HTMLDecode(text) { var reg = /<[^>]+>/g; if (reg.test(text)) { retur ...
- 2023-02-19:请用go语言调用ffmepg,输出视频文件信息。
2023-02-19:请用go语言调用ffmepg,输出视频文件信息. 答案2023-02-19: 用 github.com/moonfdd/ffmpeg-go 这个库. 代码参考ffmpeg5入门教 ...
- 2021-02-04:第一年农场有1只成熟的母牛A,往后的每年:①每一只成熟的母牛都会生一只母牛 ②每一只新出生的母牛都在出生的第三年成熟 ③每一只母牛永远不会死 。请问N年后牛的数量是多少 ?
2021-02-04:第一年农场有1只成熟的母牛A,往后的每年:①每一只成熟的母牛都会生一只母牛 ②每一只新出生的母牛都在出生的第三年成熟 ③每一只母牛永远不会死 .请问N年后牛的数量是多少 ?福哥答 ...
- 2021-08-17:谷歌面试题扩展版,面值为1~N的牌组成一组,每次你从组里等概率的抽出1~N中的一张,下次抽会换一个新的组,有无限组,当累加和<a时,你将一直抽牌,当累加和>=a且<b时,你将获胜
2021-08-17:谷歌面试题扩展版,面值为1N的牌组成一组,每次你从组里等概率的抽出1N中的一张,下次抽会换一个新的组,有无限组,当累加和<a时,你将一直抽牌,当累加和>=a且< ...