项目中需要用到正则表达式校验复杂字符串有效性。于是想到了使用boost中的regex。
后来在具体实施时发现boost文件过于庞大,不能仅仅因为要使用regex就需要要将所有文件包含进来,更何况还要上传svn(此处有争议,后面介绍)。
尝试手动提取regex依赖文件,发现工作量太大于是放弃。由于使用vs2008开发环境且安装了sp1补丁,想到了tr1(C++ technical report 1)中的自带的regex。问题虽然搞定,但仍觉得有必要研究下boost中的regex。于是才有这篇文章。
目前了解到C++项目集成正则表达式有以下三种方案:
1.使用boost中的regex
2.使用C++ tr1自带的regex库。
3.使用atl中自带的regex。(vs2008中需要手动安装)。
这里仅对提取boost中的regex并集成到项目的过程进行介绍,一为记录,而来可以让后来人少走弯路。如有纰漏还望指正。
在集成boost中regex时想到了手工提取regex依赖文件,这是笨方法也是最容易想到的方法。在与他人交流时也被建议这样做。但boost文件众多,regex中也会用到其他基础设施。其实boost已经为我们提供了一个工具,将繁琐的工作简单化 。这个工具就是bcp.exe。但boost包中仅包含其源代码,需要编译才能得到。
编译boost我们不做介绍,网上相关的资料多余牛毛。这里仅介绍编译bcp.exe。
1.首先要得到bjam.exe。(不知道如何得到?网上搜下)
2.控制台运行bjam tools/bcp 编译bcp代码。
3.在dist\bin目录下会生成bcp.exe。(很简单吧)。
4.拷贝到boost主目录(与bjam.exe相同目录)。
5.提取regex:控制台输入 “bcp regex.hpp C:\regex” (将regex相关源文件提取到C:\regex)。
可以看到regex被提取到了C:\regex下。打开看了下发现依赖文件还是很多的,人工提取确实不是件容易的事情。
提取之后下面就该编译regex了。Boost中90%的代码不需要编译即可使用,但regex就是那10%的例外。在boost源文件目录编译regex很简单,这里也不再介绍。但提取出regex后如何编译又让人犯了难。
可以看到regex下有名为Jamroot的文件。其实它是bjam的工程文件。Bjam是专门为boost库设计的make工具。一个解决方案对应一个Jamroot文件。这点很类似与vs的sln文件。在编译boost工程时,bjam会自动查找这个文件。以上为科普。
下面正式开始编译,说了那么多其实对我们编译没多大用处。进入到C:\regex\libs\regex\build 可以看到有多个用于vc编译器的.mak文件。从vc6到最新编译器应有尽有。
我们知道.mak文件就相当于windows下的makefile。下面就来介绍下如何来使用。
1. 运行xxxx\Microsoft Visual Studio 9.0/VC/bin/VCVARS32.BAT(拖至控制台窗口)。(此处针对vs2008)。
2.控制台 nmake vc9.0.mak。(注意路径,此处省略)
3.开始编译。
一段时间后编译完毕。build目录下新建了vc90目录。
可以看到已经为我们编译了多个链接选项的库。可以通过前缀来区分它们。
库命名规则
libboost_regex-vc90-mt-sgd-1_53.lib
前缀:统一为lib,在Windows下前缀lib表示静态库。
库名称:以”boost一”开头的库名称,在这里是boost_regex;
编译器标识:编译器名称和版本,这里是-vc90;
多线程标识:Mt(multithread static) 、md(multithread dynamic)为链接的CRT库选项。
ABI标识:标识了Boost库的几个编译链接选项;
s:静态库。
gd:debug版;
p:使用STlport而不是编译器自带STL实现;
版本号:Boost库的版本号,小数点用下画线代替,在这里是1_53
扩展名:在Windows上是lib,在Linux等类Unix操作系统上是a或者.so。
编译好之后就可以使用了。首先要配置头文件附加包含目录。这里是C:\regex\
接着设置附加库目录:
然后是测试代码:
#include <iostream>
#include "boost/regex.hpp"
#include <string>
using namespace boost;
using namespace std;
int main()
{
boost::cmatch what;
regex expression("^(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$");//匹配ip
string in("192.168.1.120");
if(regex_match(in.c_str(), what, expression))
{
cout<<"匹配成功!\r\n"; }
else
{
cout<<"匹配失败!\r\n";
}
getchar();
return 0;
}
程序编译运行成功。
不知大家有没有发现什么问题。上面在设置环境时,我们仅仅设置了附加包含和附加库目录,并没有设置附加依赖项。程序依然会链接成功。但是此时程序究竟链接的是哪个版本的boost库?静态?动态?mt?md?
这时我们可以使用宏BOOST_LIB_DIAGNOSTIC来打印当前链接的库版本。
再次编译连接可以看到在输入框打印了当前链接的库版本。Mt release版本的静态库。
之所以是release版本,是因为当前vs2008就配制成了release。设置成debug再测试下。
可以看到此时链接的是mt debug版本的静态库。
上面这些完全归功于boost的自动链接(Auto linking)技术。有了自动链接功能我们不需要手工指定依赖的库,boost会自动根据IDE环境配置自动链接依赖的库。所有这些是在auto_link.hpp(boost/config/auto_link.hpp)中定义的。有兴趣的童鞋可以打开分析下。
关于自动编译有下面这段描述。
Auto-Linking
Most Windows compilers and linkers have so-called “auto-linking support,” which eliminates the second challenge. Special code in Boost header files detects your compiler options and uses that information to encode the name of the correct library into your object files; the linker selects the library with that name from the directories you’ve told it to search.
Boost默认启用自动链接功能,而且是静态链接。它会根据当前的编译器预定义宏判断是否是DEBUG,什么版本的编译器,然后自动链接libXXX-vc90-mt-gd-1_52.lib这样的文件。其中lib的代表着是静态LIB库文件,vc90指编译器版本(VS2008),gd代表debug版本,release版本没有gd选项。
有时自动链接会让人非常烦恼,当升级了VS时,要重新用新编译器编译Boost库。
如果要开启自动链接功能链接动态库,需要定义 BOOST_ALL_DYN_LINK。这样它就自动链接 XXX-vc90-mt-gd-1_53.lib.
关闭自动链接功能需要定义宏BOOST_ALL_ NO_LIB ,这样就关闭了BOOST的自动链接LIB的功能。这是就需要在附加库里手动加入或者使用#pragma comment添加依赖库。
几个常用宏
#define BOOST_ALL_DYN_LINK //动态链接boost库
#define BOOST_ALL_NO_LIB //关闭自动链接
#define BOOST_LIB_DIAGNOSTIC // output窗口中输出链接boost库版本以及链接顺序。
文章开始曾说过,关于是否将boost传库有两种看法。一种看法认为不需要传库。Boost相关文件应该是开发环境的一部分,比如你会将vs2008上库么。另一种看法认为应该上库,boost毕竟还不是C++标准的一部分,不上库的话每个人都需要安装配置,费时费力。笔者倾向于第一种看法。你呢?
2015.12.11于浙江杭州