Linux系统移植:U-Boot 顶层 Makefile 分析(上)
Linux系统移植:U-Boot 顶层 Makefile 分析(上)
一、版本号
打开 Makefile 可以在顶层看到他的版本信息
VERSION 是主版本号,PATCHLEVEL 是补丁版本号,SUBLEVEL 是次版本号,这三个一起构成了 uboot 的版本号
EXTRAVERSION 是附加版本信息,NAME 是和名字有关的,一般不使用这两个
二、传递变量到子 make
主目录的 Makefile 文件可以调用子目录中的 Makefile 文件,进行编译,主目录调用方式如下:
$(MAKE) -C subdir
- 1
$(MAKE) 就是调用 “make” 命令,-C 指定子目录
主 Makefile 可以使用 “export” 来导出要传递给子 make 的变量,使用 “unexport” 来声明不导出
export VARIABLE …… //导出变量给子 make
unexport VARIABLE…… //不导出变量给子 make
- 1
- 2
“SHELL” 和 “MAKEFLAGS”,这两个变量除非使用 “unexport” 声明,否则的话在整个make的执行过程中,它们的值 始终自动的传递给子 make,我们可以在代码中看到 MAKEFLAGS
该代码使用 “+=” 来给变量 MAKEFLAGS 追加了一些值,“-rR”表示禁止使用内置的隐含规则和变量定义,“–include-dir”指明搜索路径,”$(CURDIR)”表示当前目录
三、命令输出
uboot 编译时会打印许多数据信息,内容较多,不利于分析 uboot 的编译过程,所以默认编译是不会在终端中显示完整的命令,具体通过设置变量 “V=1“ 来实现完整的命令输出
关于这个变量的判断,在 Makefile 文件内有写到:
代码如下:
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
其中 ifeq 判断 $(origin V) 和 command line 是否相等,相等则执行下面的语句
其中 origin 用于告诉你变量是哪来的,语法为:
$(origin <variable>)
- 1
上面的判断就是判断变量 V 的定义是来自 command line ,也就是命令行,然后执行变量 KBUILD_VERBOSE 等于 V 的值,如果没有在命令行输入 V 的话 KBUILD_VERBOSE 就等于 0 !
第二个 ifeq 用来判断 KBUILD_VERBOSE 是否为 1,如果 KBUILD_VERBOSE 为 1 的话变量 quiet ,和 Q 都为空,如果 KBUILD_VERBOSE=0 的话变量 quiet 为 “quiet_“,变量 Q 为 “@” !
变量 quiet 和 Q 来控制编译的时候是否在终端输出完整的命令,比如如下一段代码
Q = @ 时就不会执行后面的命令,不会在终端上输出命令,而有些命令会有多个版本,使用 quiet 进行控制,如下:
quiet_cmd_sym ?= SYM $@
cmd_sym ?= $(OBJDUMP) -t $< > $@
- 1
- 2
如果变量 quiet 为空的话,整个命令都会输出
如果变量 quiet 为 “quiet_” 的话,仅输出短版本
如果变量 quiet 为 “silent_” 的话,整个命令都不会输出
四、静默输出
设置 V=0 或者在命令行中不定义 V 的话,编译 uboot 的时候终端中显示的短命令,但是还是会有命令输出,有时候我们在编译 uboot 的时候不需要输出命令,这个时候就可以使用 uboot 的静默输出功能,我们编译的时候用 “make -s” 即可实现静默输出
比如,我在 uboot 的编译脚本使用 -s 对 uboot 进行编译,编译时将进行静默输出,命令行只显示部分内容
在顶层 Makefile 内就有相关代码:
# If the user is running make -s (silent mode), suppress echoing of
# commands
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
其中 filter 函数是个过滤函数,函数格式如下:
$(filter <pattern...>,<text>)
- 1
表示以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,可以有多个模式。函数返回值就是符合 pattern 的字符串
比如 $(filter 4.%,$(MAKE_VERSION)) 的含义就是在字符串“MAKE_VERSION”中找出符合“ 4.%”的字符 (%为通配符)
五、编译输出目录
Makefile 可以将编译出来的目标文件输出到单独的目录中,在 make 的时候使用 “O” 来指定输出目录,比如 “make O=dir” 就是设置目标文件输出到 dir 目录中,通过生成到指定的目录,可以使编译结果更加简明,如果不指定 O 参数,源文件和编译产生的文件都在同一个目录内
Makefile 中相关的代码如下:
具体代码如下:
# 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?
ifeq ("$(origin O)", "command line")
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: ;
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)
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),)
# We process the rest of the Makefile if this is the final invocation of make
ifeq ($(skip-makefile),)
# Do not print "Entering directory ...",
# but we want to display it when entering to the output directory
# so that IDEs/editors are able to understand relative filenames.
MAKEFLAGS += --no-print-directory
- 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
代码判断 “O” 是否来自于命令行,来自命令行就将 KBUILD_OUTPUT 等于 $(O) ,然后创建 KBUILD_OUTPUT 对应的文件夹
六、代码检查
uboot 的 Makefile 支持代码检查,使用命令 “make C=1” 使能代码检查,检查有哪些文件需要重新编译,“make C=2” 检查所有的源码文件,对应代码如下:
# 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 "Documentation/sparse.txt" for more details, including
# where to get the "sparse" utility.
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
此处代码,如果 C 来源于命令行,那就将 C 赋值给变量 KBUILD_CHECKSRC,如果命令行没有 C 的话 KBUILD_CHECKSRC 就为 0,代码会根据他的值进行判断执行不同程序
七、模块编译
uboot 的 Makefile 支持单独编译一个模块,使用命令 “make M=dir” 即可,旧语法“make SUBDIRS=dir”也支持
代码:
# 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
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif
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
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
ifeq ($(KBUILD_SRC),)
# building in the source tree
srctree := .
else
ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
# building in a subdirectory of the source tree
srctree := ..
else
srctree := $(KBUILD_SRC)
endif
endif
objtree := .
src := $(srctree)
obj := $(objtree)
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH
- 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
代码还是老样子,判断 M 来自命令行,然后赋值给 KBUILD_EXTMOD ,之后判断 KBUILD_EXTMOD 是否为空,如果为空的话目标 _all 依赖 all,先编译出 all,否则的话默认目标 _all 依赖 modules,先编译出 modules,也就是编译模块
之后判断 KBUILD_SRC 是否为空,如果为空的话就设置变量 srctree 为当前目录,即 srctree 为 “.”,一般不设置 KBUILD_SRC,之后将前两个变量关联到 VPATH 变量,然后导出 scrtree、objtree 和 VPATH
八、获取主机架构和系统
顶层 Makefile 会也会获取主机架构和系统
第一部分代码调用 shell 命令 “uname -m” 获取架构名称,同时 shell 中的 “|” 表示管道,意思是将左边的输出作为右边的输入,sed -e 是替换命令,“sed -e s/i.86/x86/” 表示将管道输入的字符串中的 “i.86” 替换为 “x86”,其他的“sed -e s”命令同理
第二部分使用 shell 命令“uname-s”来获取主机 OS,然后替换保存
第三部分代码导出 HOSTARCH、HOSTOS
九、设置目标架构、交叉编译器和配置文件
编译 uboot 的时要设置目标板架构和交叉编译器,配置代码如下:
编译时使用脚本需要加入 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 就是用于设置 ARCH 和 CROSS_COMPILE
然后 Makefile 代码中判断 HOSTARCH 和 ARCH 这两个变量是否相等,不相等就 CROSS_COMPILE= arm-linux-gnueabihf- 使用交叉编译器
当然默认每次编译 uboot 的时候都要在 make 命令后面设置 ARCH 和 CROSS_COMPILE,使用起来很麻烦,我们可以直接在 Makefile 内加入 两者的定义,方便我们开发
后面的代码定义变量 KCONFIG_CONFIG,因为 uboot 是可以配置的,这里配置文件为.config,.config 默认是没有的,需要使用命令 “make xxx_defconfig” 对 uboot 进行配置,配置完成以后就会在 uboot 根目录下生成 .config。默认情况下 .config 和 xxx_defconfig 内容是一样的,因为.config 就是从 xxx_defconfig 复制过来的。如果后续自行调整了 uboot 的一些配置参数,那么这些新的配置参数就添加到了.config 中,而不是 xxx_defconfig。相当于 xxx_defconfig 只是一些初始配置,而.config 里面的才是实时有效的配置
文章来源: blog.csdn.net,作者:JeckXu666,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_45396672/article/details/121713437
- 点赞
- 收藏
- 关注作者
评论(0)