C++开源库 - 包管理工具Vcpkg安装使用教程

一、编译开源库的传统方法

Windows 下开发 C/C++ 程序,少不了编译开源的第三方库。比如用于网络连接的高性能库 libcurl、用于压缩解压的 zlib 等等。使用这些库开发极大的方便了程序员,使得我们不必重复造*。但是使用这些库必须要处理以下问题。

编译方式
由于这些开源库绝大部分都来源于 Linux 系统,导致其工程文件、编译系统都使用 gnu 系列工具,使得将其移植到 Windows 的 VC 开发环境下一直是难点。尽管最近几年很多开源库都支持了跨平台的 CMake,但是编译过程仍然复杂和多样化。

常见的编译方式有:

编译方式 特点 举例
configure、make 需要msys这样的unix环境才可以编译 ffmpeg
自定义编译工具 需要学习特定的编译命令和工具 openssl、boost
cmake 相对简单轻松 libcurl
VC工程文件 这种最简单,直接拿来即可编译

编译类型
当了解了这些还不够,我们还需要考虑预先编译出哪种类型的开源库程序。比如:Debug还是Release、动态库还是静态库、MD还是MT、32位还是64位。光是这三种组合就有16种可能性。如果像libcurl这种还要考虑是否引用其他开源库的功能,那么编译类型的组合会更多。管理起来很麻烦。

工程目录设定
由于多样的编译类型,工程目录也必须仔细设定才能保证自己的软件项目能够正常编译。

二、为什么要用Vcpkg

正是由于编译开源库的传统方法的缺陷,所以出现了 Vcpkg,优点如下:

  • 自动下载开源库源代码。
  • 源码包的缓存管理和版本管理,可以升级版本。
  • 轻松编译。
  • 依赖关系检查(比如编译 libcurl,会自动下载 zlib、openssl 进行编译)。
  • 无缝集成 Visual Studio,不需要设置库文件、头文件的所在目录,自动集成。
  • Visual Studio 全平台支持,不仅支持 Debug/Release、x86/x64 编译,还支持 UWP、ARM 平台的编译。

三、windows下安装Vcpkg

(1)由于官方建议把 vcpkg 目录放到 C:\src\ 下,所以先创建再移动到该目录:

$ cd c:/src

(2)git 克隆官方的 git 仓库:

$ git clone https://github.com/microsoft/vcpkg

(3)进入到仓库中,编译 Vcpkg:

$ cd vcpkg
$ ./bootstrap-vcpkg.bat

注意:

  • Vcpkg 大量使用 psl 脚本,所以官方强烈推荐使用 PowerShell 而不是 CMD 命令行来执行各种操作。尽管在使用的时候兼容 CMD,但是在编译这一步,请使用 PowerShell,以下所有操作也如此。

  • 如果下载失败,输出 Downloading vcpkg.exe failed. Please check your internet connection, ...,说明外网下载不稳定,需要尝试多次下载或*上网。

成功后输出:

Downloading https://github.com/microsoft/vcpkg-tool/releases/download/2021-02-24-d67989bce1043b98092ac45996a8230a059a2d7e/vcpkg.exe -> C:\src\vcpkg\vcpkg.exe
Done.

更详细可以参考 Vcpkg 的官方 git 地址:https://github.com/microsoft/vcpkg/blob/master/README_zh_CN.md

四、使用Vcpkg

4.1 查看Vcpkg支持的开源库列表

$ ./vcpkg.exe search

执行命令后,两三分钟后才显示出来支持的开源库列表,基本上常用的 C++ 开源库都支持。(使用 PowerShell 执行)


4.2 指定编译某种架构的程序库

如果不指定安装的架构,vcpkg 默认把开源库编译成 x86 的 Windows 版本的库。那 vcpkg 总共支持多少种架构呢?我们可以使用如下命令便知:

$ ./vcpkg.exe help triplet

我们可以看到会列出如下清单:

  • arm-uwp
  • arm-windows
  • arm64-uwp
  • arm64-windows
  • x64-uwp
  • x64-windows-static
  • x64-windows
  • x86-uwp
  • x86-windows-static
  • x86-windows

这个清单以后随着版本的迭代还会再增加。vcpkg 不仅支持 x86 架构,还支持 arm 架构。注意:这里的 arm 架构特指类似于 surface 这种运行在 arm 处理器上的 Win10 平台,而并非我们传统意义上的 Linux 或 android 的 ARM 平台。


4.3 安装一个开源库

那如果要安装编译某一个架构的开源库,我们该怎么写呢?我们只需要在需要安装的包后面指定相应的 triplet 即可。例如我们需要编译 64 位 Windows 版本的 jsoncpp,那么执行如下命令即可。

$ ./vcpkg.exe install jsoncpp:x64-windows

看到Installing package jsoncpp[core]:x64-windows... done,则说明安装成功。

