学习目标:

uboot顶层Makefile分析。

学习内容:

学习使用了正点原子的I.MX6ULL教程及开发平台。
uboot的make mx6ull_14x14_ddr512_emmc_defconfig配置过程

学习时间:

2022-06-05

学习产出:

1、make xxx_defconfig的过程
在顶层Makefile下有如下代码,

version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.hno-dot-config-targets := clean clobber mrproper distclean \help %docs check% coccicheck \ubootversion backup
$(info #########################1#############################)
$(info no-dot-config-targets=$(no-dot-config-targets))
$(info MAKECMDGOALS=$(MAKECMDGOALS))config-targets := 0
mixed-targets  := 0
dot-config     := 1ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)dot-config := 0endif
endif
$(info dot-config=$(dot-config))
$(info KBUILD_EXTMOD=$(KBUILD_EXTMOD))ifeq ($(KBUILD_EXTMOD),)ifneq ($(filter config %config,$(MAKECMDGOALS)),)config-targets := 1ifneq ($(words $(MAKECMDGOALS)),1)mixed-targets := 1endifendif
endif
$(info config-targets=$(config-targets))
$(info mixed-targets=$(mixed-targets))ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.PHONY += $(MAKECMDGOALS) __build_one_by_one$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one@:__build_one_by_one:$(Q)set -e; \for i in $(MAKECMDGOALS); do \$(MAKE) -f $(srctree)/Makefile $$i; \doneelse
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config targetKBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIGconfig: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@else
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
-include include/config/auto.conf.cmd# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig@# If the following part fails, include/config/auto.conf should be@# deleted so "make silentoldconfig" will be re-run on the next build.$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \{ rm -f include/config/auto.conf; false; }@# include/config.h has been updated after "make silentoldconfig".@# We need to touch include/config/auto.conf so it gets newer@# than include/config.h.@# Otherwise, 'make silentoldconfig' would be invoked twice.$(Q)touch include/config/auto.conf-include include/autoconf.mk
-include include/autoconf.mk.dep# We want to include arch/$(ARCH)/config.mk only when include/config/auto.conf
# is up-to-date. When we switch to a different board configuration, old CONFIG
# macros are still remaining in include/config/auto.conf. Without the following
# gimmick, wrong config.mk would be included leading nasty warnings/errors.
ifneq ($(wildcard $(KCONFIG_CONFIG)),)
ifneq ($(wildcard include/config/auto.conf),)
autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \include/config/auto.conf)
$(info autoconf_is_old=$(autoconf_is_old))
ifeq ($(autoconf_is_old),)
$(info ##########################################2################################################)
include config.mk
include arch/$(ARCH)/Makefile
endif
endif
endif

首先定义了两个变量,

version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h

version_h 变量是保存uboot的版本号文件,此文件在make时才能自动生成。
timestamp_h 变量是保存ubot的时间戳文件,此文件在make时才能自动生成。
接下来定义了变量no-dot-config-targets := clean clobber mrproper distclean
help %docs check% coccicheck ubootversion backup
定义变量config-targets初值为0;
定义变量mixed-targets初值为0;
定义变量dot-config初值为1。
然后判断MAKECMDGOALS中是否有符合no-dot-config-targets的,此时的MAKECMDFLASG的值为mx6ull_14x14_ddr512_emmc_defconfig,不满足条件判断,dot-config的值仍然为1。
之后判断KBUILD_EXTMOD是否为空,从前面章节的分析中可知,KBUILD_EXTMOD是关于模块编译的,未用模块编译,其值为空,满足判断条件,后面再判断,MAKECMDGOALS中是否有符合config和%config的部分,很明显条件成立,此时config-targets的值变为1,然后继续判断MAKECMDGOALS变量中的单词数是否为1,此处单词数为1,判断条件不成立。mixed-targets的值仍为0。
下面根据config-targets、mixed-targets、dot-config的值进入ifeq…else ifeq判断,这里进入else ifeq ($(config-targets),1)之中。
首先给变量KBUILD_DEFCONFIG赋值为sandbox_defconfig,然后导出变量,KBUILD_DEFCONFIG值为sandbox_defconfig,KBUILD_KCONFIG值为空。
因为我们make的目标为mx6ull_14x14_ddr512_emmc_defconfig,所以不会执行下面的语句:

config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@

直接匹配进入下面的语句执行,后面的else ifeq将不再执行。

%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@

可以看出匹配的目标中有三个依赖分别为scripts_basic 、outputmakefile 和FORCE,一条规则为$(Q)$(MAKE) $(build)=scripts/kconfig $@
1.1 FORCE
在顶层Makefile中有如下代码:

PHONY += FORCE
FORCE:

可以看出FORCE是没有依赖和规则的,所以每此都会执行FORCE。当FORCE作为其他目标的依赖时,由于FORCE总是被更新的,因此依赖所在的规则总是会执行的。
1.2 outputmakefile
在顶层Makefile中规则outputmakefile作为目标有如下代码:

PHONY += outputmakefile
outputmakefile:
ifneq ($(KBUILD_SRC),)$(Q)ln -fsn $(srctree) source$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

outputakefile作为目标时没有依赖,因此也总是会被更新的,首先判断变量KBUILD_SRC是否为空,没有设置KBUILD_SRC的值,因此KBUILD_SRC的值空,所以判断条件不成立,依赖outputmakefile直接结束。
1.3 scripts_basic
在顶层makefile下有如下代码,

PHONY += scripts_basic
scripts_basic:$(Q)$(MAKE) $(build)=scripts/basic$(Q)rm -f .tmp_quiet_recordmcount

scripts_basic作为目标时,也没有依赖,一次总是被更新的。其中包含两条规则。从前面章节的分析可知,$(Q)为空。$(MAKE)就是make。而build在文件
scripts/Kbuild.include中有定义,顶层Makefile中也包含了此文件include scripts/Kbuild.include。而在scripts/Kbuild.include文件中对build有如下定义:

# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj

而srctree为顶层Makefile导出的变量值为.,所以,build := -f ./scripts/Makefile.build obj,回到scripts_basic的规则中,其规则经过展开为:

scripts_basic:
make -f ./scripts/Makefile.build obj=scripts/basic
rm -f . tmp_quiet_recordmcount

scripts_basic会调用./scripts/Makefile.build文件,且传入的参数值为obj=scripts/basic。
进入./scripts/Makefile.build文件中,首先有如下代码:

# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif

首先,定义了变量prefix 的值为tpl,然后定义变量src,这里用到了函数patsubst。此函数的格式如下:

$(patsubst <pattern>,<replacement>,<text>)

此函数用于在text中查找符合patttern的部分,如果匹配的话就用replacement替换掉。pattern是可以包含通配符"%“,如果在replacement中也包含通配符”%“,那么replacement中的这个”%“,将是pattern中的那个”%"所代表的字符串。函数的返回值就是替换后的字符串。因此,$(patsubst $(prefix)/%,%,$(obj))的意思就是在scripts/basic中查找符合tpl/%的部分然后替换掉,但是scripts/basic中没有tpl/%,所以src=scripts/basic。
接下来判断obj的值和src的值是否相等,很明显此处条件成立,继续执行。prefix的值变为了spl。继续执行src := $(patsubst $(prefix)/%,%,$(obj)),src的值仍为src=scripts/basic。
再继续obj和src的值相等,所以,prefix=.。
继续向下有如下代码:

# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)

将kbuild-dir展开后的结果为:

$(if $(filter /%,scripts/basic),scripts/basic,./scripts/basic)

因为没有以/%开头的单词,所以$(filter /%,scripts/basic)的值为空,kbuild-dir的值为./scripts/basic,kbuild-dir:=./scripts/basic
将kbuild-file展开后为:

$(if $(wildcard ./scripts/basic/Kbuild),./scripts/basic/Kbuild,./scripts/basic/Makefile)

因为./scripts/basic/下没有Kbuild这个文件,所以kbuild-file的值为./scripts/basic/Makefile,kbuild-file:=./scripts/basic/Makefile
下面的include $(kbuild-file),变为了include ./scripts/basic/Makefile,也就是读取./scripts/basic下面的Makefile文件。
继续向下会有如下代码:

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \$(subdir-ym) $(always)@:

因为在顶层Makefile执行make -f ./scripts/Makefile.build obj=scripts/basic时,没有指明目标,所以会使用__build作为默认目标,在顶层Makefile导出的变量中,KBUILD_BUILTIN的值为1,KBUILD_MODULES为空。因此将目标展开后为:

__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:

可以看出有五个依赖,$(builtin-target),$(lib-target),$(extra-y)),$(subdir-ym),$(always),将这五个依赖的值直接打印出来,如图所示:

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \$(subdir-ym) $(always)@:@echo builtin-target=$(builtin-target)@echo lib-target=$(lib-target)@echo extra-y=$(extra-y)@echo subdir-ym=$(subdir-ym)@echo always=$(always)

