今天和大家分享一下glib库的交叉编译过程和如何对程序进行编译以及运行。
glib库的移植资料比较少,比较零散,这里我就写一下亲自移植的过程,和大家分享一下。按照我的过程移植应该是不会有问题,如果遇到了问题可以留言联系我,一起讨论研究。
这里需要强调一下:libc、glibc、glib是不同的库!
glibc和 libc 都是 Linux 下的 C 函数库,而glib是GTK+的基础库
libc 是 Linux 下的 ANSI C 函数库;glibc 是 Linux 下的 GUN C 函数库。
具体的区分与概念可以参考:http://user.qzone.qq.com/452215612/2
先说一下我的上位机环境:
PC:XP sp3,深度完美 纯净标准版
虚拟机: VMware® Workstation,版本:9.0.2 build-1031769
ubuntu:12.04
在之前我已经在ubuntu上安装过glib2.0.6,并做了一些数据结构相关的教程,有兴趣的可以参考以下博文:
http://blog.csdn.net/andylauren/article/category/6219334
开发板环境:
FS4412开发板:采用三星ARM Exynos 4412四核处理器,
Linux3.14内核版本,
Uboot
2013.03,gcc-4.6.4交叉编译链
我们最终目的是在我们的开发板上能够执行使用了glib库的可执行文件。
要达到这个目的我们需要几个步骤:
1、需要使用交叉编译链交叉编译glib库;
2、将生成的动态库加入到文件系统的lib目录中;
3、使用交叉编译出来的glib库,交叉编译.c文件,然后在开发板中执行文件;
安装前准备:
glib源码包下载地址:
http://ftp.gnome.org/pub/gnome/sources/glib/2.24/
这里我们使用的是
glib-2.22.5.tar.gz
libffi源码包下载地址:
https://www.sourceware.org/libffi/
libffi是glib的依赖库,所以需要先交叉编译这个库,我们使用的是
libffi-3.2.1.tar.gz
pkg的安装:
pkg-config是一个很好的文本替换命令,主要用于编译命令上,用法下文会详细介绍
安装:apt-getinstall pkg-config
第一步:交叉编译glib库
在交叉编译glib前我们需要先交叉编译glib的依赖库libffi
1、libffi的安装
ffi是glib依赖的一个库,在交叉编译以前需要先交叉编译libffi
首先安装pc上的开发使用命令libffi-dev
键入:apt-getinstall libffi-dev 这一步为了解决configure时出现的问题,后文有介绍。
将libffi-3.2.1.tar.gz甩入ubuntu中
解压缩源码,并建立安装路径
这个没什么好看的,直接开始配置操作
键入:CC=arm-linux-gcc ./configure --prefix=/home/linux/glib/ffi/ --host=arm-linux
应该不会遇到任何问题,然后就会生成我们需要的Makefile文件。
然后就是三部曲中的
make
make insall
为了更好地在编译时使用自定义安装路径里的库,我们使用pkg-config来辅助我们编译glib,但要运行pkg-config,首先需要制作xx.pc文件:
我们先来到安装目录下的lib/pkgconfig目录下,里面有一个libffi.pc文件,由于这个库是给arm用的,所以我习惯在文件名后加上-arm:cp libffi.pc libffi-arm.pc
然后将libffi-arm.pc拷贝到/usr/local/lib/pkgconfig/下:cp libffi-arm.pc /usr/local/lib/pkgconfig/
这样pkg-config命令就可以识别到这个文件,大家可以先键入pkg-config --cflags libffi-arm看看会打印出什么呢?
-I/home/linux/glib/ffi/lib/libffi-3.2.1/include
这就是我们在交叉编译时需要用到的头文件路径。
2、交叉编译glib库
跟一般的安装一样,开始使用configure生成Makefile:
解压glib-2.22.5.tar.gz得到glib-2.22.5源码包目录。
先在glib-2.22.5目录下创建cache文件:gedit arm-linux.cache
然后在文件中输入:
glib_cv_stack_grows=no
glib_cv_uscore=no
ac_cv_func_posix_getpwuid_r=yes
ac_cv_func_posix_getgrgid_r=yes
glib_cv_have_qsort_r=no
运行configure的时候会从cache文件中读入配置,再将配置的log写入此文件
键入命令:CC=arm-linux-gcc ./configure --prefix=/home/linux/glib/glib-2.22/ --host=arm-linux --cache-file=arm-linux.cache
应该不会遇到任何问题,并生成了Makefile文件。
然后在glib目录下创建glib-2.22文件夹,用于保存生成的glib库文件。
然后就是三部曲中的
make
make insall
这个时候就会在glib-2.22文件夹下看到交叉编译好的glib库文件。里面会有bin,include,lib,share四个文件夹,分别有我们编译和运行时的文件和库。
第二步:将生成的动态库加入到文件系统的lib目录中
现在我们需要将编译好的glib动态库放到nfs文件系统的lib目录下,这样我们的程序在开发板上执行的时候就可以调用glib动态库了。
我们输入命令cp /home/linux/glib/glib-2.22/lib/libglib-2.0* /nfs/rootfs/lib/
这里我们将glib的所有库都拷贝到了nfs中,包括静态库,这是不必要的,我们只需要拷贝动态库就可以了。
其中文件libglib-2.0.so是一个硬链接,所以我们直接拷贝这个文
件就会在nfs中得到一个库的副本文件。正确的做法是拷贝libglib-2.0.so.0.2200.5文件,并做两个硬链接到这个文件,连接文件分别是libglib-2.0.so.0和libglib-2.0.so。
其实正确的做法是使用cp -a命令,其中的-a参数相当于-dpR,保持文件的连接(d),保持原文件的属性(p)并作递归处理(R),所以应该输入:
cp -a /home/linux/glib/glib-2.22/lib/libglib-2.0* /nfs/rootfs/lib/
然后在删除静态编译库文件 libglib-2.0.la
rm /home/linux/glib/glib-2.22/lib/libglib-2.0.la
第三步:使用交叉编译出来的glib库,交叉编译.c文件,然后在开发板中执行文件
我们现在拥有了glib的交叉编译库,而且在nfs文件系统中也有了动态库,我们需要使用一下这个库编译一个有glib函数的.C文件,并在开发板上运行起来。
我们从
http://blog.csdn.net/andylauren/article/category/6219334中选择一个.c文件来作为我们的源程序,然后我们需要知道一些编译时的参数,比如头文件路径的设置,库文件路径的设置,在编译时使用
-I加上路径来表示头文件的路径,-L表示库文件的路径。
在ubuntu上我们编译glib库文件时使用的方法是gcc xxx.c -o xxx -lglib-2.0 这里的-o后面是生成的目标文件名,不是必须要的,如果不加会生成a.out文件,-l后面是我门使用的库文件名,是去掉了lib开头的库文件名,这里为什么我们没有使用-I -L呢,因为我们已经把这些文件放到了系统默认路径中,编译的时候会自动去默认路径下找相应的文件。交叉编译的时候我们也需要对应的书写编译命令,这里我先把命令写出来,然后在讲解,编译命令如下:
arm-linux-gcc GTree.c -o gtree-arm -I/home/linux/glib/glib-2.22/include/glib-2.0 -I/home/linux/glib/glib-2.22/lib/glib-2.0/include -L/home/linux/glib/glib-2.22/lib -lglib-2.0
其中arm-linux-gcc是交叉编译用的gcc,还有一个arm-none-linux-gnueabi-gcc命令,其实和它一模一样的,后边我们会对他进行讲解;
GTree.c 是我们要编译的源码文件,-o gtree-arm我们要生成的目标文件;
-I/home/linux/glib/glib-2.22/include/glib-2.0 -I/home/linux/glib/glib-2.22/lib/glib-2.0/include我们头文件路径;
-L/home/linux/glib/glib-2.22/lib我们库文件路径;
-lglib-2.0我们调用的库文件;
然后我们将生成的gtree-arm文件复制到nfs文件系统目录中,cp gtree-arm /nfs/rootfs
将开发板设置为nfs挂载,然后我们启动开发板,运行./gtree-arm,哈哈看到运行结果了,和电脑上的运行结果一样,表示我们移植成功了。
[root@farsight ]# ls
a.out fs4412_led_app mnt sys
bin fs4412_led_drv.ko proc tmp
dev lib root usr
etc linuxrc sbin var
[root@farsight ]# ./a.out
12345
[root@farsight ]# ls
a.out fs4412_led_drv.ko proc usr
bin gtree-arm root var
dev lib sbin
etc linuxrc sys
fs4412_led_app mnt tmp
[root@farsight ]# ./gtree-arm
BEGIN:
************************************************************
Now the tree:
Key: 0 Vaule: zero
Key: 1 Vaule: one
Key: 2 Vaule: two
Key: 3 Vaule: three
Key: 4 Vaule: four
Key: 5 Vaule: five
Key: 6 Vaule: six
Key: 7 Vaule: seven
Key: 8 Vaule: eight
Key: 9 Vaule: nine
The tree should have '10' items now. Result: 10.
The height of tree is '4' now.
Now the vaule of '3' should be '3333' now.
Key: 0 Vaule: zero
Key: 1 Vaule: one
Key: 2 Vaule: two
Key: 3 Vaule: 3333
Key: 4 Vaule: four
Key: 5 Vaule: five
Key: 6 Vaule: six
Key: 7 Vaule: seven
Key: 8 Vaule: eight
Key: 9 Vaule: nine
Now the vaule of '3' should be '3333' now[lookup].
The key '3' has been found and removed now.
Now the vaule which should be removed of '3' should be '(null)' now[search].
Now the tree look like:
Key: 0 Vaule: zero
Key: 1 Vaule: one
Key: 2 Vaule: two
Key: 4 Vaule: four
Key: 5 Vaule: five
Key: 6 Vaule: six
Key: 7 Vaule: seven
Key: 8 Vaule: eight
Key: 9 Vaule: nine
************************************************************
DONE
[root@farsight ]#
第一次移植血泪史:
下面我来讲一下我这次移植的过程中遇到的问题,可以说是一步一个砍,十步一个坑,坑里还有水,水里还有丁,进去就没影。感觉就像是体验了一次西天取经的99,81难一样。
首先在网上根本就找不到一个完整的glib移植的教程,有的也只是只言片语,我就这里摸索着前进。
第一劫:版本选择
首先我想我的ubuntu上安装的是glib2.0.6,那么我也是用这个进行移植吧,然后我就开始解压,配置./configure,然后遇到了根本找不到答案的问题,
checking for extra flags to get ANSI library prototypes... configure: error: cannot run test program while cross compiling
在网上根本找不到相应的解决办法,甚至于帖子都没有,没办法,我就换了版本,glib2.0.7,glib2.12,都是这样,都来我试着读了一下,意思是某个测试文件不能在交叉编译环境中运行,真的不知道是什么情况,我觉得应该,glib低版本和交叉编译链或者编译环境不匹配,或者低版本不支持交叉编译。
好,我换了最新版的glib2.48,报错缺少zlib的lib和头文件,换了多个版本,从glib2.32到glib2.28都是这样,最后我在网上找到一个帖子说glib-2.23开始就需要zlib,也就是我还需要交叉编译zlib,我想了想,这个zlib还不知道会遇到什么险阻,放弃最新版,反正我不是处女座,只要有个好用的库就可以了,不需要是最新的。然后就在2.23之后的版本选择了2.22.5版本。
这里我只是写了不到100字,但是应该能想象到我在做的时候一次次地下载,然后倒入ubuntu虚拟机,然后xvf解压,然后./configure,然后看着各种错误是的心情,我下载实验的版本不少于20个,很是崩溃。
第二劫:下载网址与autoconf
在开始的时候我通过他们提供的官方下载网址下载源码包,但是有的源码包中有configure文件,而有的只有configure.ac文件,这个configure.ac文件是需要autoconf工具去生成configure的,我怕我选择的版本有问题,所有特意安装了autoconf工具去生成configure。
这个时候问题又来了,autoconf工具生成configure过程中有报错,我的天啊,真是一波未平一波又起,但是我不打算进行问题嵌套处理,我就放弃了使用autoconf,然后我去找其他的下载源码包网站,终于我找到了一个网站,提供所有都带有configure文件的源码包,也就是我上面贴出来的那个网址。
当我遇到为了解决一个问题而去解决另一个问题的时候,我在想cpu进行中断嵌套的时候是一种什么心情呢?一定很崩溃,怪不得A9以后就不支持中断嵌套了呢。
第三劫:交叉编译参数
其实我也只是一个初学者,在学习的时候就使用的都是老师给配置好的环境,只要一个gcc都搞定,哪里用自己去找头文件,库文件。接触到了交叉编译之后这是一个过不去的坎,必须要能够自己指定头文件和库文件路径,这一劫还算是比较好过的,毕竟是基础知识,网上资料教程很多。
最后我在补充一个我自己发现的知识,那就是arm-linux-gcc和arm-none-linux-guneabi-gcc其实是同一个东西。
我们使用which arm-linux-gcc
看到/home/linux/sys/gcc-4.6.4/bin/arm-linux-gcc
说明arm-linux-gcc指向交叉编译链里的bin文件夹下的arm-linux-gcc
然后我们使用arm-linux-gcc -v
linux@ubuntu:~/16021/glibDemo$ arm-linux-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gcc
COLLECT_LTO_WRAPPER=/home/linux/sys/gcc-4.6.4/bin/../libexec/gcc/arm-arm1176jzfssf-linux-gnueabi/4.6.4/lto-wrapper
Target: arm-arm1176jzfssf-linux-gnueabi
Configured with: /work/builddir/src/gcc-4.6.4/configure
--build=i686-build_pc-linux-gnu
--host=i686-build_pc-linux-gnu
--target=arm-arm1176jzfssf-linux-gnueabi
--prefix=/opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi/gcc-4.6.4
--with-sysroot=/opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/sysroot
--enable-languages=c,c++
--with-arch=armv6zk
--with-cpu=arm1176jzf-s
--with-tune=arm1176jzf-s
--with-fpu=vfp
--with-float=softfp
--with-pkgversion='crosstool-NG hg+default-2685dfa9de14 - tc0002'
--disable-sjlj-exceptions
--enable-__cxa_atexit
--disable-libmudflap
--disable-libgomp
--disable-libssp
--disable-libquadmath
--disable-libquadmath-support
--with-gmp=/work/builddir/arm-arm1176jzfssf-linux-gnueabi/buildtools
--with-mpfr=/work/builddir/arm-arm1176jzfssf-linux-gnueabi/buildtools
--with-mpc=/work/builddir/arm-arm1176jzfssf-linux-gnueabi/buildtools
--with-ppl=/work/builddir/arm-arm1176jzfssf-linux-gnueabi/buildtools
--with-cloog=/work/builddir/arm-arm1176jzfssf-linux-gnueabi/buildtools
--with-libelf=/work/builddir/arm-arm1176jzfssf-linux-gnueabi/buildtools
--with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm'
--enable-threads=posix
--enable-target-optspace
--without-long-double-128
--disable-nls
--disable-multilib
--with-local-prefix=/opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/sysroot
--enable-c99
--enable-long-long
Thread model: posix
gcc version 4.6.4 (crosstool-NG hg+default-2685dfa9de14 - tc0002)
好了我们使用arm-none-linux-guneabi-gcc -v
与上面的返回一样,所有的路径都是一样的,最主要的是Target: arm-arm1176jzfssf-linux-gnueabi,目标都是一模一样的,所以以后我们在需要使用arm-none-linux-guneabi-的时候我们只需要使用arm-linux-就可以。