使用buildroot创建自己的交叉编译工具链
关键字:buildroot 交叉编译
Author: chad
Mail: linczone@163.com
开发环境: deepin 14.03 + mini2440 (使用原厂linux2.6.29)
曾经,很长一段时间我一直有个疑惑:为什么我用at91sam9260交叉编译工具链编译的程序只能在at91sam9260上运行,在mini2440上就不能运行?相反,用使用于mini2440的交叉编译工具链编译的程序在at91上也不能运行?mini2440与at91sam9260都是arm平台,同样使用linux系统,为何二进制程序不能通用呢?
本文将解答这些疑惑。我们是不建议重复发明轮子的,但如果我们不自己发明一次,我们永远不知道轮子是怎么来的。
进行嵌入式Linux开发的第一步是创建交叉编译工具链,在过去很长的一段时间里,构建一套交叉编译工具链对于嵌入式开发者来说简直是一场恶梦,因为他们得手动跟踪各种源码包(及其更新包)之间的依赖关系。直到buildroot的出现改变了这一事实。
Buildroot是一个Makefiles和patches的命令集,它可以非常简单的为你的目标系统产生一个交叉编译工具链和根文件系统,整个创建过程就如同编译Linux内核一般。
1、下载buildroot
直接从官网下载最新的源码包:http://buildroot.net/downloads/
2、安装依赖库、软件包
下文摘自buildroot官网操作说明:
1. Build tools:
gcc (version 2.95 or any later)
g++ (version 2.95 or any later)
python (version 2.6 or 2.7)
2. dependencies packages:
下面的自己根据需要安装
ncurses5 ;menuconfig 使用
qt4 ;xconfig 使用
glib2, gtk2 and glade2 ;gconfig 使用
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
3、 解压buildroot压缩包
4、 进入源码目录,make menuconfig配置
配着之前看看下s3c2440数据手册摘录:
接下来简单解释几个比较重要的选项:
Target Architecture ---> 用于选择目标的架构,我这里选择ARM (little endian)(s3c2440可以运行在小端模式和大端模式,默认是小端模式)
Target Architecture Variant ---> 内核类型(arm920t)
Target ABI (EABI) ---> 目标使用的应用程序二进制接口,其中有两个选择
①EABI(Embedded ABI) 我们选EABI.
②OABI(Old ABI)
Build options ---> 主要是一些编译时用到的选项,比如dl的路径,下载代码包使用的路径,同时运行多个编译的上限,是否使能编译器缓冲区等等,这里按照默认就行了.
Toolchain ---> 工具链选项
Toolchain type (Buildroottoolchain) ---> 工具链类型,这里我们没使用外部Buildroot,默认 .
*** Kernel Header Options ***
Kernel Headers (Linux 3.18.x kernel headers) --->
C library (glibc) ---> 有uclibc/glibc等选项,此处我选择glibc,后面会解释原因
glibc version (2.20) --->
*** Binutils Options ***
Binutils Version (binutils 2.24) --->
() Additional binutils options
*** GCC Options ***
GCC compiler Version (gcc 4.8.x) --->
() Additional gcc options
[*] Enable C++ support
[ ] Enable compiler OpenMP support
[ ] Enable libmudflap support
[ ] Enable graphite support
[ ] Build cross gdb for the host
[ ] Purge unwanted locales
() Generate locale data
[ ] Copy gconv libraries
[*] Enable MMU support
() Target Optimizations
() Target linker options
- 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
5、保存退出,生成.config 文件
6、编译
$make
这里不能使用make-jN,因为Buildroot不支持top-levelparallel make , 反之 , 使用BR2_JLEVEL选项来告诉Buildroot运行编译每一个package使用make -JN.
使用make命令之后会执行下面几个步骤:
①下载源文件(所要求的)
②配置,编译和安装cross-compiling toolchain(如果使用内部工具链),或者输出一个toolchain(如果一个外部工具链使用)
③构建/安装杯选择的目标包
④构建内核镜像(如果有选择)
⑤构建启动代码镜像(如果有选择)
⑥创建根文件系统(如果有选择)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
7、输出文件介绍
输出文件全部在output/目录下:
- images/ — 存放编译后产生的所有镜像文件( 内核镜像 , 加载引导镜像 和 根文件系统镜像)
- build/ — 存放所有的组件除了构建交叉编译工具链的组件 , 在这个目录里面每一个功能对应一个子目录存放他们各自的组件.
- staging/ — 包含一个类似于根文件系统等级层次的层级 . 这个目录包含了 安装的交叉编译工具链 和 所有被选择用于目标板的所有用户空间包.
- target/ — 包含了根文件系统,但不能用于你的开发板的
- host/ — 包含了我们需要的交叉编译工具集
我们可以在host/usr/bin/里面看到很多我们需要的二进制文件,如下所示:# cd host/usr/bin/
8、修改环境变量
在/etc/profile文件里加入:
# vim/etc/profile
添加上: exportPATH=$PATH:/home/chad/works/binutils/buildroot-2015.02/output/host/usr/bin
保存之后,执行以下命令使其生效:
# source/etc/profile
- 1
- 2
- 3
- 4
9、测试arm-linux-gcc
打印出版本号说明编译成功:
10、hello.c测试
编写一个hello.c程序,使用arm-linux-gcc编译并下载到开发板进行测试。
按照上文的配置,程序运行肯定是正常的。
但是如果上面选择的是uclibc,duang!程序运行就会出错!
C library (uclibc) ---> 有uclibc/glibc等选项,此处如果选择uclibc
- 1
如果我们用hexdump 查看hello的二进制文件,会发现如下信息:
#hexdump -C hello
- 1
然后我们用同样的方法查看能正确执行的二进制程序的信息,随便打开一个信息如下:
发现区别没?mini2440默认调用的是glibc库,而不是uclibc库。
需要注意的是,buildroot编译效率很低,一次编译完成后,如果你想修改某些东西,则必须重新全部编译!!也即先make clean 再 make。
如何重新编译软件包?
经过第一次完整编译后,如果我们需要对源码包重新配置,我们不能直接在buildroot上的根目录下直接make,buildroot是不知道你已经对源码进行重新配置,它只会将第一次编译出来的文件,再次打包成根文件系统镜像文件。不过,我们可以通过以下两个方法修改源码的配置。
- 直接删除源码包,例如我们要重新编译openssh,那么可以直接删除output/build/openssh-vesion 文件夹,那么当你make的时候,他就会自动从dl文件夹下,解压缩源码包,并重新安装
- 也是以openssh为例子,如果我们不想重新编译,只想重新配置,也就是./configure,
我们可以直接删除 output/build/openssh-version 目录下的 .stamp_configured
如果你只是想重新安装可以删除.stamp_target_install
重新make可以删除.stamp_built
总结:
为什么针对mini2440的交叉编译工具链与针对at91sam9260的交叉编译工具链不通用?
看下我们前面制作交叉编译工具链都指定了那些重要参数:
Target Architecture ---> 目标的架构,s3c2440 与 at9260 都是arm,这个相同
Target Architecture Variant ---> 内核类型(s3c2440[arm920t] 而 at91sam9260[arm926EJ-S],但是配置时选择arm926t),此处不同
Target ABI (EABI) ---> 目标使用的应用程序二进制接口,此处不同
①EABI(Embedded ABI) mini2440的选择。
②OABI(Old ABI) at91sam9260的选择
Kernel Headers (Linux 3.18.x kernel headers) ---> 此处差别影响不大
C library (glibc) ---> 都选择的是glibc
glibc version (2.20) ---> 版本不一样
至此,我想两个平台的交叉编译工具链不可通用的原因应该已经很清楚了。
—————–2015-05-21