其结果如图所示:

可以看出只有always有值。
由此可见,__build最终变为:

__build: scripts/basic/fixdep@:

__build的最终依赖为scripts/basic/fixdep。因此就会编译scripts/basic/fixdep.c这个文件,最终生成scripts/basic/fixdep这个软件,用于再构建过程中生成依赖项信息。
1.4、%config的规则
回到顶层Makefile中,%config的三个依赖已经分析完了,下面看规则,内容如下。

%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@

将规则展开就为:

make -f ./scripts/Makefile.build obj=scripts/kconfig mx6ull_14x14_ddr512_emmc_defconfig

同样进入./scripts/Makefile.build文件中,此时:

src= scripts/kconfig
kbuild-dir = ./scripts/kconfig
kbuild-file = ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile

可以看出,Makefile.build会读取./scripts/kconfig/Makefile中的内容,此Makefile中有如下代码:

%_defconfig: $(obj)/conf$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

目标%_defconfig刚好和我们输入的mx6ull_14x14_ddr512_emmc_defconfig相匹配,所以会执行这条规则。其依赖为$(obj)/conf,展开后就是scripts/kconfig/conf。下面就是检查并生成依赖 scripts/kconfig/conf。conf 是主机软件这里先到此为止,conf工具从根目录开始树状读取默认的Kconfig文件,分析其配置保存在内存里,分析完默认的Kconfig文件后再读取指定的xxx_defconfig文件,更新得到最终的符号表,并输出到.config文件中。
得到 scripts/kconfig/conf 以后就要执行目标%_defconfig 的命令:

