Kbuild系统源码分析(三)—./scripts/Makefile.lib

版权声明:本文为CSDN博主「ashimida@」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lidan113lidan/article/details/119768728

更多内容可关注微信公众号  

  ./scripts/Makefile.lib是被include使用的,在Kbuild系统中只在两个脚本中包含了此文件,分别是:

./scripts/Makefile.build 
./scripts/Makefile.modpost

  在使用此文件之前通常会先include某个源码目录下的Makefile(见Makefile.build/Makefile.modpos代码),而Kbuild子目录中的Makefile中通常会指定如obj-m/obj-y等一些编译目标,此库函数首先会处理这些目标


1. 增加当前Makefile的特有编译选项

asflags-y  += $(EXTRA_AFLAGS)
ccflags-y  += $(EXTRA_CFLAGS)    
cppflags-y += $(EXTRA_CPPFLAGS)
ldflags-y  += $(EXTRA_LDFLAGS)

  按照makefiles.text中的说明(3.7 Compilation flags), EXTRA_XXFLAGS是老的命名方式,xxflags-y这种是新的命名方式,这里的操作的目的是为了兼容老的命名方式.以ccflags-y为例,其集成的顺序为:ccflags-y => orig_c_flags => _c_flags => c_flags(代码在./script/Makefile.lib中,见后),最终:
 * 在./script/Makefile.build中,基本使用$(CC)/$(CPP)/$(CHECK)的地方都会加入c_flags,如:

cmd_gensymtypes_c
cmd_gensymtypes_S
cmd_cc_lst_c
cmd_cc_o_c
cmd_cc_ll_c
cmd_cpp_i_c
cmd_cc_s_c

 * 在./script/Makefiel.modpost中同样cmd_cc_o_c也使用了c_flags.
  这几个flag不是export的,也就是说其只在当前make中其作用,而任何submake(如make -f重启的make),或者上层make中是无效的。这也是为什么除了全局的KBUILD_CFLAGS还要增加此FLAG的原因.正常的使用方式是在某个目录的Makefile中指定此flag,那么针对这个目录的编译(不包括子目录,因为子目录是重启的submake)都会应用此flags,如:

# drivers/acpi/acpica/Makefile
ccflags-y            := -Os -D_LINUX -DBUILDING_ACPICA
ccflags-$(CONFIG_ACPI_DEBUG)    += -DACPI_DEBUG_OUTPUT

2. 增加当前Makefile及所有子目录的特有编译选项

KBUILD_AFLAGS += $(subdir-asflags-y)
KBUILD_CFLAGS += $(subdir-ccflags-y)

  这两个变量和前面4个大体类似,因为如KBUILD_CFLAGS最终也集成到了c_flags中(当然还有其他路径),其集成路径为 KBUILD_CFLAGS => orig_c_flags => _c_flags => c_flags, 但二者的区别在于KBUILD_CFLAGS是./Makefile(根makefile)中export的全局变量,其在所有的submake中生效(在上层目录中无效),故当前在KBUILD_AFLAGS增加的$(subdir-asflags-y)是对当前目录以及所有子目录(submake)的编译均生效的.

3. 处理编译目标中的变量
  这段代码根据用户输入的obj-m/obj-y等派生出以下变量,包括:
  * 模块相关的: obj-m/__subdir-m/subdir-m/multi-used-m/single-used-m/real-obj-m
  * 内核相关的: obj-y/__subdir-y/subdir-y/multi-used-y/subdir-obj-y/real-obj-y
  * 库相关的: lib-y/lib-m
  * 其他的: subdir-ym/muitl-used/extra-y/modorder
  在这段代码中用户输入的obj-m,obj-y和lib-y也同时被处理了,也就是说在后面代码解析中看到的obj-m,obj-y,lib-y并不是原始的用户输入,其区别主要如下(假设用户输入正确,即用户的目标只指定了.o和%/这样的目录,而非其他异常格式):
  * obj-y 中所有 %/ 结尾的(贪婪匹配)都被当做目录,在obj-y中被替换为 %/built-in.a(也就是不管输入如何,后续的obj-y中都不再拥有目录,正常是.o或%/built-in.a)
  * obj-m 和原始的obj-y做了一个异或,即出现在原始obj-y中的目标都不会出现在obj-m中
    obj-m 之后去除了所有 %/结尾的目录,正常只保留.o目标.
    obj-m 中所有%/结尾的目录都保存到subdir-m中后续同一处理了
  * lib-y 实际上是将lib-y,lib-m中的所有变量都放到lib-y中了,然后再与obj-y做异或,排除obj-y中的文件
    后续所有用户输入的lib-y,lib-m中的变量只用lib-y表示了
  相关代码如下:

