如何交叉编译应用程序,技巧,注意事项。
最近大家都涉及交叉编译应用程序,感觉大家的路子有点偏,觉得有必要纠正一下。
一般的应用程序编译的步骤无外呼./configur e&&mak e&&m ake install但是对于交叉编译不能照搬,尤其要注意不能轻易mak e install(当然如果指定了--prefix就无所谓了,否则可能会覆盖标准路径的程序就惨了)这里有两个思路:1>对于刚开始交叉编译的人来说,往往很晕,总想借助./configure后面加一堆参数来解决,比如./ configure--tar get=ar m-9tdm i-linux-gnu--host=arm-9tdmi-linux-gnu来搞定,对于一般的小的程序来说,应该没有问题,而且也推荐大家这样用,但是要注意,这样作之前,先要./ configure--help|grep--host,看看有没有这样的选项,如果没有呢?想想也可能,如果程序的作者根本没有考虑到除了x86的平台呢?你只能自己改写Mak efile了。
所以,./configur e不是万能的,而且语法很混乱,不要指望./configure给你作一切。
而且局限很大。
2>所以这个时候,就要求交叉编译的第二个层次,自己改写Mak efile,想怎么改就怎么改,灵活性最大需要你开始就./configure一下,跟平台有关的参数一律不加。
./configur e过后就会生成Makefile了,里面的gcc相关的参数,包括lib的路径当然是x86下的了,比如/usr/local/lib/,/usr/lib/,/lib/什么的,改掉就是了。
或者注释掉。
gcc要换成ar m-linux-gcc一类的编译器,(如果不想每次都改,参考下面的include prer ules.m k的做法),总之,这要求你的Makefile掌握的很熟练,思路就是边编译,发现问题,再改,即使一开始Mak efile 不熟练,到后来,也熟练了。
是个练习Mak efile的好方式。
总之,我们最后要的就是Makefile,看你怎么能得到它。
一个最标准的Mak efile(去掉很多无用的东西)通过./configure生成的Makefile,你会发现冗余的地方非常多,其实关键的地方,就那么20几条,可以试着精简一下,这样对程序的组织架构会熟悉的快一些,毕竟Makefile反应了程序(具体就是.c和. h)之间的依赖关系。
openssh的Mak efile我没有精简过(当然要精简也很容易),举个telnetd的例子,说明一下:---------------------------telnetd----------------------------------------#-----------------------------------------------------TOPDIR:=$(shell/bin/pwd)TOPDIR:=$(TOPDIR)/..#prerules.mk包含了这些变量的定义,比如$CC,$CPP,$CXX,$CFLAGS等等。
#尽量不要在这里出现,CC=arm-linux-gcc这样的定义,扩展性不好,尽量用全局变量,便于管理和拓展。
include$(TOPDIR)/pr erules.mk#-----------------------------------------------------EXEC=telnetd#好的Makefile都是这样写的,也就是具体生成一个可执行文件或者lib库,需要哪些.o,这些.o会依据后面的.c.o:规则来编译出来的。
OBJS=telnetd.o state.o term stat.o slc.o sys_term.o\utility.o global.o authenc.o logwtm p.o logout.o#$(CC)的编译选项,一般程序自己的带的,不要改它,而且一般都是+=,不要用=,CFLAGS+=-DEMBED-DPARANOID_TT YS-DUSE_TERMIO-DKLUDGELINEMODE-D_GNU_SOURCE-Wallifdef CONFIG_DEFAULT S_LIBC_UCLIBCLDLIBS:=-lutil$(LDLIBS)endifall:$(EXEC)#很显然all是最关键的了,也要发在最开始的地方。
这样m ak e就相当于m ak e all,这是大家的潜规则。
.c.o:$(CC)-c-o$@$<$(CFLAGS)-I../include/-I.-Ixxx在交叉编译的时候,要在这个后面添上自己的头文件的路径。
$(EXEC):$(OBJS)$(CC)$(LDFLAGS)-o$@$(OBJS)$(LDLIBS$(LDLIBS_$@))#这里的LDFLAGS=-lcrypt-lzlib-L../lib-L.总之根据自己的需要往里面增加。
$(STRIP)telnetd#如果不需要调试,一定要strip一下,比如15M的file,strip过后,可能变成3M,还不影响功能。
install:cp$(EXEC)$(T_USBIN)#自己写install,不要用原来的,可以copy到自己的r am disk中去。
clean:-r m-f$(EXEC)*.elf*.gdb*.[do]$(OBJS):defs.h ext.h pathnames.h telnetd.h logwtm p.h logout.h交叉编译成功后,就万事大吉了,这才万里长征的第一步。
剩下的也许更麻烦呢。
首先拿到一个opensour ce,我们首先要让它在pc上run起来才行至少我们要稍微了解了一下它,才可以开始我们的cr oss compile的工作。
至少,我们要了解要r un这个程式,哪些东西是需要的,哪些是不需要的。
一开始,谁也不会了解的那么多,只能一步步的拿到板子上跑跑看了。
准备工作:1>如果是应用程序的可执行文件,我们可以用ldd命令来查看它需要哪些必要的库。
具体的命令:refer,http://infom ax/bbs/viewthr ead.php?tid=52&extra=page%3D12>看看需要哪些配置文件,也就是conf文件。
其实如果想知道上面的这些,还有个办法,就是先在pc上编译,安装,./configure--prefix=/work/bob(改成你自己的目录即可),m ake&&m ak e install,看看/work/bob/下面到底生成了哪些file,你不就心里有数了吗。
先把你知道的应用程序可执行文件copy到板子上去,执行一下,如果缺少哪些库,屏幕上会打出来一些出错信息的。
缺什么,就copy什么到板子上好了,多半缺的都是库(.so文件).如果还是莫名其妙的出什么问题(ps结果就是没有该进程),有可能是缺少什么配置文件,可以用str ace 来查查看:具体str ace的用法可以refer:http://infom ax/bbs/viewthread.php?tid=56&extr a=page%3D1如果程序运行的结果和pc上不太一样。
就要注意几个根本的问题了。
1>板子的endian是什么类型的呢?x86是little endian,arm的板子可能是little endian,也可能是big-endian的,如果是big-endian,就要注意了。
要在程序里面改,添加什么le32_to_cpu()这样的函数来转换的。
2>对齐问题,x86和arm的对齐处理方式是不一样的。
3>中文的问题,有些程序需要支持中文,繁体,什么的,pc上可以,拿到板子上就不可以了。
你要考虑一下glibc库上面是否支持locale,libiconv一类的库。
生成动态链接库的一个例子,也是标准的Makefile#Star t of Makefile#-----------------------------------------------------TOPDIR:=$(shell/bin/pwd)TOPDIR:=$(TOPDIR)/../../include$(TOPDIR)/pr erules.mk#-----------------------------------------------------SRCS=download.c cur l_err.c DownloadStatusQuer y.cOBJS=download.o curl_err.o DownloadStatusQuery.oCFLAGS+=-I../../include-Wall#-g-ggdball:libdownload.so.1.0.0#test_main:#$(CC)$(CFLAGS)-I../../../include/-o m ain main.c$(LIBS)-ldownload-L.-L../../../lib %.o:%.c或者.c.o:均可$(CC)-c-o$@$(CFLAGS)$<libdownload.so.1.0.0:$(OBJS)$(CC)-shar ed-Wl,-soname,libdownload.so.1.0-o libdownload.so.1.0.0$(OBJS) $(STRIP)libdownload.so.1.0.0r m-r f libdownload.so.1.0r m-r f libdownload.soln-s libdownload.so.1.0.0libdownload.so.1.0ln-s libdownload.so.1.0libdownload.socp-afv libdownload.so*$(COMM_LIB_PATH)cp-f download_oper ation.h$(COMM_INC_PAT H)cp-f oper ation.h$(COMM_INC_PAT H)cp-r f cur l$(COMM_INC_PATH)cp-f cur l_err.h$(COMM_INC_PATH)cp-f DownloadStatusQuer y.h$(COMM_INC_PAT H)install:#copy到ramdisk里面就好了cp-afv libdownload.so*$(T_LIB)#用-afv参数比较好,保证一模一样clean:r m-r f libdownload.so*r m-r f$(COMM_LIB_PAT H)/libdownload.so*r m-r f$(COMM_INC_PATH)/download_operation.hr m-r f$(COMM_INC_PATH)/oper ation.hr m-r f$(COMM_INC_PATH)/curl/r m-r f$(COMM_INC_PATH)/curl_err.hr m-r f$(COMM_INC_PATH)/DownloadStatusQuery.hr m-r f*.o----最后的时候,解释一下:$(CC)-shared-Wl,-sonam e,libdownload.so.1.0-o libdownload.so.1.0.0$(OBJS)会得到文件,libdownload.so.1.0.0,我们通常要作两个链接ln-s libdownload.so.1.0.0libdownload.so.1.0(这个是在板子上运行的时候,一定要有的,because,-Wl,-sonam e,libdownload.so.1.0了,写死了。