[toc]

art-pi构建命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export CROSS_COMPILE=arm-none-eabi- ARCH=arm
make stm32h750-art-pi_defconfig
make menuconfig
> Boot options (console=ttySTM0,115200 root=/dev/ram loglevel=8) Boot arguments
> Device Drivers > Serial drivers (115200) Default baudrate
u-boot-v2021.07\arch\arm\dts\stm32h750i-art-pi.dts
chosen {
bootargs = "root=/dev/ram";
stdout-path = "serial0:2000000n8";
};
chosen {
bootargs = "root=/dev/ram";
stdout-path = "serial0:115200n8";
};
make -j 12

F4 构建命令

1
2
3
4
export CROSS_COMPILE=arm-none-eabi- ARCH=arm
make stm32f429-discovery_defconfig
arch/arm/dts/stm32f429-disco.dts
make -j 12

Makefile

功能

V=1 显示完成命令输出

  • V=1:告诉 make 显示完成的命令输出。这对于调试构建过程非常有用,因为它可以显示构建过程中执行的所有命令。
  • 没有设置 V 时,make 默认不显示命令输出。
  • 其中 Q = @,@用于抑制命令的输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# make V=1 显示完成命令输出
ifeq ("$(origin V)", "command line") #获取V是否输入
KBUILD_VERBOSE = $(V) # KBUILD_VERBOSE = 1
endif
ifndef KBUILD_VERBOSE # 如果没有输入V,则KBUILD_VERBOSE = 0
KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1) # 如果KBUILD_VERBOSE = 1,则显示完成命令输出
quiet =
Q =
else # 否则不显示完成命令输出
quiet=quiet_
Q = @
endif

-s 静默模式

  • -s:告诉 make 进入静默模式。在静默模式下,make 不会显示构建过程中执行的命令。
  • 设置 quiet变量为 silent_,这样就可以在构建过程中使用 $(quiet)前缀来隐藏命令的输出。
1
2
3
4
5
6
7
8
9
ifneq ($(filter 4.%,$(MAKE_VERSION)),)	# make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
quiet=silent_
endif
else # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
quiet=silent_
endif
endif

O= 输出目录

1
make CROSS_COMPILE=arm-none-eabi- ARCH=arm -j3 O=output/
  • 使用 KBUILD_SRC设置输出目录。使用 O变量设置输出目录,如果 O变量没有设置,则使用 KBUILD_SRC变量设置输出目录。
1
2
3
4
ifeq ($(KBUILD_SRC),)
ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif

C=1 启用静态检查

  • 使用 ‘make C=1’ 来启用仅检查重新编译的文件。
  • 使用 ‘make C=2’ 来启用对 所有 源文件的检查,无论它们是否被重新编译。

M = 构建的外部模块的目录

  • 使用 make M=dir 指定要构建的外部模块的目录
  • 旧语法 make …SUBDIRS=$PWD 仍受支持
  • 设置环境变量KBUILD_EXTMOD优先

cc-option CC编译器选项测试检查

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
# output 目录进行以下测试
# 如果 KBUILD_EXTMOD 被定义,则使用其第一个值作为临时输出目录;否则,TMPOUT 为空。
TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)

# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
# 退出代码选择选项。“$$TMP” 可以用作临时文件,并会自动清理。
# 针对 U-Boot 进行了修改:防止 cc-option 留下 .*.su 文件

# set -e 确保在命令失败时立即退出。
# 定义了三个临时文件,分别用于存储编译输出和中间文件。$$$$ 用于生成唯一的文件名。
# 执行编译命令 $(1),并根据其退出状态选择输出。如果编译成功,输出 $(2);否则,输出 $(3)。
# 删除临时文件,确保不会留下多余的文件。
try-run = $(shell set -e; \
TMP="$(TMPOUT).$$$$.tmp"; \
TMPO="$(TMPOUT).$$$$.o"; \
TMPSU="$(TMPOUT).$$$$.su"; \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
fi; \
rm -f "$$TMP" "$$TMPO" "$$TMPSU")

