林炎,张友益
(1.江苏科技大学 电子信息学院,镇江212003;2.中国船舶重工集团公司 第七二三研究所)
随着计算机技术、网络技术和微电子技术的深入发展,嵌入式系统的应用无处不在。交叉编译是伴随嵌入式系统的发展而来的[1]。传统的程序编译方式,生成的程序直接在本地运行,这种编译方式称作本地编译;嵌入式系统多采用交叉编译的方式,在本机编译好的程序是不能在本机运行的,需要通过特定的手段(例如烧写、下载等)安装到目标系统上执行。交叉编译的实现克服了嵌入式系统目标平台存储空间和运算能力有限的缺点[2],完善的工具链可以保证项目开发的进度和质量[3],是嵌入式开发的第一步,也是关键的一步[4]。
交叉编译环境包括两个部分,其中,本机Linux环境是重要的基础。基于本机Linux环境,构建交叉编译工具链是关键。
本机的Linux环境可以选择安装Linux操作系统,或者在Windows下安装虚拟Linux环境软件[5]。Linux环境中有很多优秀的开源开发工具,而Windows是目前PC机上最普及的操作系统。为了兼顾Linux和Windows,选择在Windows下安装虚拟Linux环境。Windows下安装虚拟Linux环境主要有以下3种方式:
①虚拟机,如Vmware、VirtualBox等。虚拟机虚拟出一台真实的计算机出来,只需要在这台虚拟计算机上安装Linux,其效果和真实Linux系统完全一样。但这样所需占用的系统资源相当多,速度受硬件配置的限制很大[6]。
②CoLinux及其衍生品,如AndLinux。CoLinux 创建的是一个真正的Linux操作系统[7],其原理是将一个发行版Linux“改造”为一个Windows平台下的应用程序,并以原生方式运行Linux的软件。这是一个很有潜力的解决方案,但目前存在两个很明显的软肋:一是被改造好的发行版数量非常有限,版本也非常陈旧;二是仅仅支持32位机的安装。
③Cygwin。Cygwin是由RedHat公司负责维护的,经多年来不断的发展,对于Linux的虚拟日臻成熟。Cygwin的设计思想十分巧妙,它在Windows上设计了一个Linux系统调用中间层,模拟Linux的系统调用,只需要把Linux下的工具在Windows系统重新编译,做一些较小的修改即可移植到Windows 系统。Cygwin 几乎移植了Linux系统常用的所有开发工具[2],用户可以根据自身的需要装卸,十分灵活。Cygwin作为开源软件,支持32/64位机的安装,占用系统资源少,运行速度快,指令与Linux基本一致,更可以方便地与Windows共享文件(夹)。
①从http://cygwin.com 下载最新的Cygwin。
②安装Cygwin。首次安装通常选择直接从Internet下载(Install from Internet)安装的模式,并选择一个目录作为安装包的存放路径(Local Package Directory)。下载好的安装包将被保留在这个目录中,以便再次安装时直接由本地安装(Install from Local Directory)。更新时,安装程序将只下载比这个目录中更新的安装包。
③下载镜像的选择。Cygwin提供了大量的镜像下载站点,用户可以选择一个合适的站点下载安装包。再次安装时,还应选择同一个站点。
④安装包的选择是Cygwin安装与配置过程中最重要的一步。选择全部安装包下载,需要很长的时间,且安装大量无用的安装包之后,还会大大地影响到Cygwin运行的速度。对于嵌入式开发而言,建议将Archive、Base、Devel、Doc、Editors、Interpreters、Libs、Net、Shells、System、Text、Utils、Web下的安装包全部(all)安装,其他安装包缺省(default)安装。
安装成功后,便可进入到Cygwin环境,命令行提示符为“$”。Linux的文件系统都是从“/”开始的,Cygwin的“/”就是在Windows中的安装路径(如X:\cygwin)。
对于Cygwin而言,交叉工具链通常有3个来源——已经制作好的交叉编译链、分步手工编译交叉工具链以及使用脚本自动生成的交叉工具链。
如GNU ARM toolchain[9],选择Cygwin版本下载、安装好后,在Cygwin中就可直接使用,十分方便,但只适用于无MMU 的嵌入式Linux(如ucLinux);又如厂商提供的交叉工具链,都是厂商测试通过的,可靠性很高,而且与开发板能够很好地吻合,但是由于时间滞后的原因,往往都不是最新的版本,当系统内核升级后,会出现兼容性问题[10]。最重要的是,Cygwin 并不支持以原生方式运行Linux程序,如果厂商没有提供Cygwin中可以使用的交叉工具链,这种方法就是不可行的。总而言之,使用已经做好的交叉工具链有很大的局限性。
分步手工编译交叉工具链即分别编译和安装交叉工具链所需要的库和源代码。执行上比较困难,需要比较清楚地了解每个工具链软件的相互匹配情况,而且也可能会受到不同的发行版之间差别的影响,比较容易出错或者编译不通过[11]。
自动生成的交叉工具链最著名的当属Crosstool。但用Crosstool编译的交叉工具链,GCC版本只能到4.1.1,无法编译版本高于2.6.29的Linux内核。Crosstool-NG(Crosstool-Next Generation)是Crosstool 的替代者。Crosstool-NG一直保持着更新,随着开源社区更新和改进GCC、Glibc以及相关的工具,与编译工具链相关的代码也会不断发生演化,这使得它能很好地完成维护任务。[12]
Crosstool-NG 会自动完成Linux环境下头文件、库文件、内核版本和交叉编译工具链的匹配,方法简单易行,也不容易出错[11]。下文就详细介绍了如何在“Windows 7 64bit+Cygwin 1.7.16-1”平台下,利用Crosstool-NG 1.16.0,针对32 位ARM 核S3C6410 微处理器,搭建Linux交叉编译环境。
①将Windows系统设置区分大小写模式。Unix和类Unix系统(如Linux)都是区分大小写的。Cygwin模拟Unix环境也要求区分大小写,但Windows系统本身对大小写并不加以区分。解决的办法是将注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Kernel项中“obcaseinsensitive”值置为“0”,重启计算机后,Cygwin下就可以区分大小写了。
②从http://crosstool-ng.org下载最新的Crosstool-NG,将压缩包复制到Cygwin 的/home/ng/下,进入目录,解压压缩包$tar-jxvf crosstool-ng-1.16.0.tar.bz2,再进入解压目录$cd crosstool-ng-1.16.0。如果有补丁文件,也下载到此目录下,为Crosstool-NG 打补丁($patch-p1 <<补丁文件>)。
③针对Cygwin,对Crosstool-NG 作如下几处修改。(a)修改kconfig/Makefile。在“$(conf_OBJ)$(conf_DEP):CFLAGS+= $(INTL_CFLAGS)”后加上“conf:LDFLAGS+=-lintl”一行,将“mconf:LDFLAGS+= $(NCURSES_LDFLAGS)”修改为“mconf:LDFLAGS+= -lintl $(NCURSES_LDFLAGS)”,将“nconf:LDFLAGS+=-lmenu-lpanel-lncurses”修改为“nconf:LDFLAGS+=-lintl-lmenu-lpanel-lncurses”。(b)修改kconfig/nconf.c。将“ESCDELAY=1;”修改为“set_escdelay(1);”。
④配置Crosstool-NG($./configure--prefix=/opt/ng/install),经过编译($make)后,安装Crosstool-NG($make install)。
⑤创建交叉工具链的构造目录($mkdir-p/opt/ng/build)和源码包目录($mkdir-p/opt/ng/src),并根据目标系统CPU 的情况,从配置模板目录中拷贝相应的参考config文件到构造目录($cp/opt/ng/install/lib/ct-ng.1.16. 0/samples/arm-unknown-linux-gnueabi/*/opt/ng/build),进入构造目录($cd/opt/ng/build),将config文件改更名为.config($mv crosstool.config.config)。为方便调用 ct-ng,修改环境变量 ($export PATH=${PATH}:/opt/ng/install/bin)。
⑥进入配置交叉工具链界面($ct-ng menuconfig)。
(a)首先,设置保存编译的中间步骤,勾选上Debug Crosstool-NG,以及随之产生的Save intermediate steps项。编译工具链出错是很难避免的,记录下编译的每一步状态,在出现错误并纠正错误之后,Crosstool NG 就可以从出错的那一步开始继续编译。然后,设置编译工具链所需源码包的目录(Local tarballs directory)为/opt/ng/src以及交叉编译器的安装目录(Prefix directory)为/usr/crosstool-ng。最后,增加编译时的并行进程数(Number of parallel jobs),以提高运行效率。这个数值一般应为CPU核数的两倍,如双核CPU 就应填4。
(b)对于ARM 核S3C6410而言,Target Architecture和Default instruction set mode缺省的配置已经是arm,不用修改。指令集的架构(Architecture level)应设置为armv6。处理器的类型(Emit assembly for CPU)应设为arm1176jzf-s。浮点选项(Floating point)应选硬件VFP(hardware FPU)。
(c)Toolchain options。在Tuple's vendor string前的括号中可以输入个性化的前缀名,如输入lynn,就将产生名为arm-lynn-linux-gnueabi-的交叉工具链。留空的话,最后生成的工具链的名字是arm-unknown-linux-gnueabi-。
(d)在Operating System 中选择合适的嵌入式Linux内核版本号。
(e)在Binary Utilities中设置Binutils库的版本号。Binutils是一个二进制工具集合,包含了汇编器、反汇编器、连接器、ELF可执行文件分析器等重要工具[14]。
(f)在C Compiler中设置交叉编译器GCC的版本号和所要支持的语言。GCC 是一组编译工具的总称,包括C/C++语言编译器、源代码处理程序和各种库文件[15]。建议关闭Fortran和Java语言的支持,因为这些语言通常无法针对目标机通过编译。[12]
(g)在C--library中设置交叉编译器所要支持的C库及其版本号(注意选上“Forced unwind support”)。Glibc是Linux系统中最底层的应用程序开发接口(API),包含了各种函数库[6],所有动态链接的程序都要用到它。这里需要注意的是,Glibc和内核源代码的版本必须与目标机上实际使用的版本保持一致[15]。
(h)在Debug facilitites中配置交叉编译器的调试工具。其中,ltrace不支持Linux的虚拟环境,不要选择;而duma需要进行一定的修改之后才能被编译(将duma源码包解压缩,打开GNU makefile文件,在ECHOLF=echo后添加OS=cygwin,再将duma重新打包);GDB 最为常用,可以调试C和C++语言程序[1]。
(i)在Companion library中设置GMP、MPFR、PPL、CLooG/ppl、MPC的版本号,它们是除C 库以外,交叉编译工具额外需要的库。
(j)保存配置(Save an Alternate Configuration File),退出配置界面(Exit)。
Crosstool-NG 会自动下载、解压、配置、编译、链接所需的源码包。不过,为了加快制作工具链的进度,可以通过查看经过完成配置之后的config文件,预先下载好其中提及的源码包(压缩包格式不限),并将它们全部放入源码包目录内,便可交由脚本工具开始制作交叉编译链($ctng build)。
经过若干小时的编译,编译好的工具链将保存在交叉编译器的安装目录中。我们可以看到,生成的所有工具扩展名都是“.exe”,也就是说,这些工具都是在Windows系统下运行的执行程序。
添加交叉工具链到环境变量($vi/etc/profile,也可在Windows中用文本编辑器修改X:\cygwin\etc\profile),在文件的末尾添加交叉工具链的路径(PATH=$PATH:/usr/crosstool-ng/arm-lynn-linux-gnueabi/buildtools/bin),立即更新环境变量($source/etc/profile),工具链就可以直接使用了。如输入指令“$arm-lynn-linuxgnueabi-gcc-v/--version”,就可查看工具链的版本。
为方便使用,可以为交叉工具链建立“快捷方式”。进入交叉工具链的目录($cd/usr/crosstool-ng/arm-lynnlinux-gnueabi/buildtools/bin),建立符号链接(如$ln-s arm-lynn-linux-gnueabi-gcc arm-linux-gcc)。注意链接名不要与本地编译器同名。
交叉编译环境搭建好之后,必须通过编译文件来验证其是否能够正常工作。写一个最简单hello.c源文件:
在交叉编译环境中,对以上程序进行交叉编译($arm-linux-gcc hello.c-o hello),生成名为hello 的文件。查看文件信息($file hello),看到类似“hello:ELF 32-bit LSB executable,ARM,version1(SYSV),dynamically linked(uses shared libs),for GUN/Linux 2.6.39,not stripped”的信息,即表明成功地编译了一个可以在ARM体系结构下运行的可执行文件,交叉编译环境已经被成功地搭建。
本文介绍了在Windows平台下,基于Cygwin 虚拟Linux系统,利用Crosstool-NG 建立ARM-Linux交叉编译环境的方法。验证结果表明,本方法适用于ARMLinux的开发。对于Crosstool-NG 所支持的基于其他嵌入式CPU 的目标系统,如MIPS、PowerPC 等,在Windows下构建Linux交叉编译环境,完全可以参照ARMLinux交叉编译环境的构建方法进行。
[1]雷鸿.基于虚拟机架构下嵌入式开发环境搭建的研究与实现[J].信息通信,2011(4):11-13.
[2]弓雷.ARM 嵌入式Linux系统开发详解[M].北京:清华大学出版社,2010.
[3]李新峰,何广生.基于ARM9的嵌入式Linux开发技术[M].北京:电子工业出版社,2008.
[4]华清远见.嵌入式Linux C语言应用程序设计[M].北京:人民邮电出版社,2007.
[5]熊光泽,罗蕾.嵌入式软件技术的发展现状与发展动向[J].计算机应用,2000,20(7):23-26.
[6]刘永林,梁莹,王诗琴,等.基于Linux的嵌入式交叉编译环境的建立及实现[J].电脑开发与应用,2011,24(7):68-70.
[7]赵庆明,罗蕾,周建斌,等.CoLinux在构建嵌入式开发环境中的应用[J].微计算机信息,2009(23):15-17.
[8]Cygwin.Cygwin User's Guide[R/OL].[2012-11-10].http://cygwin.com/cygwin-ug-net/cygwin-ug-net.html.
[9]赵峰.ARM 交叉编译和调试[R/OL].[2012-11-10].http://www.eefocus.com/article/07-11/28362s.html.
[10]张欢庆,高丽,宋承祥.基于ARM 的嵌入式Linux交叉编译环境的研究与实现[J].计算机与数字工程,2012,40(2):151-153.
[11]刘二钢.利用Crosstool-NG 构建交叉编译工具链[J].电脑知识与技术,2011,7(7):4553-4554,4567.
[12]Gene Sally.Pro linux embedded systems[M].California:Apress,2009.
[13]Yann Morin.Download and usage[R/OL].[2012-11-10].http://crosstool-ng.org.
[14]张瑞,于德海,马明龙.基于ARM 的嵌入式Linux的交叉编译环境的建立[J].科技信息,2009(25):508-509.
[15]李胜琴,张国荣,许岩.基于ARM 的交叉编译工具的制作[J].太原师范学院学报:自然科学版,2010,9(2):36-38.