如何交叉编译应用程序,技巧,注意事项

如何交叉编译应用程序,技巧,注意事项。

最近大家都涉及交叉编译应用程序,感觉大家的路子有点偏,觉得有必要纠正一下。 一般的应用程序编译的步骤无外呼 ./configure && make && make install
   
但是对于交叉编译不能照搬,尤其要注意不能轻易make install(当然如果指定了 --prefix就无所谓了, 否则可能会覆盖标准路径的程序就惨了)
这里有两个思路:
1>
对于刚开始交叉编译的人来说,往往很晕,总想借助 ./configure后面加一堆参数来解决,比如 ./configure --target=arm-9tdmi-linux-gnu --host=arm-9tdmi-linux-gnu 来搞定
  
对于一般的小的程序来说,应该没有问题,而且也推荐大家这样用,但是要注意, 这样作之前,先要 ./configure --help |grep --host,看看有没有这样的选项,如果没有呢?想想也可能,如果程序的作者根本没有考虑到除了x86的平台呢?你只能自己改写Makefile 了。
  
所以 ./configure 不是万能的,而且语法很混乱,不要指望 ./configure给你作一切。而且局限很大。  
2>
所以这个时候 ,就要求交叉编译的第二个层次,自己改写Makefile,想怎么改就怎么改,灵活性最大 需要你开始就./configure一下, 跟平台有关的参数一律不加。./configure 过后就会生成Makefile了,里面的gcc相关的参数,包括lib的路径当然是x86下的了, 比如 /usr/local/lib//usr/lib/ ,/lib/ 什么的,改掉就是了。或者注释掉。 gcc 要换成 arm-linuxgcc一类的编译器,(如果不想每次都改, 参考下面的 include prerules.mk的做法),
  
总之,这要求你的Makefile掌握的很熟练, 思路就是边编译,发现问题,再改,即使一开始Makefile不熟练,到后来,也熟练了。 是个练习Makefile的好方式。
  
总之,我们最后要的就是Makefile 看你怎么能得到它。

一个最标准的Makefile (去掉很多无用的东西)

通过./configure 生成的Makefile ,你会发现冗余的地方非常多,其实关键的地方,就那么20几条, 可以试着精简一下,这样对程序的组织架构会熟悉的快一些,毕竟Makefile反应了程序(具体就是 .c .h )之间的依赖关系
     openssh
Makefile我没有精简过(当然要精简也很容易) 举个telnetd的例子,说明一下:
---------------------------telnetd ----------------------------------------
#-----------------------------------------------------
TOPDIR  :=  $(shell /bin/pwd)
TOPDIR  :=  $(TOPDIR)/..
#prerules.mk
包含了这些变量的定义,比如 $CC , $CPP , $CXX , $CFLAGS 等等。
#
尽量不要在这里出现, CC=arm-linux-gcc这样的定义,扩展性不好,尽量用全局变量,便于管理和拓展。
include $(TOPDIR)/prerules.mk
#-----------------------------------------------------
EXEC = telnetd
#
好的Makefile都是这样写的, 也就是具体生成一个可执行文件或者lib库,需要哪些.o,这些.o 会依据后面的 .c.o : 规则来编译出来的。
OBJS = telnetd.o state.o termstat.o slc.o sys_term.o /
utility.o global.o authenc.o logwtmp.o logout.o
#$(CC)
的编译选项,一般程序自己的带的,不要改它,而且一般都是+= , 不要用 =
CFLAGS += -DEMBED -DPARANOID_TTYS -DUSE_TERMIO -DKLUDGELINEMODE -D_GNU_SOURCE -Wall
ifdef CONFIG_DEFAULTS_LIBC_UCLIBC
LDLIBS := -lutil $(LDLIBS)
endif
all: $(EXEC)      
#很显然all是最关键的了,也要发在最开始的地方。 这样make 就相当于make 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一下,比如 15Mfilestrip过后,可能变成 3M,还不影响功能。
install:
cp $(EXEC) $(T_USBIN)       #
自己写install,不要用原来的,可以copy到自己的ramdisk中去。

clean:
        -rm -f $(EXEC) *.elf *.gdb *.[do]            

$(OBJS): defs.h ext.h pathnames.h telnetd.h logwtmp.h logout.h

 

交叉编译成功后,就万事大吉了,这才万里长征的第一步。 剩下的也许更麻烦呢。首先拿到一个opensource 我们首先要让它在pcrun起来才行至少我们要稍微了解了一下它, 才可以开始我们的cross compile的工作。至少,我们要了解要run这个程式,哪些东西是需要的,哪些是不需要的。一开始, 谁也不会了解的那么多,只能一步步的拿到板子上跑跑看了。
准备工作:
        1>