## obj-m是Makefile中指定的 obj-m 并排除 obj-y中的内容
obj-m := $(filter-out $(obj-y),$(obj-m))

## lib-y 是 按照首字母排序的 $(lib-y) 和 $(lib-m),并过滤掉 $(obj)-y中的内容后的结果, 在内核中如lib目录下经常会出现 lib-y的目标(lib-m源码中没有看到)如:
## ./lib/Makefile: lib-y := ctype.o string.o vsprintf.o cmdline.o ...
## ./arch/arm64/lib/Makefile: lib-y := clear_user.o delay.o copy_from_user.o ...
lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))

## 简单说,就是内核输出目录下的所有子目录中,都有一个modules.order文件,其用来记录当前子目录(递归)中所有ko的编译顺序
## * 对于同一个目录下的ko,文件中的记录顺序就是其编译顺序(这个顺序也是用户输入的obj-m中的目标文件顺序)
## * 所有子目录的ko都是在父目录ko编译完之后编译的
## 也就是说在modules.order中子目录若出现在父目录前,也不代表其编译的早,因为这里面只有同目录的顺序是准确的
## 再就是父目录的modules.order完全包含子目录modules.order中的内容
## 这里的modorder是取obj-y中的目录,和obj-m中的目录一起被替换成对应的%/modules.order, 然后加上 obj-m中的.o -> .ko;按照用户输入的顺序排序
modorder    := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko))

## 这里需要注意,在obj-y/obj-m中,只有明确指定以/结尾的(贪婪匹配),才会被认为是目录,其他都会被认为是目标
## 而通过 subdir-y/subdir-m 可以指定一个子目录,此时不要写目录的结尾符号/
## 这里过滤obj-y中所有的/的目录,并将目录尾部的/去掉,得到的是obj-y中所有/结尾的目录的目录名
__subdir-y    := $(patsubst %/,%,$(filter %/, $(obj-y)))
## 这里是 obj-y中指定的所有子目录,在Makefile中也可以通过如subdir-y += actions直接指定一个目录,这应该是单独使用了一个__subdir-y的原因
subdir-y    += $(__subdir-y)
## 这里是所有obj-m中自定的子目录
__subdir-m    := $(patsubst %/,%,$(filter %/, $(obj-m)))
subdir-m    += $(__subdir-m)

## obj-y中所有的目录,都被替换为对应目录下的built-in.a文件,注意多级目录的情况下目标会被保留下来
## 但实际上正常看到过类似 */*/xx.o的形式,没有看到 */*/的情况,因为子目录会在子目录的make中默认处理的,
## 正常应该是是不会越级传入子目录的(但如果父目录不变异,只传入子目录理论上应该是可以编译的)
obj-y        := $(patsubst %/, %/built-in.a, $(obj-y))
# 所有模块的%/结尾的(目录)都直接删除,剩下的都是直接编译的目标,而目录是放到subdir-m中统一处理的
obj-m        := $(filter-out %/, $(obj-m))

# Subdirectories we need to descend into
## 字母顺序排序所有buildin和模块中的子目录
subdir-ym    := $(sort $(subdir-y) $(subdir-m))

