目录
三、编译生成xapian静态库(Release版),生成相关文件
一、安装环境
操作系统 | win11专业版 | 64位操作系统 |
VS版本 | VS2017 | Enterprise,版本15.8.8, |
xapian-core版本 | 1.4.21 | 历史版本路径:Index of /xapian |
zlib版本 | 1.2.11 | 历史版本路径:Index of /fossils |
msys版本 | msys2-x86_64-20221028.exe |
二、编译zlib,生成相关文件
下载并解压zlib源代码文件。
生成32位的lib
1、设置msvc的32位命令行运行环境:
找到vs的vcvars32.bat文件,我的VS2017的
vcvars32.bat文件
路径:\VS2017\VC\Auxiliary\Build\,进入此目录,
在此目录的窗口的地址栏中输入"cmd",弹出命令行窗口。
在CMD窗口中输入vcvars32.bat。不要直接双击
vcvars32.bat文件,那样CMD窗口会自动关闭。
因为这几个步骤后面要经常做,写了个脚本如下(命名:vs_x86.bat,可以直接双击):
call "C:\VS2017\VC\Auxiliary\Build\vcvars32.bat"
cmd /k
puase
2、在msvc的32位命令行环境中编译、链接、生成zlib库: 继续在上面的CMD窗口中进入zlib源代码目录,输入如下命令,在zlib源代码目录会生成zlib.dll、zlib.lib文件:
nmake -f win32/Makefile.msc
注意:zlib1.2.5版本用上面面命令会报错 , zlib1.2.8版本也有一点小错误,需要额外处理。
生成64位的lib
1、
设置msvc的64位命令行运行环境
:方法同32位lib编译方法,只是运行文件为
vcvars64.bat
文件。也可以同上文写一个脚本文件(vs_x64.bat)。
call "C:\VS2017\VC\Auxiliary\Build\vcvars64.bat"
cmd /k
puase
2、在msvc的64位命令行环境中编译、链接、生成zlib库:在cmd输入命令如下:
nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj"
上述命令执行完成后,在源代码目录下会生成一堆的.obj文件,.pdb文件,还有.exe文件,最主要的还有
zdll.lib,zlib.lib,zlib1.dll
,在磁盘其他地方建立一个名为 zlib-1.2.11-lib64 的目录用于存放头文件和库文件(此目录后续有用,我建在c盘根目录
C:\zlib-1.2.11-lib64
),此目录下再建一个include目录(将1.2.11源代码目录中的
zconf.h、zlib.h
文件拷贝到此目录),建一个lib目录(将
源代码目录中刚生产的zdll.lib,zlib.lib,zlib1.dll文件拷贝到此目录
)。
下面编写一个脚本文件自动实现编译生成32位zlib库,首先用文本编辑器打开源代码中.\win32\Makefile.msc文件,将文件中
-del *.pdb一行删除。然后运行下面脚本文件。
REM 文件名:vs2017-32zlib.bat,将此文件放到zlib源代码目录的根目录,然后运行此脚本即可生成相应的ZLIB库文件
@REM 这是我的VS2017中vcvars32.bat的全路径
set VS= "C:\VS2017\VC\Auxiliary\Build\vcvars32.bat"
@REM 设置输出路径,将会自动生成此目录,并且会生成bin、lib、include、pdb目录,程序运行完成后,会将生成的.dll、.lib、.pdb、还有程序所需要包含的.h文件都会拷贝到这些目录
set OUT="C:\zlib-1.2.11-lib32"
call %VS%
@REM 下面这两行代码,64位的zlib与32位的不同
nmake /f win32/Makefile.msc clean
nmake /f win32/Makefile.msc
md %OUT%\lib
md %OUT%\bin
md %OUT%\include
md %OUT%\pdb
copy /Y *.lib %OUT%\lib
copy /Y *.h %OUT%\include
copy /Y *.dll %OUT%\bin
copy /Y *.exe %OUT%\bin
copy /Y *.pdb %OUT%\pdb
del *.pdb
pause
自动生成64位zlib库的脚本略有不同,下面只列出不同的部分
nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" clean
nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj"
zdll.lib与zlib.lib的区别:
在编译 zlib 库时生成的zdll.lib
和zlib.lib
文件之间的区别在于它们对于库的链接方式和使用环境的不同:
zdll.lib
:- 这是用于链接动态链接库(DLL)的导入库文件,与之相关联的为zlib.dll。当您编译动态链接版本的 zlib 库时,会生成这个文件。
- 它包含了在运行时加载并使用 zlib.DLL 的相关信息,允许您在编译时将应用程序与 zlib.DLL 进行链接。应用程序运行时,需要将对应的zlib.dll放到与应用程序相同的目录。
- 如果您的应用程序需要在运行时动态加载 zlib 库,通常需要使用
zdll.lib
文件。
zlib
.lib
:- 这是用于链接静态链接库(Static Library)的库文件。当您编译静态链接版本的 zlib 库时,会生成这个文件。
- 它包含了 zlib 库的所有功能,以便在编译时将这些功能直接嵌入到您的应用程序中。
- 如果您的应用程序需要在编译时将 zlib 的功能静态链接到应用程序中,通常需要使用
zlib.lib
文件。
总之,zdll.lib
用于链接动态链接版本的 zlib 库,而zlib.lib
用于链接静态链接版本的 zlib 库。您应该根据您的应用程序的需要选择适当的库文件进行链接。
三、编译生成xapian静态库(Release版),生成相关文件
准备环境
1、下载xapian源代码:下载地址见本文第一章节,下载后解压即可。
2、安装msys2环境:
msys2 | 此网址保持着最近10几个版本,随便装一个即可,安装后,根目录会出现mingw32与mingw64两个空目录 | msys2-distrib-x86_64安装包下载_开源镜像站-阿里云 | |
MinGW32 | 下载i686-win32-sjlj或者i686-win32-dwarf | 解压后替换msys2安装目录下的mingw32与mingw64两个空目录 | https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds |
MinGW64 | 下载x86_64-win32-sjlj或者x86_64-win32-seh, | https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds |
运行msys2,在msys2窗口下运行如下命令,安装make,默认情况下是随msys2环境已经安装好了的。
pacman -S make
生成32位的xapian库
1、启动msys2、配置32位编译环境:执行本文第二章节中提到的脚本文件vs_x86.bat,在CMD窗口中输入如下命令:msys2_shell.cmd -use-full-path ,会出现msys2窗口。
2、
生成xapian编译环境、生成Makefile:
在msys2窗口中进入
xapian源代码目录
。(msys2是什么?自己百度。msys2中要访问本地windows环境下的c盘怎么办?直接用“cd /c”即可,msys2是仿真linux环境,linux下没有盘符概念,只有目录。因此要进入d盘,输入“cd /d”即可。)输入如下命令行
:
./configure LD=link CC="cl -nologo" CXX="$PWD/compile cl -nologo" CXXFLAGS="-EHsc -Z7" AR=lib CPPFLAGS=-IC:/zlib-1.2.11-lib32/include LDFLAGS="-LC:/zlib-1.2.11-lib32/lib" --prefix="d:/xapian-install-1.4.21-X86"
3、
编译xapian,生成xapian静态库:上述命令跑完后,执行
make ,过程中会出现很多warning,不用在意。
4、打包生成的xapian:make完后,执行 make install ,跑完后,会生成d:/xapian-intall-1.4.21目录,里面会有4个子目录(bin、include、lib、share),其中lib子目录下会有libxapian.a库文件。
生成64位的xapian库
1、启动msys2,配置64位编译环境:
执行本文第二章节中提到的脚本文件
vs_x64.bat
,在CMD窗口中输入如下命令:msys2_shell.cmd -use-full-path ,会出现msys2窗口。
2、
生成xapian编译环境、生成Makefile:
在msys2窗口中进入
xapian源代码目录
。输入如下两条命令,第一条命令的目的是将mingw64\bin 的路径添加到 PATH 变量的前面
:
export PATH="/mingw64/bin:$PATH"
./configure LD=link CC="cl -nologo" CXX="$PWD/compile cl -nologo" CXXFLAGS="-EHsc -Z7" AR=lib CPPFLAGS=-IC:/zlib-1.2.11-lib64/include LDFLAGS="-LC:/zlib-1.2.11-lib64/lib" --prefix="d:/xapian-install-1.4.21-X64"
最后要注意:我们生成的xapian库文件既不是.lib、也不是.dll文件,而是libxapian.a文件,不用诧异,只是文件后缀不同而已,就是一个静态lib文件。
四、举个栗子
- 创建VS2017 控制台工程,项目设置为Release x86;
- 在项目属性的 C/C++-->General 修改"Addtional Include Directories",加上xapian的include路径;
- 在项目属性的 C/C++-->Code Generation修改Release下的Runtime Library为 /MT (我们编译的xapian运行时库用的MT,需要确保一致)
- 在项目属性中 Linker-->General修改"Additional Library Directories",加上xapian的lib目录和zlib的lib目录;
- 在项目属性的 Linker-->input中加上Rpcrt4.lib 和 Ws2_32.lib
- 在项目属性的 C/C++-->General 修改“SDL检查”,由“是/(sdl)”改为“否(/sdl-)”
- cpp代码中加入如下代码
#pragma warning(disable : 4996)
#pragma comment(lib, "libxapian.a")
#pragma comment(lib, "zdll.lib")
- 将zlib1.dll拷贝到跟编译生成的exe文件同目录下,否则exe启动会有错误提示:应用程序无法正常启动(0xc000007b)
- 下面是具体代码示例:
#pragma warning(disable : 4996)
#include <iostream>
#include <string>
#include "xapian.h"
#pragma comment(lib, "libxapian.a")
#pragma comment(lib, "zdll.lib")
using namespace std;
const string index_data_path = "./index_data";
const std::string doc_id1 = "doc1";
const std::string doc_keylist1 = "中国 to build self search engine";
const std::string doc_content1 = "What is the search engine?\nMaybe How you should ask baidu or google.\nBut I want to develop my own app.\nThen you may need the xapian source code.";
const std::string doc_id2 = "doc2";
const std::string doc_keylist2 = "NeXa generation search platform";
const std::string doc_content2 = "Every one know search is use full\nIt can Nexa be done just by a PC or phone.\nPlatform is very important";
const int DOC_ID_FIELD = 101;
void save_data()
{
std::cout << "--- save_data----" << std::endl;
Xapian::WritableDatabase db(index_data_path, Xapian::DB_CREATE_OR_OPEN);
Xapian::TermGenerator indexer;
Xapian::Document doc1;
doc1.add_term(doc_id1);
// doc1.add_value(DOC_ID_FIELD, doc_id1); // 用户自定义信息,也可以用此字段作为其他用途
doc1.set_data(doc_content1); // payload
indexer.set_document(doc1);
indexer.index_text(doc_keylist1); // could use space seperated text line like terms or article
db.replace_document(doc_id1, doc1);
Xapian::Document doc2;
doc2.add_term(doc_id2);
// doc2.add_value(DOC_ID_FIELD, doc_id2); // custom property
doc2.set_data(doc_content2);
indexer.set_document(doc2);
indexer.index_text(doc_keylist2);
db.replace_document(doc_id2, doc2);
db.commit();
}
void search_data1()
{
std::cout << "--- search_data1----" << std::endl;
Xapian::Database db(index_data_path);
Xapian::Enquire enquire(db);
Xapian::QueryParser qp;
Xapian::Query term1("中国");
Xapian::Query term2("nexa"); //查询语句输入关键字不能用大写,原文中关键字可以大、小写
Xapian::Query query = Xapian::Query(Xapian::Query::OP_OR, term1, term2);
std::cout << "query is: " << query.get_description() << std::endl;
enquire.set_query(query);
Xapian::MSet matches = enquire.get_mset(0, db.get_doccount()); // find top 10 results
std::cout << matches.get_matches_estimated() << " results found" << std::endl;
std::cout << "matches " << matches.size() << std::endl;
for (Xapian::MSetIterator it = matches.begin(); it != matches.end(); ++it)
{
Xapian::Document doc = it.get_document();
std::string doc_id = doc.get_value(DOC_ID_FIELD);
// FIXME: not every record will show field value, should do filter later
std::cout << "rank: " << it.get_rank() + 1 << ", weight: " << it.get_weight() << ", match_ratio: " << it.get_percent() << "%, match_no: " << *it << ", doc_id: " << doc_id << ", doc content: [" << doc.get_data() << "]\n" << std::endl;
}
}
void search_data2()
{
std::cout << "--- search_data2----" << std::endl;
Xapian::Database db(index_data_path);
Xapian::Enquire enquire(db);
Xapian::QueryParser qp;
Xapian::Query term1("search");
Xapian::Query term2("platform");
Xapian::Query query = Xapian::Query(Xapian::Query::OP_AND, term1, term2);
std::cout << "query is: " << query.get_description() << std::endl;
enquire.set_query(query);
Xapian::MSet matches = enquire.get_mset(0, 10); // find top 10 results, like split page
std::cout << matches.get_matches_estimated() << " results found" << std::endl;
std::cout << "matches " << matches.size() << std::endl;
for (Xapian::MSetIterator it = matches.begin(); it != matches.end(); ++it)
{
Xapian::Document doc = it.get_document();
std::string doc_id = doc.get_value(DOC_ID_FIELD);
// FIXME: not every record will show field value, should do filter later
std::cout << "rank: " << it.get_rank() + 1 << ", weight: " << it.get_weight() << ", match_ratio: " << it.get_percent() << "%, match_no: " << *it << ", doc_id: " << doc_id << ", doc content: [" << doc.get_data() << "]\n" << std::endl;
}
}
void search_data3()
{
std::cout << "--- search_data3-------" << std::endl;
Xapian::Database db(index_data_path);
Xapian::Enquire enquire(db);
Xapian::Query term("nexa");
std::cout << "query is: include \"" << "nexa" << "\"" << std::endl;
enquire.set_query(term);
Xapian::MSet matches = enquire.get_mset(0, db.get_doccount()); // find top 10 results
std::cout << matches.get_matches_estimated() << " results found" << std::endl;
std::cout << "matches " << matches.size() << std::endl;
for (Xapian::MSetIterator it = matches.begin(); it != matches.end(); ++it)
{
Xapian::Document doc = it.get_document();
std::string doc_id = doc.get_value(DOC_ID_FIELD);
std::cout << "rank: " << it.get_rank() + 1 << ", weight: " << it.get_weight() << ", match_ratio: " << it.get_percent() << "%, match_no: " << *it << ", doc_id: " << doc_id << ", doc content: [" << doc.get_data() << "]\n" << std::endl;
}
}
int main(int argc, char** argv)
{
std::cout << "hello xapian" << std::endl;
save_data();
search_data1();
search_data2();
search_data3();
return 0;
}
文本参考如下文档: