1.5.4 链接Boost C++库
无论是自己构建库,还是下载安装预编译的库,我们现在总算已经安装好了Boost静态库或动态库的二进制文件。接下来将借助它们完成更复杂的功能!本小节将使用Boost Regex库提取一段文本中出现的所有URL。
使用Boost Regex库提取URL
主程序main.cpp如代码清单1.25所示。
代码清单1.25 ch001/链接Boost/main.cpp
#include <boost/regex.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace boost;
int main() {
string s = R"(
Search Engines: http://baidu.com https://google.com
About Me: https://xuhongxu.com/about/
)";
regex e(R"(([a-zA-Z]*)://[a-zA-Z0-9./]+)");
for (sregex_iterator m(s.begin(), s.end(), e), end; m != end; ++m) {
cout << "URL: " << (*m)[0].str() << endl;
cout << "Scheme: " << (*m)[1].str() << endl;
cout << endl;
}
return 0;
}
其中,首先引用了头文件boost/regex.hpp,然后在主程序中初始化了一个boost::Regex类型的变量,即用于提取URL的正则表达式:
([a-zA-Z]*)://[a-zA-Z0-9./]+
注意:由于该表达式仅用于演示,刻意写得较为简短,并不能准确提取URL。
for循环起始条件中,初始化了sregex_iterator迭代器m,用于遍历字符串中匹配到的全部结果;还有一个空迭代器end,用于指示迭代器的终止位置。迭代器的值,也就是匹配结果,采用类似数组的形式,可以通过索引访问。第0项为完全匹配的结果,后续索引项则依次是各个捕获组的结果。
使用MSVC/NMake构建本例
这里将构建两次主程序main.cpp,分别演示对Boost库的静态链接和动态链接。其中,静态链接Boost库的可执行文件名为static_boost.exe,动态链接Boost库的可执行文件名为shared_boost.exe。 Makefile如代码清单1.26所示。
代码清单1.26 ch001/链接Boost/NMakefile
# 自行构建的Boost库
BOOST_DIR=C:\boost
BOOST_LIB_DIR=$(BOOST_DIR)\stage\lib
# 下载安装的预编译Boost库
# BOOST_DIR=C:\boost_prebuilt
# BOOST_LIB_DIR=$(BOOST_DIR)\lib64-msvc-14.2
CXXFLAGS=/I $(BOOST_DIR) /MD /EHsc
LINKFLAGS=/LIBPATH:$(BOOST_LIB_DIR)
all: static_boost.exe shared_boost.exe
static_boost.exe: main.cpp
cl libboost_regex-vc142-mt-x64-1_74.lib \
main.cpp $(CXXFLAGS) /Fe"static_boost.exe" /link $(LINKFLAGS)
shared_boost.exe: main.cpp
cl boost_regex-vc142-mt-x64-1_74.lib /DBOOST_ALL_NO_LIB \
main.cpp $(CXXFLAGS) /Fe"shared_boost.exe" /link $(LINKFLAGS)
clean:
del *.obj *.exe
其中定义了BOOST_DIR和BOOST_LIB_DIR两个变量,分别代表Boost的根目录和库文件所在的目录。这里有两组变量的定义,其中第二组被注释掉了。第一组的目录是自行构建的Boost库所在的目录,第二组则是预编译库的安装目录。读者可以自行切换,构建结果是相同的。
CXXFLAGS变量用于向编译器传递公共参数。/I用于指定头文件搜索目录,这里直接设置为Boost的根目录即可。/MD参数代表程序将会动态链接C++运行时库,与之相对地,MSVC还有一个/MT参数,表示程序将会静态链接C++运行时库。由于Boost库的构建过程会默认指定/MD,这里引用Boost库的主程序也应该使用匹配的方式。
LINKFLAGS变量定义了向链接器传递的公共参数LIBPATH,即链接库的搜索目录。
下面是构建目标规则。由于本例将构建两个可执行文件,所以第一条规则将构建目标写为 all,同时依赖这两个可执行文件。这样,执行nmake all可以同时构建二者。另外,Makefile 的第一条规则是默认规则,当不提供目标参数执行nmake时会默认执行,因此执行nmake就相当于执行nmake all(不过对于本例来说,记得指定/F NMakefile参数)。
静态链接Boost库的主程序static_boost.exe的构建规则中,除了将CXXFLAGS和LINKFLAGS变量中定义的参数传递给编译器和链接器外,还向编译器传递了Boost Regex静态库的文件名。这与之前在代码清单1.12中静态链接自己编写的静态库几乎是一样的,仅仅是增加了指定搜索目录的参数。
动态链接Boost库的主程序shared_boost.exe的构建规则稍微复杂。与静态库相似但不同的是它所链接的.lib库是动态库对应的导入库。另外还多了一个宏的定义:BOOST_ALL_NO_LIB。这个宏用于指示Boost库不要试图寻找静态库进行链接,当动态链接Boost库时,都应该定义这个宏。
执行NMake构建该项目:
> cd CMake-Book\src\ch001\链接Boost
> nmake /F Makefile
> static_boost
URL: http://baidu.com
Scheme: http
URL: https://google.com
Scheme: https
URL: https://xuhongxu.com/about/
Scheme: https
> shared_boost # 无法启动
静态链接Boost库的主程序一切正常!但是,动态链接Boost库的主程序在运行时会抱怨找不到Boost 的动态库。这也是意料之中的事情,毕竟Boost的动态库与主程序并不在同一目录,而且Windows中也没有RUNPATH和RPATH,我们需要先复制动态库boost_regex-vc142-mt- x64-1_74.dll再运行。
使用GCC/GNU make构建本例
为了更好地对比,在Linux操作系统中,这里仍然以静态和动态两种链接Boost库的形式来构建本例。 Makefile如代码清单1.27所示。
代码清单1.27 ch001/链接Boost/Makefile
# 自行构建的Boost库
BOOST_DIR = $${HOME}/boost
BOOST_LIB_DIR = ${BOOST_DIR}/stage/lib
CXXFLAGS = -I $(BOOST_DIR)
LDFLAGS = -L $(BOOST_LIB_DIR) -Wl,-R$(BOOST_LIB_DIR)
# 将以上几行全部注释,即可使用安装的预编译Boost库
all: static_boost shared_boost
static_boost: main.cpp
g++ main.cpp $(CXXFLAGS) $(LDFLAGS) -l:libboost_regex.a -o static_boost
shared_boost: main.cpp
g++ main.cpp $(CXXFLAGS) $(LDFLAGS) -lboost_regex -o shared_boost
clean:
rm *_boost
首先定义与Boost库目录相关的变量。BOOST_DIR是自行构建的Boost库所在的根目录,也就是~/boost;但由于RUNPATH需要使用绝对路径,我们将它写作$${HOME}。两个$代表$的转义,因此这里实际上引用了${HOME},它是代表Home目录绝对路径的环境变量。BOOST_LIB_DIR变量,与Windows中一样,定义了Boost库的库文件目录。
不过这里为什么不像NMake Makefile中一样,提供预编译库的路径变量呢?答案很简单,因为GCC会主动搜索系统的头文件目录和库文件目录,而系统包管理器安装的Boost预编译库正是安装在系统目录中。如果想让构建的程序直接链接它们,只需将Makefile 中前面这四个变量的定义注释掉,让GCC自动去默认的目录搜索头文件和库文件。
CXXFLAGS和LDFLAGS变量分别代表公共的编译和链接参数。编译参数-I指定了头文件库搜索目录,链接参数-L指定了链接库文件搜索目录,链接参数-Wl,-R 指定了RUNPATH的值。
最后,构建主程序的规则:无论是静态链接Boost库,还是动态链接Boost库,调用GCC的方式都是一样的,区别仅仅在于链接库的名称。由于链接库时,-l参数默认接受的是库的名称,而非文件名。所以,链接静态库libboost_regex.a或动态库libboost_regex.so时,应该指定参数-lboost_regex,这就冲突了,此时 GCC会优先链接动态库。为了能够实现对Boost静态库的链接,这里需要使用-l:加静态库文件全名的参数形式。
执行make构建该项目:
$ cd CMake-Book/src/ch001/链接Boost
$ make
$ ./static_boost
...
$ ./shared_boost
...
Linux中的程序可以指定RUNPATH,因此无须复制Boost动态库文件就可以运行shared_boost。