linux系统移植:u-boot顶层makefile分析(上)(代码片段)

JeckXu666 JeckXu666     2023-02-20     774

关键词:

Linux系统移植:U-Boot 顶层 Makefile 分析(上)

一、版本号

打开 Makefile 可以在顶层看到他的版本信息

VERSION 是主版本号,PATCHLEVEL 是补丁版本号,SUBLEVEL 是次版本号,这三个一起构成了 uboot 的版本号

EXTRAVERSION 是附加版本信息,NAME 是和名字有关的,一般不使用这两个

二、传递变量到子 make

主目录的 Makefile 文件可以调用子目录中的 Makefile 文件,进行编译,主目录调用方式如下:

$(MAKE) -C subdir

$(MAKE) 就是调用 “make” 命令,-C 指定子目录

主 Makefile 可以使用 “export” 来导出要传递给子 make 的变量,使用 “unexport” 来声明不导出

export VARIABLE ……	//导出变量给子 make
unexport VARIABLE……	//不导出变量给子 make

“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

其中 ifeq 判断 $(origin V) 和 command line 是否相等,相等则执行下面的语句

其中 origin 用于告诉你变量是哪来的,语法为:

$(origin <variable>)

上面的判断就是判断变量 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 $< > $@

如果变量 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

其中 filter 函数是个过滤函数,函数格式如下:

$(filter <pattern...>,<text>)

表示以 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

代码判断 “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

此处代码,如果 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

代码还是老样子,判断 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 里面的才是实时有效的配置

linux系统移植:kernel顶层makefile(下)(代码片段)

文章目录Linux系统移植:Kernel顶层Makefile(下)一、makedefconfig过程二、Makefile.build脚本分析三、make过程四、built-in.o文件编译生成过程五、makezImage过程Linux系统移植:Kernel顶层Makefile(下)继续分析Linux内核... 查看详情

linux系统移植:kernel顶层makefile(上)(代码片段)

文章目录Linux系统移植:Kernel顶层Makefile(上)一、版本号二、MAKEFLAGS变量三、命令输出四、静默输出五、编译结果输出目录六、代码检查七、模块编译八、设置目标架构和交叉编译器九、调用构建文件十、交叉编译... 查看详情

04.移植u-boot

1.读readme获取信息   1.1由BuildingtheSoftware可知,需修改顶层makefile,指定架构和编译器   ifeq($(HOSTARCH),$(ARCH))   CROSS_COMPILE?=arm-linux-   endif   查看详情

u-boot-2016.07移植(第一篇)初步分析

...m-linux-gcc443安装环境Ubuntu910下载u-boot-201607并解压分析顶层Makefile1找出目标依赖关系2总结初次编译u-boot1配置2编译分析u-boot启动流程1分析startS 查看详情

linux内核顶层makefile详解

...c;在具体移植之前,我们先来学习一下Linux内核的顶层Makefile文件,因为顶层Makefile控制着Linux内核的编译流程。 查看详情

linux系统移植:u-boot工程创建(代码片段)

...件夹2.2board文件夹2.3config文件夹2.4.u-boot.xxx_cmd文件2.5顶层Makefile文件2.6u-boot.xxx文件2.7.config文件2.8README文件三、U-Boot过程创建3.1打开工程文件夹3.2保存工作区3.3建立构建关系Linux系统移植:U-Boot工程创建本章用于分析U-Boot的工... 查看详情

u-boot顶层makefile分析

...本执行后会生成以下3个文件,这些文件中提供的变量会在Makefile中其它地方使用。116#loadARCH,BOARD,andCPUconfiguration117include$ 查看详情

u-boot顶层makefile介绍(*)(代码片段)

参考:U-Boot顶层Makefile介绍作者:一只青木呀发布时间:2020-10-2216:22:17网址:https://blog.csdn.net/weixin_45309916/article/details/109218569目录1、准备好uboot源码2、分析顶层Makefile2.1、版本号2.2、MAKEFLAGS变量2.3、 查看详情

