06_Uboot顶层Makefile分析_前期所做内容

news2024/11/18 5:35:21

目录

U-Boot顶层Makefile分析

版本号

MAKEFLAGS变量

命令输出

静默输出

设置编译结果输出目录

代码检查

模块编译

获取主机架构和系统

设置目标架构、交叉编译器和配置文件

调用scripts/Kbuild.include

交叉编译工具变量设置

导出其他变量


U-Boot顶层Makefile分析

在阅读uboot源码之前,肯定是要先看一下顶层Makefile,分析gcc版本代码的时候一定是先从顶层Makefile开始的,然后再是子Makefile,这样通过层层分析Makefile即可了解整个工程的组织结构。顶层Makefile也就是uboot根目录下的Makefile文件,由于顶层Makefile文件内容比较多,所以我们将其分开来看。

版本号

顶层Makefile一开始是版本号,内容如下(为了方便分析,顶层Makefile代码段前段行号采用 Makefile中的行号,因为uboot会更新,因此行号可能会与你所看的顶层Makefile有所不同):

 VERSION是主版本号, PATCHLEVEL是补丁版本号, SUBLEVEL是次版本号,这三个一,起构成了uboot的版本号,比如当前的uboot版本号就是"2016.03"。EXTRAVERSION是附加版本信息,NAME是和名字有关的,一般不使用这两个。

MAKEFLAGS变量

make是支持递归调用的,也就是在Makefile中使用"make”命令来执行其他的Makefile文件,一般都是子目录中的Makefile文件。假如在当前目录下存在一个"subdir”子目录,这个子目录中又有其对应的Makefile文件,那么这个工程在编译的时候其主目录中的Makefile就可以调用子目录中的Makefile,以此来完成所有子目录的编译。主目录的Makefile可以使用如下代码来编译这个子目录:

$(MAKE) -C subdir

$(MAKE)就是调用"make”命令, -C指定子目录。有时候我们需要向子make传递变量,这个时候使用"export”来导出要传递给子make的变量即可,如果不希望哪个变量传递给子make的话就使用“unexport”来声明不导出: 

export VARIABLE ......  //导出变量给子make。

unexport VARIABLE .......   //不导出变量给子make。

 

有两个特殊的变量:“SHELL”和"MAKEFLAGS”,这两个变量除非使用“unexport”声明,否则的话在整个make的执行过程中,它们的值始终自动的传递给子make。在uboot的主Makefile中有如下代码: 

 上述代码使用“+=”来给变量MAKEFLAGS追加了一些值,“-rR”表示禁止使用内置的隐含规则和变量定义,“--include-dir”指明搜索路径,”$(CURDIR)”表示当前目录。

 

命令输出

uboot默认编译是不会在终端中显示完整的命令,都是短命令,如图所示:

在终端中输出短命令虽然看起来很清爽,但是不利于分uboot的编译过程。可以通过设置变量"V=1"来实现完整的命令输出,这个在调试uboot的时候很有用,结果如图所示: 

 顶层Makefile中控制命令输出的代码如下:

上述代码中先使用ifeq来判断"$(origin V)"和"command line"是否相等。这里用到了Makefile中的函数origin,origin和其他的函数不一样,它不操作变量的值,origin用于告诉你变量是哪来的,语法为: 

$(origin <variable>) 

 variable是变量名, origin函数的返回值就是变量来源,因此$(origin V)就是变量V的来源。如果变量V是在命令行定义的那么它的来源就是"command line",这样"$(origin V)"和"commandline"就相等了。当这两个相等的时候变量 KBUILD_VERBOSE就等于V的值,比如在命令行中输入"V=1"的话那么KBUILD-VERBOSE=1。如果没有在命令行输入V的话KBUILD_VERBOSE=0。

第80行判断KBUILD_VERBOSE是否为1,如果KBUILD_VERBOSE为1的话变量quiet,和Q都为空,如果KBUILD_VERBOSE=0的话变量quiet为“quiet_“,变量Q为“@”,综上所述:

V=1的话:

 

V=0或者命令行不定义V的话: 

 

Makefile中会用到变量quiet和Q来控制编译的时候是否在终端输出完整的命令,在顶层Makefile中有很多如下所示的命令: 

 $(Q)$(MAKE) $(build)=tools

 如果V=0的话上述命令展开就是"@make $(build)-tools", make在执行的时候默认会在终端输出命令,但是在命令前面加上“@”就不会在终端输出命令了。当 V=1 的时候Q就为空,上述命令就是"make $(build)-tools”,因此在make执行的过程,命令会被完整的输出在终端上。

有些命令会有两个版本,比如:

quiet_cmd_sym ?= SYM  $@

cmd_sym ?= $(OBJDUMP) -t $<> $@

 

 sym命令分为"quiet_cmd_sym”和"cmd_sym”两个版本,这两个命令的功能都是一样的,区别在于make执行的时候输出的命令不同。quiet_cmd_xxx命令输出信息少,也就是短命令,而cmd_xxx命令输出信息多,也就是完整的命令。

如果变量quiet为空的话,整个命令都会输出。如果变量quiet为“quiet_”的话,仅输出短版本。如果变量quiet为"silent_”的话,整个命令都不会输出。

 

 

静默输出

设置V=0或者在命令行中不定义V的话,编译uboot的时候终端中显示的短命令,但是还是会有命令输出,有时候我们在编译uboot的时候不需要输出命令,这个时候就可以使用uboot的静默输出功能。编译的时候使用"make-s"即可实现静默输出,顶层Makefile中相应的代码如下:

 

第91行判断当前正在使用的编译器版本号是否为4.x,判断$(filter 4.%,$(MAKE_VERSION))和“”(空)是否相等,如果不相等的话就成立,执行里面的语句。也就是说$(filter4.%,$(MAKE_VERSION))不为空的话条件就成立,这里用到了Makefile中的filter函数,这是个过滤函数,函数格式如下:

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

filter函数表示以pattern模式过滤text字符串中的单词,仅保留符合模式pattern的单词,可以有多个模式。函数返回值就是符合pattern的字符串。因此$(filter 4.%,$(MAKE_VERSION))的含义就是在字符串"MAKE-VERSION”中找出符合"4.%”的字符(%为通配符),MAKE_VERSION是make工具的版本号,ubuntu16.04里面默认自带的make工具版本号为 4.1,大家可以输入“make-v”查看。因此$(filter 4.%,$(MAKE_VERSION))不为空,条件成立,执行92~94行的语句。

第92行也是一个判断语句,如果$(filter %s,$(firstword x$(MAKEFLAGS)))不为空的话条件,成立,变量quiet等于"silent”。这里也用到了函数filter,在$(firstword xS(MAKEFLAGS)))中过滤出符合"%s”的单词。到了函数firstword,函数firstword是获取首单词,函数格式如下:

 $(firstword <text>)