# __cc-option
# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
# $(1) 表示编译器命令(如 $(CC))。
# $(2) 表示已有的编译标志。
# $(3) 表示要测试的编译选项。
# $(4) 表示备用选项。
# 宏会尝试编译一个空的 C 文件 null,并将输出重定向到临时文件 $$TMP。如果编译成功,则返回 $(3),否则返回 $(4)
__cc-option = $(call try-run,\
$(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4))

# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
# 编译器CC 编译条件KBUILD_CPPFLAGS KBUILD_CFLAGS 成功返回$(1) 失败返回$(2)
cc-option = $(call __cc-option, $(CC),\
$(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS),$(1),$(2))

scripts 用于构建脚本的工具

Kconfig 相关的功能

  • Kconfig 是一个配置文件,用于定义内核的配置选项。它使用一种类似于 C 语言的语法,包含一系列配置选项和依赖关系。Kconfig 文件通常由 Kconfig 工具解析,生成配置文件(.config)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
config          - 使用行定向程序更新当前配置
nconfig - 使用基于 ncurses 菜单的程序更新当前配置
menuconfig - 使用基于菜单的程序更新当前配置
xconfig - 使用基于 Qt 前端的程序更新当前配置
gconfig - 使用基于 GTK+ 前端的程序更新当前配置
oldconfig - 使用提供的 .config 作为基础更新当前配置
localmodconfig - 更新当前配置,禁用未加载的模块
localyesconfig - 更新当前配置,将本地模块转换为核心
defconfig - 使用 ARCH 提供的默认配置创建新配置
savedefconfig - 将当前配置保存为 ./defconfig(最小配置)
allnoconfig - 创建一个所有选项都回答为 no 的新配置
allyesconfig - 创建一个所有选项都接受为 yes 的新配置
allmodconfig - 创建一个尽可能选择模块的新配置
alldefconfig - 创建一个所有符号都设置为默认值的新配置
randconfig - 创建一个所有选项都随机回答的新配置
listnewconfig - 列出新选项
olddefconfig - 与 oldconfig 相同,但将新符号设置为默认值而不提示
testconfig - 运行 Kconfig 单元测试(需要 python3 和 pytest)
  • 强制使用需修改Kconfig文件
1
2
3
mainmenu "U-Boot $(UBOOTVERSION) Configuration"
srctree := .
CC = $(CROSS_COMPILE)gcc

config 使用行定向程序更新当前配置

  • 通过命令 ./scripts/kconfig/conf --oldaskconfig Kconfig运行

  • 运行的是命令行版本的配置工具,用于解析Kconfig文件并生成配置文件。

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
*
* U-Boot Configuration
*
*
* Compiler:
*
Architecture select
1. ARC architecture (ARC)
> 2. ARM architecture (ARM)
3. M68000 architecture (M68K)
4. MicroBlaze architecture (MICROBLAZE)
5. MIPS architecture (MIPS)
6. Nios II architecture (NIOS2)
7. PowerPC architecture (PPC)
8. RISC-V architecture (RISCV)
9. Sandbox (SANDBOX)
10. SuperH architecture (SH)
11. x86 architecture (X86)
12. Xtensa architecture (XTENSA)
choice[1-12?]: 2
*
* Skipping low level initialization functions
*
Skip calls to certain low level initialization functions (SKIP_LOWLEVEL_INIT) [N/y/?] N
Skip call to lowlevel_init during early boot ONLY (SKIP_LOWLEVEL_INIT_ONLY) [N/y/?] N
*
* ARM architecture
*
ARM GICV2 driver (DRIVER_GICV2) [N/y/?] N
ARM GICV3 ITS (GIC_V3_ITS) [N/y/?] N
ARM GICV3 GIC600 SUPPORT (GICV3_SUPPORT_GIC600) [N/y/?] N
Do not enable icache (SYS_ICACHE_OFF) [N/y/?] N
Do not enable dcache (SYS_DCACHE_OFF) [N/y/?] N
CP15 based cache enabling support (SYS_ARM_CACHE_CP15) [N/y/?] N
MMU-based Paged Memory Management Support (SYS_ARM_MMU) [N/y/?] N
Use the ARM v7 PMSA Compliant MPU (SYS_ARM_MPU) [Y/?] y
Select the ARM data write cache policy
> 1. Write-back (WB) (SYS_ARM_CACHE_WRITEBACK)
2. Write-through (WT) (SYS_ARM_CACHE_WRITETHROUGH)
3. Write allocation (WA) (SYS_ARM_CACHE_WRITEALLOC)
choice[1-3?]: 0
Select the ARM data write cache policy
> 1. Write-back (WB) (SYS_ARM_CACHE_WRITEBACK)
2. Write-through (WT) (SYS_ARM_CACHE_WRITETHROUGH)
3. Write allocation (WA) (SYS_ARM_CACHE_WRITEALLOC)
choice[1-3?]: 1
Enable ARCH_CPU_INIT (ARCH_CPU_INIT) [N/y/?] n
Build U-Boot using the Thumb instruction set (SYS_THUMB_BUILD) [Y/?] y

ARM PL310 L2 cache controller (SYS_L2_PL310) [N/y/?] n
ARM PL310 L2 cache controller in SPL (SPL_SYS_L2_PL310) [N/y/?] ^C

embedsky@ubuntu:~/share/u-boot$ ./scripts/kconfig/conf --oldaskconfig Kconfig
  • 用法
1
2
3
4
5
6
7
8
9
10
11
12
--listnewconfig         列出新的选项
--oldaskconfig 使用行定向程序开始新的配置
--oldconfig 使用提供的 .config 文件作为基础更新配置
--syncconfig 类似于 oldconfig,但生成的配置文件位于 include/{generated/,config/}
--olddefconfig 与 oldconfig 相同,但将新符号设置为默认值
--defconfig <file> 使用 <file> 中定义的默认值创建新的配置
--savedefconfig <file> 将当前最小配置保存到 <file>
--allnoconfig 创建一个所有选项都回答为 no 的新配置
--allyesconfig 创建一个所有选项都回答为 yes 的新配置
--allmodconfig 创建一个所有选项都回答为 mod 的新配置
--alldefconfig 创建一个所有符号都设置为默认值的新配置
--randconfig 创建一个所有选项都随机回答的新配置
  • 代码解析
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
int main(int ac, char **av)
{
const char *progname = av[0];
int opt;
const char *name, *defconfig_file = NULL /* gcc uninit */;
struct stat tmpstat;
int no_conf_write = 0;

tty_stdio = isatty(0) && isatty(1); //判断标准输入输出是否指向终端
//从命令行获取短选项-s参数或者long_opts结构体的选项
// 执行对应配置操作
while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
//如果存在-s参数,则设置消息输出回调为空,即不输出消息
if (opt == 's') {
conf_set_message_callback(NULL);
continue;
}
}
//如果 ac 等于 optind,则表示没有提供额外的命令行参数,即没有提供配置文件
if (ac == optind) {
fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
conf_usage(progname);
exit(1);
}
//获取配置文件
name = av[optind];
//执行配置操作
//通过scripts/kconfig/zconf.y 使用 bison -d zconf.y 生成 zconf.tab.c
//这里会需要进行用户配置
conf _parse(name);
//执行配置操作


re turn 0;
}

  • 通过命令 ./scripts/kconfig/mconf Kconfig 运行
  • 运行的是menuconfig的配置工具,使用基于菜单的程序更新当前配置
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
embedsky@ubuntu:~/share/u-boot$ ./scripts/kconfig/mconf Kconfig 
.config:37:warning: symbol value '' invalid for ENV_OFFSET
.config:38:warning: symbol value '' invalid for ENV_SECT_SIZE
.config:47:warning: symbol value '' invalid for TPL_STACK
.config:52:warning: symbol value '' invalid for SYS_LOAD_ADDR
.config:57:warning: symbol value '' invalid for PRE_CON_BUF_ADDR
.config:108:warning: symbol value '' invalid for BOARD_SIZE_LIMIT
.config:116:warning: symbol value '' invalid for SYS_MONITOR_BASE
.config:827:warning: symbol value '' invalid for SYS_SATA_MAX_DEVICE

WARNING: unmet direct dependencies detected for NPCM_OTP
Depends on [n]: ARM [=n] && ARCH_NPCM [=n]
Selected by [y]:
- NPCM_AES [=y]
Your display is too small to run Menuconfig!
It m ust be at least 19 lines by 80 columns.


WAING: unmet direct dependencies detected for NPCM_OTP
Dpends on [n]: ARM [=n] && ARCH_NPCM [=n]
S lected by [y]:
- NP CM_AES [=y]



configuration changes were NOT saved.

`


建说明



执 make xxx_defconfig`时,会执行conf可执行文件的编译
后执 `./scripts/kconfig/conf --defconfig=generated_defconfig Kconfig`命令,生成配置文件

`ma

kefile
# scripts/kcon fig/Makefile


%defconfig: $(obj)/conf
$(Q)$(CPP) -nostdinc -P -I $(srctree) -undef -x assembler-with-cpp $(srctree)/arch/$(SRCARCH)/configs/$@ -o generated_defconfig
$(Q)$< $(silent) --defconfig=generated_defconfig $(Kconfig)
  • 展开为
1
2
arm-none-eabi-gcc -E -nostdinc -P -I . -undef -x assembler-with-cpp ./arch/../configs/stm32h750-art-pi_defconfig -o generated_defconfig
nfig/conf --defconfig=generated_defconfig Kconfig

构建流程

Ubootb编译第一步通常是执行make xxx_config

  • 在编译指定顶层目录生成.c onfig文件,这种方式要求厂商 提供一个基础的xxx_config文件(通常来说开发者不会通过执行make menuconfig从零开始配置,这个工作过量太大了)。

  • 查看编译流程时,优先查看 xxx:这类可执行目标;如果make 没有带目标时,则优先查看第一个目标,因为是执行的这个目标;从头开始查看,需要注意查看 include是否引入的 xxx:

  • 这里的目标是 xxx_config:,即 %config:

1
2
3
# 定义了一个模式规则,匹配所有以 config 结尾的目标
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
  • %config 还会依赖于 scripts_basicoutputmakefileFORCE是一个空目标,用于强制执行规则。

build变量的定义

  • 观察顶层makefile
1
2
3
4
# 我们需要一些通用定义(不要尝试重新制作文件)。
# 里面定义了$(build)
scripts/Kbuild.include: ;
include scripts/Kbuild.include
  • 在scripts/Kbuild.include 中定义:
1
2
3
4
5
6
7

###

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

编译scripts_basic 生成fixep

outputmakefile 生成Makefile

执行scripts/kconfig Makefile

编译生成conf

执行conf –defconfig=generated_defconfig Kconfig

include/config/auto.conf、 include/config/auto.conf.cmd、 include/generated/autoconf.h

Ubootb编译 执行make 操作

shell 命令

GNU C

objdump 工具

反汇编 -d

1
objdump -d start.o
  • 更多的详细信息,可以使用 -S 选项,它会将源代码和反汇编代码一起显示
  • 问题:
    1. objdump: can't disassemble for architecture UNKNOWN!
    • 出现这个错误可能是因为 objdump 工具无法识别目标文件的架构。你可以尝试显式指定架构来解决这个问题。
    1
    objdump -d -m arm start.o
    • 使用file命令查看文件类型
      1
      2
      $file start.o
      arch/arm/cpu/armv7m/start.o: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), with debug_info, not stripped
    • 使用objdump -i查看支持的架构
    • 根据你的架构 armv7m,使用arm-none-eabi-objdump

查看段信息 -h

显示段内容 -s

反汇编指定的段 -j