U-Boot 顶层 Makefile 详解
U-Boot 工程目录分析
arch 文件夹
与 架构有关的文件
board 文件夹
与具体的板子有关的
configs文件夹
uboot 配置文件
在编译 uboot 之前一定要使用 defconfig 来配置 uboot!
.u-boot.xxx_cmd 文件
编译生成的,都是一些命令文件
.u-boot.bin.cmd
// 拷贝 u-boot-nodtb.bin 文件,并重命名为 u-boot.bin
cmd_u-boot.bin := cp u-boot-dtb.bin u-boot.bin
u-boot-nodtb.bin
文 件 .u-boot-nodtb.bin.cmd 就 是 用 于 生 成 uboot.nodtb.bin
cmd_u-boot-nodtb.bin := arm-linux-gnueabihf-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 -j .efi_runtime -j .efi_runtime_rel -O \
binary u-boot u-boot-nodtb.bin
arm-linux-gnueabihf-objcopy : 使用 objcopy 将 ELF 格式的 u-boot 文件转换为 二进制的 u-boot-nodtb.bin 文件
u-boot 文件 是 ELF 格式
.u-boot.cmd
生成 u-boot
cmd_u-boot := arm-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic \
--no-dynamic-linker -Ttext 0x4a000000 -o u-boot -T u-boot.lds \
arch/arm/cpu/armv7/start.o --start-group arch/arm/cpu/built-in.o \
arch/arm/cpu/armv7/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; \
true
链接工具 : arm-linux-gnueabihf-ld.bfd
ld.bfd 将各个 builtin.o 文件链接在一起就形成了 u-boot 文件
.u-boot.img.cmd
cmd_u-boot.img := ./tools/mkimage -A arm -T firmware -C none -O u-boot -a\
0x4a000000 -e 0 -n "U-Boot 2020.01"" for sunxi board" -d u-boot.bin u-boot.img\
>/dev/null
.u-boot.lds.cmd
生成 u-boot.lds 链接脚本
来源于 arch/arm/cpu/u-boot.lds文件
Makefile 文件
顶层 Makefile 文件,顶层 Makefile 可以调用子目录中的 Makefile 文件
u-boot.xxx 文件
u-boot | 编译ELF格式的uboot镜像文件 |
u-boot.bin | 编译二进制格式的uboot可执行镜像文件 |
u-boot.cfg | uboot的另一配置文件 |
u-boot.img | u-boot.bin添加头部信息的文件 |
u-boot.srec | S-Record格式的镜像文件 |
u-boot.lds | 链接脚本 |
u-boot.map | uboot映射文件 |
u-boot.sym | uboot符号文件 |
u-boot-nodtb.bin | u-boot.bin复制文件 |
config 文件
uboot 配置文件,使用命令“make xxx_defconfig”配置 uboot 以后就会自动生成
#
# Automatically generated file; DO NOT EDIT.
# U-Boot 2020.01 Configuration
#
CONFIG_CREATE_ARCH_SYMLINK=y
# CONFIG_ARC is not set
CONFIG_ARM=y
# CONFIG_M68K is not set
# CONFIG_MICROBLAZE is not set
# CONFIG_MIPS is not set
# CONFIG_NDS32 is not set
# CONFIG_NIOS2 is not set
# CONFIG_PPC is not set
# CONFIG_RISCV is not set
# CONFIG_SANDBOX is not set
# CONFIG_SH is not set
# CONFIG_X86 is not set
# CONFIG_XTENSA is not set
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="sunxi"
CONFIG_SYS_BOARD="sunxi"
CONFIG_SYS_CONFIG_NAME="sun7i"
# CONFIG_SYS_ICACHE_OFF is not set
# CONFIG_SPL_SYS_ICACHE_OFF is not set
# CONFIG_SYS_DCACHE_OFF is not set
# CONFIG_SPL_SYS_DCACHE_OFF is not set
#
以“ CONFIG_ ”开始的配置项
‘ y ’的变量一般用于控制某项功能是否使能
README
描述了 uboot 的详细信息
U-Boot 顶层 Makefile 分析
版本号
# SPDX-License-Identifier: GPL-2.0+
# 主版本号
VERSION = 2020
# 补丁版本号
PATCHLEVEL = 01
# 次版本号
SUBLEVEL =
# 附加版本信息
EXTRAVERSION =
# 名字
NAME =
# o Do not use make's built-in rules and variables
# (this increases performance and avoids hard-to-debug behaviour);
# o Look for make include files relative to root of kernel src
# += : 追加
# -rR : 禁止使用内置的隐含规则和变量定义
# --include-dir : 搜索路径
# $(CURDIR) : $(CURDIR)
MAKEFLAGS += -rR --include-dir=$(CURDIR)
# 不导出变量给子 make
unexport HOST_ARCH
else ifeq ("armv7l", $(MK_ARCH))
# 导出变量给子 make
export HOST_ARCH=$(HOST_ARCH_ARM)
命令输出
uboot 默认编译是 短命令
变量“ V=1 “ : 长命令
变量 quiet 和 Q 控制编译时是否在终端输出完整的命令
# If $(quiet) is empty, the whole command will be printed.
# If it is set to "quiet_", only the short version will be printed.
# If it is set to "silent_", nothing will be printed at all, since
# the variable $(silent_cmd_cc_o_c) doesn't exist.
#
# A simple variant is to prefix commands with $(Q) - that's useful
# for commands that shall be hidden in non-verbose mode.
#
# $(Q)ln $@ :<
#
# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
# If KBUILD_VERBOSE equals 1 then the above command is displayed.
#
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
# ifeq 判断" $(origin V) "和" command line "是否相等
# origin 返回值:变量来源
ifeq ("$(origin V)", "command line")
# KBUILD_VERBOSE=1
KBUILD_VERBOSE = $(V)
endif
# KBUILD_VERBOSE=0
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
# 判断 KBUILD_VERBOSE 是否为 1
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
# 命令前加“ @ ”,不会在终端输出命令
Q = @
endif
# quiet 为空 长命令
# quiet 为“ quiet_ ” 短命令
# quiet 为" silent_ " 无输出
# 短命令
quiet_cmd_sym ?= SYM $@
# 长命令
cmd_sym ?= $(OBJDUMP) -t $< > $@
静默输出
make -s :静默输出
# If the user is running make -s (silent mode), suppress echoing of commands
# 判断 编译器版本号是否为 4.x
# $(filter <pattern...>,<text>):过滤函数
# %:通配符
# text :过滤单词
# MAKE_VERSION :make工具的版本号
# make -v:查看 make工具版本号
# 不为空:条件成立
ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
# $(firstword <text>)
# 滤出符合“ %s ”的单词
# firstword :获取 text 的首单词
# 返回值不为空,条件成立
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
quiet=silent_
endif
else # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
quiet=silent_
endif
endif
# 导出变量 quiet Q KBUILD_VERBOSE
export quiet Q KBUILD_VERBOSE
设置编译结果输出目录
# kbuild supports saving output files in a separate directory.
# To locate output files in a separate directory two syntaxes are supported.
# In both cases the working directory must be the root of the kernel src.
# 1) O=
# Use "make O=dir/to/store/output/files/"
#
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.
# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
ifeq ($(KBUILD_SRC),)
# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
# 判断“ O ”是否来自于命令行
# 来自,条件成立
ifeq ("$(origin O)", "command line")
# KBUILD_OUTPUT:输出目录
KBUILD_OUTPUT := $(O)
endif
# That's our default target when none is given on the command line
PHONY := _all
_all:
# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;
# 判断 KBUILD_OUTPUT 是否为空
ifneq ($(KBUILD_OUTPUT),)
# Invoke a second make in the output directory, passing relevant variables
# check that the output directory actually exists
saved-output := $(KBUILD_OUTPUT)
# mkdir :创建 KBUILD_OUTPUT 目录
# 创建成功,绝对路径给 KBUILD_OUTPUT
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \
&& /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
$(error failed to create output directory "$(saved-output)"))
PHONY += $(MAKECMDGOALS) sub-make
$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
@:
sub-make: FORCE
$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))
# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)
代码检查
# Call a source code checker (by default, "sparse") as part of the
# C compilation.
#
# Use 'make C=1' to enable checking of only re-compiled files.
# Use 'make C=2' to enable checking of *all* source files, regardless
# of whether they are re-compiled or not.
#
# See the file "doc/sparse.txt" for more details, including
# where to get the "sparse" utility.
# 判断 C 是否来源于命令行
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
# 命令行没有 C
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
模块编译
uboot 允许单独编译某个模块
# Use make M=dir to specify directory of external module to build
# Old syntax make ... SUBDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
# 判断是否定义SUBDIRS
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif
# 判断命令行是否定义了 M
ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
# If building an external module we do not care about the all: rule
# but instead _all depend on modules
PHONY += all
# KBUILD_EXTMOD为空
ifeq ($(KBUILD_EXTMOD),)
# 目标_all 依赖 all
_all: all
else
# _all 依赖 modules
# 先编译模块
_all: modules
endif
# KBUILD_SRC 为空
ifeq ($(KBUILD_SRC),)
# building in the source tree
# 设置变量 srctree 为当前目录
srctree := .
else
ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
# building in a subdirectory of the source tree
srctree := ..
else
srctree := $(KBUILD_SRC)
endif
endif
# 设置变量 objtree 为当前目录
objtree := .
# 设置变量 obj为srctree的目录
src := $(srctree)
# 设置变量 obj 为当前目录
obj := $(objtree)
# 设置 VPATH
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
# 导出变量 scrtree objtree VPATH
export srctree objtree VPATH
获取主机架构和系统
# 变量 HOSTARCH:保存主机架构
# shell 命令“ uname -m “:获取架构名称
# | :管道
# sed -e :替换命令
HOSTARCH := $(shell uname -m | \
sed -e s/i.86/x86/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ \
-e s/sa110/arm/ \
-e s/ppc64/powerpc/ \
-e s/ppc/powerpc/ \
-e s/macppc/powerpc/\
-e s/sh.*/sh/)
# HOSTOS : 保存主机 OS 的值
# shell 命令“name -s”: 获取主机 OS
# “tr '[:upper:]' '[:lower:]'”: 将所有的大写字母替换为小写字母
# ” | “管道:将“ Linux ”作为“sed -e 's/\(cygwin\).*/cygwin/'”的输入
# sed -e:将cygwin.*替换为 cygwin
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
# 导出 HOSTARCH=x86_64 HOSTOS=linux
export HOSTARCH HOSTOS
设置目标架构、交叉编译器和配置文件
# set default to nothing for native builds
# 设置目标板架构和 交叉编译器
# 判断 HOSTARCH 和 ARCH 是否相等
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
# 可定义
#ARCH ?= arm
#CROSS_COMPILE ?= arm-linux-gnueabihf-
# .config:实时有效的配置
KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG
调用 scripts/Kbuild.include
# We need some generic definitions (do not try to remake the file).
# 调用文件 scripts/Kbuild.include
scripts/Kbuild.include: ;
include scripts/Kbuild.include
交叉编译工具变量设置
# Make variables (CC, etc...)
AS = $(CROSS_COMPILE)as
# Always use GNU ld
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
导出其他变量
export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
export MAKE LEX YACC AWK PERL PYTHON PYTHON2 PYTHON3
export HOSTCXX HOSTCXXFLAGS CHECK CHECKFLAGS DTC DTC_FLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS KBUILD_AFLAGS
#mytext:
# @echo 'ARCH=' $(ARCH)
# @echo 'CPU=' $(CPU)
# @echo 'BOARD=' $(BOARD)
# @echo 'VENDOR=' $(VENDOR)
# @echo 'SOC=' $(SOC)
# @echo 'CPURIR' $(CPUDIR)
# @echo 'BOARDDIR'$(BOARDDIR)
uboot 根目录下文件 config.mk
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2013
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#########################################################################
# This file is included from ./Makefile and spl/Makefile.
# Clean the state to avoid the same flags added twice.
#
# (Tegra needs different flags for SPL.
# That's the reason why this file must be included from spl/Makefile too.
# If we did not have Tegra SoCs, build system would be much simpler...)
PLATFORM_RELFLAGS :=
PLATFORM_CPPFLAGS :=
PLATFORM_LDFLAGS :=
LDFLAGS :=
LDFLAGS_FINAL :=
LDFLAGS_STANDALONE :=
OBJCOPYFLAGS :=
# clear VENDOR for tcsh
VENDOR :=
#########################################################################
# 提取CONFIG_SYS_ARCH 里面双引号""内容
ARCH := $(CONFIG_SYS_ARCH:"%"=%)
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_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
# Some architecture config.mk files need to know what CPUDIR is set to,
# so calculate CPUDIR before including ARCH/SOC/CPU config.mk files.
# Check if arch/$ARCH/cpu/$CPU exists, otherwise assume arch/$ARCH/cpu contains
# CPU-specific code.
CPUDIR=arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)
# 读取文件$(srctree)/arch/$(ARCH)/config.mk 的内容
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
ifdef FTRACE
PLATFORM_CPPFLAGS += -finstrument-functions -DFTRACE
endif
#########################################################################
RELFLAGS := $(PLATFORM_RELFLAGS)
PLATFORM_CPPFLAGS += $(RELFLAGS)
PLATFORM_CPPFLAGS += -pipe
LDFLAGS += $(PLATFORM_LDFLAGS)
LDFLAGS_FINAL += -Bstatic
# uboot 根目录下的.config 文件
export PLATFORM_CPPFLAGS
export RELFLAGS
export LDFLAGS_FINAL
export LDFLAGS_STANDALONE
export CONFIG_STANDALONE_LOAD_ADDR
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="sunxi"
CONFIG_SYS_BOARD="sunxi"
CONFIG_SYS_CONFIG_NAME="sun7i"
# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
# mixing *config targets and build targets.
# For example 'make oldconfig all'.
# Detect when mixed targets is specified, and make a second invocation
# of make so .config is not included in this case either (for *config).
version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h
defaultenv_h := include/generated/defaultenv_autogenerated.h
no-dot-config-targets := clean clobber mrproper distclean \
help %docs check% coccicheck \
ubootversion backup tests check qcheck
config-targets := 0
mixed-targets := 0
dot-config := 1
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endif
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(words $(MAKECMDGOALS)),1)
mixed-targets := 1
endif
endif
endif
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; \
done
else
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG
config: 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.
# Additional helpers built in scripts/
# Carefully list dependencies so we do not try to build scripts twice
# in parallel
PHONY += scripts
scripts: scripts_basic include/config/auto.conf
$(Q)$(MAKE) $(build)=$(@)
ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf