调试经验--交叉编译
嵌入式开发,通常由于嵌入式环境的资源较少,只能够存放运行环境,所以将资源需求较大的开发环境都存放在PC上。这种情况,由于开发环境与运行环境不一致,所以就出现了交叉编译--即在开发环境下,编译出能在运行环境上运行的可执行程序。具体到davinci开发,其交叉编译过程就是在x86的linux系统下,编译出在davinci平台上linux系统下运行的可执行程序。
下面介绍了交叉编译的几个实例:
1,交叉编译一个驱动模块;
2,网络测试工具软件Iperf的交叉编译;
3,交叉编译activeMQ-cpp。
一、交叉编译一个驱动模块
交叉编译驱动模块,非常类似于直接编译驱动模块,区别只在于内核路径不同,修改为交叉编译环境的内核源代码路径即可。
另外需要注意两点:
1,内核源代码需要是编译过的,否则可能会遇到找不到某些头文件的错误。
2,目标文件名需要与.c文件名一致。
更详细的操作示例,参见我前面的一篇文章《Linux设备驱动学习-Davinci开发板上运行的hello模块》。
二、网络测试工具软件Iperf的交叉编译
Iperf 是一个网络性能测试工具,可以测试最大TCP和UDP带宽性能,数据包丢失情况等,Iperf既可以测试网络发送性能,也可以测试网络接收性能。
Iperf是一个开源软件,下载地址如下:
http://sourceforge.net/projects/iperf/
iperf是使用autoconf配置的makefile ,在linux下本地编译可以直接编译成功。
在linux下交叉编译到dm6467上运行,步骤如下:
1,配置编译工具的路径,如CROSS_COMPILE、CC、CXX、AR、RANLIB、NM、AS、LD、ARCH等。
2,在运行configure时指定 --host=arm-linux
3,在config.h.in中屏蔽一句:#undef malloc
关于前2步,我们通常是将其统一到一个执行脚本(例如命名为configure_cross)里面,在编译前配置时执行一次即可,具体内容如下:
export CROSS_COMPILE=/opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export RANLIB=${CROSS_COMPILE}ranlib
export NM=${CROSS_COMPILE}nm
export AS=${CROSS_COMPILE}as
export LD=${CROSS_COMPILE}ld
export ARCH=arm
./configure --host=arm-linux --prefix=/root/armfs_6467/usr/local/
说明:
CROSS_COMPILE 指示交叉编译路径及前缀,根据实际情况调整。
--prefix 指示最终生成文件的存放路径,根据实际情况调整。我这里设置的路径 /root/armfs_6467 是一个nfs文件系统对应的路径,用于嵌入式设备远程访问,作为嵌入式设备中Linux的根路径。
三、交叉编译activeMQ-cpp
一般的应用程序,进行交叉编译,参考Iperf的交叉编译,就可以解决问题了。这里之所以再说明一下activeMQ-cpp的交叉编译,实在是其依赖太多了,编译过程非常复杂。
ActiveMQ 是Apache出品,比较流行的,能力强劲的开源消息总线。
它支持多种语言和协议编写客户端,例如有使用c++编写的客户端,即我们使用的activeMQ-cpp。
1,下载ActiveMQ-CPP,其下载地址如下:
http://activemq.apache.org/cms/
2,查看依赖关系:
我下载的是 activemq-cpp-library-3.1.0 ,查看其 README.txt 中的 Dependencies,依赖非常多,具体如下:
Tool Recommended Version
-------------------------------
autoconf >= 2.61
automake >= 1.10
libtool >= 1.5.24
APR >= 1.3*
APR-Util >= 1.3* or higher
CPPUnit >= 1.10.2*
libuuid >= ?*
这是已经列出来的,在我实际编译过程中,还发现autoconf在产生“configure”脚本时还依赖于m4。
另外,libuuid不能直接下载,它是包含在e2fsprogs中。
3,下载ActiveMQ-CPP编译运行的依赖工具与库:
autoconf: http://www.gnu.org/software/autoconf/
m4: http://www.gnu.org/software/m4/
automake: http://www.gnu.org/software/automake/
libtool: http://www.gnu.org/software/libtool/
cppunit: http://sourceforge.net/projects/cppunit/
apr与apr-util都在一个网站上可以找到相应下载点:http://apr.apache.org/
libuuid: http://sourceforge.net/projects/e2fsprogs/
4,先不着急交叉编译,在PC上的linux下编译一遍。基本步骤是,先准备好编译工具(如autoconf、m4、automake),再编译依赖库,最后编译ActiveMQ-CPP库。
5,在PC上测试运行。这里测试也比较容易,因为开发人员实在考虑得周全,将测试代码已经准备好了。
测试ActiveMQ-CPP库是否编译成功:
make check
然后可以进行整合测试,当然,这时需要搭建ActiveMQ服务器,本文不做介绍,网上有相关介绍。
cd src/test-integration
./activemq-test-integration
6,PC上本地编译测试通过之后,再开始交叉编译。此时各源代码都需要交叉编译,除了只是在PC上生成进一步编译脚本的3个工程不需要重新编译。不需要交叉编译的3个工程是:
autoconf,m4,automake。
交叉编译,与本地编译比较,最大的差异,就是使用Iperf的交叉编译时的脚本configure_cross来替代configure。
另外还有一些小的差异:
如apr,apr-util,amq-cpp,都需要修改configure的参数。
apr的最后一句脚本修改:
./configure --host=arm-linux --prefix=/root/armfs_6467/usr/local/ ac_cv_file__dev_zero="yes" ac_cv_func_setpgrp_void="yes" apr_cv_process_shared_works="yes" apr_cv_mutex_robust_shared="no" apr_cv_tcp_nodelay_with_cork="yes" ac_cv_sizeof_struct_iovec="8" apr_cv_mutex_recursive="yes"
apr-util的最后一句脚本修改:
./configure --host=arm-linux --prefix=/root/armfs_6467/usr/local --with-apr=/root/armfs_6467/usr/local CPPFLAGS=-I/root/armfs_6467/usr/include LDFLAGS=-L/root/armfs_6467/usr/lib
并且apr_util的makefile 需要修改 -lexpat 为指定libexpat.so的全路径。
ActiveMQ-CPP的最后一句脚本修改:
./configure --host=arm-linux --prefix=/root/armfs_6467/usr/local/ --with-apr=/root/armfs_6467/usr/local --with-apr-util=/root/armfs_6467/usr/local
并且ActiveMQ-CPP可能还涉及某些内部makefile的修改(也可能是我的某些配置没配好?)。
另外,MQ-cpp目录下的libtool,需要用交叉编译出来的libtool替换。
7,考虑到测试,需要将源文件中的服务器IP改动为实际MQ服务器IP。
8,生成的库文件libactivemq-cpp.so非常大,都超过100M,在嵌入式环境下完全不能接受。运行arm_v5t_le-strip,缩小尺寸。
9,测试相关的simple_async_consumer、simple_producer文件也需要相应配置路径。
10,都编译完成,就启动嵌入式设备,测试运行一下吧。