sqlite3 配置交叉编译环境
大体上分为三个步骤:1.在虚拟机上配置交叉编译环境arm-linux-gcc;2、安装和配置在交叉编译环境下的sqlite3;3.通过nfs挂载测试程序。三个步骤都必须成功才行,才能配置成功。
以Ubuntu13.0为例,我们找到光盘里面arm-linux-gcc的安装包,并把这个包导入Ubuntu虚拟机。导入的方法有很多,可以通过vm tools直接拖动,也可以用ssh导入,也可以通过vm自带的共享目录导入。这里介绍vm的共享目录。
点击vm->settings->options->Shared Folders
如图选择add,然后在文件
这样就可以了,共享文件夹就设置好了,打开终端,会在/mnt/hgfs目录下面看到共享文件夹。
设置完之后,我们把arm-linux-gcc的编译环境arm-linux-gcc-3.4.6-glibc-2.3.6.tar.bz2 拷到linux目录中去。
tar jxvf arm-linux-gcc-3.4.6-glibc-2.3.6.tar.bz2 解压出来,进入解压后的目录,里面会有:arm-linux include bin lib等等目录,把这些所有的东西拷贝到/usr/local/arm/2.95.3目录 下。
然后,修改环境变量,目的是能让终端找到arm-linux-gcc的安装目录,输入命令
vim /etc/profile ,在文件的最后一行加上:
exportPATH=$PATH:/usr/local/arm/2.95.3/bin
然后,使新的环境变量生效:source /etc/profile
查看环境变量是否设置成功:echo $PATH,如果有/usr/local/arm/2.95.3/bin,说明设置成功了。
到此,arm-linux-gcc交叉编译环境就搭建成功了。
sqlite3官网提供了两种源代码的方式,一种叫作amalgamation,另外一种叫作autoconf,这两种源码包有点不一样。amalgamation的源码包是把sqlite的所有源文件都集成到了sqlite3.c这一个文件里面去,而且这个包只适合单独编译出一个shell版本的sqlite3,它并不会编译出linux里面常见的开发库(也就是基于sqlite3编写的软件必须要依赖的sqlite3库)。而autoconf版就很明显了,是使用linux上面常见的./configure make make install方式来编译sqlite3的,可以编译出所有需要的依赖库。虽然sqlite官方建议使用amalgamation包,但经过个人测试,使用autoconf的包对于sqlite开发者来说是必须的,对于ARM的交叉编译来说就更是如此了。
我们这里安装autoconf版本。解压该文件,进入目录,
sudo ./configure
sudo make
sudo make install
执行完这三条,sqlite3就已经被默认安装到了/usr/local/bin里面去了,但是还没完呢,如果在终端直接执行一下sqlite3,多半会报错,类似于这样:
SQLite headerand source version mismatch
2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e
2012-10-04 19:37:12 091570e46d04e84b67228e0bdbcd6e1fb60c6bdb
这个问题是因为ubuntu里面原来自带了一个老版的sqlite运行库,这个库由一个库文件和一个符号链接组成,位于/usr/lib/i386-linux-gnu目录,分别是libsqlite3.so.0.8.6和一个符号链接到它的libsqlite3.so.0,由于上面进行的autoconf包的sqlite3并不是静态编译,所以就会出现库不匹配的情况而程序拒绝执行的问题了。
由于不知道系统自带的那个老版的sqlite库还会不会有用,我们就留着它:
mv/usr/lib/i386-linux-gnu/libsqlite3.so.0.8.6 /usr/lib/i386-linux-gnu/libsqlite3.so.0.8.6_bak
然后把刚才编译好的autoconf包里面的这个库复制过去:
cp .libs/libsqlite3.so.0.8.6/usr/lib/i386-linux-gnu
OK,现在执行一下sqlite3,完全没有问题了
下面是交叉编译sqlite所有相关文件的问题。
进入以sqlite3-autoconf的目录里面去,执行:
sudo ./configure--host=arm-linux --prefix=/opt/sqlite3
--host接的是arm的交叉编译器的名称,--prefix接的是编译好之后安装到的路径,这里建议不要直接安装到交叉编译器的路径,而是安装到其它地方,等安装完之后到目标目录确认一下之后再手动拷到交叉编译器的目录里面去。
这样其实就已经配置了sqlite3的交叉编译环境。这时我们写一个sqlite3的.c文件,测试一下。文件代码如下:
#include
#include
#include "sqlite3.h"
//#define _DEBUG_
int main( void )
{
sqlite3 *db=NULL;
char *zErrMsg =0;
char *dbPath ="sq3.s3db";
int rc;
char *sql ="CREATE TABLE SensorData(ID INTEGER PRIMARY KEY,SensorID INTEGER,SiteNumINTEGER,Time VARCHAR(12),SensorParameter REAL);" ;
int nrow = 0, ncolumn= 0;
char **azResult; //二维数组存放结果
int i = 0 ;
rc =sqlite3_open(dbPath, &db); //打开指定的数据库文件,如果不存在将创建一个同名的数据库文件
if( rc )
{
fprintf(stderr,"Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
else
{
printf("Youhave opened a sqlite3 database saved in %s successfully!\n",dbPath);
}
//创建一个表,如果该表存在,则不创建,
//返回值为SQLITE_OK为成功
//函数参数:第一个为操作数据库的指针,第二句为SQL命令字符串
//第三个参数为callback函数,这里没有用,第四个参数为callback函数
//第五个参数给出提示信息,存储在 zErrMsg中
sqlite3_exec( db , sql, 0 , 0 , &zErrMsg );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
//插入数据
sql = "INSERTINTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011206', 18.9);" ;
sqlite3_exec( db , sql, 0 , 0 , &zErrMsg );
sql = "INSERTINTO \"SensorData\" VALUES(NULL , 1 , 1 , '200605011306', 16.4);" ;
sqlite3_exec( db , sql, 0 , 0 , &zErrMsg );
//查询数据
/*
intsqlite3_get_table(sqlite3*, const char *sql,char***result , int *nrow , int*ncolumn ,char **errmsg );
result中是以数组的形式存放你所查询的数据,首先是表名,再是数据。
nrow ,ncolumn分别为查询语句返回的结果集的行数,列数,没有查到结果时返回0
*/
sql = "SELECT *FROM SensorData ";
sqlite3_get_table( db, sql , &azResult , &nrow , &ncolumn , &zErrMsg );
printf( "row:%dcolumn=%d \n" , nrow , ncolumn );
printf( "\nTheresult of querying is : \n" );
for( i=0 ; i<( nrow+ 1 ) * ncolumn ; i++ )
printf("azResult[%d] = %s\n", i , azResult[i] );
//释放掉 azResult的内存空间
sqlite3_free_table(azResult );
#ifdef _DEBUG_
printf("zErrMsg = %s \n", zErrMsg);
#endif
sqlite3_close(db); //关闭数据库
return 0;
}
写完之后,我们首先使用gcc来编译,注意,输入的命令为:
gcc sqlitetest.c-o sqltest -L /usr/local/lib -I/usr/local/include -lsqlite3 –pthread
其中,-L 是指定sqlite3的lib文件 ,-I 是指定sqlite的头文件,最后那个-lsqlite3是引用sqlite3的开发库。
编译通过,会产生一个sqltest的可执行文件。成功
下面我们使用用交叉编译来编译这个.c文件。
arm-linux-gcc sqlitetest.c -o sqlitetest -I /opt/sqlite3/include -L/opt/sqlite3/lib -lsqlite3
编译成功,会产生一个sqlitetest文件。如果我们直接./sqlitetest,会提示bash: ./sqlitetest: cannot execute binary file,这是因为是交叉编译的文件,只能在开发板上面运行。
搭建nfs服务器,这里就不再详细说了,文档有很多。我搭建的nfs目录在根目录下的/nfs中。
Nfs搭建完成后,我们在开发板这一端首先改变开发板的ip,将ip改为与虚拟机同一个网段:
ifconfig eth0 192.168.10.86
然后挂载:mount -t nfs 192.168.10.67:/nfs /mnt/yaffs
如果不想每次开机都设置IP并挂载,可以把这两个命令写到一个.sh文件里,开机后直接执行该文件,就可以了。
挂载成功后,进入目录,执行交叉编译过的可执行文件
./sqlitetest
这时会发现过了很长时间,都没有反应,最后提示
nfs: server 192.168.10.67 notresponding, still trying
这是因为,mount命令默认的读和写大小为32768,太大了,导致响应时间太长。我们可以通过加入wsize和rsize参数和nolock来控制
mount -t nfs -orsize=8192,wsize=8192,nolock 192.168.10.67:/nfs /mnt/yaffs
这样就可以运行了。
注:在使用sqlite3直接操作数据库的时候,可能会遇到Backspace这个键不能用的情况,会出现一串^H^H^H^H^H^H^H
解决办法是结束sqlite程序(移植时sqlite自动生成一个可执行文件)然后在超级终端输入“stty erase ^H”即可。