firstword函数用于取出text字符串中的第一个单词,函数的返回值就是获取到的单词。当使用“make-s”编译的时候, “-s”会作为MAKEFLAGS变量的一部分传递给Makefile。在顶层Makfile中添加如图所示的代码: 

 图中的两行代码用于输出$(firstword x$(MAKEFLAGS))的结果,最后修改文件mx6ull alientek emmc.sh,在里面加入"-s”选项,结果如图所示:

 修改完成以后执行mx6ull_alientek_emmc.sh,结果如图所示:

 从图可以看出第一个单词是"xrRs",将$(filter %s ,$(firstword x$(MAKEFLAGS))展开就是$(filter %s, xrRs),而$(filter %s, xrRs)的返回值肯定不为空,条件成立, quiet-silent_第101行使用export导出变量quiet、Q和KBUILD_VERBOSE。

 

设置编译结果输出目录

uboot可以将编译出来的目标文件输出到单独的目录中,在make的时候使用“O”来指定输出目录,比如"make O-out”就是设置目标文件输出到out目录中。这么做是为了将源文件和编译产生的文件分开,当然也可以不指定0参数,不指定的话源文件和编译产生的文件都在同一个目录内,一般我们不指定0参数。顶层Makefile中相关的代码如下:

 第124行判断"O”是否来自于命令行,如果来自命令行的话条件成立, KBUILD_OUTPUT就为$(O),因此变量KBUILD_OUTPUT就是输出目录。

第135行判断KBUILD_OUTPUT是否为空。

第139行调用mkdir命令,创建KBUILD_OUTPUT目录,并且将创建成功以后的绝对路径赋值给KBUILD_OUTPUT。至此,通过O指定的输出目录就存在了。

 

代码检查

uboot支持代码检查,使用命令"make C=1”使能代码检查,检查那些需要重新编译的文件。“make C-2”用于检查所有的源码文件,顶层Makefile中的代码如下:

第176行判断C是否来源于命令行,如果C来源于命令行,那就将C赋值给变量KBUILD_CHECKSRC,如果命令行没有C的话KBUILD_CHECKSRC就为0。 

 

 

模块编译

在uboot中允许单独编译某个模块,使用命令"make M=dir”即可,旧语法"makeSUBDIRS=dir”也是支持的。顶层Makefile中的代码如下:

 第186行判断是否定义了SUBDIRS, 如果定义了SUBDIRS ,变量KBUILD_EXTMOD=SUBDIRS,这里是为了支持老语法“make SUBIDRS=dir”

第190 行判断是否在命令行定义了M,如果定义了的话KBUILD_EXTMOD=$(M)

第197行判断KBUILD_EXTMOD时为空,如果为空的话目标_all 依赖all,因此要先编译出all。否则的话默认目标_all依赖modules,要先编译出modules,也就是编译模块。一般情况下我们不会在uboot中编译模块,所以此处会编译all这个目标。

第203行判断KBUILD_SRC是否为空,如果为空的话就设置变量sretree为当前目录,即srctree为“.”,一般不设置 KBUILD_SRC。

第214行设置变量objtree为当前目录。

第215和216行分别设置变量src和obj,都为当前目录。

第218行设置VPATH。

第220行导出变量scrtree、objtree和VPATH。

获取主机架构和系统

接下来顶层Makefile会获取主机架构和系统,也就是我们电脑的架构和系统,代码如下:

 第227行定义了一个变量HOSTARCH,用于保存主机架构,这里调用shell命令“uname-m获取架构名称,结果如图所示:

 从图可以看出当前电脑主机架构为“x86_64", shell中的"1”表示管道,意思是将左边的输出作为右边的输入, sed-e是替换命令,"sed-e s/i.86/x86/”表示将管道输入的字符串中的"i.86"替换为"x86",其他的"sed-es"命令同理。对于我的电脑而言, HOSTARCH-x86_64。

第237行定义了变量HOSTOS,此变量用于保存主机OS的值,先使用shell命令"uname-s”来获取主机OS,结果如图所示:

从图可以看出此时的主机OS为“Linux”,使用管道将“Linux”作为后面“tr'[:upper:]"[:lower:]"的输入, "tr'[:upper:]'"[:lower:]'"表示将所有的大写字母替换为小写字母,因此得到“linux”。最后同样使用管道,将“linux”作为"sed-e'sA(cygwinl).*/cygwin/”的输入,用于将cygwin.*替换为 cygwin*因此,HOSTOS=linux。

第240行导出HOSTARCH=x86_64, HOSTOS=linux。

设置目标架构、交叉编译器和配置文件

编译uboot 的时候需要设置目标板架构和交叉编译器,

“make ARCH=armCROSS_COMPILE=arm-linux-gnueabihf-”就是用于设置ARCH和 CROSS_COMPILE,在顶层Makefile中代码如下:

 第245行判断HOSTARCH和ARCH这两个变量是否相等,主机架构(变量HOSTARCH)是x86-64,而我们编译的是ARM版本uboot,肯定不相等,所以CROsS_COMPILE= arm-linuxgnueabihf-。从示例代码可以看出,每次编译 uboot 的时候都要在make 命令后面设置ARCH 和 CROSS_COMPILE,使用起来很麻烦,可以直接修改顶层Makefile,在里面加入 ARCH和CROSS COMPILE的定义,如图所示:

 按照图所示,直接在顶层Makefile里面定义ARCH和CROSS_COMPILE,这样就不用每次编译的时候都要在make命令后面定义ARCH和CROSS_COMPILE。

继续回到示例代码中,第249行定义变量KCONFIG-CONFIG, uboot是可以配置的,这里设置配置文件为.config, .config默认是没有的,需要使用命令“make xxx_defconfig"对uboot 进行配置,配置完成以后就会在uboot根目录下生成.config。默认情况下.config和xxx_defconfig 内容是一样的,因为.config就是从xxx_defconfig复制过来的。如果后续自行调整了uboot的一些配置参数,那么这些新的配置参数就添加到了.config中,而不是xxx_defconfig。相当于 xxx_defconfig只是一些初始配置,而.config里面的才是实时有效的配置。

调用scripts/Kbuild.include

 示例代码中使用"include"包含了文件scripts/Kbuild.include,此文件里面定义了很多变量,如图所示:

 在uboot的编译过程中会用到scripts/Kbuild.include中的这些变量。

 

 

交叉编译工具变量设置

上面只是设置了CROSS-COMPILE的名字,但是交叉编译器其他的工具还没有设置,顶层Makefile中相关代码如下:

 

导出其他变量

接下来在顶层Makefile会导出很多变量,代码如下:

这些变量中大部分都已经在前面定义了,我们重点来看一下下面这几个变量:

ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR

这7个变量在顶层Makefile是找不到的,说明这7个变量是在其他文件里面定义的,先来看一下这7个变量都是什么内容,在顶层Makefile中输入如图所示的内容:

 修改好顶层Makefile以后执行如下命令:

make ARCH=arm CROSS COMPILE=arm-linux-gnueabihf- mytest

从图可以看到这7个变量的值,这7个变量是从哪里来的呢?在uboot根目录下有个文件叫做 config.mk,这7个变量就是在config.mk里面定义的,打开config.mk内容如下: 

第25行定义变量ARCH,值为$(CONFIG_SYS_ARCH:"%"=%),也就是提取.CONFIG_SYS_ARCH里面双引号"”之间的内容。比如CONFIG_SYS_ARCH= "arm"的话,ARCH=arm。

第 26 行定义变量 CPU,值为$(CONFIG_SYS_CPU:"%"=%)。

第32行定义变量BOARD,值为(CONFIG_SYS_BOARD:"%"=%)。

第34行定义变量VENDOR,值为$(CONFIG_SYS_VENDOR:"%"=%)。

第37 行定义变量 SOC,值为$(CONFIG_SYS_SOC:"%"=%)。

第44行定义变量CPUDIR,值为arch/$(ARCH)/cpu$(if $(CPU),/$(CPU),)。

第46行sinclude和include的功能类似,在Makefile中都是读取指定文件内容,这里读取文件$(srctree)/arch/S(ARCH)/config.mk的内容。sinclude读取的文件如果不存在的话不会报错。

第47行读取文件$(srctree)/$(CPUDIR)/config.mk的内容。

第50行读取文件$(srctree)/$(CPUDIR)/S(SOC)/config.mk的内容。

第54行定义变量BOARDDIR,如果定义了VENDOR 那么BOARDDIR=$(VENDOR)/$(BOARD),否则的 BOARDDIR=$(BOARD)。

第60行读取文件$(srctree)/board/$(BOARDDIR)/config.mk。

 接下来需要找到CONFIG_SYS_ARCH、CONFIG_SYS_CPU、CONFIG_SYS_BOARD、CONFIG_SYS_VENDOR和CONFIG_SYS_SOC这5个变量的值。这5个变量在uboot根目录下的.config文件中有定义.定义如下:

 根据示例代码可知: 

 在config.mk中读取的文件有:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka架构原理(三)

三、Kafka架构原理 3.1 整体架构图 一个典型的kafka集群中包含若干个Producer&#xff0c;若干个Broker&#xff0c;若干个Consumer&#xff0c;以及一个zookeeper集群&#xff1b; kafka通过zookeeper管理集群配置&#xff0c;选举leader&#xff0c;以及在Consumer Group发…

软件多语言文案脚本自动化方案

开发高效提速系列目录 软件多语言文案脚本自动化方案 软件多语言文案脚本自动化方案 背景目标整体方案1. 创建文案资源文件2. python脚本开发3. Python脚本执行与管理4. 人员职责分配 PyCharm使用说明1. PyCharm下载2. PyCharm安装配置3. 异常情况解决 总结 博客创建时间&…

中间件漏洞(一)CVE-2013-4547(文件名逻辑漏洞)

目录 1. 了解nginx的工作原理 2. 漏洞原理及举例分析 3. 前端php源码分析 4. 注入思路 5. 漏洞复现 5.1 上传文件并抓包分析 5.2 通过访问文件执行php 注意一点 6. 漏洞修复 1. 了解nginx的工作原理 nginx是以PHP语言为主。像Apache一样&#xff0c;Nginx自身是不支持解…

基于黏菌算法的极限学习机(ELM)回归预测-附代码

基于黏菌算法的极限学习机(ELM)回归预测 文章目录 基于黏菌算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于黏菌算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用黏菌算法对极限学习机进行优化&#xff0c;并…

国民技术N32G430开发笔记(15)- IAP升级 树莓派串口发送数据

IAP升级 树莓派串口发送数据 1、树莓派接入usb转串口模块后&#xff0c;会生成/dev/ttyUSB0节点&#xff0c;因为树莓派内核已经编译usb_serial以及各模块的驱动。 我们直接对ttyUSB0节点编程即可。 2、协议同上一节 cmd data_lenght data0 … datax checksum 1、获取版本…

AutoDL-GPU租用平台使用(LLM 备用)

网址&#xff1a;AutoDL-品质GPU租用平台-租GPU就上AutoDL 1 打开网址 查看下显卡型号及价格&#xff1a;A100 ( 80 G 显存) 6.68/小时 、4090&#xff08;24G 显存&#xff09;2.68/小时 2 创建实例 1.注册登录后进入控制台&#xff08;页面右上角&#xff09;&#xff0…

08 KVM虚拟机配置-总体介绍

文章目录 08 KVM虚拟机配置-总体介绍8.1 概述8.2 基本格式8.3 配置流程 08 KVM虚拟机配置-总体介绍 8.1 概述 Libvirt工具采用XML格式的文件描述一个虚拟机特征&#xff0c;包括虚拟机名称、CPU、内存、磁盘、网卡、鼠标、键盘等信息。用户可以通过修改配置文件&#xff0c;对…

【应急响应】日志自动提取分析项目ELKLogkitLogonTracerAnolog等

日志自动提取-七牛Logkit&观星应急工具 1、七牛Logkit&#xff1a;(Windows&Linux&Mac等) https://github.com/qiniu/logkit/ 支持的数据源&#xff08;各类日志&#xff0c;各个系统&#xff0c;各个应用等&#xff09; File: 读取文件中的日志数据&#xff0c;包…

第二章 主机规划与磁盘分区

要安装好一部Linux主机并不是那么简单的事情&#xff0c;你必须要针对distributions的特性、服务器软件的能力、未来的升级需求、硬件扩充性需求等等来考虑&#xff0c;还得要知道磁盘分区、文件系统、Linux操作较频繁的目录等等&#xff0c;都得要有一定程度的了解才行。 2.1…

训练CV模型常用的Tips Tricks

训练CV模型常用的Tips & Tricks主要从以下9个方面进行介绍&#xff1a; 图像增强更好的模型学习率和scheduler优化器正则化手段标签平滑知识蒸馏伪标签错误分析 1. 图像增强 以下列出了许多增强方式&#xff0c;有的甚至没见过&#xff0c;但是也不是每一种增强方式都是…

极化码的入门与探索

文章目录 极化码的基础先验知识二进制输入离散无记忆信道模型(Binary-input Discreten Memoryless Channel, B-DMC)二进制离散输入信道的ML判决和错误率B-DMC相关参数的定义和理解 两信道极化N信道极化的解释信道极化分解的蝶形结构补充&#xff1a;生成矩阵的结构 极化码的基础…

Python算法设计 - 快速排序

目录 一、快速排序二、Python算法实现 一、快速排序 快速排序的概念相信大家都能理解&#xff0c;下面这个算法是基于同样想法的另一种算法&#xff0c;其中利用到了分区。如果实施正确&#xff0c;这是一种非常有效的算法&#xff0c;在预期的O(n.log n) 时间内运行&#xff…

性能测试场景分析并设计?超细案例讲解,看这篇就够了

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试场景&…

1.1 基于B/S 结构的 Web 应用

文章目录 1.1 基于B/S 结构的 Web 应用1.2 JDK安装与配置1.3 服务器Tomcat下载与安装1.4 Eclipse安装与使用1.4.1 Eclipse 下载及创建Dynamic Web Project1.4.2 Eclipse 中的编码问题1.4.3 将Tomcat和Eclipse相关联1.4.4 Eclipse 自动部署项目到 Tomcat 的 webapps 目录 1.5 My…

ChatGLM-6B模型微调实战(以 ADGEN (广告生成) 数据集为例)

1 介绍 对于 ChatGLM-6B 模型基于 P-Tuning v2 的微调。P-Tuning v2 将需要微调的参数量减少到原来的 0.1%&#xff0c;再通过模型量化、Gradient Checkpoint 等方法&#xff0c;差不多需要 7GB或则8GB 显存即可运行。 2 环境 2.1 python 环境 conda create -n py310_cha…

go 打包文件夹成zip文件

go 打包文件夹成zip文件 代码有些乱&#xff0c;找不到合适的例子&#xff0c;和优雅的代码 当前代码打包文件是在 需要打包的目录下&#xff0c;测试的时候注意文件翻倍容量 writer, err : zzip.CreateHeader(header) //这里创建文件时注意不要用完整路径 zip中会生产完整路径…

【51单片机】蜂鸣器

&#x1f38a;专栏【51单片机】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Love Story】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; &#x1f354;效果 &#xff08;注意听声音哦&#xff09; 按…

Blob File

文章目录 学习链接Blob创建演示 分片演示 Fileinput手动拖拽fetch 从后端获取流前端代码后端代码 window.showOpenFilePicker Filereader示例1示例2 ArrayBuffer创建bufferTypedArray读写bufferDataView读写buffer与Blob对比 Blob Url & DataUrl示例1示例2 学习链接 Blog …

WIFI密码hacking学习

1 wifite sudo -i 切换到root终端&#xff0c;执行wifite CtrlC 停止WIFI列表扫描 这里选择爆破目标1&#xff0c;他会先监听客户端和wifi的连接的数据包&#xff0c;然后用wordlist-probable.txt里面的字典进行爆破 区别 WPS 是 no 的和yes no会自动化爆破 这种模式默认下…

软件测试行业前景怎么样

软件测试工程师工作好找&#xff0c;但是企业有时却很难招聘到合适的软件测试工程师&#xff0c;这是因为现在企业需要的是自动化测试人才和测试开发人才&#xff01;前些年的手动测试员早已不能满足企业现在的发展需求。 随着人工智能时代的到来&#xff0c;IT行业受到了越来…