配置 uboot 的 vscode 工程
准备工作
- 对 uboot 进行一次编译;
- 在 vscode 的 remote-wsl 的状态下打开 u-boot-2020.07 目录;
屏蔽多余目录
-
在工程根目录新建 .vscode 目录
-
在 .vscode 目录中新建 “settings.json” 文件
files.exclude 排除左侧目录中的显示;
search.exclude 排除搜索结果中的显示,和 files.exclude 基本相同;
** 表示任意层级目录的通配,* 表示通配,
[0-9]
表示单字符在 0-9,[^abc]
表示单字符但不是 abc 中的任意一个;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
{ "files.exclude": { "**/.git": true, "**/.svn": true, "**/.hg": true, "**/CVS": true, "**/.DS_Store": true, "**/.gitignore": true, "**/*.o": true, "**/*.su": true, "**/*.cmd": true, "Licenses": true, ".git*": true, ".stamp*": true, "*.yml": true, // 排除 arch/* 无关目录得到 arch/arm "arch/{arc,m68k,microblaze,mips,nds32,nios2,powerpc,riscv,sandbox,sh,x86,xtensa}": true, // 排除 arch/arm/mach* 无关目录得到 arch/arm/mach-sunxi "arch/arm/mach-[^s]*": true, "arch/arm/mach-s[^u]*": true, "arch/arm/mach-su[^n]*": true, //"arch/arm/mach*": true, // 排除 arch/arm/cpu/* 无关目录得到 arch/arm/cpu/arm926ejs "arch/arm/cpu/{arm11,arm720t,arm920t,arm946es,arm1136,arm1176,armv7,armv7m,armv8,pxa,sa1100}": true, // 排除 arch/arm/dts/* 无关文件得到 arch/arm/dts/sunxi* "arch/arm/dts/[^.iMs]*": true, "arch/arm/dts/i[^n]*": true, "arch/arm/dts/M[^a]*": true, "arch/arm/dts/s[^u]*": true, "arch/arm/dts/su[^n]*": true, "arch/arm/dts/sun[^i]*": true, // 排除 arch/arm/include/asm 无关目录 "arch/arm/include/asm/{arch-am33xx,arch-armada*,arch-aspeed,arch-[b-r]*,arch-s[^u]*,arch-[t-z]*}": true, // 排除 board/* 无关目录得到 board/sunxi "board/[^s]*": true, "board/s[^u]*": true, "board/s[^u][^n]*": true, // 排除 configs/* 无关目录得到 configs/sunxi* "configs/[^s]*": true, "configs/s[^u]*": true, "configs/s[^u][^n]*": true }, "search.exclude": { "**/node_modules": true, "**/bower_components": true, "**/*.code-search": true, "**/.gitignore": true, "**/*.o": true, "**/*.su": true, "**/*.cmd": true, "Licenses": true, ".git*": true, ".stamp*": true, "*.yml": true, // 排除 arch/* 无关目录得到 arch/arm "arch/{arc,m68k,microblaze,mips,nds32,nios2,powerpc,riscv,sandbox,sh,x86,xtensa}": true, // 排除 arch/arm/mach* 无关目录得到 arch/arm/mach-sunxi "arch/arm/mach-[^s]*": true, "arch/arm/mach-s[^u]*": true, "arch/arm/mach-su[^n]*": true, //"arch/arm/mach*": true, // 排除 arch/arm/cpu/* 无关目录得到 arch/arm/cpu/arm926ejs "arch/arm/cpu/{arm11,arm720t,arm920t,arm946es,arm1136,arm1176,armv7,armv7m,armv8,pxa,sa1100}": true, // 排除 arch/arm/dts/* 无关文件得到 arch/arm/dts/sunxi* "arch/arm/dts/[^.iMs]*": true, "arch/arm/dts/i[^n]*": true, "arch/arm/dts/M[^a]*": true, "arch/arm/dts/s[^u]*": true, "arch/arm/dts/su[^n]*": true, "arch/arm/dts/sun[^i]*": true, // 排除 arch/arm/include/asm 无关目录 "arch/arm/include/asm/{arch-am33xx,arch-armada*,arch-aspeed,arch-[b-r]*,arch-s[^u]*,arch-[t-z]*}": true, // 排除 board/* 无关目录得到 board/sunxi "board/[^s]*": true, "board/s[^u]*": true, "board/s[^u][^n]*": true, // 排除 configs/* 无关目录得到 configs/sunxi* "configs/[^s]*": true, "configs/s[^u]*": true, "configs/s[^u][^n]*": true } }
uboot 顶层 Makefile 调用流程
初步走读
- 确定 uboot 编译工具;
- 确定顶层 Makefile 导入到子 Makefile 中的变量;
- 确定部分引入的子 Makefile 文件;
-
一般情况下,编译 uboot 的指令是:
调用
make
后,工具会去解析当前目录下的 Makefile;1
make ARCH=arm CROSS_COMPILE=arm-linux-
-
顶层 Makefile 如下:
-
设置编译器
HOSTARCH 由
uname -m
的结果经过转换后得到;如果目标 ARCH 的值和主机 ARCH 相等会直接使用主机编译器;
如果 CROSS_COMPILE 没有设置也会使用主机编译器;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# set default to nothing for native builds ifeq ($(HOSTARCH),$(ARCH)) CROSS_COMPILE ?= endif # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),) LD = $(CROSS_COMPILE)ld.bfd else LD = $(CROSS_COMPILE)ld endif CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm LDR = $(CROSS_COMPILE)ldr STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump
-
引入文件
从 scripts/Kbuild.include 文件引入封装好的定义:
1 2 3
# We need some generic definitions (do not try to remake the file). scripts/Kbuild.include: ; include scripts/Kbuild.include
引入 config.mk、arch/$(ARCH)/Makefile 文件:
1 2 3 4 5 6 7 8 9 10
ifneq ($(wildcard $(KCONFIG_CONFIG)),) ifneq ($(wildcard include/config/auto.conf),) autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \ include/config/auto.conf) ifeq ($(autoconf_is_old),) include config.mk include arch/$(ARCH)/Makefile endif endif endif
-
从 .config 文件引入环境变量
.config 文件经
make xxx_defconfig
生成;1 2
KCONFIG_CONFIG ?= .config export KCONFIG_CONFIG
-
导出给子 Makefile 使用
其中,
ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
这些变量没有直接在顶层 Makefile 中定义,而是在工程根目录下的 config.mk 中定义的。此外,还有如
KBUILD_KCONFIG
的变量也没有在顶层 Makefile 中定义,可能是需要调用 make 时传入;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
export HOST_ARCH export LC_COLLATE LC_NUMERIC export quiet Q KBUILD_VERBOSE export srctree objtree VPATH export KCONFIG_CONFIG export size_check export KBUILD_MODULES KBUILD_BUILTIN export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR export CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC export CPP AR NM LDR STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS export MAKE LEX YACC AWK PERL PYTHON PYTHON2 PYTHON3 export HOSTCXX KBUILD_HOSTCXXFLAGS CHECK CHECKFLAGS DTC DTC_FLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS export KBUILD_CFLAGS KBUILD_AFLAGS export CC_VERSION_TEXT export MODVERDIR export RCS_FIND_IGNORE export RCS_TAR_IGNORE export KBUILD_DEFCONFIG KBUILD_KCONFIG export EFI_LDS # Filename of EFI link script in arch/$(ARCH)/lib export EFI_CRT0 # Filename of EFI CRT0 in arch/$(ARCH)/lib export EFI_RELOC # Filename of EFU relocation code in arch/$(ARCH)/lib export CFLAGS_EFI # Compiler flags to add when building EFI app export CFLAGS_NON_EFI # Compiler flags to remove when building EFI app export EFI_TARGET # binutils target if EFI is natively supported export PLATFORM_LIBS export PLATFORM_LIBGCC tools-only: export TOOLS_ONLY=y tools-all: export HOST_TOOLS_ALL=y cross_tools: export CROSS_BUILD_TOOLS=y
-
包含自动创建的头文件(里面是一些宏定义)
version_autogenerated.h 保存版本号;
timestamp_autogenerated.h 保存时间戳;
1 2 3 4
version_h := include/generated/version_autogenerated.h timestamp_h := include/generated/timestamp_autogenerated.h defaultenv_h := include/generated/defaultenv_autogenerated.h dt_h := include/generated/dt.h
我编译后的 include/generated/version_autogenerated.h 如下:
1 2 3 4
#define PLAIN_VERSION "2020.07" #define U_BOOT_VERSION "U-Boot " PLAIN_VERSION #define CC_VERSION_STRING "arm-buildroot-linux-gnueabi-gcc.br_real (Buildroot -g1fae138) 8.4.0" #define LD_VERSION_STRING "GNU ld (GNU Binutils) 2.32"
我编译后的 include/generated/timestamp_autogenerated.h 如下:
1 2 3 4 5
#define U_BOOT_DATE "Apr 22 2021" #define U_BOOT_TIME "10:54:49" #define U_BOOT_TZ "+0800" #define U_BOOT_DMI_DATE "04/22/2021" #define U_BOOT_BUILD_DATE 0x20210422
-
-
工程根目录下的 config.mk:
- 该文件中设置了
ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
这些变量; - 形如 CONFIG_SYS_ARCH 的变量来自于工程根目录下的 .config 文件,在顶层 Makefile 中有调用该文件并导出到环境变量的操作;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
ARCH := $(CONFIG_SYS_ARCH:"%"=%) CPU := $(CONFIG_SYS_CPU:"%"=%) ifdef CONFIG_SPL_BUILD ifdef CONFIG_ARCH_TEGRA CPU := arm720t endif endif BOARD := $(CONFIG_SYS_BOARD:"%"=%) ifneq ($(CONFIG_SYS_VENDOR),) VENDOR := $(CONFIG_SYS_VENDOR:"%"=%) endif ifneq ($(CONFIG_SYS_SOC),) SOC := $(CONFIG_SYS_SOC:"%"=%) endif CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),) sinclude $(srctree)/arch/$(ARCH)/config.mk # include architecture dependend rules sinclude $(srctree)/$(CPUDIR)/config.mk # include CPU specific rules ifdef SOC sinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk # include SoC specific rules endif ifneq ($(BOARD),) ifdef VENDOR BOARDDIR = $(VENDOR)/$(BOARD) else BOARDDIR = $(BOARD) endif endif ifdef BOARD sinclude $(srctree)/board/$(BOARDDIR)/config.mk # include board specific rules endif
引入了如下文件:
1 2 3 4 5 6 7 8 9 10
sinclude $(srctree)/arch/$(ARCH)/config.mk sinclude $(srctree)/$(CPUDIR)/config.mk ifdef SOC sinclude $(srctree)/$(CPUDIR)/$(SOC)/config.mk endif ifdef BOARD sinclude $(srctree)/board/$(BOARDDIR)/config.mk endif
引入文件的翻译如下:
1 2 3 4
sinclude ./arch/arm/config.mk sinclude ./arch/arm/cpu/config.mk sinclude ./arch/arm/cpu/sunxi/config.mk sinclude ./board/sunxi/config.mk
- 该文件中设置了
make xxx_defconfig 过程
按照步骤剥析如下:
-
调用
make xxx_defconfig
会调用顶层 Makefile -
顶层 Makefile
Makefile 命令前加 @ 表示该命令执行但不打印;
$(Q) 在顶层赋值 @ 或空;
Makefile 中 $(MAKE) 是 make 工具中预置环境变量,存放 make 工具的路径;
$(srctree) 在顶层赋值 . 或 $(KBUILD_SRC);
$(build) 变量在 scripts/Kbuild.include 中声明,值为
-f $(srctree)/scripts/Makefile.build obj
;特别注意:
$(build)=scripts/kconfig
执行时定义了变量 obj=scripts/kconfig;1 2 3 4 5 6 7 8 9 10 11 12 13
scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic $(Q)rm -f .tmp_quiet_recordmcount outputmakefile: ifneq ($(KBUILD_SRC),) $(Q)ln -fsn $(srctree) source $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) endif %config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@
上面可以翻译为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
scripts_basic: @make -f ./scripts/Makefile.build obj=scripts/basic @rm -f . tmp_quiet_recordmcount # KBUILD_SRC 通过 make ARCH=arm CROSS_COMPILE=arm-linux- KBUILD_SRC=xxx 传入 # 如果指定了 KBUILD_SRC,将调用 KBUILD_SRC 目录中的脚本在当前目录中生成一个 Makefile # 事实上一般不会指定 KBUILD_SRC outputmakefile: ifneq ($(KBUILD_SRC),) # 为当前目录建立一个 source 的符号链接(-f 强制,-s 软链接,-n 链接视为目录) @ln -fsn $(KBUILD_SRC) source @/bin/bash $(KBUILD_SRC)/scripts/mkmakefile $(KBUILD_SRC) . 2020 07 endif # FORCE 没有构建命令 %config: scripts_basic outputmakefile FORCE @make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
-
scripts/Makefile.build(也是 Makefile 文件)
-
scripts/Makefile.build 中的 include 机制:
@make -f ./scripts/Makefile.build obj=xxxxx
执行时会给 obj 赋值;scripts/Makefile.build 对 obj 进行处理和判断后,最终包含了 obj 目录下的 Makefile 文件;
$(patsubst $(prefix)/%,%,$(obj))
的意思是把 obj 中所有满足 $(prefix)/xxx 的字符串全部变为 xxx;$(if condition,a,b)
的意思是 condition 为 true 时结果为 a,condition 为 false 时结果为 b;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# 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 # 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)
-
调用 scripts_basic 的过程(
@make -f ./scripts/Makefile.build obj=scripts/basic
):由传参可知 obj 为 scripts/basic,包含代码翻译为:
1 2 3 4 5 6 7 8
# scripts/basic 和 /scripts/basic 相等时 kbuild-dir 取 scripts/basic,反之取 ./scripts/basic kbuild-dir := $(if $(filter /%,scripts/basic),scripts/basic,./scripts/basic) # ./scripts/basic/Kbuild 存在时 kbuild-file 取 ./scripts/basic/Kbuild,反之取 ./scripts/basic/Makefile kbuild-file := $(if $(wildcard ./scripts/basic/Kbuild),./scripts/basic/Kbuild,./scripts/basic/Makefile) # 包含 ./scripts/basic/Makefile,等同把目标内容拷贝到这里 include ./scripts/basic/Makefile
在 ./scripts/basic/Makefile 中会给 always 赋值为 fixdep:
1 2 3 4 5
hostprogs-y := fixdep always := $(hostprogs-y) # fixdep is needed to compile other host programs $(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
再回到 scripts/Makefile.build 中,因为 make 时没有传入 target,故会去执行 ./scripts/Makefile.build 中的第一个 target——__build;
值得注意的是 ./scripts/Makefile.build 中有两个 __build 的 target,make 处理时会合并 target 的依赖项,并以后面出现的 target 操作为准;
1 2 3 4 5 6 7
PHONY := __build __build: __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \ $(subdir-ym) $(always) @:
加个打印可知 __build 的 5 个依赖项只有 always 非空,也就是最终生成了 ./scripts/basic/fixdep 文件;
-
调用 %config 的过程(
@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
):由传参可知 obj 为 scripts/kconfig,包含代码翻译为:
1 2 3 4 5 6 7 8
# scripts/kconfig 和 /scripts/kconfig 相等时 kbuild-dir 取 scripts/kconfig,反之取 ./scripts/kconfig kbuild-dir := $(if $(filter /%,scripts/kconfig),scripts/kconfig,./scripts/kconfig) # ./scripts/kconfig/Kbuild 存在时 kbuild-file 取 ./scripts/kconfig/Kbuild,反之取 ./scripts/kconfig/Makefile kbuild-file := $(if $(wildcard ./scripts/kconfig/Kbuild),./scripts/kconfig/Kbuild,./scripts/kconfig/Makefile) # 包含 ./scripts/kconfig/Makefile,等同把目标内容拷贝到这里 include ./scripts/kconfig/Makefile
在 ./scripts/kconfig/Makefile 可以找到目标 target——xxx_defconfig;
-
-
scripts/kconfig/Makefile:
首先是生成 conf 执行程序:
1 2 3 4
# conf: Used for defconfig, oldconfig and related targets # object files used by all kconfig flavours conf-objs := conf.o zconf.tab.o hostprogs-y := conf
接着调用 conf 处理 xxx_defconfig:
KBUILD_KCONFIG 顶层无定义,故这里值为 Kconfig;
obj 顶层定义值为 .;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# Set SRCARCH to .. fake this Makefile. SRCARCH := .. ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) else Kconfig := Kconfig endif ifeq ($(quiet),silent_) silent := -s endif %_defconfig: $(obj)/conf $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) # Added for U-Boot (backward compatibility) %_config: %_defconfig @:
上面的重要处理部分可翻译为:
也就是先生成
make xxx_defconfig
的依赖项 ./conf(scripts/kconfig/conf);然后当前目录下的 conf 解析 xxx_defconfig 和工程根目录下 Kconfig 生成 .config;
1 2
%_defconfig: ./conf @./conf -s --defconfig=arch/../configs/xxx_defconfig Kconfig
最终,可以得到 make xxx_defconfig
的执行流程图如下:
make menuconfig 过程
-
调用
make menuconfig
会调用顶层 Makefile -
顶层 Makefile
Makefile 命令前加 @ 表示该命令执行但不打印;
$(Q) 在顶层赋值 @ 或空;
Makefile 中 $(MAKE) 是 make 工具中预置环境变量,存放 make 工具的路径;
$(srctree) 在顶层赋值 . 或 $(KBUILD_SRC);
$(build) 变量在 scripts/Kbuild.include 中声明,值为
-f $(srctree)/scripts/Makefile.build obj
;特别注意:
$(build)=scripts/kconfig
执行时定义了变量 obj=scripts/kconfig;1 2 3 4 5 6 7 8 9 10 11 12 13
scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic $(Q)rm -f .tmp_quiet_recordmcount outputmakefile: ifneq ($(KBUILD_SRC),) $(Q)ln -fsn $(srctree) source $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) endif %config: scripts_basic outputmakefile FORCE $(Q)$(MAKE) $(build)=scripts/kconfig $@
上面可以翻译为:
KBUILD_SRC 为空,故 outputmakefile 没有实际执行的内容;
FORCE 也没有构建命令;
1 2 3 4 5 6
scripts_basic: @make -f ./scripts/Makefile.build obj=scripts/basic @rm -f . tmp_quiet_recordmcount %config: scripts_basic @make -f ./scripts/Makefile.build obj=scripts/kconfig menuconfig
-
scripts/Makefile.build(也是 Makefile 文件)
-
scripts/Makefile.build 中的 include 机制:
对该机制的分析在 make xxx_defconfig 过程中有写过,这里不赘述;
@make -f ./scripts/Makefile.build obj=xxxxx
执行时会给 obj 赋值;scripts/Makefile.build 对 obj 进行处理和判断后,最终包含了 obj 目录下的 Makefile 文件;
-
调用 scripts_basic 最终生成了 ./scripts/basic/fixdep 文件,这里也不赘述;
-
调用 %config 最终包含了 ./scripts/kconfig/Makefile(实际调用这个文件中的 menuconfig);
-
-
scripts/kconfig/Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# mconf: Used for the menuconfig target based on lxdialog hostprogs-y += mconf lxdialog := checklist.o inputbox.o menubox.o textbox.o util.o yesno.o mconf-objs := mconf.o zconf.tab.o $(addprefix lxdialog/, $(lxdialog)) HOSTLDLIBS_mconf = $(shell . $(obj)/.mconf-cfg && echo $$libs) $(foreach f, mconf.o $(lxdialog), \ $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/.mconf-cfg && echo $$$$cflags))) $(obj)/mconf.o: $(obj)/.mconf-cfg $(addprefix $(obj)/lxdialog/, $(lxdialog)): $(obj)/.mconf-cfg # check if necessary packages are available, and configure build flags define filechk_conf_cfg $(CONFIG_SHELL) $< endef $(obj)/.%conf-cfg: $(src)/%conf-cfg.sh FORCE $(call filechk,conf_cfg) menuconfig: $(obj)/mconf $< $(silent) $(Kconfig)
- 首先调用了
scripts/kconfig/mconf-cfg.sh
; - 接着在 scripts/kconfig 目录生成了 mconf 工具;
- 最后执行了
scripts/kconfig/mconf -s Kconfig
(Kconfig 来自工程根目录);
- 首先调用了
分析至此,在存在 mconf 的情况下,手动执行 scripts/kconfig/mconf -s Kconfig
的结果如下:
make 过程
通过编译输出信息进行分析
-
输入如下命令进行编译
uboot 的编译器(GCC)版本不能低于 6.0;
此处编译使用 buildroot 内部下载的交叉编译器;
1
make ARCH=arm CROSS_COMPILE=/home/jerry/vscode/mgp_r/buildroot-mangopi-r/output/host/bin/arm-buildroot-linux-gnueabi- V=1 > build.log
-
编译完成后,在 build.log 中搜索 “-o u-boot”
可知链接器 ld.bfd 根据 u-boot.lds 上的规则将 *.o 链接生成了 u-boot,其中符号地址等信息存储在了 u-boot.map 文件;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
arm-buildroot-linux-gnueabi-ld.bfd -pie --gc-sections -Bstatic --no-dynamic-linker -Ttext 0x81700000 \ -o u-boot -T u-boot.lds \ arch/arm/cpu/arm926ejs/start.o \ --start-group \ arch/arm/cpu/built-in.o \ arch/arm/cpu/arm926ejs/built-in.o \ arch/arm/lib/built-in.o \ arch/arm/mach-sunxi/built-in.o \ board/sunxi/built-in.o \ cmd/built-in.o \ common/built-in.o \ disk/built-in.o \ drivers/built-in.o \ drivers/dma/built-in.o \ drivers/gpio/built-in.o \ drivers/i2c/built-in.o \ drivers/net/built-in.o \ drivers/net/phy/built-in.o \ drivers/power/built-in.o \ drivers/power/battery/built-in.o \ drivers/power/domain/built-in.o \ drivers/power/fuel_gauge/built-in.o \ drivers/power/mfd/built-in.o \ drivers/power/pmic/built-in.o \ drivers/power/regulator/built-in.o \ drivers/serial/built-in.o \ drivers/spi/built-in.o \ drivers/usb/cdns3/built-in.o \ drivers/usb/common/built-in.o \ drivers/usb/dwc3/built-in.o \ drivers/usb/emul/built-in.o \ drivers/usb/eth/built-in.o \ drivers/usb/gadget/built-in.o \ drivers/usb/gadget/udc/built-in.o \ drivers/usb/host/built-in.o \ drivers/usb/musb-new/built-in.o \ drivers/usb/musb/built-in.o \ drivers/usb/phy/built-in.o \ drivers/usb/ulpi/built-in.o \ env/built-in.o \ fs/built-in.o \ lib/built-in.o \ net/built-in.o \ --end-group \ arch/arm/lib/eabi_compat.o \ arch/arm/lib/lib.a \ -Map u-boot.map
接着使用 objcopy 拷贝 u-boot 中的特定段内容生成了 u-boot-nodtb.bin;
-j section_name
表示只将由 section_name 指定的 section 拷贝到输出文件;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
arm-buildroot-linux-gnueabi-objcopy --gap-fill=0xff \ -j .text \ -j .secure_text \ -j .secure_data \ -j .rodata \ -j .hash \ -j .data \ -j .got \ -j .got.plt \ -j .u_boot_list \ -j .rel.dyn \ -j .binman_sym_table \ -j .text_rest \ -j .dtb.init.rodata \ -O binary u-boot u-boot-nodtb.bin
-
再看下 dtb 文件的生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
mkdir -p arch/arm/dts/ ; # .suniv-f1c100s-generic.dtb.pre.tmp 内容为 suniv-f1c100s-generic.dts + '#include "sunxi-u-boot.dtsi"'(尾行) (cat arch/arm/dts/suniv-f1c100s-generic.dts; echo '#include "sunxi-u-boot.dtsi"') > arch/arm/dts/.suniv-f1c100s-generic.dtb.pre.tmp; # 生成预处理文件 .suniv-f1c100s-generic.dtb.d.pre.tmp arm-buildroot-linux-gnueabi-gcc -E -Wp,-MD,arch/arm/dts/.suniv-f1c100s-generic.dtb.d.pre.tmp \ -nostdinc \ -I./arch/arm/dts \ -I./arch/arm/dts/include \ -Iinclude \ -I./include \ -I./arch/arm/include \ -include ./include/linux/kconfig.h \ -D__ASSEMBLY__ \ -undef -D__DTS__ \ -x assembler-with-cpp \ -o arch/arm/dts/.suniv-f1c100s-generic.dtb.dts.tmp arch/arm/dts/.suniv-f1c100s-generic.dtb.pre.tmp ; # 生成预处理文件 .suniv-f1c100s-generic.dtb.d.dtc.tmp # 生成设备树文件 arch/arm/dts/suniv-f1c100s-generic.dtb ./scripts/dtc/dtc -O dtb \ -o arch/arm/dts/suniv-f1c100s-generic.dtb \ -b 0 -i arch/arm/dts/ \ -Wno-unit_address_vs_reg -Wno-unit_address_format -Wno-avoid_unnecessary_addr_size -Wno-alias_paths -Wno-graph_child_address -Wno-graph_port -Wno-unique_unit_address -Wno-simple_bus_reg -Wno-pci_device_reg -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-unit_address_vs_reg -Wno-unit_address_format -Wno-avoid_unnecessary_addr_size -Wno-alias_paths -Wno-graph_child_address -Wno-graph_port -Wno-unique_unit_address -Wno-simple_bus_reg -Wno-pci_device_reg -Wno-pci_bridge -Wno-pci_device_bus_num \ -d arch/arm/dts/.suniv-f1c100s-generic.dtb.d.dtc.tmp arch/arm/dts/.suniv-f1c100s-generic.dtb.dts.tmp \ || \ (echo "Check arch/arm/dts/.suniv-f1c100s-generic.dtb.pre.tmp for errors" && false) ; # 合并生成的两个预处理文件 cat arch/arm/dts/.suniv-f1c100s-generic.dtb.d.pre.tmp arch/arm/dts/.suniv-f1c100s-generic.dtb.d.dtc.tmp > arch/arm/dts/.suniv-f1c100s-generic.dtb.d ; # 替换预处理文件中的关键字 sed -i "s:arch/arm/dts/.suniv-f1c100s-generic.dtb.pre.tmp:arch/arm/dts/suniv-f1c100s-generic.dts:" arch/arm/dts/.suniv-f1c100s-generic.dtb.d
-
生成 u-boot.bin
u-boot.bin 是我们最终需要的二进制文件;
1 2 3 4 5 6 7 8
# 读取 suniv-f1c100s-generic.dtb 存放到 dts/dt.dtb cat arch/arm/dts/suniv-f1c100s-generic.dtb > dts/dt.dtb # 将 u-boot-nodtb.bin 和 dts/dt.dtb 拼接成 u-boot-dtb.bin cat u-boot-nodtb.bin dts/dt.dtb > u-boot-dtb.bin # 拷贝 u-boot-dtb.bin 为 u-boot.bin cp u-boot-dtb.bin u-boot.bin
通过 Makefile 进行分析
-
make 时没有指定 target,这样会默认执行 Makefile 中第一个 target;
最终执行了 all 这个 target;
1 2 3 4 5 6 7 8 9 10
PHONY := _all _all: # but instead _all depend on modules PHONY += all ifeq ($(KBUILD_EXTMOD),) _all: all else _all: modules endif
-
target 为 all 的 Makefile 代码段
可以看到编译依赖 ALL-y(生成项);
中间部分都是判断 .config 中的配置打印警告信息;
最后调用了一个检查配置的脚本;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
all: $(ALL-y) ifeq ($(CONFIG_DEPRECATED),y) $(warning "You have deprecated configuration options enabled in your .config! Please check your configuration.") ifeq ($(CONFIG_SPI),y) ifneq ($(CONFIG_DM_SPI)$(CONFIG_OF_CONTROL),yy) $(warning "The relevant config item with associated code will remove in v2019.07 release.") endif endif endif ifneq ($(CONFIG_DM),y) @echo >&2 "===================== WARNING ======================" endif ifeq ($(CONFIG_MMC),y) ifneq ($(CONFIG_DM_MMC)$(CONFIG_OF_CONTROL)$(CONFIG_BLK),yyy) @echo >&2 "===================== WARNING ======================" endif endif ifeq ($(CONFIG_USB),y) ifneq ($(CONFIG_DM_USB)$(CONFIG_OF_CONTROL)$(CONFIG_BLK),yyy) @echo >&2 "===================== WARNING ======================" endif endif ifeq ($(CONFIG_MVSATA_IDE),y) @echo >&2 "===================== WARNING ======================" endif ifeq ($(CONFIG_LIBATA),y) ifneq ($(CONFIG_AHCI),y) @echo >&2 "===================== WARNING ======================" endif endif ifeq ($(CONFIG_PCI),y) ifneq ($(CONFIG_DM_PCI),y) @echo >&2 "===================== WARNING ======================" endif endif ifneq ($(CONFIG_LCD)$(CONFIG_VIDEO),) ifneq ($(CONFIG_DM_VIDEO),y) @echo >&2 "===================== WARNING ======================" endif endif ifeq ($(CONFIG_OF_EMBED),y) @echo >&2 "===================== WARNING ======================" endif ifeq ($(CONFIG_SPI_FLASH),y) ifneq ($(CONFIG_DM_SPI_FLASH)$(CONFIG_OF_CONTROL),yy) @echo >&2 "===================== WARNING ======================" endif endif ifneq ($(CONFIG_WATCHDOG)$(CONFIG_HW_WATCHDOG),) ifneq ($(CONFIG_WDT),y) @echo >&2 "===================== WARNING ======================" endif endif ifneq ($(CONFIG_NET),) ifneq ($(CONFIG_DM_ETH),y) @echo >&2 "===================== WARNING ======================" endif endif @# Check that this build does not use CONFIG options that we do not @# know about unless they are in Kconfig. All the existing CONFIG @# options are whitelisted, so new ones should not be added. $(call cmd,cfgcheck,u-boot.cfg)
-
target 为 ALL-y 的 Makefile 代码段
- 生成主要文件:u-boot.srec、u-boot.bin、u-boot.sym、System.map、binary_size_check;
- 生成厂商相关文件:u-boot-sunxi-with-spl.bin、u-boot-tegra.bin、u-boot-nodtb-tegra.bin、init_sp_bss_offset_check、u-boot-with-dtb.bin、u-boot-rockchip.bin;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# Always append ALL so that arch config.mk's can add custom ones ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map binary_size_check # Build a combined spl + u-boot image for sunxi ifeq ($(CONFIG_ARCH_SUNXI)$(CONFIG_SPL),yy) ALL-y += u-boot-sunxi-with-spl.bin endif # enable combined SPL/u-boot/dtb rules for tegra ifeq ($(CONFIG_ARCH_TEGRA)$(CONFIG_SPL),yy) ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin endif # Add optional build target if defined in board/cpu/soc headers ifneq ($(CONFIG_BUILD_TARGET),) ALL-y += $(CONFIG_BUILD_TARGET:"%"=%) endif ifeq ($(CONFIG_INIT_SP_RELATIVE)$(CONFIG_OF_SEPARATE),yy) ALL-y += init_sp_bss_offset_check endif ifeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy) ALL-y += u-boot-with-dtb.bin endif ifeq ($(CONFIG_ARCH_ROCKCHIP)$(CONFIG_SPL),yy) ALL-y += u-boot-rockchip.bin endif
-
target 为 u-boot.bin 的 Makefile 代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
ifeq ($(CONFIG_MULTI_DTB_FIT),y) # 存在 dtb 容器(lzo、gz 压缩包)的情况 u-boot.bin: u-boot-fit-dtb.bin FORCE $(call if_changed,copy) else ifeq ($(CONFIG_OF_SEPARATE),y) # 存在单个 dtb(dts/dt.dtb)的情况 u-boot.bin: u-boot-dtb.bin FORCE $(call if_changed,copy) else # 没有适用 dtb 的情况 u-boot.bin: u-boot-nodtb.bin FORCE $(call if_changed,copy) endif
给上面的三种情况均加上打印,接着再编译一次:
编译命令:
make ARCH=arm CROSS_COMPILE=/home/jerry/vscode/mgp_r/buildroot-mangopi-r/output/host/bin/arm-buildroot-linux-gnueabi-
;1 2 3 4 5 6 7 8 9 10 11
u-boot.bin: u-boot-fit-dtb.bin FORCE + @echo "u-boot.bin: u-boot-fit-dtb.bin FORCE" $(call if_changed,copy) u-boot.bin: u-boot-dtb.bin FORCE + @echo "u-boot.bin: u-boot-dtb.bin FORCE" $(call if_changed,copy) u-boot.bin: u-boot-nodtb.bin FORCE + @echo "u-boot.bin: u-boot-nodtb.bin FORCE" $(call if_changed,copy)
查询 .config 文件得知其中存在 “CONFIG_OF_SEPARATE=y”,从编译打印结果上也证实了编译流程属于情况二;
-
待补充;