开发环境ubuntu12.04,x86_64,gcc4.6
arm板子环境armeabi,32bit,gcc5.3
以shell里面经常用到的file程序为例子
从ftp://ftp.astron.com/pub/file/上面下载源代码,因为我的ubuntu使用的是file5.09,不支持编译最新版本的file.5.25,所以我就下载file5.09了。
如果是从源代码编译安装file程序,应该这样做:
./configure make sudo make install
没啥好说的
如果我没有root权限,不是sudo组的,或者想把file安装到其他目录,怎么办呢?有两种情况:
第一种,错误的方法
./configure make make install DESTDIR=/home/tree/tools
编译完了,使用DESTDIR参数指定了一个安装路径,也没什么难理解的。运行/home/tree/tools/bin/file /home/tree/tools/bin/file:
/home/tree/tools/bin/file: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x1be35519b339d86fd2d4f73686b27c3573bdd988, not stripped
这不可以运行嘛,怎么能说是错误的方法呢?确实可以运行,但是如果你
sudo mv /usr/share/misc/magic.mgc{,.bak}然后就发现你的/home/tree/tools/bin/file用不了了,即使你重新编译安装也用不了了,所以说这是一种错误的方法。
仔细看/home/tree/tools/bin/file的错误提示(可以使用/home/tree/tools/bin/file -v查看file需要的magic file的路径),说找不到/usr/share/misc/magic.mgc,肯定找不到,因为你编译安装的被magic.mgc安装在/home/tree/tools/share/misc/magic.mgc。
file程序使用绝对路径去找它需要的magic file,谁知道你把magic file安装到哪里了(测试前需要删除/usr/share/misc/magic.mgc,这是系统自带的,/home/tree/tools/bin/file会使用一个默认值去找这个文件,编译安装前删除它,防止干扰),所以用不了,如果file程序使用相对路径去找magic file的话,是可以正确运行的。
第二种方法,当然是正确的方法了
./configure --prefix=/home/tree/tools make make install挺像的吧,即使你删除了/usr/share/misc/magic.mgc,编译出来的file也是可以正确运行的,毫无压力。vi config.log查看一下:
prefix='/home/tree/rootfs' datarootdir='${prefix}/share' datadir='${datarootdir}' pkgdatadir='$(datadir)/misc'
vi src/Makefile.am可以看到:
MAGIC = $(pkgdatadir)/magic AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"'--prefix参数被用来拼接目录,然后定义MAGIC宏传递给file程序,file从这个目录里面找magic file(当然,file也会从一些默认的位置查找magic file,自己看源码)
可以这样理解,--prefix为程序运行所需的目录的前缀,默认为/usr,经过和/bin, /etc, /lib等拼接后,指定程序运行时需要dlopen的.so存放的位置,配置文件/数据文件存放的位置等
DESTDIR指定安装程序的前缀,默认为空,程序最终将安装到DESTDIR/prefix的位置,里面有bin/file, share/misc/magic.mgc等。
ps:如果将tools文件夹重命名了,file程序就用不了了,原理很简单,file程序找不到/home/tree/tools/share/misc/magic.mgc了,所以程序中使用这种绝对路径的方式是有一些不便之处的,不能将程序安装到任意位置了,使用相对路径就可以解决这个问题。
那么--build, --host, --target又是什么鬼呢?
--build指定编译机器的架构,configure程序基本上可以自己猜出来这个值,不用设置
--host指编译出来的程序,运行在哪里,默认值为--build
--target指编译出来的程序,处理什么平台的文件,默认为--host
比如编译x86_64程序,在x86_64上编译,编译出来的程序运行在x86_64上面,处理x86_64的文件,不用指定这三个参数,默认都为x86_64-unknown-linux-gnu这样的
编译交叉编译工具链,在x86_64上编译,编译出来的程序运行在x86_64上面,处理arm的文件,需要修改--target=arm-unknown-linux-gnueabi这样的
使用交叉编译工具链编译arm程序,在x86_64上编译,编译出来的程序运行在arm上面,处理arm的文件,需要修改--host=arm-unknown-linux-gnueabi,--target默认和--host相同,可以不指定(注意configure时需要指定CC=arm-unknown-linux-gnueabi)
好了,我们来编译一个arm版本的file程序玩玩吧:
CC=arm-unknown-linux-gnueabi ./configure --prefix=/home/tree/rootfs make make install
能用不,不能用。把file,libmagic.so,magic.mgc拷贝到arm板子上,提示找不到magic file /home/tree/rootfs/share/misc/magic.mgc,能找到才怪了呢,那是编译机器上面的路径,那么怎么玩呢?
CC=arm-unknown-linux-gnueabi ./configure --prefix=/usr make make install DESTDIR=/home/tree/rootfs/usr这个才能用,arm版本的file觉得我应该去/usr/share/misc/magic.mgc里面找文件,刚好能找到。如果make install时不指定DESTDIR,就会把arm程序安装到编译机器的/usr目录了,顺便还没有安装权限。
再把file, libmagic.so, magic.mgc文件拷贝到板子上去,发现可以正常使用了。
还有一个参数,--with-sysroot,整啥的?
一般是交叉编译才能用得到的,包括编译交叉编译工具链和使用交叉编译编译arm程序,用于指定从编译器从哪里找所要的.so, .h什么的,不指定--with-sysroot的话,就会找编译机器的/usr/include, /usr/lib下面的东西。编译arm程序去找x86_64的头文件,那肯定是有问题的,如果有一些硬件平台相关的文件,才会暴露出问题,否则也看不出来有什么问题,比如之前编译的arm版本的file程序,就没有--with-sysroot参数。
总结一下,交叉编译arm的程序,--prefix必需设置为/usr这样的,不能够带编译机器的绝对路径,必需指定--with-sysroot=${arm_rootfs},必需使用DESTDIR=${arm_rootfs}去make install,${arm_rootfs}是你的arm的rootfs的路径,需要设置一下。
编译x86_64程序,程序很可能使用了--prefix去拼接一些目录,使用绝对路径去查找一些文件,这种情况下,不能够使用DESTDIR参数,也不能随便将编译出来的程序放到别的文件夹下面去运行;如果没使用绝对路径查找文件,而是使用相对路径,那么可以指定DESTDIR ,也可以将程序拷贝到其他位置,或者其他机器上运行。