## makefile中obj-m/obj-y指定的目标可以分为单目标和符合目标:
## * 单目标指的目标只对应唯一的源码文件,
##   如 存在foo.c源码,指定 obj-m = foo.o 那么 foo.o就是一个单目标,会被加入到单目标列表(single-used-m)(y没有单目标列表)
## * 复合目标指的是对应多个源码,那么此时复合目标名就无法表示其源码
##   对于复合目标,必须通过 额外的 foo-objs/foo-y/foo-m来确定其具体对应那些源码文件
## multi-used-y记录的$(obj-y)中的复合目标名(没有做任何展开,其判断依据是是否存在foo-objs/foo-y)
## multi-used-m中记录的是$(obj-m)中的复合目标名(同样没做任何展开,其判断依据是是否存在foo-objs/foo-y/foo-m)
## 注意这里的复合目标名是通过sort按照名称排序的!!!
## 若出现非.o结尾的(也非/结尾的),则直接根据变量是否定义,判断是简单对象还是符合对象
multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))), $(m))))
## 全部的复合对象
multi-used   := $(multi-used-y) $(multi-used-m)
## 这是m中的非复合对象
## 没有对应定义的则加到single-used-m中
single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))


# $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to
# tell kbuild to descend
## 这里记录obj-m中所有的非符合对象,通常来说就是 objs-m中的某个对象如foo.o,同时 foo-objs/foo-y/foo-m为空的对象.
subdir-obj-y := $(filter %/built-in.a, $(obj-y))

## 对于obj-y中的每个对象, 如果是复合对象,则将%.o替换为变量%-objs %-y, 否则还是保持%.o
## 如 fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o
## 如 ./fs/proc/Makefile:proc-y := nommu.o task_nommu.o
## 这里实际上是将复合对象展开成真正的变量
## real-obj-y和real-obj-m实际上是 obj-y/obj-m的展开(二者已经去除目录了),是将其中的复合对象替换为了具体的对象(foo-objs/foo-y)
real-obj-y := $(foreach m, $(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
real-obj-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m)))


## extra-y记录的是只有在编译内核时编译,但不想加入到built-in的vmlinux中的一些目标,其可以来自用户输入,或者Makefile代码中,不对其中目标做任何处理
extra-y                += $(dtb-y)
extra-$(CONFIG_OF_ALL_DTBS)    += $(dtb-)

ifneq ($(CHECK_DTBS),)
extra-y += $(patsubst %.dtb,%.dt.yaml, $(dtb-y))
extra-$(CONFIG_OF_ALL_DTBS) += $(patsubst %.dtb,%.dt.yaml, $(dtb-))
endif

## 这里为以下变量中的每个字符串都加上 $(obj)前缀
extra-y        := $(addprefix $(obj)/,$(extra-y))
## always 完全来自用户输入,其含义是不论是编译内核还是模块,总是要编译的目标,且此目标与模块和内核的集成没有关系,不走模块和内核的集成路程
## 其和extra-y的区别在于,extra-y通常只用于内核,而always用于内核+模块,见注2
always        := $(addprefix $(obj)/,$(always))
## targets也完全来自于用户输入,其主要有两个作用:
## 1是对if_changed系列函数做支持,如果一个目标想通过if_changed来判断只有更改时才重新编译,那么就必须要加入到targets中
## 2是对clean的支持,clean的时候会清除targets中的所有相关文件
targets        := $(addprefix $(obj)/,$(targets))
modorder    := $(addprefix $(obj)/,$(modorder))
obj-m        := $(addprefix $(obj)/,$(obj-m))
lib-y        := $(addprefix $(obj)/,$(lib-y))
subdir-obj-y    := $(addprefix $(obj)/,$(subdir-obj-y))
real-obj-y    := $(addprefix $(obj)/,$(real-obj-y))
real-obj-m    := $(addprefix $(obj)/,$(real-obj-m))
single-used-m    := $(addprefix $(obj)/,$(single-used-m))
multi-used-m    := $(addprefix $(obj)/,$(multi-used-m))
subdir-ym    := $(addprefix $(obj)/,$(subdir-ym))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值