- 1. 前言
- 2. 概述
- 3. 目标$(version_h)
- 3.1 $(version_h)依赖分析
- 3.1.1 依赖include/config/uboot.release
- 3.1.2 依赖FORCE
- 3.2 $(version_h)规则分析
- 4. 目标$(timestamp_h)
- 4.1 $(timestamp_h)依赖分析
- 4.2 $(timestamp_h)规则分析
UBOOT版本:uboot2018.03,开发板myimx8mmek240。2. 概述
在编译uboot的过程中,有两个特别的依赖version_h 和 timestamp_h,它们定义在顶层Makefile中(这里只讲解编译直接在源目录的情况,即srctree 为空),如下:
# 顶层Makefile version_h := include/generated/version_autogenerated.h timestamp_h := include/generated/timestamp_autogenerated.h ...... $(version_h): include/config/uboot.release FORCE $(call filechk,version.h) $(timestamp_h): $(srctree)/Makefile FORCE $(call filechk,timestamp.h)
3. 目标$(version_h)
# 顶层Makefile $(version_h): include/config/uboot.release FORCE $(call filechk,version.h)3.1 $(version_h)依赖分析 3.1.1 依赖include/config/uboot.release
使用scripts/setlocalversion工具来生成include/config/uboot.release,只是一个版本号,不需要特别关注,参见LINUX 内核编译 LOCALVERSION 配置(分析内核版本号自动添加的"+"号):https://www.freesion.com/article/8993880966/。
# 顶层Makefile # Store (new) UBOOTRELEASE string in include/config/uboot.release include/config/uboot.release: include/config/auto.conf FORCE $(call filechk,uboot.release)
include/config/uboot.release定义在顶层Makefile中,该目标又依赖于include/config/auto.conf(参见UBOOT编译— include/config/auto.conf、 include/config/auto.conf.cmd、 include/generated/autoconf.h (二)) 和 FORCE。
接下来我们看规则$(call filechk,uboot.release):
#note:scripts/Kbuild.include ### # filechk is used to check if the content of a generated file is updated. # Sample usage: # define filechk_sample # echo $KERNELRELEASE # endef # version.h : Makefile # $(call filechk,sample) # The rule defined shall write to stdout the content of the new file. # The existing file will be compared with the new one. # - If no file exist it is created # - If the content differ the new file is used # - If they are equal no change, and no timestamp update # - stdin is piped in from the first prerequisite ($<) so one has # to specify a valid file as first prerequisite (often the kbuild file) define filechk $(Q)set -e; $(kecho) ' CHK $@'; mkdir -p $(dir $@); $(filechk_$(1)) < $< > $@.tmp; if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else $(kecho) ' UPD $@'; mv -f $@.tmp $@; fi endef
上述代码中:
- ‘$@’ :目标include/config/uboot.release ;
- ‘$(1)’ :第一个参数uboot.release;
- ‘$ <’ :第一个依赖include/config/auto.conf ;
- ‘filechk_$(1)’ :filechk_uboot.release;
filechk_uboot.release定义在顶层Makefile中:
#note:顶层Makefile # Read UBOOTRELEASE from include/config/uboot.release (if it exists) UBOOTRELEASE = $(shell cat include/config/uboot.release 2> /dev/null) UBOOTVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION) ...... define filechk_uboot.release echo "$(UBOOTVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" endef
全部展开,具体编译命令如下:
set -e; : ' CHK include/config/uboot.release'; mkdir -p include/config/; echo "2018.03$(/bin/sh ./scripts/setlocalversion .)" < include/config/auto.conf > include/config/uboot.release.tmp; if [ -r include/config/uboot.release ] && cmp -s include/config/uboot.release include/config/uboot.release.tmp; then rm -f include/config/uboot.release.tmp; else : ' UPD include/config/uboot.release'; mv -f include/config/uboot.release.tmp include/config/uboot.release; fi
最终产生的include/config/uboot.release内容如下:
参见UBOOT编译— make xxx_deconfig过程详解(一) 4.3小节 - 依赖 FORCE。
接下来我们看规则$(call filechk,version.h):
#note:scripts/Kbuild.include ### # filechk is used to check if the content of a generated file is updated. # Sample usage: # define filechk_sample # echo $KERNELRELEASE # endef # version.h : Makefile # $(call filechk,sample) # The rule defined shall write to stdout the content of the new file. # The existing file will be compared with the new one. # - If no file exist it is created # - If the content differ the new file is used # - If they are equal no change, and no timestamp update # - stdin is piped in from the first prerequisite ($<) so one has # to specify a valid file as first prerequisite (often the kbuild file) define filechk $(Q)set -e; $(kecho) ' CHK $@'; mkdir -p $(dir $@); $(filechk_$(1)) < $< > $@.tmp; if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else $(kecho) ' UPD $@'; mv -f $@.tmp $@; fi endef
上述代码中:
- ‘$@’ :目标include/generated/version_autogenerated.h;
- ‘$(1)’ :第一个参数version.h;
- ‘$ <’ :第一个依赖include/config/uboot.release;
- ‘filechk_$(1)’ :filechk_version.h;
filechk_version.h定义在顶层Makefile中:
#note:顶层Makefile define filechk_version.h (echo #define PLAIN_VERSION "$(UBOOTRELEASE)"; echo #define U_BOOT_VERSION "U-Boot " PLAIN_VERSION; echo #define CC_VERSION_STRING "$$(LC_ALL=C $(CC) --version | head -n 1)"; echo #define LD_VERSION_STRING "$$(LC_ALL=C $(LD) --version | head -n 1)"; ) endef
这上面主要时输出uboot版本和编译器版本。整个命令的流程如下:
(1)打印 ’ CHK include/generated/version_autogenerated.h’;
(2)创建include/generated/目录;
(3)输出指定信息到include/generated/version_autogenerated.h中;
(4)如果include/generated/version_autogenerated.h 文件存在,且与include/generated/version_autogenerated.h.tmp相同,则直接删除include/generated/version_autogenerated.h.tmp;
(5)如果4不成立,打印’ UPD include/generated/version_autogenerated.h’,并把include/generated/version_autogenerated.h.tmp更名为include/generated/version_autogenerated.h。
使用cmp命令比较include/generated/version_autogenerated.h include/generated/version_autogenerated.h.tmp两个文件(Linux中的cmp命令用于比较两个文件的不同,若发现两个文件有不同支出,则会标出来第一处不同的位置和列数编号;s或--quiet或--silent: 不显示错误信息)
全部展开,具体编译命令如下:
set -e; : ' CHK include/generated/version_autogenerated.h'; mkdir -p include/generated/; (echo #define PLAIN_VERSION "2018.03"""; echo #define U_BOOT_VERSION "U-Boot " PLAIN_VERSION; echo #define CC_VERSION_STRING "$(LC_ALL=C /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc --version | head -n 1)"; echo #define LD_VERSION_STRING "$(LC_ALL=C /home/h/my-work/03_toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-ld.bfd --version | head -n 1)"; ) < include/config/uboot.release > include/generated/version_autogenerated.h.tmp; if [ -r include/generated/version_autogenerated.h ] && cmp -s include/generated/version_autogenerated.h include/generated/version_autogenerated.h.tmp; then rm -f include/generated/version_autogenerated.h.tmp; else : ' UPD include/generated/version_autogenerated.h'; mv -f include/generated/version_autogenerated.h.tmp include/generated/version_autogenerated.h; fi
include/generated/version_autogenerated.h内容如下:
# 顶层Makefile $(timestamp_h): $(srctree)/Makefile FORCE $(call filechk,timestamp.h)4.1 $(timestamp_h)依赖分析
目标 timestamp_h依赖$(srctree)/Makefile 和FORCE。假设直接在源目录编译,顶层Makefile存在,依赖FORCE见UBOOT编译— make xxx_deconfig过程详解(一) 4.3小节 - 依赖 FORCE。
接下来我们看规则$(call filechk,timestamp.h):
#note:scripts/Kbuild.include ### # filechk is used to check if the content of a generated file is updated. # Sample usage: # define filechk_sample # echo $KERNELRELEASE # endef # version.h : Makefile # $(call filechk,sample) # The rule defined shall write to stdout the content of the new file. # The existing file will be compared with the new one. # - If no file exist it is created # - If the content differ the new file is used # - If they are equal no change, and no timestamp update # - stdin is piped in from the first prerequisite ($<) so one has # to specify a valid file as first prerequisite (often the kbuild file) define filechk $(Q)set -e; $(kecho) ' CHK $@'; mkdir -p $(dir $@); $(filechk_$(1)) < $< > $@.tmp; if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else $(kecho) ' UPD $@'; mv -f $@.tmp $@; fi endef
上述代码中:
- ‘$@’ :目标timestamp_h (include/generated/timestamp_autogenerated.h);
- ‘$(1)’ :第一个参数timestamp.h;
- ‘$ <’ :第一个依赖$(srctree)/Makefile ;
- ‘filechk_$(1)’ :filechk_timestamp.h;
filechk_timestamp.h定义在顶层Makefile中:
#note:顶层Makefile
define filechk_timestamp.h
(if test -n "$${SOURCE_DATE_EPOCH}"; then
SOURCE_DATE="@$${SOURCE_DATE_EPOCH}";
DATE="";
for date in gdate date.gnu date; do
$${date} -u -d "$${SOURCE_DATE}" >/dev/null 2>&1 && DATE="$${date}";
done;
if test -n "$${DATE}"; then
LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DATE "%b %d %C%y"';
LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TIME "%T"';
LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TZ "%z"';
LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DMI_DATE "%m/%d/%Y"';
LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_BUILD_DATE 0x%Y%m%d';
else
return 42;
fi;
else
LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"';
LC_ALL=C date +'#define U_BOOT_TIME "%T"';
LC_ALL=C date +'#define U_BOOT_TZ "%z"';
LC_ALL=C date +'#define U_BOOT_DMI_DATE "%m/%d/%Y"';
LC_ALL=C date +'#define U_BOOT_BUILD_DATE 0x%Y%m%d';
fi)
endef
这上面首先判断在环境变量中是否定义了 SOURCE_DATE_EPOCH ,有则使用 SOURCE_DATE_EPOCH 生成时间戳,没有则使用当前时间。有些编译环境会设置,这个目前我所了解的作用是保证uboot二进制一致性会用到(有机会我们后面会针对镜像二进制一致性单独写一篇)。LC_ALL=C 是为了去除所有本地化的设置,让命令能正确执行。date命令的功能是显示和设置系统日期和时间,使用规则可以参见:linux date命令。在我所使用的的平台暂时没有定义,因此走else分支。整个命令的流程如下:
(1)打印 ’ CHK include/generated/timestamp_autogenerated.h’;
(2)创建include/generated/目录;
(3)通过date命令,定义几个宏定义,并输出到include/generated/timestamp_autogenerated.h.tmp中;
(4)如果include/generated/timestamp_autogenerated.h 文件存在,且与include/generated/timestamp_autogenerated.h.tmp相同,则直接删除include/generated/timestamp_autogenerated.h.tmp;
(5)如果4不成立,打印’ UPD include/generated/timestamp_autogenerated.h’,并把include/generated/timestamp_autogenerated.h.tmp更名为include/generated/timestamp_autogenerated.h。
使用cmp命令比较include/generated/timestamp_autogenerated.h include/generated/timestamp_autogenerated.h.tmp两个文件(Linux中的cmp命令用于比较两个文件的不同,若发现两个文件有不同支出,则会标出来第一处不同的位置和列数编号;s或--quiet或--silent: 不显示错误信息)
全部展开,具体编译命令如下:
set -e; : ' CHK include/generated/timestamp_autogenerated.h'; mkdir -p include/generated/; (if test -n "${SOURCE_DATE_EPOCH}"; then SOURCE_DATE="@${SOURCE_DATE_EPOCH}"; DATE=""; for date in gdate date.gnu date; do ${date} -u -d "${SOURCE_DATE}" >/dev/null 2>&1 && DATE="${date}"; done; if test -n "${DATE}"; then LC_ALL=C ${DATE} -u -d "${SOURCE_DATE}" +'#define U_BOOT_DATE "%b %d %C%y"'; LC_ALL=C ${DATE} -u -d "${SOURCE_DATE}" +'#define U_BOOT_TIME "%T"'; LC_ALL=C ${DATE} -u -d "${SOURCE_DATE}" +'#efine U_BOOT_TZ "%z"'; LC_ALL=C ${DATE} -u -d "${SOURCE_DATE}" +'#define U_BOOT_DMI_DATE "%m/%d/%Y"'; LC_ALL=C ${DATE} -u -d "${SOURCE_DATE}" +'#define U_BOOT_BUILD_DATE 0x%Y%m%d'; else return 42; fi; else LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"'; LC_ALL=C date +'#define U_BOOT_TIME "%T"'; LC_ALL=C date +'#define U_BOOT_TZ "%z"'; LC_ALL=C date +'#define U_BOOT_DMI_DATE "%m/%d/%Y"'; LC_ALL=C date +'#define U_BOOT_BUILD_DATE 0x%Y%m%d'; fi) < Makefile > include/generated/timestamp_autogenerated.h.tmp; if [ -r include/generated/timestamp_autogenerated.h ] && cmp -s include/generated/timestamp_autogenerated.h include/generated/timestamp_autogenerated.h.tmp; then rm -f include/generated/timestamp_autogenerated.h.tmp; else : ' UPD include/generated/timestamp_autogenerated.h'; mv -f include/generated/timestamp_autogenerated.h.tmp include/generated/timestamp_autogenerated.h; fi
include/generated/timestamp_autogenerated.h内容如下:



