最近项目手中的项目进展到了一个阶段,需要保存索引数据,于是想到了sqlite这个东东。
从www.sqlite.com上下载了最新的3.7.9版本源代码,最先下载的是sqlite-amalgamation-3070900.zip这个文件。展开文件后发现项目仅包含个位数的几个文件。其中,所有的数据库引擎实现代码都放在了一个文件中,另外加上个用户头文件。实现文件长达120000行。将这两个文件添加到一个新建的vc工程,工程设置为静态库,无预编译头文件支持。项目顺利得编译成功。
接着,随便写个程序就引用了刚才的静态库。代码如下:
sqlite3 *db;
sqlite3_stmt *stmt;
const char *pzTail;
int r = sqlite3_open("d:\\test.db", &db);
if (r != 0) {
MessageBox(_T("Open database fail. "));
return FALSE;
}
sqlite3_prepare_v2(db, "CREATE TABLE test(id INTEGER PRIMARY KEY, name, age);",
-1, &stmt, &pzTail);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_prepare_v2(db, "INSERT INTO test(name, age) VALUES(?,?);",
-1, &stmt, &pzTail);
sqlite3_bind_text(stmt, 1, "mz", -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 2, 10);
r = sqlite3_step(stmt);
if (r != SQLITE_DONE) {
MessageBox(CA2CT(sqlite3_errmsg(db)).m_psz);
}
sqlite3_reset(stmt);
sqlite3_bind_text(stmt, 1, "zry", -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 2, 20);
r = sqlite3_step(stmt);
if (r != SQLITE_DONE) {
MessageBox(CA2CT(sqlite3_errmsg(db)).m_psz);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
这段代码基本是从网上摘录,大家无视那些错误处理吧。
兴趣来了还想调试一下sqlite的代码。在sqlite3_open调用行上设了断点,跟入后发现调试器反馈执行路径竟然位于源代码的注释行上。-_-!!。
琢磨了一下觉得还是源代码的行数太过离谱,而调试器仅支持16位的行指示,行号截断后使得调试器显示了注释代码位置。看来想要调试sqlite的源代码需要得到sqlite其它形式的源代码发布包。
在sqlite上搜索了下,找到了这么个东东sqlite-src-3070900.zip,注释该包由版本控制系统获取后打包得到。
解压该包后大致看了下目录结构,先不管三七二十一,将src中所有的文件拖出来,先排除了其中的main.c,然后目测看了下剩下文件,果断删除了*test.*。接着以和刚才一样的方式建立了vs2008的项目,将剩下文件又排除了非源代码的后全部拖到该项目中。编译发现提示缺少头文件。
想了想后,打开main.mk查看生成文件是怎么编译的。
在mk文件的第354行找到了该项目所有的编译项:all: sqlite3.h libsqlite3.a sqlite3$(EXE)。sqlite3$(EXE)这个可能是命令行的工具,我暂时不需要。libsqlite3.a应该是我需要的静态库,看来我应该看看这个文件的生成方法了。sqlite3.h文件看来也是需要通过某种方式生成的,但是我这个人爱偷懒,直接就从之前的那个包中顺走了这个文件(事实证明这个行为是绝对正确的)。由mk文件得知libsqlite3.a依赖于LIBOBJ,在mk的53行找到了所有需要的源代码文件,一一比对当前加到vc项目中的源文件,发现main.c文件是需要的(-_-!)。且还有几个文件不存在他们是parse.c、opcodes.c。
生成parse.c:在mk文件中又找到了相关的内容位于第445行及其后的几行的内容描述了该文件的生成方法,于是parse.y文件也加入到了项目中,还需要借助另外一个工具lemon。
lemon:这个工具的信息在mk文件的409行找到了生成方法。于是再新建一个win32命令行项目,去掉预编译配置,将lemon.c加入到源代码中。又将lempar.c也加入到了项目中,由mk文件来看后一个文件编译是不需要的,于是在vc中排除了该文件在生成时的行为。。在新建的工程中加入了生成后事件来处理mk中‘./lemon $(OPTS) parse.y’这行。由mk的450行得知为了生成parse.c还需要awk工具,这个工具我有,立马将该工具复制到项目中,在生成事件中添加了相应的命令来生成parse.c和parse.h(由mk文件得知还有这么个玩意儿),命令还要将这两个文件复制到sqlite项目中。
先运行一个lemon项目,使得parse.h和parse.c文件生成并复制到了sqlite的项目目录中。然后将这两个文件从资源管理器拖动到vc的sqlite项目中,此时项目文件中就增加了这两个文件的引用,最后,再资源管理器中删除这两个文件(不要着急,生成lemon后会自动得到这两个文件的)。
在434行上了解到生成opcodes.c所需的工具和文件,工具是awk,刚才生成lemon已经用过了。文件在sqlite的压缩包中搜索得到,统统复制到我指定的项目目录中,加入到某个项目中,在项目的生成事件中加入命令列表,命令就按照mk文件中指示的那样就行了。生成后用处理parse.c文件的方法在vc工程中处理一遍,使得vc项目中存在该文件的引用,那样在生成解决方案时就可以去编译这个文件。
编译整个解决方案后发现还缺少keywordhash.h,这个文件刚才在搜索其它信息时瞄到过,已经注意到了。在mk文件中也很容易的找到了生成它的方法。在压缩包中找到了mkkeywordhash.c,然后再新建一个vc命令行工程加入该文件。用生成的程序就可以生成keywordhash.h了(还需要压缩包中的keywordhash.c,搜索一下压缩包就有了)。
至此,所有的文件就齐备了,设置解决方案中项目之间的以来,使得lemon和mkkeywordhash这些工具可以以合适的顺序生成,并最终产生出sqlite所需的各种文件。sqlite项目最终成功编译通过,生成了静态库文件。用文章开头的代码来测试顺利通过。加断点调试也能够可以正确的断到代码中的位置。
注:这篇文章是最后完事后的总结,可能有所遗漏。所有的结果都在一个vc解决方案中,只需打开解决方案选择生成后即可产生静态库和测试工程。如有需要和我联系。