如果是应用程序的可执行文件, 我们可以用ldd 命令来查看它需要哪些必要的库。 具体的命令:
refer
http://infomax/bbs/viewthread.php?tid=52&extra=page%3D1  

        2>看看需要哪些配置文件,也就是conf文件。  

其实如果想知道上面的这些,还有个办法,就是先在pc上编译,安装, ./configure --prefix=/work/bob (改成你自己的目录即可) make && make install
看看/work/bob/下面到底生成了哪些file 你不就心里有数了吗。  

先把你知道的应用程序可执行文件copy到板子上去,执行一下,如果缺少哪些库 屏幕上会打出来一些出错信息的。缺什么 ,就copy什么到板子上好了,多半缺的都是库(.so 文件) .
  
如果还是莫名其妙的出什么问题(ps 结果就是没有该进程),有可能是缺少什么配置文件, 可以用strace 来查查看:
  
具体strace的用法可以 refer http://infomax/bbs/viewthread.php?tid=56&extra=page%3D1

如果程序运行的结果和pc上不太一样 就要注意几个根本的问题了。
      1>
板子的endian是什么类型的呢? x86 little endian arm的板子可能是little endian ,也可能是big-endian 的,如果是big-endian , 就要注意了。要在程序里面改,添加什么 le32_to_cpu() 这样的函数来转换的。
      2>
对齐问题, x86arm的对齐处理方式是不一样的。
      3>
中文的问题,有些程序需要支持中文,繁体,什么的, pc上可以, 拿到板子上就不可以了。 你要考虑一下 glibc库上面是否支持 localelibiconv一类的库。

 

生成动态链接库的一个例子,也是标准的Makefile

#Start of Makefile
#-----------------------------------------------------
TOPDIR  :=  $(shell /bin/pwd)
TOPDIR  :=  $(TOPDIR)/../../

include $(TOPDIR)/prerules.mk
#-----------------------------------------------------
SRCS = download.c curl_err.c DownloadStatusQuery.c
OBJS = download.o curl_err.o DownloadStatusQuery.o

CFLAGS += -I../../include -Wall  # -g -ggdb

all: libdownload.so. 1.0.0

#test_main:
# $(CC) $(CFLAGS) -I../../../include/  -o main main.c $(LIBS) -ldownload -L. -L../../../lib

%.o:%.c         
或者 .c.o:  均可
        $(CC) -c -o $@ $(CFLAGS)   $<

libdownload.so.1.0.0 : $(OBJS)
        $(CC) -shared -Wl,-soname,libdownload.so.1.0 -o libdownload.so.1.0.0 $(OBJS)       
                $(STRIP) libdownload.so.1.0.0
        rm -rf libdownload.so.1.0
        rm -rf libdownload.so
        ln -s libdownload.so.1.0.0 libdownload.so.1.0
        ln -s libdownload.so.1.0 libdownload.so
        cp -afv libdownload.so* $(COMM_LIB_PATH)
        cp -f download_operation.h $(COMM_INC_PATH)
        cp -f operation.h $(COMM_INC_PATH)
        cp -rf curl $(COMM_INC_PATH)
        cp -f curl_err.h  $(COMM_INC_PATH)
        cp -f DownloadStatusQuery.h   $(COMM_INC_PATH)

install:   # copy
ramdisk里面就好了
        cp -afv libdownload.so* $(T_LIB)    #
-afv 参数比较好,保证一模一样
clean:
        rm -rf libdownload.so*
        rm -rf  $(COMM_LIB_PATH)/libdownload.so*
        rm -rf  $(COMM_INC_PATH)/download_operation.h
        rm -rf  $(COMM_INC_PATH)/operation.h
        rm -rf  $(COMM_INC_PATH)/curl/
        rm -rf  $(COMM_INC_PATH)/curl_err.h
        rm -rf  $(COMM_INC_PATH)/DownloadStatusQuery.h
        rm -rf *.o

----

最后的时候, 解释一下:

$(CC) -shared -Wl,-soname,libdownload.so.1.0 -o libdownload.so. 1.0.0 $(OBJS)  

会得到文件,  libdownload.so.1.0.0

我们通常要作两个链接

ln -s libdownload.so.1.0.0  libdownload.so.1.0 (
这个是在板子上运行的时候,一定要有的,
because
-Wl,-soname,libdownload.so.1.0 了,写死了。
ln -s libdownload.so.1.0    libdownload.so (
这个是给别人链接的时候用的)

 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值