最近需要编译一个arm平台上面的nginx,项目使用的buildroot构建环境,实现自动化的编译。前期的构建工具之类的已经由平台组的同事弄好了,主要的工作就是进行nginx的交叉编译,中间陆续踩了许多坑,简单聊聊吧。
做事的第一步就是磨刀,了解编译系统的基础使用。项目资料也挺缺的,没有人提供一个指导性的文档。一开始就是口头让写个Config.in和xxx.mk文件。我也丈二的和尚没摸着头脑,第一次接触这个编译环境,不熟悉。直接参照其他模块编写了Config.in和xxx.mk,下载nginx的源码,就这么开始了构建了。
首先 make xxxdefconfig
,然后创建host的sysroot目录,安装一下基础的组件包。 然后就是 make menuconfig
选择了编译nginx。接下来就是make nginx
了。一切就开始了,各种报错,基本的参数设置也没有搞懂。这样下去可不行,然后通过BR2这个关键字上网查到了使用的是buildroot, 对比一下项目的结构,大同小异。
然后就是上官网看文档了。 还是有许多的错误解决不了,在讨论组里面询问一下问题,呵呵 平台的人就让拷贝官方的buildroot包里面的nginx脚本,我石化了 既然有这东西怎么在任务安排的时候不提前讲了。 哦了, 就赶紧去下载官方buildroot包,拷贝nginx的脚本,修改修改开始编译。
中间遇到许多编译错误,通过错误找到对应的脚本,基本都是缺失了某个库,然后再到buildroot下查找对应的包目录,拷贝脚本然后编译安装,然后继续nginx的编译。 期间发现有一个问题, 每次make clean的时候,之前安装的基础包也会被清掉,需要重新安装一下。然后我就取巧了一下,编译的时候不make clean,而是删除output/build/nginx-xxx的目录,再执行make nginx的时候,就只会进行nginx的编译,顺利解决基础包需要重装的问题。(今天看网络文章,发现有make <package>-dirclean
这个命令) 中间还有许多的问题,边编译边解决,哈哈, 这么来回搞了2天吧,目前还有错误,下周继续再战吧。
等搞定nginx的编译,到时候再来发一个问题汇总。
嗯,今天周末我再来熟悉熟悉buildroot的使用。
buildroot
buildroot主要用来作交叉编译的。需要交叉编译的基本上都是嵌入式系统,目标系统没有足够的资源用于编译。buildroot支持许多目标处理器的编译。
buildroot是需要运行于linux系统上的。buildroot首先需要基于许多主机包,在主机(执行编译的系统)上需要安装好所需要的依赖软件。
依赖包:
必须的,比如:wget, which, sed, binutils, gcc, g++, bash, patch, gzip, bzip2, perl, tar, unzip, bc 等
可选的, 比如: python, glib2, git, svn, javac, jar, w3m, graphviz等
buildroot快速入门
主要的编译命令
1 | make menuconfig // 选择要编译的项目, 生成.config文件, 会被顶级的Makefile引用。 |
make执行的步骤:
- 下载源文件
- 配置工具链
- 配置编译安装选择的目标包
- 编译一个内核镜像, if selected
- 编译一个bootloader镜像, if selected
- 创建一个root filesystem in selected formats.
所有的编译输出到output目录下, 这个目录下包含几个子目录
- images/ 所有映像存储的位置,这些是需要放到目标系统的文件
- build/ 所有组件执行编译的位置,各个组件都会有一个对应的目录
- host/ 包含host的编译工具和sysroot of target的编译工具链。首先安装了buildroot运行所必须的编译工具,然后就是一个root目录的结构,主要包含编译包所依赖的各种头文件、lib及包。这个目录主要用来编译的,并不是最终嵌入式系统的root结构。
- staging/ 这是一个符号链接, 指向host/…/sysroot, 主要是为了向前兼容而保留的。
- target/ 包含了目标系统几乎完整的root 文件系统,除了没有/dev/。也缺失了准确的权限,也不能直接用到最终的嵌入式系统。我们最终使用的是images目录下的安装文件来安装的。目标系统最终安装的文件,将缺失开发所需要的文件, 而且二进制文件是被stripped的
使用指南
make menuconfig有一个快捷搜索工具,通过按下 / 调出。然后输入字符串查找到指定的项, 最后输入列表的数字索引即可定位到具体的条目。
交叉工具链
pass
1 | make sdk |
/dev管理
pass
init system
pass
通用指南
有一些帮助命令
1 | make V=1 <target> // 显示make执行的所有命令 |
关于是否需要完整编译
- 目标架构变更时, 需要重新完整编译
- 工具链变更时, 需要完整编译
- 新增了一个package,不需要完整编译。如果新增了一个lib,需要手动编译lib或者完整编译。
- 删除了一个package,默认什么也不做。不会主动删除对应包已经安装到target root文件系统的sysroot的文件。
- 一个package修改了suboption,只需要重新编译package。一旦一个package编译了,那么它将不会被重新编译。
- 当依赖包重新编译或者删除了,该package不会自动重新编译。需要手动编译package。
重新完整编译命令
1 | make clean all |
使用buildroot开发
buildroot的正常的操作是下载压缩包、解压、配置然后编译、安装软件。源码会被解压到output/build/<pkg>-<version>
目录,这个目录在make clean的时候会被删除。开发过程中,直接在这个目录作修改的话,很容易被清除掉。buildroot提供了一个机制,叫做<pkg>_OVERRIDE_SRCDIR
, buildroot会读取一个文件,用户可以指定源码的路径。
可以通过$(CONFIG_DIR)/local.mk
文件来定义位置关系。格式如下:
1 | <pkg1>_OVERRIDE_SRCDIR = /path/to/pkg1/sources |
一旦buildroot发现定义了某个包的位置,那么它将不会下载、解压package了。而是直接使用指定的目录, 并且调用make clean时,也不会清除目录。buildroot会拷贝源文件到output/build/<pkg>-custom
. 我们在修改完代码后,只需要make <pkg>-rebuild all
就会自动拷贝代码,很是方便。还可以指定不同步的目录:
1 | # local.mk |
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。