如果电脑中没有安装 CMake、7zip 等软件,Vcpkg 会自动下载 portable 版本的 CMake、7zip 等软件。但是由于各种原因,下载的网速很慢,所以建议先自行下载合适版本的对应软件。最好是下载最新版本的。实际测试发现,会先同时下载以下软件:

7zip-18.1.0-windows
cmake-3.19.2-windows
nuget-5.5.1-windows
powershell-core-7.1.0-windows

报错及解决办法

(1)在下载 powershell 时会下载不成功,提示:

Failed to download from mirror set:
https://github.com/PowerShell/PowerShell/releases/download/v7.1.0/PowerShell-7.1.0-win-x86.zip: WinHttpSendRequest() failed: 12002

只能复制上面下载链接,发现手动下载正常,下载完成后拷贝 PowerShell-7.1.0-win-x86.zipC:\src\vcpkg\downloads 目录下,然后再执行安装指令,会跳过下载这步直接开始解压 PowerShell 压缩包。

遇到下载其他依赖库的压缩包失败时,也可考虑使用这种手动下载的方法。

后面下载 jsoncpp/archive/9059f5cad030ba11d37818847443a53918c327b1.tar.gz 也不成功,采用上面方法后,修改名称为 open-source-parsers-jsoncpp-9059f5cad030ba11d37818847443a53918c327b1.tar.gz

(2)缺少英文语言包,报错:

Warning: The following VS instances are excluded because the English language pack is unavailable.

解决办法:到 VS 安装向导,修改安装,点语言包,勾选英语;安装即可。


4.4 移除一个已经安装(编译)的开源库

如果移除一个已经安装的开源库,那么执行 remove 指令即可。比如我们要移除 jsoncpp,那么执行命令:

$ ./vcpkg.exe remove jsoncpp

注意:

这个时候只是移除了默认的 x86-winodws 版本的文件,如果有其他平台的版本需要移除,需要制定相应的 triplet。移除也只是移除了二进制程序库而已,源码包和解压缩的源码并没有删除。

如果想要一键移除“过时”的包,执行命令:

$ ./vcpkg.exe remove --outdated

4.5 列出已经安装的开源库

执行 list 指令即可,例如:

$ ./vcpkg.exe list

假如前面安装了 jsoncpp,会输出:jsoncpp:x64-windows 1.9.4 jsoncpp is an implementation of a JSON reader an...


4.6 更新已经安装的开源库

一般有两种更新方式。一个是 update 指令,可以显示可以升级的开源库的列表。另一个是 upgrade 的指令,会重新编译所有需要更新的包。

4.7 导出已经安装的开源库

有的时候,一个项目组中有很多人,不需要每个人都参与编译。一个人编译好所有开源库后到处给别人即可。有的时候也是出于备份的目的,也会导出已经安装的开源库。导出可以执行 export 指令。例如,我要导出 jsoncpp 库,那么执行:

$ ./vcpkg.exe export jsoncpp --zip

注意,导出时必须指定导出的包格式。vcpkg 支持 5 种导出包格式,有:

参数 格式
–raw 以不打包的目录格式导出
–nuget 以 nuget 包形式导出
–ifw 我也不知道这是啥格式
–zip 以 zip 压缩包形式导出
–7zip 以 7z 压缩包形式导出

一般地,导出包的格式为:vcpkg-export-<日期>-<时间>

默认情况下只会导出 x86-windows 的包,如果要导出所有包,那需要制定相应的 triplet。比如,如果同时导出 x86 和 x64 版本的 jsoncpp,那执行命令:

$ ./vcpkg.exe export jsoncpp:x86-windows jsoncpp:x64-windows --zip

如果要指定输出目录和特定文件名,需使用 "–output=" 参数。

4.8 导入备份的开源库

导入比较简单,执行 import 指令即可。例如:

$ ./vcpkg.exe import xxx.7z

五、Vcpkg和Visual Studio的集成

5.1 什么是集成?

上面我们已经安装了一些第三方库,那如何使用呢?常规情况下,我们需要设置 include 目录、lib 目录等,会有很多工作量。Vcpkg 提供了一套机制,可以全自动的适配目录,而开发者不需要关心已安装的库的目录在哪里,也不需要设置。这是 Vcpkg 的一大优势。


5.2 集成到全局

“集成到全局” 适用于 Visual Studio 开发环境和 msbuild 命令行。执行命令:

$ ./vcpkg.exe integrate install

当出现 Applied user-wide integration for this vcpkg root. 字样的时候,说明已经集成成功。这时候可以在任意的工程中使用安装好的第三方库。

5.3. 移除全局集成

移除全局集成只要执行下列命令即可:

$ ./vcpkg.exe integrate remove

5.4 集成到工程

