作为一名古老的语言,c++ 还在缝缝补补的路上尽力地跟上这个时代。之前了解过 Rust 觉得它最吸引人的地方就是有独立的包管理器 Cargo。若你维护过使用 Autotool 或 Makefile 来进行管理的 c++ 项目,可能会对包管理器的需求有一个深刻的认识。一直使用 CMake 的 FetchContent 模块来从网络上获得项目需要的库,在一定程度上,FetchContent 模块可以代替一些包管理器的工作。但是,不同的库使用的编译方式都是不一样的。所以,每次对于不同的第三方库的维护和脚本编写都挺折腾,若有一种统一的方式来对各种第三方库进行安装,那会在这方面节省非常多的时间。
VcPkg 刚出来的时候,在一定程度上其实解决了这个问题,但是它是被安装到系统中,可以同时支持很多的项目。不过这也带来了一个问题,就是对于一个库的不同的版本的支持并不完善,而且对于 Github 的自动构件那一套东西似乎也支持得并不好。最近做了一个 BIP39 的 c++ implementation 库,想在每次项目的代码被 Push 到 Github 的时候使用自动化工具,对库进行编译并自动运行测试用例。最初是使用 VcPkg 来管理第三方库,然后在挂 Github 的自动脚本的时候出现问题:我的 VcPkg 在本地,而在 Github 上是没有对应的 VcPkg 的,所以自动化脚本是无法正确被运行。于是,继续沿用老的传统使用 FetchContent 来下载各第三方库,并且根据当前提供的编译参数进行编译,似乎是解决了问题,并且在每次 Push 后都能够开始编译并运行测试用例。但是,难道没有节省心智的更好的办法了吗?
在国外的论坛上浏览 VcPkg 相关的帖子,突然发现原来 VcPkg 有一种新的模式,叫做 Manifest Mode。它可以在当前项目的根目录下编写一个第三方库列表,然后再执行vcpkg install
就会将需要的库自动安装完成,然后使用这样的模式,将 VcPkg 以一个 Submodule 的方式加到当前的 Git 代码里,最后修改一下 CMake 脚本,添加相应的一句指名 CMAKE_TOOLCHAIN_FILE 的位置,即可在当前的项目的 CMake 文件中正常的使用 find_package 来寻找对应的第三方库并进行链接和编译工作。这样一来,不再需要自己手动编写下载和编译第三方库的脚本,而且也解决了全局 VcPkg 的版本问题。这种方式,也可以很好的被 Github 自动化工具执行,只需要在自动化脚本中添加 run-vcpkg 这个 Action 即可。
这一次的问题解决得彻底且完美,我也突然意识到,使用 CMake + VcPkg 其实就已经解决了 c++ 没有包管理器这一痛点,未来新的 c++ 项目都应该使用这一方式来管理第三方库。