上次说到了将loudmouth在pc机上顺利编译和运行,这次主要讲将其移植到arm开发板的过程。
loudmouth库是需要glib-2.0和gnutls的支持的,但是后者是不必须的。所以在移植loudmouth之前需要先将glib-2.0移植到arm上。
这个移植过程我主要是参考了下面这篇文章:
http://ppbabytiger.spaces.live.com/blog/cns!549302309A9552BE!397.entry
这是一个移植webkit的文章,主要是里边同时用到了glib-2.0的库。
下面我就讲一下我的移植步骤。
1.创建交叉编译环境
首先当然是要创建交叉编译环境,这个过程一般在开发板的
使用手册里有明确的说明,大部分的开发板应该是直接将交叉编译环境打包放在配套的光盘里,我们要做的就是解包,然后在PATH里加一下bin的地址就好了。当然了,所有的工作是在linux下完成。最后只要arm-linux-gcc可以工作就可以了。这里就不再敷述了。
2.glib-2.0的移植
这是loudmouth的唯一必须依赖的库。就是按照上文中我提到的地址中的方法即可。这里我选择的是glib-2.12.0这个版本。可以在记得要看文章中全局变量的一些设定,可以将下面的内容保存为cross_glib.sh:
#!/bin/bash
export ARCH=arm
export ROOTFS_DIR=/home/peter/workspace
CC=$ARCH-linux-gcc
echo ac_cv_type_long_long=yes>$ARCH-linux.cache
echo glib_cv_long_long_format=ll>>$ARCH-linux.cache
echo glib_cv_stack_grows=no>>$ARCH-linux.cache
echo glib_cv_uscore=no>>$ARCH-linux.cache
echo ac_cv_func_posix_getpwuid_r=yes>>$ARCH-linux.cache
make distclean
./configure --prefix=$ROOTFS_DIR/usr --cache-file=$ARCH-linux.cache --build=i686-pc-linux-gnu --target=$ARCH-linux --host=$ARCH-linux
export ARCH=arm
export ROOTFS_DIR=/home/peter/workspace
CC=$ARCH-linux-gcc
echo ac_cv_type_long_long=yes>$ARCH-linux.cache
echo glib_cv_long_long_format=ll>>$ARCH-linux.cache
echo glib_cv_stack_grows=no>>$ARCH-linux.cache
echo glib_cv_uscore=no>>$ARCH-linux.cache
echo ac_cv_func_posix_getpwuid_r=yes>>$ARCH-linux.cache
make distclean
./configure --prefix=$ROOTFS_DIR/usr --cache-file=$ARCH-linux.cache --build=i686-pc-linux-gnu --target=$ARCH-linux --host=$ARCH-linux
比较特殊的地方就是先要写好这个arm-linux.cache这个文件。这里,ROOTFS_DIR是我们的工作目录,可以任意的修改,之后的一些相关的参数也要跟随这个目录而做相应的改动。然后在shell里运行:
chmod a+x cross_glib.sh
./cross_glib.sh
./cross_glib.sh
如果配置过程没问题,下面就可以踏实的make了。
make
make install
make install
我一般会将配置和编译分开做,这样我觉得碰到问题的时候会比较清楚,可以直接将这个过程放到脚本里。
3.loudmouth-1.0的移植
对于loudmouth的移植和上面的方法类似。请参见下面的脚本:
#!/bin/bash
export ROOTFS_DIR=/home/peter/workspace
export ARCH=arm
export CC=$ARCH-linux-gcc
./configure --prefix=$ROOTFS_DIR/usr --build=i686-pc-linux-gnu --target=$ARCH-linux --host=$ARCH-linux --with-ssl=no "CFLAGS=-I$ROOTFS_DIR/usr/include/glib-2.0 -I$ROOTFS_DIR/usr/lib/glib-2.0/include" "LIBS=-L$ROOTFS_DIR/usr/lib -lglib-2.0"
make
make install
export ROOTFS_DIR=/home/peter/workspace
export ARCH=arm
export CC=$ARCH-linux-gcc
./configure --prefix=$ROOTFS_DIR/usr --build=i686-pc-linux-gnu --target=$ARCH-linux --host=$ARCH-linux --with-ssl=no "CFLAGS=-I$ROOTFS_DIR/usr/include/glib-2.0 -I$ROOTFS_DIR/usr/lib/glib-2.0/include" "LIBS=-L$ROOTFS_DIR/usr/lib -lglib-2.0"
make
make install
这里应该是要指定一下glib的头文件和库文件的地址。我这里还是使用的--with-ssl=no的方式。
经过这个过程后,在$ROOTFS_DIR/usr/lib就可以看到编译好的glib的库文件还有loudmouth的库文件了。我们可以用file命令检查一下,看看是否是arm的格式。
4.嵌入式应用程序中loudmouth库的使用
下面,我们就可以开始使用了。我这里讲的当然不是怎么写源程序,这要参考loudmouth的手册。我还是主要说编译和运行的方法。
编译的话,应该可以想到,直接arm-linux-gcc mysource.c肯定是不行的。主要是要告诉编译器需要的库和头文件的具体位置。这里我们还是可以用到pkg-config这个东西的。我们这里不能直接pkg-config --cflags glib-2.0,因为要知道,现在机器里会有两个glib,一个是环境linux本身要使用的,另一个是我们想要移植到arm上的,这样调用返回的flags标志都是针对环境linux本身的。要知道,pkg-config可以对*.pc文件直接进行解析,所以这里我们可以这样:
pkg-config --cflags --libs /home/peter/workspace/usr/lib/pkgconfig/glib-2.0.pc
后边的目录要修改一下,改为自己的工作目录下的地址,也就是$ROOTFS_DIR/usr/lib/pkgconfig/glib-2.0.pc。最后,我把Makefile写一下。
project = test
cc = arm-linux-gcc
$(project) : $(project).c
$(cc) -g -o $@ `pkg-config --cflags --libs /home/peter/workspace/usr/lib/pkgconfig/glib-2.0.pc /home/peter/workspace/usr/lib/pkgconfig/loudmouth-1.pc` $<
cc = arm-linux-gcc
$(project) : $(project).c
$(cc) -g -o $@ `pkg-config --cflags --libs /home/peter/workspace/usr/lib/pkgconfig/glib-2.0.pc /home/peter/workspace/usr/lib/pkgconfig/loudmouth-1.pc` $<
其实这里loudmouth-1.pc理论上会自动包含glib的目录的,但是如果你运行一下pkg-config你会发现,它包含的是/usr/local/lib/...或者其他目录(如果你在机器上安装glib的时候修改过的话),所以这个glib的地址是错的,因此需要再将glib-2.0.pc加进去。
这样,编译工作也完成了。我们假设已经有了一个链接好的test文件了,下面要做的就是放到arm板上跑就是了。这里需要再参考开发板的手册,一般手册上都会给出一个用户程序如何下载到开发板。我建议大家用nfs这个方式,也就是在开发平台上建立nfs服务,然后在开发板上mount,这样效率可以非常高,测试的时候只要make一下,然后切换到串口通讯界面就可以直接运行了。(因为根本没有下载的过程,运行的时候网线上小电流嗖的一下搞定……)具体步骤这里也不再敷述。
在运行前记得将我们工作目录下的lib下的文件放到开发板的/lib下,否则会报错,说动态链接库无法找到。我在复制库文件的时候发现开发板空间不足……这里gobject, gthread ... 是没用的,只需要glib*和loudmouth*就可以了。
然后,挂上nfs目录,到test所在的文件夹,./test一下试试吧~
5.总结
下面解释一下我对这个过程的理解。因为两个移植的过程是类似的,我就以glib的移植过程举例。可以看到,脚本开始对一些全局变量做了设置,主要这里要提一下ROOTFS_DIR。它是我们所有工作的一个工作目录。这个目录在linux下通过源代码安装软件的时候一般是可以通过./configure --prefix=$ROOTFS_DIR实现的。
下面我顺便说一下我对“linux三部曲”的理解吧:
这里./configure其实是生成各种配置文件,而在配置文件中需要用到这个目录的名称。实际的configure的工作是不会向这个目录中写入内容的;之后的make就是具体的编译过程,最后会生成我们所需要的二进制文件,这些工作应该也是在当前的目录下完成的;最后的make install才会将所有生成了的有用的文件放到当时在./configure时prefix参数所指定的目录中去。
所以,我们在执行了以上的脚本后,就可以在$ROOTFS_DIR里看到最后的成果了。这里,我们主要需要的是头文件(一般是*.h)和链接库文件(一般是*.so),前者在我们以后写应用程序时进行编译时会用到,而后者会在链接以及最后运行的时候动态调用。
当时觉得移植是一个很困难的过程吧,你想,一个玩意要从pc上放到arm上,我靠那区别得多大啊!其实,现在很多人已经把繁冗的过程帮我们做好了。我们会发现,很多情况下,我们只需要修改一下编译器,从gcc换成arm-linux-gcc(当然还可以是别的什么玩意)就好了。可能还要在设置的时候加入一些例如--host, --target, --build的参数(build好像不用设置的,应该就是编译环境,默认的应该就是可以的)。这里我觉得主要是需要对程序的编译过程,以及动态链接的基本知识的了解,就可以了。
周末有空,这里把我前两天移植loudmouth的过程也写了一下~因为不在公司,这些大多是靠一些记录和记忆来写的,如果有什么问题,欢迎大家email讨论: [email protected]。当然了,我对自己的底子还是有一定认识的,所以大家不要对我抱太大希望……over。