一. 一种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内核编译基础知识储备 --- 过渡篇(四)的更多相关文章

  1. 十天学Linux内核之第十天---总结篇(kconfig和Makefile & 讲不出再见)

    原文:十天学Linux内核之第十天---总结篇(kconfig和Makefile & 讲不出再见) 非常开心能够和大家一起分享这些,让我受益匪浅,感激之情也溢于言表,,code monkey的 ...

  2. 1)Linux程序设计入门--基础知识

    )Linux程序设计入门--基础知识 Linux下C语言编程基础知识 前言: 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将 会学到以下内容: 源程序编译 Makef ...

  3. Linux内核编译与安装

    2013-04-16    Linux内核介绍  Linux内核是一个用C语言写成的,符合POSIX标准的类Unix操作系统.内核是操作系统中最基本的一部分,提供了众多应用程序访问计算机硬件的机制.L ...

  4. Linux 内核编译步骤及配置详解

    前言    Linux内核是操作系统的核心,也是操作系统最基本的部分. Linux内核的体积结构是单内核的.但是他充分采用了微内核的设计思想.使得虽然是单内核.但工作在模块化的方式下.并且这个模块可以 ...

  5. Linux内核编译完整过程

    Linux内核编译完整过程 通过网上的资料我自己的实际内核编译,我把对Linux内核编译的过程写在这里,也许对其他的Linux爱好者的编译学习有些帮助,其中很大部分是网上的资料,另外就是我在实际编译过 ...

  6. jQuery学习笔记 - 基础知识扫盲入门篇

    jQuery学习笔记 - 基础知识扫盲入门篇 2013-06-16 18:42 by 全新时代, 11 阅读, 0 评论, 收藏, 编辑 1.为什么要使用jQuery? 提供了强大的功能函数解决浏览器 ...

  7. 运行在TQ2440开发板上以及X86平台上的linux内核编译

    一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的“linux-2.6.30.4_20100531.tar.bz2”源码包. 解压(天嵌默认解压到/opt/E ...

  8. linux内核编译环境配置

    linux内核编译环境配置 如果不是编译内核,只需要安装与内核相匹配的kernel-devel开发包即可.即是/lib/modules/`uname -r`/build -> /usr/src/ ...

  9. linux运维基础知识

    linux运维基础知识大全 一,序言 每一个微不足道的知识,也是未来的铺垫.每一份工作的薪资职位,也是曾经努力的结果. 二,服务器 1,运维人员工作职责: 1)保证数据不丢失:2)保证服务器24小时运 ...

  10. Lab1:Linux内核编译及添加系统调用(详细版)

    实验一:Linux内核编译及添加系统调用(HDU) 花了一上午的时间来写这个,良心制作,发现自己刚学的时候没有找到很详细的,就是泛泛的说了下细节地方也没有,于是自己写了这个,有点长,如果你认真的看完了 ...

随机推荐

  1. jmap执行失败了,怎么获取heapdump?

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明. 在之前的OOM问题复盘中,我们添加了jmap脚本来自动dump内存现场,方便排查OOM问题. 但当我反复模拟OO ...

  2. Network Science: 巴拉巴西网络科学阅读笔记

    前言: 最小生成树中Kruskal算法对应了统计物理中的著名模型invasion percolation.由此写了一篇文章:invasion percolation and global optimi ...

  3. 关于Java中方法重载和方法重写

    方法重写是子类继承父类(默认继承Object类)后覆盖父类的方法 需要保证同名 同参 同返回值 且访问权限范围不能缩小(public>protected>default>privat ...

  4. 世界读书日:推荐15本AI从入门到放弃的书

    hi,我是熵减,见字如面. 在世界读书日即将到来的前,以及借着ChatGPT的火热,各种AI大模型的创业东风,今天给大家推荐一些AI相关的图书,希望大家能从入门到放弃,找到适合自己的热爱. 本次推荐图 ...

  5. 下一代大数据分布式存储技术Apache Ozone初步研究

    @ 目录 概述 定义 特性 架构 总体架构 写数据 读数据 部署 安装方式 安装 Docker启动 Docker-compose启动 企业预置型(On Premise)安装 实践 命令行接口 Ofs ...

  6. 我的第一个项目(十二) :分数和生命值的更新(后端增删查改的"改")

    好家伙,写后端,这多是一件美逝. 关于这个项目的代码前面的博客有写  我的第一个独立项目 - 随笔分类 - 养肥胖虎 - 博客园 (cnblogs.com) 现在,我们登陆进去了,我开始和敌人战斗,诶 ...

  7. Prism Sample 23-RegionMemberLifetime

    在导航中跳转时,视图是缓存的.如果要求某视图在离开后就销毁,需要实现 public class ViewAViewModel : BindableBase, INavigationAware, IRe ...

  8. 使用GitHub当博客图床提升博客访问速度

    前言 作为一个穷逼来说站长来说,只有一个1M宽带这样的小水管服务器,如果博客稍微放一点图片到本地,然后人多点访问网站基本就很卡了,但又不想去吧图片放到图床里然后复制链接到文章里面那么麻烦 如何解决这个 ...

  9. 【C#】图片上传并根据长宽大小进行正方形、长方形及等比缩放。

    #region 正方型裁剪并缩放 /// <summary> /// 正方型裁剪 /// 以图片中心为轴心,截取正方型,然后等比缩放 /// 用于头像处理 /// </summary ...

  10. 2023-04-14:n对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手, 人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的ID, 情侣们按顺序编号,第一对

    2023-04-14:n对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手, 人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的ID, 情侣们按顺序编号,第一对 ...