$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

相关变量的值如下:
silent=
SRCARCH=…
Kconfig=Kconfig
将其展开就是:

scripts/kconfig/conf --defconfig=arch/../configs/mx6ull_14x14_ddr512_emmc_defconfig Kconfig

这里会将mx6ull_alientek_emmc_defconfig 中的配置输出到.config 文件中,最终生成 uboot 根目录下的.config 文件。

uboot-Makefile学习(4)相关推荐

  1. U-boot 顶层Makefile 学习(1)

    U-boot 顶层Makefile 学习(1) Makefile可以说是学习路上的难点之一,刚开始看视频学习时,很难跟得上讲师的步伐,虽然讲的很详细,但是由于没有Makefile基础,理解较为困难.建 ...

  2. Makefile学习笔记 - 我的CPP之路 - C++博客

    Makefile学习笔记 - 我的CPP之路 - C++博客 Makefile学习笔记 Makefile学习笔记 先列出一个很简单的Makefile例子: --------- hd.cpp #incl ...

  3. Makefile学习笔记-备忘

    2019独角兽企业重金招聘Python工程师标准>>> ##makefile学习 makefile是编译C和C++文件依赖的脚本文件 ###基本语法 target... : prer ...

  4. zz Makefile学习教程: 跟我一起写 Makefile

    Makefile学习教程: 跟我一起写 Makefile 转载于:https://www.cnblogs.com/bioinfo/archive/2008/07/07/1237522.html

  5. 从零开始的UBOOT的学习8--命令体系

    从零开始的UBOOT的学习8--命令体系 参考朱有鹏UBOOT全集的一部分 1.从UBOOT的启动阶段的第二流程到命令体系 (1)在UBOOT中使用一个死循环,实现了命令体系: 在这个main_loo ...

  6. arm linux 移植过程——uboot makefile注释

    uboot makefile注释 为什么要注释uboot的Makefile呢?这是一个玄学问题,首先,我本人对make的工作机制比较清楚,但是从来没自己写过Makefile,而且很多语法在配置编译条件 ...

  7. Makefile学习笔记07|编译静态库并通过ifeq语句

    Makefile学习笔记07|编译静态库并通过ifeq语句   希望看到这篇文章的朋友能在评论区留下宝贵的建议来让我们共同成长,谢谢.   这里是目录   本篇与上一篇有较多联系,有兴趣的可以先看上一 ...

  8. Makefile学习笔记06|编译动态链接库

    Makefile学习笔记06|编译动态链接库   希望看到这篇文章的朋友能在评论区留下宝贵的建议来让我们共同成长,谢谢.   这里是目录 静态链接与动态链接   链接分为两种:静态链接.动态链接. 静 ...

  9. [转]Windows平台下Makefile学习笔记

    Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译 ...

  10. Makefile 学习笔记

    Makefile学习笔记 1. gcc编译过程 预处理 gcc -E hello.c -o hello.i 编译 gcc -S hello.i -o hello.s 汇编 gcc -c hello.s ...

