u-boot-2016.09 make工具之fixdep
- u-boot-201609 make工具之fixdep
- 概述
- 哪里调用
- 1 直接搜索fixdep
- 11 if_changed_dep调用fixdep
- 12 rule_cc_o_c调用fixdep
- 13 fixdep调用结论
- 1 直接搜索fixdep
- 如何调用
- 输入和输出
- 1 输入和输出
- 2 cmd的引用
- TLDR
u-boot-2016.09 make工具之fixdep
1. 概述
fixdep
工具的源码位于scripts/basic/fixdep.c
,代码本身并不复杂。但作用是什么?哪里调用,如何调用,输入和输出是什么?咋一看却不甚清楚。
本文废话太多,如果只想看结论,请直接跳转到文末查看“TL;DR”一节。
2. 哪里调用?
到底哪里调用了fixdep?
2.1 直接搜索fixdep
不妨在u-boot代码里搜索下:
ygu@ubuntu:/opt/work/u-boot/u-boot-2016.09$ grep -rnw fixdep . --exclude-dir=basic
./scripts/Kbuild.include:230:# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
./scripts/Kbuild.include:266: scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
./scripts/Makefile.build:272: scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
./board/bosch/shc/README:30: HOSTCC scripts/basic/fixdep
grep
参数说明:
-r
,递归搜索目录
-n
,显示匹配结果的行号
-w
,按单词搜索
--exclude-dir=basic
,忽略basic子目录,此目录是fixdep.c
自身的代码目录
总共有4条匹配结果,只有在scripts/Kbuild.include
的266行和scripts/Makefile.build
的272行有调用,其余都跟fixdep调用无关。
2.1.1 if_changed_dep
调用fixdep
scripts/Kbuild.include
中的匹配结果是自定义函数if_changed_dep
调用了fixdep
:
# Execute the command and also postprocess generated .d dependencies file.
if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \@set -e; \$(echo-cmd) $(cmd_$(1)); \scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\rm -f $(depfile); \mv -f $(dot-target).tmp $(dot-target).cmd)
进一步搜索对if_changed_dep
的调用:
ygu@ubuntu:/opt/work/u-boot/u-boot-2016.09$ grep -rnw if_changed_dep .
./scripts/Makefile.spl:299: $(call if_changed_dep,cpp_lds)
./scripts/Makefile.lib:299: $(call if_changed_dep,dtc)
./scripts/Kbuild.include:229:# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
./scripts/Kbuild.include:263:if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
./scripts/Makefile.build:175: $(call if_changed_dep,cc_s_c)
./scripts/Makefile.build:181: $(call if_changed_dep,cc_i_c)
./scripts/Makefile.build:296: $(call if_changed_dep,cc_lst_c)
./scripts/Makefile.build:310: $(call if_changed_dep,as_s_S)
./scripts/Makefile.build:316: $(call if_changed_dep,as_o_S)
./scripts/Makefile.build:328: $(call if_changed_dep,cpp_lds_S)
./scripts/Makefile.host:99: $(call if_changed_dep,host-csingle)
./scripts/Makefile.host:116: $(call if_changed_dep,host-cobjs)
./scripts/Makefile.host:133: $(call if_changed_dep,host-cxxobjs)
./Kbuild:44: $(call if_changed_dep,cc_s_c)
./Kbuild:65: $(call if_changed_dep,cc_s_c)
./arch/arm/imx-common/Makefile:48: $(call if_changed_dep,cpp_cfg)
./arch/sandbox/cpu/Makefile:22: $(call if_changed_dep,cc_os.o)
./arch/sandbox/cpu/Makefile:24: $(call if_changed_dep,cc_os.o)
./arch/sandbox/cpu/Makefile:33: $(call if_changed_dep,cc_eth-raw-os.o)
./examples/api/Makefile:64: $(call if_changed_dep,as_o_S)
./Makefile:1118: $(call if_changed_dep,cpp_lds)
./Makefile:1328: $(call if_changed_dep,cpp_lds)
检查以上所有对if_changed_dep
调用的地方,都有一个共同点。那就是新生成一个目标时,调用if_changed_dep
去生成它的依赖文件。
例如,
scripts/Makefile.lib
中将%.dts
编译输出为%.dtb
:
$(obj)/%.dtb: $(src)/%.dts FORCE$(call if_changed_dep,dtc)
scripts/Makefile.build
中将%.S
编译输出为%.o
:
$(obj)/%.o: $(src)/%.S FORCE$(call if_changed_dep,as_o_S)
scripts/Makefile.host
中将%.c
编译输出为可执行文件%
:`
$(host-csingle): $(obj)/%: $(src)/%.c FORCE$(call if_changed_dep,host-csingle)
以上所有对if_changed_dep
调用的地方,还有另外一个共同点,if_changed_dep
的调用也还有另外一个特别的地方,就是除了Makefile.host
中调用if-_changed_dep
,是将%.c
编译输出为%.o
外,还没有其它的调用是用于编译%.c
文件的。
Makefile.host
在Kbuild
体系中,用于编译在在主机上运行的程序,而不是编译u-boot
自身的文件。
2.1.2 rule_cc_o_c
调用fixdep
scripts/Makefile.build
中的匹配结果是自定义宏rule_cc_o_c
调用了fixdep
:
define rule_cc_o_c$(call echo-cmd,checksrc) $(cmd_checksrc) \$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \$(cmd_modversions) \$(call echo-cmd,record_mcount) \$(cmd_record_mcount) \scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \$(dot-target).tmp; \rm -f $(depfile); \mv -f $(dot-target).tmp $(dot-target).cmd
endef
进一步搜索对rule_cc_o_c
的调用:
ygu@ubuntu:/opt/work/u-boot/u-boot-2016.09$ grep -rnw rule_cc_o_c .
./scripts/Makefile.build:201:# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
./scripts/Makefile.build:266:define rule_cc_o_c
结果显示除了定义之外,并没有显示rule_cc_o_c
被引用。那换一种方式,搜索cc_o_c
:
ygu@ubuntu:/opt/work/u-boot/u-boot-2016.09$ grep -rnw cc_o_c .
./scripts/Makefile.build:268: $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
./scripts/Makefile.build:272: scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
./scripts/Makefile.build:281: $(call if_changed_rule,cc_o_c)
./scripts/Makefile.build:287: $(call if_changed_rule,cc_o_c)
./examples/api/Makefile:60: $(call if_changed_rule,cc_o_c)
得到5项搜索结果,其前两行实际上是宏rule_cc_o_c
定义本身,最后一行是u-boot
例子里面的调用,也可以忽略。
重点是scripts/Makefile.build
的中间两项:
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE$(call cmd,force_checksrc)$(call if_changed_rule,cc_o_c)# Single-part modules are special since we need to mark them in $(MODVERDIR)$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE$(call cmd,force_checksrc)$(call if_changed_rule,cc_o_c)@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
很显然,$(simple-used-m)
规则从字面上看是用于生成.ko
文件的,而u-boot
并不生成模块文件,所以实际上用于编译%.c
生成%.o
的是前一个规则。
2.1.3 fixdep
调用结论
从前两节的分析看,以下情况会调用fixdep
进行处理:
- 新生成一个目标时,调用
if_changed_dep
检测并更新依赖文件,其中if_changed_dep
会调用fixdep
去处理依赖文件,但是将用于生成u-boot
的%.c
文件编译为%.o
规则除外 - 将生成
u-boot
的%.c
编译为%.o
时会调用rule_cc_o_c
,rule_cc_o_c
中又会调用fixdep
生成%.o
的依赖文件.%.cmd
3. 如何调用?
通过fixdep.c
的usage()
函数,我们可以看到fixdep
的用法:
fixdep <depfile> <target> <cmdline>
fixdep
接收三个参数,分别是:
<depfile>
:编译产生的依赖文件*.d<target>
:编译生成的目标<cmdline>
:编译使用的命令
4. 输入和输出
看一看调用if_changed_dep
的实例:
修改if_changed_dep
中,显示调用fixdep
的命令,并保留原有的依赖文件:
if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \@set -e; \$(echo-cmd) $(cmd_$(1)); \echo 'call fixdep: scripts/basic/fixdep $(depfile) $@ "$(make-cmd)"';\scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\mv -f $(dot-target).tmp $(dot-target).cmd)
重新执行make rpi_3_32b_defconfig
,得到如下log:
ygu@fs-ygu:/opt/work/u-boot/u-boot-2016.09$ make rpi_3_32b_defconfigHOSTCC scripts/basic/fixdep
call fixdep: scripts/basic/fixdep scripts/basic/.fixdep.d scripts/basic/fixdep "cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c "HOSTCC scripts/kconfig/conf.o
call fixdep: scripts/basic/fixdep scripts/kconfig/.conf.o.d scripts/kconfig/conf.o "cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -I/usr/include/ncursesw -DCURSES_LOC="<ncurses.h>" -DLOCALE -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c"SHIPPED scripts/kconfig/zconf.tab.cSHIPPED scripts/kconfig/zconf.lex.cSHIPPED scripts/kconfig/zconf.hash.cHOSTCC scripts/kconfig/zconf.tab.o
call fixdep: scripts/basic/fixdep scripts/kconfig/.zconf.tab.o.d scripts/kconfig/zconf.tab.o "cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -I/usr/include/ncursesw -DCURSES_LOC="<ncurses.h>" -DLOCALE -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c"HOSTLD scripts/kconfig/conf
#
# configuration written to .config
#
从log可以看到,执行make rpi_3_32b_defconfig
一共调用了3次fixdep
,以处理scripts/basic/.fixdep.d
为例,调用的命令的参数分别为:
depfile = scripts/basic/.fixdep.d
target = scripts/basic/fixdep
cmdline = "cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c "
4.1 输入和输出
编译过程中生成的依赖文件.fixdep.d
作为输入,经过处理得到.fixdep.cmd
文件,对比其中的变化:
原来的.fixdep.d
:
fixdep.o: scripts/basic/fixdep.c /usr/include/stdc-predef.h \... \ /* 省略中间的若干头文件 *//usr/include/x86_64-linux-gnu/bits/in.h
新生成的.fixdep.cmd
:
cmd_scripts/basic/fixdep := "cc -Wp,-MD,...scripts/basic/fixdep.c"source_scripts/basic/fixdep := scripts/basic/fixdep.cdeps_scripts/basic/fixdep := xxx.h \$(wildcard include/config/his/driver.h) \$(wildcard include/config/my/option.h) \$(wildcard include/config/.h) \$(wildcard include/config/foo.h) \$(wildcard include/config/boom.h) \$(wildcard include/config/is/.h) \/usr/include/stdc-predef.h \... \ /* 省略中间的若干头文件,同.fixdep.d *//usr/include/x86_64-linux-gnu/bits/in.h \scripts/basic/fixdep: $(deps_scripts/basic/fixdep)$(deps_scripts/basic/fixdep):
新的.fixdep.cmd
中增加了跟目标相关的变量cmd_xxx
,source_xxx
,deps_xxx
和目标xxx
对deps_xxx
的依赖规则。
fixdep.c
的代码操作比较简单,这里略去对代码的分析。
>
**有个疑问,没搞懂
dep_xxx
开始部分匹配wildcard
包含的头文件到底是如何来的?
很明显,这部分是由use_config()
函数生成的,具体如何生成,大神们的请来指点下。**
4.2 .*.cmd
的引用
顶层Makefile是这样引用.*.cmd
文件的:
# read all saved command linestargets := $(wildcard $(sort $(targets)))
cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))ifneq ($(cmd_files),)$(cmd_files): ; # Do not try to update included dependency filesinclude $(cmd_files)
endif
根据待生成的目标targets
生成cmd_files
列表,然后用include
指令包含所有这些.*.cmd
文件。
以生成的arm/cpu/armv7/.start.o.cmd
为例,文件中包含:
cmd_arch/arm/cpu/armv7/start.o := arm-linux-gnueabi-gcc ... -c -o arch/arm/cpu/armv7/start.o arch/arm/cpu/armv7/start.Ssource_arch/arm/cpu/armv7/start.o := arch/arm/cpu/armv7/start.Sdeps_arch/arm/cpu/armv7/start.o := \$(wildcard include/config/omap44xx.h) \$(wildcard include/config/spl/build.h) \...arch/arm/cpu/armv7/start.o: $(deps_arch/arm/cpu/armv7/start.o)$(deps_arch/arm/cpu/armv7/start.o):
实际上只用到了依赖规则:
deps_arch/arm/cpu/armv7/start.o := \$(wildcard include/config/omap44xx.h) \$(wildcard include/config/spl/build.h) \...arch/arm/cpu/armv7/start.o: $(deps_arch/arm/cpu/armv7/start.o)$(deps_arch/arm/cpu/armv7/start.o):
对于cmd_arch/arm/cpu/armv7/start.o
和source_arch/arm/cpu/armv7/start.o
,u-boot编译时并没有用到。
至于cmd_xxx和source_xxx,我能够想到的用处就是存放一些编译用到的信息,例如cmd_xxx表示生成所用的命令,source_xxx表示生成目标的source code,如果想看某一个文件时如何生成的,去检查.*.cmd
文件就行了。其实这也是蛮有用的。
例如,我想看看文件u-boot.bin
是如何生成的,那就去检查.u-boot.bin.cmd
,一目了然了:
cmd_u-boot.bin := cp u-boot-nodtb.bin u-boot.bin
我去,编译生成的u-boot.bin
竟然是u-boot-nodtb.bin
通过cp
来的~~哈哈。
5. TL;DR
上面部分主要表述整个分析的过程,废话太多。以下简略说明重点。
编译时,编译器会根据选项-MD
自动生成依赖文件*.d
,用fixdep
更新*.d
文件生成新的依赖文件.*.cmd
。
fixdep
被两个地方调用:
rule_cc_o_c
:编译u-boot自身的*.c
文件时,rule_cc_o_c
调用fixdep
去更新生成%.c
的依赖文件.%.cmd
if_changed_dep
:适用于除了上述的rule_cc_o_c
外的其它目标依赖文件的生成,例如生成主机上执行的程序,处理dts文件等,也包括汇编文件生成*.o
,生成*.s
,*.lst
等。
通过查看fixdep
输出的.*.cmd
文件可以知道对应的目标文件*
是如何生成的。
u-boot-2016.09 make工具之fixdep相关推荐
- 2016.09.14,英语,《Using English at Work》全书笔记
半个月时间,听完了ESLPod出品的<Using English at Work>,笔记和自己听的时候的备注列在下面.准备把每个语音里的快速阅读部分截取出来,放在手机里反复听. 下一阶段把 ...
- 电大计算机网考怎么过,史上最牛--电大计算机网考小抄(考试必备)--2016.09.08【呕心沥血整理、电大考试必过】.doc...
史上最牛--电大计算机网考小抄(考试必备)--2016.09.08[呕心沥血整理.电大考试必过] 计算机网考Windows操作系统及其应用-选择题B A.Ctrl + Alt B.Ctrl + Shi ...
- Spring Boot Initilizr - 使用ThirdParty工具
Spring Boot Initilizr - 使用ThirdParty工具 这是我之前的两篇文章的延续.在阅读本文之前,请先阅读我之前在" Spring Boot Initilizr We ...
- 华为校招2016.09机试 第2题: 字符串查找
华为校招2016.09机试 第2题: 字符串查找 描述: 输入两个字符串,查找字符串1中与字符串2最先匹配的内容,将匹配的字符串输出.字符串2支持?通配符,?代表任意一个字符. 已知字符串2不可能出现 ...
- 滴滴2016.09.06校招 在线笔试 - 2道编程题
滴滴2016.09.06校招 在线笔试 - 2道编程题 1.连续子数组的最大和 题目描述 一个数组有N个元素,求连续子数组的最大和.例如:[-1,2,1],和最大的连续子数组为[2,1],其和为3. ...
- 菜鸟网络工程师的成长笔记——第19天(2016.09.05)
菜鸟网络工程师的成长笔记--第19天(2016.09.05) 不知道要有多久的浸润,才能算是精通web全栈开发 30.前端的日期选择插件 问题类型:前端 解决状态:已解决 问题描述 日期选择是web上 ...
- spring boot 文件上传工具类(bug 已修改)
以前的文件上传都是之前前辈写的,现在自己来写一个,大家可以看看,有什么问题可以在评论中提出来. 写的这个文件上传是在spring boot 2.0中测试的,测试了,可以正常上传,下面贴代码 第一步:引 ...
- spring boot 学习(七)小工具篇:表单重复提交
注解 + 拦截器:解决表单重复提交 前言 学习 Spring Boot 中,我想将我在项目中添加几个我在 SpringMVC 框架中常用的工具类(主要都是涉及到 Spring AOP 部分知识).比如 ...
- 2016/09/12
1. Python作业 HAproxy配置文件操作 -> 完成 def fetch(backend):result = []with open('ha.conf', 'r', encoding= ...
- Spring Boot(09)——使用SpringMVC
使用SpringMVC 使用SpringMVC最简单的方法是在pom.xml中加入spring-boot-starter-web依赖,这样Spring Boot的AutoConfiguration模块 ...
最新文章
- 开发日记-20190725 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 15
- xss劫持 HTML 表单,XSS 之 form表单劫持(通用明文记录)
- 服务器重启导致无法启动MySQL
- PS如何生成svg代码格式的path路径 - PS技巧篇
- 近期要养成的学习习惯
- 北语发布 | 汉语学习者文本多维标注数据集YACLC V1.0 -- 文本纠错方向
- Linux socket等于0,Linux系统环境下的Socket编程详细解析
- 数据库连接客户端 dbeaver 程序包以及使用说明
- Flume 1.8.0 用户指南(Flume 1.8.0 User Guide)
- Asp.Net服务器控件添加OnClientClick属性绑定
- 走进javascript——DOM事件
- 汽车主要电子控制系统模块
- java之uml类图的介绍
- 中台服务架构的一点思考
- PCL笔记二:PCD解析;PCD读取;PCD与XYZ转换;
- android蓝牙耳机来电铃声,Android实现积极连接蓝牙耳机
- CDMA HERT平台分布式基站 DBS3900 CDMA
- 首席新媒体运营黎想教程:线上活动推广策划及方案解析
- 华为 Eth-Trunk链路聚合
- 火影段位赛服务器响应超时,火影手游,谜一样的跨服积分赛已上线,奖励不到位惹人嫌弃...
热门文章
- 【深度学习入门案例】Senta情感分析
- 广东省的身份证号码开头
- word2010设置护眼背景
- This scheduler instance (...) is still active but was recovered by another instance in the cluste
- centos6.5 大于16T硬盘 分区和格式化挂载
- 13-02-uniapp供热服务接口配置
- 【JSON】JSON入门详解(一)
- docker学习(二)docker入门
- 【203】SSL证书常见格式转换
- 杭州逆行崩溃小伙首度回应