上面已经可以集成到全局,为什么还要 “集成到工程” 呢?因为在大部分情况下,我们不希望集成到全局,毕竟有很多第三方库我们希望自定义处理一下,或者干脆不想集成第三方库。那么集成到工程是最灵活的处理方式。也是工程级项目推荐的处理方式。

“集成到工程” 是整个 vcpkg 中最复杂的一项,它需要利用 Visual Studio 中的 nuget 插件来实现。我们接下来一步一步来说。


1. 生成配置

执行命令:

$ ./vcpkg.exe integrate project

这时候会在 <vcpkg_dir>\scripts\buildsystems 目录下,生成 nuget 配置文件。其中 <vcpkg_dir> 是指 vcpkg 实际所在目录。


2. 基本配置

打开 Visual Studio,点击菜单工具 -> NuGet 包管理器 -> 程序包管理器设置”,进入设置界面,点击 “程序包源”。

C++开源库 - 包管理工具Vcpkg安装使用教程


点击 “加号” 增加一个源。修改源的名字为 vcpkg。在“源”的选项中点击右侧的 "…" 选择 vcpkg 目录下的 “scripts\buildsystems” 目录,然后点击右侧的“更新按钮”。点击 “确定”,关闭设置对话框。

到此,全局性的设置已经完成,以后不必再重复设置了。


3. 工程配置
用 Visual Studio 打开一个工程或解决方案。右键点击需要设置的工程,选择 “管理NuGet程序包”。在右上角的 “程序包源” 中选择刚刚设置的 “vcpkg”。这样在 “浏览” 选项卡中就可以看到 “vcpkg.H.Repos.vcpkg”。点击最右侧的 “安装”。这样就可以集成到某个工程了。
C++开源库 - 包管理工具Vcpkg安装使用教程


5.5 测试使用

#include <iostream>
#include <fstream>
#include <cassert>
#include "json/json.h" // 直接就可以include,无需额外配置

std::string createJson(void)
{
    std::string jsonStr;
    Json::Value root;
    Json::StreamWriterBuilder writerBuilder;
    std::ostringstream os;
    // 设置默认无格式化的输出
    writerBuilder.settings_["indentation"] = "";
    root["Name"] = "Zhangsan";
    root["Age"] = 25;
    // jsonWriter是智能指针, 当jsonWriter被析构时, 它所指向的对象(内存)也被自动释放
    std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
    jsonWriter->write(root, &os);
    jsonStr = os.str();

    return jsonStr;
}

void saveJsonStringToFile(const char* file, std::string& jsonStr)
{
    std::ofstream ofs;
    ofs.open(file);
    assert(ofs.is_open());
    ofs << jsonStr;
    ofs.close();
}

int main()
{
    std::string jsonStr;
    jsonStr = createJson();
    saveJsonStringToFile("./test.json", jsonStr);

    return 0;
}

jsoncpp 的更多使用请参考:新版jsoncpp的一些基本用法

到此,就可以在 VS 上随意使用 jsoncpp 库了,在 exe 生成目录下也发现了 jsoncpp.dll


5.6 集成到CMake

最新的 Visual Studio 2015、2017 和 2019 大力支持 CMake 工程,所以对 cmake 的支持当然不能少。在 cmake 中集成只要在 cmake 文件中加入下面这句话即可。

-DCMAKE_TOOLCHAIN_FILE=<vcpkg_dir>/scripts/buildsystems/vcpkg.cmake

其中 <vcpkg_dir> 是指 vcpkg 实际所在目录。

5.7 集成静态库

Vcpkg 默认编译链接的是动态库,如果要链接静态库,目前还没有简便的方法。需要做如下操作

  1. 用文本方式打开 vcxproj 工程文件。
  2. 在 xml 的段里面增加如下两句话即可:
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
<VcpkgEnabled>true</VcpkgEnabled>

在 CMake 中集成静态库,需要额外指令:

cmake .. -DCMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x86-windows-static

六、使用Vcpkg时的注意点

  • Vcpkg 仅支持 Visual Studio 2015 update 3 及以上版本,究其原因,很可能和 C++11 的支持度以及集成原理有关系。
  • 目前 Vcpkg 编译静态库,默认只支持 MT 模式。

七、小结

Vcpkg 目前还在不断的完善中,但不可否认,它已经极大的减少了我们在项目启动时,准备第三方库的时间。提高了工作效率。按照时髦的话来说,就是避免了重复造*。目前 Vcpkg 已经集成了上百个常用的开源库,而且数量还在不停增长。毕竟是微软旗下的开源项目,质量还是可以得到保障的,完全可以在工业级项目中得以使用。源代码托管在 github上,github 社区很活跃,有兴趣的朋友也可以参与进来。

参考:

microsoft/vcpkg

Visual Studio开源库集成器Vcpkg全教程--利用Vcpkg轻松集成开源第三方库


上一篇:jsoncpp的使用简介


下一篇:第十七章 认识系统服务 (daemons)