• u-boot-201609 make工具之fixdep

    • 概述
    • 哪里调用
      • 1 直接搜索fixdep

        • 11 if_changed_dep调用fixdep
        • 12 rule_cc_o_c调用fixdep
      • 13 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.hostKbuild体系中,用于编译在在主机上运行的程序,而不是编译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_crule_cc_o_c中又会调用fixdep生成%.o的依赖文件.%.cmd

3. 如何调用?

通过fixdep.cusage()函数,我们可以看到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_xxxsource_xxxdeps_xxx和目标xxxdeps_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.osource_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相关推荐

  1. 2016.09.14,英语,《Using English at Work》全书笔记

    半个月时间,听完了ESLPod出品的<Using English at Work>,笔记和自己听的时候的备注列在下面.准备把每个语音里的快速阅读部分截取出来,放在手机里反复听. 下一阶段把 ...

  2. 电大计算机网考怎么过,史上最牛--电大计算机网考小抄(考试必备)--2016.09.08【呕心沥血整理、电大考试必过】.doc...

    史上最牛--电大计算机网考小抄(考试必备)--2016.09.08[呕心沥血整理.电大考试必过] 计算机网考Windows操作系统及其应用-选择题B A.Ctrl + Alt B.Ctrl + Shi ...

  3. Spring Boot Initilizr - 使用ThirdParty工具

    Spring Boot Initilizr - 使用ThirdParty工具 这是我之前的两篇文章的延续.在阅读本文之前,请先阅读我之前在" Spring Boot Initilizr We ...

  4. 华为校招2016.09机试 第2题: 字符串查找

    华为校招2016.09机试 第2题: 字符串查找 描述: 输入两个字符串,查找字符串1中与字符串2最先匹配的内容,将匹配的字符串输出.字符串2支持?通配符,?代表任意一个字符. 已知字符串2不可能出现 ...

  5. 滴滴2016.09.06校招 在线笔试 - 2道编程题

    滴滴2016.09.06校招 在线笔试 - 2道编程题 1.连续子数组的最大和 题目描述 一个数组有N个元素,求连续子数组的最大和.例如:[-1,2,1],和最大的连续子数组为[2,1],其和为3. ...

  6. 菜鸟网络工程师的成长笔记——第19天(2016.09.05)

    菜鸟网络工程师的成长笔记--第19天(2016.09.05) 不知道要有多久的浸润,才能算是精通web全栈开发 30.前端的日期选择插件 问题类型:前端 解决状态:已解决 问题描述 日期选择是web上 ...

  7. spring boot 文件上传工具类(bug 已修改)

    以前的文件上传都是之前前辈写的,现在自己来写一个,大家可以看看,有什么问题可以在评论中提出来. 写的这个文件上传是在spring boot 2.0中测试的,测试了,可以正常上传,下面贴代码 第一步:引 ...

  8. spring boot 学习(七)小工具篇:表单重复提交

    注解 + 拦截器:解决表单重复提交 前言 学习 Spring Boot 中,我想将我在项目中添加几个我在 SpringMVC 框架中常用的工具类(主要都是涉及到 Spring AOP 部分知识).比如 ...

  9. 2016/09/12

    1. Python作业 HAproxy配置文件操作 -> 完成 def fetch(backend):result = []with open('ha.conf', 'r', encoding= ...

  10. Spring Boot(09)——使用SpringMVC

    使用SpringMVC 使用SpringMVC最简单的方法是在pom.xml中加入spring-boot-starter-web依赖,这样Spring Boot的AutoConfiguration模块 ...

最新文章

  1. 开发日记-20190725 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 15
  2. xss劫持 HTML 表单,XSS 之 form表单劫持(通用明文记录)
  3. 服务器重启导致无法启动MySQL
  4. PS如何生成svg代码格式的path路径 - PS技巧篇
  5. 近期要养成的学习习惯
  6. 北语发布 | 汉语学习者文本多维标注数据集YACLC V1.0 -- 文本纠错方向
  7. Linux socket等于0,Linux系统环境下的Socket编程详细解析
  8. 数据库连接客户端 dbeaver 程序包以及使用说明
  9. Flume 1.8.0 用户指南(Flume 1.8.0 User Guide)
  10. Asp.Net服务器控件添加OnClientClick属性绑定
  11. 走进javascript——DOM事件
  12. 汽车主要电子控制系统模块
  13. java之uml类图的介绍
  14. 中台服务架构的一点思考
  15. PCL笔记二:PCD解析;PCD读取;PCD与XYZ转换;
  16. android蓝牙耳机来电铃声,Android实现积极连接蓝牙耳机
  17. CDMA HERT平台分布式基站 DBS3900 CDMA
  18. 首席新媒体运营黎想教程:线上活动推广策划及方案解析
  19. 华为 Eth-Trunk链路聚合
  20. 火影段位赛服务器响应超时,火影手游,谜一样的跨服积分赛已上线,奖励不到位惹人嫌弃...

热门文章

  1. 【深度学习入门案例】Senta情感分析
  2. 广东省的身份证号码开头
  3. word2010设置护眼背景
  4. This scheduler instance (...) is still active but was recovered by another instance in the cluste
  5. centos6.5 大于16T硬盘 分区和格式化挂载
  6. 13-02-uniapp供热服务接口配置
  7. 【JSON】JSON入门详解(一)
  8. docker学习(二)docker入门
  9. 【203】SSL证书常见格式转换
  10. 杭州逆行崩溃小伙首度回应