u-boot-2016.09顶层makefile分析

##SPDX-License-Identifier: GPL-2.0+#VERSION=2016PATCHLEVEL=09SUBLEVEL=EXTRAVERSION=NAME=#*DOCUMENTATION*#Toseealistoftypicaltargetsexecute"makehelp"#Moreinfocanbelocatedin./README#Commentsinthisfilear 查看详情

嵌入式linux第二部分-裸机开发/系统移植/驱动开发/内核开发

...间:2022年11月13日【嵌入式Linux】裸机开发篇LinuxC语言及Makefile基础【嵌入式Linux】1.shell概念及常用命令行【嵌入式Linux】2.LinuxC语言基础【嵌入式Linux】3.VisualStudioCode插件的安装(C/C++)U-Boot专题【嵌入式Linux】4.U-Boot入门【嵌入式... 查看详情

嵌入式linux7.u-boot顶层makefile分析(代码片段)

...用ifeq来判断"$(originV)"和"commandline"是否相等。这里用到了Makefile中的函数originorigin和其他的函数不一样,它不操作变量的值, 查看详情

嵌入式开发(s5pv210)——u-boot的顶层makefile分析(代码片段)

前言本文分析的是u-boot的主Makefile以及主Makefile调用到的一些关键文件,此Makefile可能和你手里的u-boot的Makefile不一样,这是正常的,但是从逻辑上都是一样的,无非就是把同样功能的脚本放在了不同的位置或者子Ma... 查看详情

linux系统移植博文导航

Linux系统移植专栏更新很久了,博主今天就把以前的博文整理一下,希望对感兴趣的朋友有所帮助,在此感谢CSDN这个平台给出了这个一个交流的机会,也感谢大家的支持。Linux相关的网站U-BootLinux内核busyboxLinux系统移植Linux系统移... 查看详情

嵌入式linux7.u-boot顶层makefile分析(代码片段)

1.版本号5VERSION=20166PATCHLEVEL=037SUBLEVEL=8EXTRAVERSION=9NAME=VERSION是主版本号,PATCHLEVEL是补丁版本号,SUBLEVEL是次版本号,这三个一起构成了uboot的版本号,比如当前的uboot版本号就是“2016.03”。EXTRAVERSION是附加版本信息,NAME是和名字有... 查看详情

linux内核移植入门(代码片段)

文章目录基本概念内核源码目录结构内核配置主目录Makefile各子目录Makefile如何配置内核?1.配置仓库选取2.交叉编译器的修改3.体系结构体的选择4.修改配置文件内核编译编译结果:几种linux内核文件的区别开发板上U-Boot启动linux内核... 查看详情

linux系统移植:正点原子u-boot移植(代码片段)

文章目录Linux系统移植:正点原子U-Boot移植一、What‘sU-Boot?1.1U-Boot简介1.2U-Boot选择二、正点原子U-Boot编译2.1编译环境2.2编译脚本三、U-Boot烧写与启动Linux系统移植:正点原子U-Boot移植一、What‘sU-Boot?1.1U-Boot简介Linux系统启... 查看详情

linux系统移植:u-boot启动流程(下)(代码片段)

目录Linux系统移植:U-Boot启动流程(下)一、run_main_loop函数详解二、cli_loop函数详解三、cmd_process函数详解Linux系统移植:U-Boot启动流程(下)一、run_main_loop函数详解uboot启动以后会进入3秒倒计时,如果... 查看详情

linux系统移植:u-boot链接脚本(代码片段)

文章目录Linux系统移植:U-Boot链接脚本一、u-boot.lds介绍二、u-boot.lds分析Linux系统移植:U-Boot链接脚本一、u-boot.lds介绍前面提到的U-Boot的本质就是一个大的裸机程序,执行的时候需要先找到程序入口,而程序的链接... 查看详情