最新文章

  1. 图像配准----RANSAC
  2. JMH 和 Arthas 定位问题的案例分享 !
  3. 医药信息化:GMP/GSP之后
  4. PostgreSQL 11 100亿 tpcb 性能测试 on ECS
  5. Intel汇编语言程序设计学习-第四章 数据传送、寻址和算术运算-上
  6. 一套实用的数据中心设计方案
  7. 用Python实现快速排序
  8. 钉钉api 获取 accesstoken_Thinkphp5.X异常接管后通过钉钉机器人推送通知
  9. php 环境优化,Nginx与PHP-fpm环境在大流量下的优化配置
  10. webpack2 项目构建一
  11. 操作系统-Windows操作系统的线程调度了解这些
  12. 论文阅读:A Progressive Architecture With Knowledge Review Network for Salient Object Detection
  13. wpf 开发 -TextBox背景自定义-Decorator
  14. LBMALL V3.1.1 多用户商城系统功能说明
  15. 密西西比河谷州立大学:Android应用程序开发(五)
  16. 10个在线正则表达式测试网站推荐
  17. mfc程序退出时删除托盘图标
  18. 看完《奇葩说》,还有一个千亿级的市场故事可以说说
  19. java画球_我的世界 如何用指令画球 JAVA 1.13+
  20. 计算机网络三大必备书,网络十大神书据说都看过的可以成仙

热门文章

  1. 即将搭载人工智能芯片的华为Mate10,究竟会为业界带来什么?
  2. 外贸财务英语-支票用语
  3. 服务器i文件夹,IBM i上http server实用技巧之一:访问IBM i多文件系统
  4. 纯前端 导出excel 插件xlsx和file-saver
  5. js学习笔记(1)什么是JavaScript
  6. JMockit 如何 mock 异常
  7. Python高效实现滑块验证码自动操纵
  8. win10电脑pppoe拨号模块损坏_系统pppoe拨号模块损坏怎么办
  9. 【学习总结】数学-lucas定理
  10. 一款非常不错的微信系统垃圾清理工具:微信清理大师,操作简单,清除较快。