以前的文章:《一次搞定交叉编译》 给你们讲了如何安装交叉编译工具链,搭建交叉编译环境。linux
这篇文章主要教你们如何正确的去编译 Linux Kernel、U-Boot 这些著名的开源软件。shell
也许不少同窗会说:编译是小 case 啊,我都 make 过成千上万次了!网络
但是你是否有思考过,你编译的时候每个步骤、执行的每个命令.....架构
它背后隐藏的原理是什么?工具
为何要这么作?flex
你的方法是最高效最科学的吗?ui
你的方法是否潜藏着漏洞?搜索引擎
换一个环境、换一个平台,若是编译的过程当中遇到了莫名其妙的错误,你是否知道从哪里去找突破口?spa
这就是这篇文章要告诉你的。命令行
仍是以 i.MX 的内核为例。
其实过程很简单,基本上两个命令搞定:
make ARCH=arm imx_v7_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
第一个命令是配置,第二个命令是编译。
可是这背后却隐藏着不少小细节须要咱们去注意。
配置内核的命令是 make ARCH=chiparch xxx_defconfig
,第一个参数 ARCH=chiparch 用来指定芯片的架构,第二个参数 xxx_defconfig 用来指定此次编译对应的配置文件,好比针对 i.MX六、i.MX7 这些芯片的 Linux Kernel,配置命令是这样的:
make ARCH=arm imx_v7_defconfig
若是编译 i.MX8 相关的内核的话,配置命令大概是这样的:
make ARCH=arm64 defconfig
这个命令会从指定的 defconfig 文件里面加载配置,写入到 .config 文件中。内核编译的时候就是根据 .config 文件的内容来决定哪些模块编译,哪些模块不编译的。
make 后面的两个参数是怎么来的?
由于 Linux Kernel 支持大量不一样架构的芯片、好比 arm、arm6四、x8六、mips、risc-v 等等,还支持成千上万的功能特性,在编译的时候咱们并不须要把内核支持的全部芯片和功能都编译进去,这样编译出来的内核镜像会很是的庞大。并且 Kernel 中有至关一部分代码是针对特定架构的,好比启动阶段的初始化代码、每一个架构都有本身特定的设置,这部分代码大部分是汇编写的,并且相互不兼容:
因此,Linux 内核提供了 defconfig 机制 ,开发者们能够根据本身的芯片、开发板特性本身决定内核中哪些功能须要打开,哪些功能能够关闭,生成一个和本身硬件相关的 defconfig 文件,下次编译的时候加载。这些 defconfig 文件放在 arch/chiparch/configs 下面:
因此在配置的时候,咱们须要指定具体的 ARCH、Kernel 的 Kbuild 系统才能在对应的目录下找到你指定的 defconfig 文件。若是没有指定 ARCH、通常默认会去 x86 目录下去找。
由于 i.MX六、 i.MX7 是 Arm32 ,因此对应的 ARCH 为 arm,i.MX8 是 Arm64,因此对应的 ARCH 为 arm64.
另外须要说明一点的是,你们能够看到 arm 和 mips 目录下 defconfig 文件很是多,而比较新的一些架构,好比arm64,risc-v 目录下,只有惟一的一个 defconfig 文件,这和 Linux Kernel 目前的开发风格转变有关:再也不鼓励你们提交一堆乱七八糟的 defconfig 文件, 尽可能只使用一个通用的 defconfig 文件,这里面尽可能打开内核启动须要的模块,而对内核启动影响不大的模块,以模块的形式编译。在这个设计思想下,Arm32 下面有一个通用的 multi_v7_defconfig, Arm64 和 risc-v 对应的 defconfig 文件名都叫作 defconfig。因此若是如今你想为一个新的芯片提交它本身的 defconfig 文件到 mainline 分支,是不会被接受的,Linux 社区的 Maintainer 会告诉你,把你须要打开的特性加到通用的 defconfig 里面。
固然,咱们在本地作开发的时候,通常不会这样玩,咱们仍是会根据本身的芯片和特定产品形态,建立独立的 defconfig 文件,这样方便深度裁剪。
这个配置文件是如何生成的呢?
咱们通常在一个现有配置文件的基础上,根据产品需求,经过 make menuconfig
命令加减配置,而后再经过 make savedefconfig
命令生成新的配置文件:
好比我须要打开 drivers/gpu/drm/imx/dw_hdmi-imx.c
这个 HDMI 驱动,经过查看该 C 文件同目录下 Makefile,能够发现它依赖 DRM_IMX_HDMI
这个配置项:
make ARCH=arm menuconfig
对于对内核还不怎么熟悉的同窗来讲,如何找到 DRM_IMX_HDMI
这个配置的位置呢?别急,menuconfig 界面也是能够搜索关键字的:
按 / 键,就是 ? 下面那个键,会弹出下面的界面:
而后在选择框里面输入要查找的关键字,敲 Enter 就会出现结果:
这里只有一个匹配的选项,因此咱们直接在键盘上按 1 键,就会跳到对应的选项开关处:
而后打开对应的选项便可,<*> 号表示直接编译进内核,<M> 表示以模块的方式编译,< > 则表示不编译。
按 ↑ ↓ 上下移动光标,按 ← → 光标在最下面左右移动。
配置完成后选 <Exit> 退出。这时候能够看到 DRM_IMX_HDMI
这个选项的配置已经生效了:
而后执行 make savedefconfig
命令,生成新的配置文件,并用该文件覆盖旧文件。
有人可能会疑问,为何要用 make savedefconfig
来生成一个中间的 defconfig 文件呢,直接用 .config 去覆盖不是也能够吗?
答案是: make savedefconfig
命令生成的 defconfig 文件更精简,更易读。
编译内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
这是最通用的编译内核的命令,第一个告诉内核要编译 arm 架构,第二个参数指定用什么交叉编译工具去编译。编译成功的结果大概是这样的:
最终编译后的镜像是压缩过的 zImage。
同时全部的 dts 文件也会被编译成 dtb。
固然,若是为了编译的快,咱们还能够启动并行编译,好比:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
就是同时有 8 个编译进程在运行,并行数目设置多少最合适,这个通常取决与你用来编译的电脑有多少 CPU,以及内存够不够大,通常数据能够设置的和 CPU 个数相等,或者 2 倍。
有人会说,为何我看到的有些开发板的编译说明文档和这个不太同样,好比下面这个:
这是由于,部分厂家的Kernel,为了知足本身的固件升级设计,作了一些特殊的打包和修改,你虽然看到的编译命令不同了,其实他们都是基于最基本的编译命令作的封装定制。
它在 Makefile 里面指定了 ARCH 和 CROSS_COMPILE, 因此make 的时候就不须要指定这两个参数了。
而后经过这个修改,当开发者执行 make xxx.img 这种模式的命令的时候,会自动编译 zImage,并经过mkkrnlimg 这个命令对 zImage 打包生成 kernel.img。 而且对经过 resource_tool 这个命令对 dtb 也进行了打包。
Linux Kbuid 系统还执行不少其余的 make 命令,能够经过 make help 来查看:
U-Boot 的编译步骤和 Linux Kernel 很是相似,也是两步:
make mx6ull_14x14_evk_defconfig make CROSS_COMPILE=arm-linux-gnueabihf-
惟一的差异是,U-Boot 在编译的时候不须要指定 ARCH 选项,这是 U-Boot 的编译系统相比 Linux Kbuid 的要给改进点。其实目前最新的 U-Boot 编译系统也是基于 Linux Kbuild 设计的,一样支持 make menuconfig 命令,有对应的 defconfig 文件,在 configs 目录下。
另一个区别是,U-Boot 也有本身的 dtb,可是最终编译完的 U-Boot 会和 dtb 合并在一块儿。
咱们在编译软件的时候,常常会遇到各类奇奇怪怪的报错,有些是软件自己有 Bug(对于 Linux Kernel、U-Boot 这类比较知名的开源项目,这种Bug 比较少见)、有些是由于编译环境里面缺乏一些依赖工具(这种状况很常见)。
对于刚接触的新人来讲,一条 make
命令敲下去,发现蹦出来一堆莫名其妙的错误,是很使人沮丧的。
可是不要怕,虽然你是新人,这也不要紧,由于如今是互联网时代,对于那些普遍使用的开源项目,你踩到的坑基本都有不少人踩到过,并且这个世界有那么多乐于分享的人:他们遇到问题,勇敢的去分析,寻求解决方法,而后分享出来,他们是这个数字世界的热和光。
因此,若是你遇到一个本身能看得懂搞得定的问题,那很简单,直接去搞定便可,而后若是你乐意,能再写一篇分享心得就更好了。若是你遇到了一个像天书同样,本身彻底看不懂的报错,也没关系,最实用的解决方案就是:直接把这个错误复制出来,粘贴到你的搜索引擎里,点下下一步,开始搜索便可,一条条耐心的去看,通常运气都不会太差。
固然,搜索引擎的选择也是一门学问,若是你用到是百度,能搜到答案最好,若是搜不到,你还能够试试 Bing、Stackoverflow、Github、若是你能用 Google,那就更好了。
相信我,这个方法能解决你所遇到的大部分问题。
好比 我在执行 make ARCH=arm imx_v7_defconfig
就提示 failed 了:
仔细分析这个日志,咱们会发现最开始有这样一个异常提示:/bin/sh: 1: bison: not found
通常在分析异常的时候,比较有效的方法是找到最开始报出异常的地方,先解决掉,而后再看是否是最终问题被解决掉了,其实大部分时候都是这样的,把最早冒头的问题解决掉,后面全部的问题都被打掉了。
若是你能看懂这个异常提示,其实你会发现它是说 shell 在执行 bison 这个命令的时候,发现这个命令找不到。
试试在命令行执行下 bison
这个命令,会发现以下提示:
而后按照提示 sudo apt install bison
安装便可解决。
若是你看不出来,也不要紧,用前面提到的终极解决方案,直接把这条提示复制到百度里搜搜看:
运气比较好,太多人和我踩了一样的坑,前三条链接任意打开一个,点进去都能找到答案:
sudo apt install bison
安装完后再次执行 make ARCH=arm imx_v7_defconfig
,bison 的报错没了,但是又蹦出来另一个错误:
和前面同样,仍是直接 复制——》粘贴——》搜索:
踩坑的不止我一个啊,打开任意一个连接,就能找到解决办法:
sudo apt install flex
而后再次执行 make ARCH=arm imx_v7_defconfig
,终于成功了。
而后执行 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
开始编译, 发现又报错了:
直接用前面提到的三部曲:复制——》粘贴——》搜索:
打开这些连接,你会找到答案:
sudo apt install libssl-dev
再次开始编译,好不容易编译到最后,又挑出来一个错误:
相信到这里你已经知道该怎么作了,没错,仍是 复制——》粘贴——搜索:而且你会很快找到解决问题的方法:
sudo apt-get install lzop
继续编译,终于成功了:
其实这篇文章与其说是讲述 Linux Kernel 和 U-Boot 的编译步骤,不如说是告诉你们一种在开发过程当中,遇到本身不懂的问题,如何去利用网络来寻找答案的方法,但愿能给你一点启发。
更多原创请扫码关注公众号:HackforFun