- 浏览: 151387 次
- 性别:
- 来自: 北京
文章分类
最新评论
SQLite剖析(2):编译及应用
若要编译SQLite库,需要下载单一文件版本sqlite-amalgamation-3071400.zip。它把sqlite3库的所有源码文件内容放到一个文件sqlite3.c中了(不包含管理工具shell.c),这个文件大概有110000多行,如果除去空白行和注释,则有65000多行的代码!这样做的好处是很容易应用在你的项目中,只需拷贝这一个源文件到你项目中即可。另外,编译器在编译单一的文件时能做一些额外的优化,因为只有一个编译单元。通过测试发现大概有5%-10%的性能提升。
SQLite库可以不编译,直接把单一文件sqlite3.c(或者再加上sqlite3.h)拷贝到你的项目中使用即可。但作为一个单独的库,一般建议编译成独立的二进制文件格式的库,如Linux下的.so动态链接库,Windows下的DLL动态链接库,然后在项目中通过头文件sqlite3.h来使用这个库,这样能使软件更加地模块化。
1、Linux下编译SQLite
(1)编译命令行管理工具:gcc shell.c sqlite3.c -lpthread -ldl -o sqlite3
将生成sqlit3命令行管理工具。
(2)编译SQLite为单独的动态链接库:gcc sqlite3.c -lpthread -ldl -fPIC -shared -o libsqlite3.so
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-shared:表示生成一个共享目标文件(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),即我们所说的动态链接库。它可以和其他目标文件连接产生可执行文件。只有部分系统支持该选项。
pthread系统库用于确保SQLite是线程安全的。但因为命令行工具是单线程的,对命令行工具则可编译成非线程安全的,以忽略pthread库。命令为gcc -DSQLITE_THREADSAFE=0 shell.c sqlite3.c -ldl -o sqlite3。dl系统库用于支持动态装载,sqlite3_load_extension()接口和SQL函数load_extension()需要用到它。如果不需要这些特性,可以使用SQLITE_OMIT_LOAD_EXTENSION编译选项来忽略,如gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -o sqlite3。
使用动态库libsqlite3.so:在你的程序中(例如test.c)通过包含头文件sqlite3.h来使用库中的函数,编译程序的命令为gcc test.c -L. -lsqlite3 -o test。其中-L.表示让链接库的搜索路径包含当前目录,-lsqlite3指明编译器查找动态库libsqlite3.so,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称。通过ldd test可查看test程序是如何调用动态库中的函数的。
调用动态库时有几个问题会经常碰到。有时明明已经将库的头文件所在目录通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是修改LD_LIBRARY_PATH,这个环境变量指示动态连接器可以装载动态库的路径。或者修改/etc/ld.so.conf文件,然后调用/sbin/ldconfig来达到同样的目的。通常这样做就可以解决库无法链接的问题了。
(3)编译成静态库:gcc -c sqlite3.c -lpthread -ldl -o sqlite3.o编译成目标文件,ar -r libsqlite3.a sqlite3.o将列出的各个目标文件一起打包成一个静态库libsqlite3.a。
链接静态库:gcc test.c -L. -lsqlite3 -static -o test。也可不加-static选项。
2、Windows下编译SQLite
(1)把SQLite编译成动态链接库:
打开Visual Studio 2010,新建一个名为sqlite3的Visual C++ Win32工程,在工程向导页中选择工程的类型为 "DLL", 并且把创建为空项目的复选框钩上。通过工程--->添加现有项...,把单一文件sqlite3.c添加到工程中。为了生成在链接sqlite3.dll时需要用到的lib文件,需要在工程中添加模块定义文件。根据sqlite3.h中列出的导出函数名,我们可以自己写.def文件,例如:
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_auto_extension
sqlite3_backup_finish
sqlite3_backup_init
sqlite3_backup_pagecount
sqlite3_backup_remaining
sqlite3_backup_step
sqlite3_bind_blob
sqlite3_bind_double
;......
也可以使用已写好的.def文件,下载已编译好的SQLite DLL库sqlite-dll-win32-x86-3071400.zip,里面有sqlite3.def,把它拷贝到我们的sqlite3项目中,在工程属性的Linker--->Input--->Module Definition File中输入sqlite3.def。设置项目编译成Release版本,编译后生成sqlite3.dll和sqlite3.lib。
编译命令行管理工具:如果想编译出sqlite.exe命令行程序,则需要创建一个空的Win32 控制台程序,然后在往工程里添加文件sqlite3.c和shell.c,直接编译即可。
使用动态链接库sqlite3.dll:
这个C程序的例子显示怎么使用sqlite的C/C++接口。数据库的名字由第一个参数取得,第二个参数是一条或更多的SQL执行语句。这个程序调用sqlite3_open()打开指定的数据库,调用sqlite3_exec()对数据库执行SQL语句,callback函数会作用在SQL语句结果集的每条记录上。最后用sqlite3_close()关闭数据库连接。可以用前面的alf.db数据库来测试:test.exe alf.db "select * from mytable"。
(2)把SQLite编译成静态链接库:
新建一个名为sqlite3static,空的Visual C++ Win32工程,在工程向导页中选择工程的类型为 "Static library",去年"Precompiled header"复选框,导入源文件sqlite3.c,编译生成sqlite3static.lib,这是静态链接库版本,它要比动态链接库sqlite3.dll大的多。
使用静态链接库:
新建一个空项目sqlite3statictest,添加对项目sqlite3static的引用,同样使用上面的test.cpp,编译生成sqlite3statictest.exe。可以发现它是一个独立的可执行文件,不依赖静态链接库,删除静态链接库后仍然可以运行。
实际上,静态链接库不存在导出的概念,在链接过程中,静态链接库LIB中的指令都全部被直接包含在最终生成的EXE文件中了,因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况。对于使用该静态库的EXE文件来说,直接使用LIB中的函数和全局变量即可,而不管它们有没有导出声明。另外一点在使用中需要注意的是:静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含。
3、多线程环境中使用SQLite
内容整理自http://sqlite.org/threadsafe.html。SQLite支持三种不同的线程模式:
* 单线程。在这种模式下所有的互斥锁都被禁用,在多个线程中同时使用SQLite时是不安全的。
* 多线程。在这种模式下,只要没有单个数据库连接被同时用在多个线程中的情况,SQLite就可以在多线程环境中安全地使用。
* 串行化。在这种模式中,SQLite可以无限制地在多线程环境中安全地使用。
线程模式可以在编译时(把SQLite源代码编译成库时)、启动时(使用SQLite的应用程序初始化时)或运行时(一个新的SQLite数据库连接创建时)指定。一般来说,运行时参数会覆盖掉启动时参数,启动时参数会覆盖掉编译时参数,但是单线程模式一旦被指定后,就不能被覆盖。默认的模式是串行模式。
(1)编译时的线程模式选项
通过SQLITE_THREADSAFE编译时参数来选择线程模式。如果没有指定SQLITE_THREADSAFE参数,则使用串行化模式。也可以显式地使用-DSQLITE_THREADSAFE=1来指定串行化模式。-DSQLITE_THREADSAFE=0表示单线程模式,-DSQLITE_THREADSAFE=2表示多线程模式。
sqlite3_threadsafe()接口的返回值由编译时线程模式选项来确定。如果编译时指定单线程模式,则sqlite3_threadsafe()返回false。如果指定多线程模式或串行化模式,则sqlite3_threadsafe()返回true。sqlite3_threadsafe()不能区分多线程模式和串行化模式,也不能报告启动时或运行时的模式更改。
如果编译时指定单线程模式,则编译库时关键的互斥逻辑会被忽略,因此不可能在启动时或运行不可能再激活多线程或串行化模式。
(2)启动时的线程模式选项
如果编译时没有指定单线程模式,则在使用sqlite3_config()接口进行初始化时可以改变线程模式。SQLITE_CONFIG_SINGLETHREAD谓词把SQLite设置成单线程模式,SQLITE_CONFIG_MULTITHREAD设置多线程模式,SQLITE_CONFIG_SERIALIZED设置串行化模式。
(3)运行时的线程模式选项
如果编译时或启动时没有指定单线程模式,则单个数据连接可以被创建为多线程或串行化模式,不可能将单个数据库连接降级为单线程模式。如果编译时或启动时指定单线程模式,则不可能将单个数据库连接升级为多线程或串行化模式。
单个数据库连接的线程模式由sqlite3_open_v2()的第三个参数给定的标志来确定。SQLITE_OPEN_NOMUTEX标志表示数据库连接为多线程模式,SQLITE_OPEN_FULLMUTEX表示该连接为串行化模式。如果没有指定标志,或者使用sqlite3_open(), sqlite3_open16(),而不是sqlite3_open_v2(),则使用编译时或启动时指定的线程模式。
若要编译SQLite库,需要下载单一文件版本sqlite-amalgamation-3071400.zip。它把sqlite3库的所有源码文件内容放到一个文件sqlite3.c中了(不包含管理工具shell.c),这个文件大概有110000多行,如果除去空白行和注释,则有65000多行的代码!这样做的好处是很容易应用在你的项目中,只需拷贝这一个源文件到你项目中即可。另外,编译器在编译单一的文件时能做一些额外的优化,因为只有一个编译单元。通过测试发现大概有5%-10%的性能提升。SQLite库可以不编译,直接把单一文件sqlite3.c(或者再加上sqlite3.h)拷贝到你的项目中使用即可。但作为一个单独的库,一般建议编译成独立的二进制文件格式的库,如Linux下的.so动态链接库,Windows下的DLL动态链接库,然后在项目中通过头文件sqlite3.h来使用这个库,这样能使软件更加地模块化。
1、Linux下编译SQLite
(1)编译命令行管理工具:gcc shell.c sqlite3.c -lpthread -ldl -o sqlite3
将生成sqlit3命令行管理工具。
(2)编译SQLite为单独的动态链接库:gcc sqlite3.c -lpthread -ldl -fPIC -shared -o libsqlite3.so
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-shared:表示生成一个共享目标文件(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),即我们所说的动态链接库。它可以和其他目标文件连接产生可执行文件。只有部分系统支持该选项。
pthread系统库用于确保SQLite是线程安全的。但因为命令行工具是单线程的,对命令行工具则可编译成非线程安全的,以忽略pthread库。命令为gcc -DSQLITE_THREADSAFE=0 shell.c sqlite3.c -ldl -o sqlite3。dl系统库用于支持动态装载,sqlite3_load_extension()接口和SQL函数load_extension()需要用到它。如果不需要这些特性,可以使用SQLITE_OMIT_LOAD_EXTENSION编译选项来忽略,如gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -o sqlite3。
使用动态库libsqlite3.so:在你的程序中(例如test.c)通过包含头文件sqlite3.h来使用库中的函数,编译程序的命令为gcc test.c -L. -lsqlite3 -o test。其中-L.表示让链接库的搜索路径包含当前目录,-lsqlite3指明编译器查找动态库libsqlite3.so,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称。通过ldd test可查看test程序是如何调用动态库中的函数的。
调用动态库时有几个问题会经常碰到。有时明明已经将库的头文件所在目录通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是修改LD_LIBRARY_PATH,这个环境变量指示动态连接器可以装载动态库的路径。或者修改/etc/ld.so.conf文件,然后调用/sbin/ldconfig来达到同样的目的。通常这样做就可以解决库无法链接的问题了。
(3)编译成静态库:gcc -c sqlite3.c -lpthread -ldl -o sqlite3.o编译成目标文件,ar -r libsqlite3.a sqlite3.o将列出的各个目标文件一起打包成一个静态库libsqlite3.a。
链接静态库:gcc test.c -L. -lsqlite3 -static -o test。也可不加-static选项。
2、Windows下编译SQLite
(1)把SQLite编译成动态链接库:
打开Visual Studio 2010,新建一个名为sqlite3的Visual C++ Win32工程,在工程向导页中选择工程的类型为 "DLL", 并且把创建为空项目的复选框钩上。通过工程--->添加现有项...,把单一文件sqlite3.c添加到工程中。为了生成在链接sqlite3.dll时需要用到的lib文件,需要在工程中添加模块定义文件。根据sqlite3.h中列出的导出函数名,我们可以自己写.def文件,例如:
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_auto_extension
sqlite3_backup_finish
sqlite3_backup_init
sqlite3_backup_pagecount
sqlite3_backup_remaining
sqlite3_backup_step
sqlite3_bind_blob
sqlite3_bind_double
;......
也可以使用已写好的.def文件,下载已编译好的SQLite DLL库sqlite-dll-win32-x86-3071400.zip,里面有sqlite3.def,把它拷贝到我们的sqlite3项目中,在工程属性的Linker--->Input--->Module Definition File中输入sqlite3.def。设置项目编译成Release版本,编译后生成sqlite3.dll和sqlite3.lib。
编译命令行管理工具:如果想编译出sqlite.exe命令行程序,则需要创建一个空的Win32 控制台程序,然后在往工程里添加文件sqlite3.c和shell.c,直接编译即可。
使用动态链接库sqlite3.dll:
本例子整理自http://sqlite.org/quickstart.html。新建一个空项目test,把sqlite3.dll, sqlite3.lib, sqlite3.h拷贝到项目目录下,把sqlite3.h添加到项目中。新建主程序源文件test.cpp,如下:
- #include<stdio.h>
- #include"sqlite3.h"
- #pragmacomment(lib,"sqlite3")
- /*printarecordfromtableoutputedbysqlstatement*/
- staticintcallback(void*NotUsed,intargc,char**argv,char**azColName){
- inti;
- for(i=0;i<argc;i++){
- printf("%s=%s\n",azColName[i],argv[i]?argv[i]:"NULL");
- }
- printf("\n");
- return0;
- }
- intmain(intargc,char**argv){
- sqlite3*db;
- char*zErrMsg=0;
- intrc;
- if(argc!=3){
- fprintf(stderr,"Usage:%sDATABASESQL-STATEMENT\n",argv[0]);
- return(1);
- }
- rc=sqlite3_open(argv[1],&db);/*opendatabase*/
- if(rc){
- fprintf(stderr,"Can'topendatabase:%s\n",sqlite3_errmsg(db));
- sqlite3_close(db);
- return(1);
- }
- rc=sqlite3_exec(db,argv[2],callback,0,&zErrMsg);/*executeSQLstatement*/
- if(rc!=SQLITE_OK){
- fprintf(stderr,"SQLerror:%s\n",zErrMsg);
- sqlite3_free(zErrMsg);
- }
- sqlite3_close(db);/*closedatabase*/
- return0;
- }
#include <stdio.h> #include "sqlite3.h" #pragma comment(lib,"sqlite3") /* print a record from table outputed by sql statement */ static int callback(void *NotUsed, int argc, char **argv, char **azColName){ int i; for(i=0; i<argc; i++){ printf("%s = %s\n", azColName[i], argv[i]?argv[i]:"NULL"); } printf("\n"); return 0; } int main(int argc, char **argv){ sqlite3 *db; char *zErrMsg=0; int rc; if(argc!=3){ fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]); return(1); } rc=sqlite3_open(argv[1],&db); /* open database */ if(rc){ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return(1); } rc=sqlite3_exec(db,argv[2],callback,0,&zErrMsg); /* execute SQL statement */ if(rc!=SQLITE_OK){ fprintf(stderr,"SQL error: %s\n",zErrMsg); sqlite3_free(zErrMsg); } sqlite3_close(db); /* close database */ return 0; }编译后生成test.exe程序,它的运行依赖于sqlite3.dll。注意程序中也可以不使用pragma指令导入sqlite3.lib,而是在test项目属性中添加对上面的dll项目sqlit3的引用。
这个C程序的例子显示怎么使用sqlite的C/C++接口。数据库的名字由第一个参数取得,第二个参数是一条或更多的SQL执行语句。这个程序调用sqlite3_open()打开指定的数据库,调用sqlite3_exec()对数据库执行SQL语句,callback函数会作用在SQL语句结果集的每条记录上。最后用sqlite3_close()关闭数据库连接。可以用前面的alf.db数据库来测试:test.exe alf.db "select * from mytable"。
(2)把SQLite编译成静态链接库:
新建一个名为sqlite3static,空的Visual C++ Win32工程,在工程向导页中选择工程的类型为 "Static library",去年"Precompiled header"复选框,导入源文件sqlite3.c,编译生成sqlite3static.lib,这是静态链接库版本,它要比动态链接库sqlite3.dll大的多。
使用静态链接库:
新建一个空项目sqlite3statictest,添加对项目sqlite3static的引用,同样使用上面的test.cpp,编译生成sqlite3statictest.exe。可以发现它是一个独立的可执行文件,不依赖静态链接库,删除静态链接库后仍然可以运行。
实际上,静态链接库不存在导出的概念,在链接过程中,静态链接库LIB中的指令都全部被直接包含在最终生成的EXE文件中了,因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况。对于使用该静态库的EXE文件来说,直接使用LIB中的函数和全局变量即可,而不管它们有没有导出声明。另外一点在使用中需要注意的是:静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含。
3、多线程环境中使用SQLite
内容整理自http://sqlite.org/threadsafe.html。SQLite支持三种不同的线程模式:
* 单线程。在这种模式下所有的互斥锁都被禁用,在多个线程中同时使用SQLite时是不安全的。
* 多线程。在这种模式下,只要没有单个数据库连接被同时用在多个线程中的情况,SQLite就可以在多线程环境中安全地使用。
* 串行化。在这种模式中,SQLite可以无限制地在多线程环境中安全地使用。
线程模式可以在编译时(把SQLite源代码编译成库时)、启动时(使用SQLite的应用程序初始化时)或运行时(一个新的SQLite数据库连接创建时)指定。一般来说,运行时参数会覆盖掉启动时参数,启动时参数会覆盖掉编译时参数,但是单线程模式一旦被指定后,就不能被覆盖。默认的模式是串行模式。
(1)编译时的线程模式选项
通过SQLITE_THREADSAFE编译时参数来选择线程模式。如果没有指定SQLITE_THREADSAFE参数,则使用串行化模式。也可以显式地使用-DSQLITE_THREADSAFE=1来指定串行化模式。-DSQLITE_THREADSAFE=0表示单线程模式,-DSQLITE_THREADSAFE=2表示多线程模式。
sqlite3_threadsafe()接口的返回值由编译时线程模式选项来确定。如果编译时指定单线程模式,则sqlite3_threadsafe()返回false。如果指定多线程模式或串行化模式,则sqlite3_threadsafe()返回true。sqlite3_threadsafe()不能区分多线程模式和串行化模式,也不能报告启动时或运行时的模式更改。
如果编译时指定单线程模式,则编译库时关键的互斥逻辑会被忽略,因此不可能在启动时或运行不可能再激活多线程或串行化模式。
(2)启动时的线程模式选项
如果编译时没有指定单线程模式,则在使用sqlite3_config()接口进行初始化时可以改变线程模式。SQLITE_CONFIG_SINGLETHREAD谓词把SQLite设置成单线程模式,SQLITE_CONFIG_MULTITHREAD设置多线程模式,SQLITE_CONFIG_SERIALIZED设置串行化模式。
(3)运行时的线程模式选项
如果编译时或启动时没有指定单线程模式,则单个数据连接可以被创建为多线程或串行化模式,不可能将单个数据库连接降级为单线程模式。如果编译时或启动时指定单线程模式,则不可能将单个数据库连接升级为多线程或串行化模式。
单个数据库连接的线程模式由sqlite3_open_v2()的第三个参数给定的标志来确定。SQLITE_OPEN_NOMUTEX标志表示数据库连接为多线程模式,SQLITE_OPEN_FULLMUTEX表示该连接为串行化模式。如果没有指定标志,或者使用sqlite3_open(), sqlite3_open16(),而不是sqlite3_open_v2(),则使用编译时或启动时指定的线程模式。
SQLite库可以不编译,直接把单一文件sqlite3.c(或者再加上sqlite3.h)拷贝到你的项目中使用即可。但作为一个单独的库,一般建议编译成独立的二进制文件格式的库,如Linux下的.so动态链接库,Windows下的DLL动态链接库,然后在项目中通过头文件sqlite3.h来使用这个库,这样能使软件更加地模块化。
1、Linux下编译SQLite
(1)编译命令行管理工具:gcc shell.c sqlite3.c -lpthread -ldl -o sqlite3
将生成sqlit3命令行管理工具。
(2)编译SQLite为单独的动态链接库:gcc sqlite3.c -lpthread -ldl -fPIC -shared -o libsqlite3.so
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-shared:表示生成一个共享目标文件(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),即我们所说的动态链接库。它可以和其他目标文件连接产生可执行文件。只有部分系统支持该选项。
pthread系统库用于确保SQLite是线程安全的。但因为命令行工具是单线程的,对命令行工具则可编译成非线程安全的,以忽略pthread库。命令为gcc -DSQLITE_THREADSAFE=0 shell.c sqlite3.c -ldl -o sqlite3。dl系统库用于支持动态装载,sqlite3_load_extension()接口和SQL函数load_extension()需要用到它。如果不需要这些特性,可以使用SQLITE_OMIT_LOAD_EXTENSION编译选项来忽略,如gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -o sqlite3。
使用动态库libsqlite3.so:在你的程序中(例如test.c)通过包含头文件sqlite3.h来使用库中的函数,编译程序的命令为gcc test.c -L. -lsqlite3 -o test。其中-L.表示让链接库的搜索路径包含当前目录,-lsqlite3指明编译器查找动态库libsqlite3.so,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称。通过ldd test可查看test程序是如何调用动态库中的函数的。
调用动态库时有几个问题会经常碰到。有时明明已经将库的头文件所在目录通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是修改LD_LIBRARY_PATH,这个环境变量指示动态连接器可以装载动态库的路径。或者修改/etc/ld.so.conf文件,然后调用/sbin/ldconfig来达到同样的目的。通常这样做就可以解决库无法链接的问题了。
(3)编译成静态库:gcc -c sqlite3.c -lpthread -ldl -o sqlite3.o编译成目标文件,ar -r libsqlite3.a sqlite3.o将列出的各个目标文件一起打包成一个静态库libsqlite3.a。
链接静态库:gcc test.c -L. -lsqlite3 -static -o test。也可不加-static选项。
2、Windows下编译SQLite
(1)把SQLite编译成动态链接库:
打开Visual Studio 2010,新建一个名为sqlite3的Visual C++ Win32工程,在工程向导页中选择工程的类型为 "DLL", 并且把创建为空项目的复选框钩上。通过工程--->添加现有项...,把单一文件sqlite3.c添加到工程中。为了生成在链接sqlite3.dll时需要用到的lib文件,需要在工程中添加模块定义文件。根据sqlite3.h中列出的导出函数名,我们可以自己写.def文件,例如:
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_auto_extension
sqlite3_backup_finish
sqlite3_backup_init
sqlite3_backup_pagecount
sqlite3_backup_remaining
sqlite3_backup_step
sqlite3_bind_blob
sqlite3_bind_double
;......
也可以使用已写好的.def文件,下载已编译好的SQLite DLL库sqlite-dll-win32-x86-3071400.zip,里面有sqlite3.def,把它拷贝到我们的sqlite3项目中,在工程属性的Linker--->Input--->Module Definition File中输入sqlite3.def。设置项目编译成Release版本,编译后生成sqlite3.dll和sqlite3.lib。
编译命令行管理工具:如果想编译出sqlite.exe命令行程序,则需要创建一个空的Win32 控制台程序,然后在往工程里添加文件sqlite3.c和shell.c,直接编译即可。
使用动态链接库sqlite3.dll:
本例子整理自http://sqlite.org/quickstart.html。新建一个空项目test,把sqlite3.dll, sqlite3.lib, sqlite3.h拷贝到项目目录下,把sqlite3.h添加到项目中。新建主程序源文件test.cpp,如下:
- #include<stdio.h>
- #include"sqlite3.h"
- #pragmacomment(lib,"sqlite3")
- /*printarecordfromtableoutputedbysqlstatement*/
- staticintcallback(void*NotUsed,intargc,char**argv,char**azColName){
- inti;
- for(i=0;i<argc;i++){
- printf("%s=%s\n",azColName[i],argv[i]?argv[i]:"NULL");
- }
- printf("\n");
- return0;
- }
- intmain(intargc,char**argv){
- sqlite3*db;
- char*zErrMsg=0;
- intrc;
- if(argc!=3){
- fprintf(stderr,"Usage:%sDATABASESQL-STATEMENT\n",argv[0]);
- return(1);
- }
- rc=sqlite3_open(argv[1],&db);/*opendatabase*/
- if(rc){
- fprintf(stderr,"Can'topendatabase:%s\n",sqlite3_errmsg(db));
- sqlite3_close(db);
- return(1);
- }
- rc=sqlite3_exec(db,argv[2],callback,0,&zErrMsg);/*executeSQLstatement*/
- if(rc!=SQLITE_OK){
- fprintf(stderr,"SQLerror:%s\n",zErrMsg);
- sqlite3_free(zErrMsg);
- }
- sqlite3_close(db);/*closedatabase*/
- return0;
- }
#include <stdio.h> #include "sqlite3.h" #pragma comment(lib,"sqlite3") /* print a record from table outputed by sql statement */ static int callback(void *NotUsed, int argc, char **argv, char **azColName){ int i; for(i=0; i<argc; i++){ printf("%s = %s\n", azColName[i], argv[i]?argv[i]:"NULL"); } printf("\n"); return 0; } int main(int argc, char **argv){ sqlite3 *db; char *zErrMsg=0; int rc; if(argc!=3){ fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]); return(1); } rc=sqlite3_open(argv[1],&db); /* open database */ if(rc){ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return(1); } rc=sqlite3_exec(db,argv[2],callback,0,&zErrMsg); /* execute SQL statement */ if(rc!=SQLITE_OK){ fprintf(stderr,"SQL error: %s\n",zErrMsg); sqlite3_free(zErrMsg); } sqlite3_close(db); /* close database */ return 0; }编译后生成test.exe程序,它的运行依赖于sqlite3.dll。注意程序中也可以不使用pragma指令导入sqlite3.lib,而是在test项目属性中添加对上面的dll项目sqlit3的引用。
这个C程序的例子显示怎么使用sqlite的C/C++接口。数据库的名字由第一个参数取得,第二个参数是一条或更多的SQL执行语句。这个程序调用sqlite3_open()打开指定的数据库,调用sqlite3_exec()对数据库执行SQL语句,callback函数会作用在SQL语句结果集的每条记录上。最后用sqlite3_close()关闭数据库连接。可以用前面的alf.db数据库来测试:test.exe alf.db "select * from mytable"。
(2)把SQLite编译成静态链接库:
新建一个名为sqlite3static,空的Visual C++ Win32工程,在工程向导页中选择工程的类型为 "Static library",去年"Precompiled header"复选框,导入源文件sqlite3.c,编译生成sqlite3static.lib,这是静态链接库版本,它要比动态链接库sqlite3.dll大的多。
使用静态链接库:
新建一个空项目sqlite3statictest,添加对项目sqlite3static的引用,同样使用上面的test.cpp,编译生成sqlite3statictest.exe。可以发现它是一个独立的可执行文件,不依赖静态链接库,删除静态链接库后仍然可以运行。
实际上,静态链接库不存在导出的概念,在链接过程中,静态链接库LIB中的指令都全部被直接包含在最终生成的EXE文件中了,因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况。对于使用该静态库的EXE文件来说,直接使用LIB中的函数和全局变量即可,而不管它们有没有导出声明。另外一点在使用中需要注意的是:静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含。
3、多线程环境中使用SQLite
内容整理自http://sqlite.org/threadsafe.html。SQLite支持三种不同的线程模式:
* 单线程。在这种模式下所有的互斥锁都被禁用,在多个线程中同时使用SQLite时是不安全的。
* 多线程。在这种模式下,只要没有单个数据库连接被同时用在多个线程中的情况,SQLite就可以在多线程环境中安全地使用。
* 串行化。在这种模式中,SQLite可以无限制地在多线程环境中安全地使用。
线程模式可以在编译时(把SQLite源代码编译成库时)、启动时(使用SQLite的应用程序初始化时)或运行时(一个新的SQLite数据库连接创建时)指定。一般来说,运行时参数会覆盖掉启动时参数,启动时参数会覆盖掉编译时参数,但是单线程模式一旦被指定后,就不能被覆盖。默认的模式是串行模式。
(1)编译时的线程模式选项
通过SQLITE_THREADSAFE编译时参数来选择线程模式。如果没有指定SQLITE_THREADSAFE参数,则使用串行化模式。也可以显式地使用-DSQLITE_THREADSAFE=1来指定串行化模式。-DSQLITE_THREADSAFE=0表示单线程模式,-DSQLITE_THREADSAFE=2表示多线程模式。
sqlite3_threadsafe()接口的返回值由编译时线程模式选项来确定。如果编译时指定单线程模式,则sqlite3_threadsafe()返回false。如果指定多线程模式或串行化模式,则sqlite3_threadsafe()返回true。sqlite3_threadsafe()不能区分多线程模式和串行化模式,也不能报告启动时或运行时的模式更改。
如果编译时指定单线程模式,则编译库时关键的互斥逻辑会被忽略,因此不可能在启动时或运行不可能再激活多线程或串行化模式。
(2)启动时的线程模式选项
如果编译时没有指定单线程模式,则在使用sqlite3_config()接口进行初始化时可以改变线程模式。SQLITE_CONFIG_SINGLETHREAD谓词把SQLite设置成单线程模式,SQLITE_CONFIG_MULTITHREAD设置多线程模式,SQLITE_CONFIG_SERIALIZED设置串行化模式。
(3)运行时的线程模式选项
如果编译时或启动时没有指定单线程模式,则单个数据连接可以被创建为多线程或串行化模式,不可能将单个数据库连接降级为单线程模式。如果编译时或启动时指定单线程模式,则不可能将单个数据库连接升级为多线程或串行化模式。
单个数据库连接的线程模式由sqlite3_open_v2()的第三个参数给定的标志来确定。SQLITE_OPEN_NOMUTEX标志表示数据库连接为多线程模式,SQLITE_OPEN_FULLMUTEX表示该连接为串行化模式。如果没有指定标志,或者使用sqlite3_open(), sqlite3_open16(),而不是sqlite3_open_v2(),则使用编译时或启动时指定的线程模式。
相关推荐
2. **配置SQLite3**:使用configure脚本进行配置,指定目标平台和编译选项。例如: ``` ./configure --host=arm-linux-gnueabi --prefix=/path/to/install ``` 3. **编译和安装**:执行`make`和`make install`...
QGIS是一个开源的、跨平台的地理信息系统(GIS)软件,用于浏览、编辑和分析地理空间数据,提供了一套丰富的功能,包括地图制作、空间分析、数据管理等。QGIS可以在Windows、Mac OS和Linux等操作系统上运行。 QGIS的...
QGIS是一个开源的、跨平台的地理信息系统(GIS)软件,用于浏览、编辑和分析地理空间数据,提供了一套丰富的功能,包括地图制作、空间分析、数据管理等。QGIS可以在Windows、Mac OS和Linux等操作系统上运行。 QGIS...
QGIS是一个开源的、跨平台的地理信息系统(GIS)软件,用于浏览、编辑和分析地理空间数据,提供了一套丰富的功能,包括地图制作、空间分析、数据管理等。QGIS可以在Windows、Mac OS和Linux等操作系统上运行。 QGIS的...
编译后的SQLite可以用于创建自己的应用程序,例如在C程序中嵌入SQLite: ```c #include "sqlite3.h" int main() { sqlite3 *db; int rc = sqlite3_open("example.db", &db); if (rc) { // 错误处理... } // ...
2. `sqlite3_analyzer`:分析SQLite数据库的内部结构,帮助优化性能。 3. `sqlite3_config`:配置SQLite3的编译选项。 4. `sqlite3_db_config`:配置已连接数据库的行为。 5. `sqlite3_key` 和 `sqlite3_rekey`:对...
QGIS是一个开源的、跨平台的地理信息系统(GIS)软件,用于浏览、编辑和分析地理空间数据,提供了一套丰富的功能,包括地图制作、空间分析、数据管理等。QGIS可以在Windows、Mac OS和Linux等操作系统上运行。 QGIS的...
SQLite 是一个轻量级、开源的嵌入式关系型数据库管理系统,它不需要独立的服务进程,而是作为应用程序的一部分直接运行在用户空间。SQLiteStudio 是一个功能强大的 SQLite 数据库管理工具,提供了一个直观的图形用户...
在Android开发中,SQLite是一个内置的关系型数据库管理系统,它轻量级、高效且支持SQL语法,常用于存储应用数据。...通过对该项目的分析和学习,开发者可以深入理解如何在实际的Android应用中运用SQLite数据库。
2. VDBE与执行:VDBE是SQLite的核心部分,它执行编译后的指令,负责数据的读取、写入和计算。VDBE使用一个简单的栈机模型,通过跳转指令控制流程,进行数据处理。 3. 存储结构:SQLite的数据存储在单个磁盘文件中,...
`SQLite.lvproj`是LabVIEW项目文件,包含了关于SQLite库的所有信息,包括VI、配置和编译设置。使用此文件,用户可以加载并进一步修改或扩展这个SQLite库。 `SQLite.mnu`是LabVIEW菜单项,可能用于在LabVIEW开发环境...
SQLite源码分析: SQLite的源码是用C语言编写的,这使得它能够广泛地跨平台运行。源码库包含了SQLite的所有核心功能,包括SQL解析器、B树数据结构、事务处理、索引和查询优化等。通过阅读源码,你可以深入理解数据库...
参考文献部分列出了相关的研究资料,如《SQLite的特性》、《SQLite在嵌入式系统上的实现研究》、《基于Qt/Embedded的SQLite数据库研究及应用》等,这些文献对于深入研究SQLite的内部实现以及在Qt框架下的应用提供了...
SQLite是一种轻量级的、开源的、自包含的数据库引擎,广泛应用于移动设备、嵌入式系统以及桌面应用程序。在本文中,我们将深入探讨SQLite数据库的相关知识点,包括其原理、特性、API使用、数据类型、SQL语法以及常见...
7. 应用集成:将编译好的SQLite库链接到需要使用它的应用程序中,或者在应用程序中动态加载库。 8. 考虑优化:根据具体需求,可能需要对SQLite进行一些性能或功能上的调整,如开启特定的编译选项,优化内存使用等。...
Sqlite3源码分析可以帮助我们深入了解其内部工作原理,提高数据库操作的效率和灵活性。在C++中封装Sqlite3,可以创建一个易于使用的API,使得在C++应用中集成数据库操作变得更加便捷。 首先,Sqlite3的核心功能包括...
SQLite数据库逆向分析是一门复杂的技术领域,涉及到软件逆向分析、数据库逆向分析、反汇编、反编译等技术领域。以下为本节课的知识点总结: 1. SQLite数据库逆向分析简介 SQLite数据库逆向分析是指对SQLite数据库...
2. 源码分析: 当你下载并解压“sqlite3”压缩包后,你会得到SQLite3的完整源代码。这些源代码包括头文件(如`sqlite3.h`)和实现文件(如`sqlite3.c`),它们提供了对数据库的所有操作。通过阅读和研究这些源代码...