我们知道 C++ 不像很多其他语言有包管理工具,比如 Python 有 pip,Java 有 maven,C# 有 nuget,JS 有 npm,Go 有 go mod,Rust 有 cargo,项目中需要自己手动引入第三方库,手动维护带来了很多麻烦。现在 C++ 也有了包管理工具,比如 VCpkg 和 conan,后者 conan 是跨平台的,支持 Windows、Linux、MacOS 等平台,并且支持多种编译器,本文介绍一下如何在项目中引入 conan。
- nlohmann::json/3.11.3
- sqlite3/3.48.0
1. 包管理器 conan
1.1 最小化配置
1.1.1 安装
Conan 基于 Python3 的工具,安装好 python3(3.6以上) 后,用 python 的 pip 安装 conan 很简单:
pip install conan # windows/linux下
brew install conan # macos下
1.1.2 配置
conan 的配置文件有两种,一种是 conanfile.txt
文本文件相当于配置:
[requires]
nlohmann_json/3.11.3
sqlite3/3.48.0
[generators]
CMakeDeps
CMakeToolchain
这个配置文件用来配置我们需要的第三方库,比如指定版本的 nlohmann_json 和 sqlite3。然后 generators
为我们指定的生成器。
另一种是 conanfile.py
的 python 脚本文件,我们用这个脚本文件可以结合 python 代码获得更灵活的能力:
from conan import ConanFile
class MyProjectConan(ConanFile):
name = "mytestproj"
version = "0.1"
settings = "compiler", "build_type", "arch"
generators = "CMakeDeps", "CMakeToolchain"
def requirements(self):
self.requires("nlohmann_json/3.11.3")
self.requires("sqlite3/3.48.0", options={"shared": True})
在项目根目录下创建 conanfile.py
文件,在其中的 requirements
配置我们需要的第三方库。
NOTE! 这两种配置文件是互斥的,只能选择一种。
如果只是比较轻量级使用,可以用 conanfile.txt
配置文件,否则一般用 conanfile.py
脚本文件,以获得最大自由度,比如我们可以写 python 代码将生成的 .lib
、.dll
、.so
和头文件等拷贝到指定目录下。
1.1.3 安装第三方库
项目根目录下执行:
conan install .
之后 conan 会在文件根目录生成 .cmake
、.sh
、.bat
等等一堆文件,这些文件都是 conan 生成的,用来给项目引入第三方库的脚本文件,如何引入我们在后面介绍。
上面的方式会在根目录下生成一堆文件,一般我会在根目录下放一个 thridparty
目录,将 conan 生成的文件都放在这个目录下,这样方便管理,然后一些本地的第三方库或者驱动也用 mklink /d
命令创建软链接,指向对应文件夹,这样方便管理。
这是最小化配置的 conan 配置,我们可以在 conanfile.txt
或 conanfile.py
中配置更多的选项,比如指定第三方库的版本、指定第三方库的构建类型、指定第三方库的构建选项等等。
下面介绍一下在 VS 项目中如何引入 conan。
2. VS 项目中引入 conan
2.1 修改配置文件
为了指定 conan 将我们的第三方库生成到指定目录,并且在生成结束后,将生成的 .dll
动态库文件复制到可执行文件同级目录,需要对 conanfile.py
进行一些改动:
import os
from conan import ConanFile
from conan.tools.files import copy
class MyProjectConan(ConanFile):
name = "cef_131_mytest"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
generators = "MSBuildDeps", "MSBuildToolchain"
def requirements(self):
self.requires("nlohmann_json/3.11.3")
self.requires("sqlite3/3.48.0", options={"shared": True})
def layout(self):
self.folders.generators = os.path.join("thirdparty", "conan")
self.folders.build = os.path.join("thirdparty", "conan", "build")
def deploy(self):
print(f" -->deploying env: arch={self.settings.arch}, build_type={self.settings.build_type}")
source_dir = os.path.join(self.dependencies["sqlite3"].package_folder, "bin")
print(f" -->deploy source_dir: {source_dir}")
# 动态生成目标路径(如 x64/Debug 或 x64/Release)
arch = "x64" if self.settings.arch == "x86_64" else "x86"
target_dir = os.path.join(os.getcwd(), arch, str(self.settings.build_type))
print(f" -->deploy target_dir: {target_dir}")
# 复制 DLL 到项目输出目录
dll_files = [f for f in os.listdir(source_dir) if f.endswith(".dll")]
for dll_file in dll_files:
print(f" --> Copying {dll_file}")
copy(self, dll_file, src=source_dir, dst=target_dir)
由于是 VS 项目,所以配置文件的 generators 使用的是 MSBuild 构建工具链。
然后在项目根目录下:
conan install . -s build_type=Debug --build=missing --deployer-package=*
如果是 Release 模式:
conan install . -s build_type=Release --build=missing --deployer-package=*
此时会在 thirdparty/conan
目录下生成 conandeps.props
等 VS 属性表,然后我们可以通过公共配置文件的方式引入生成的 VS 属性表,关于 VS 公共配置文件的使用方式参考 <C++ 中 VS 项目引入公共配置文件>
2.2 引入 VS 项目
对于上面的 generators 为 "MSBuildToolchain", "MSBuildDeps"
,使用的是 Microsoft Visual Studio 的 MSBuild 编译工具链,此时在 conan install
命令会生成 props
文件供 VS 引入,如果使用的 generators 是 "CMakeToolchain", "CMakeDeps"
,那么会生成 CMake 相关的一系列文件,可以从 CMakeLists.txt
文件中引入 conan 管理的库。
其中:
-Deps
:为三方库的所有依赖项生成 CMake 配置文件;-Toolchain
:根据传递给 conan 的系统、编译器、架构等信息,生成 CMake 构建三方库所需的所有信息。还会生成 cmake-presets 文件,以供一些 IDE 集成。
现在我们要引入的配置文件是 conan 在 install 的时候生成的 conandeps.props
,在项目配置 .vcxproj
中加入:
<Import Project="$(SolutionDir)\thirdparty\conan\conandeps.props" Condition="exists('$(SolutionDir)\thirdparty\conan\conandeps.props')" Label="conandeps" />
这个 conandeps.props
文件会导入 conan 给每个引入的第三方库生成的 props 配置文件:
第三方库的 props 配置文件中会分别引入其 Debug 和 Rlease 版本的目录配置和变量配置,其中指定了将第三方库目录和包含目录存放的具体位置,在项目 .vcxproj
中cli引入 conandeps.props
之后重启 VS,就可以从 conan 的缓存目录里直接 #include
相应库的头文件了。
网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出,如果本文帮助到了你,别忘了点赞支持一下,你的点赞是我更新的最大动力!~
参考文档:
PS:本文同步更新于在下的博客 Github - SHERlocked93/blog 系列文章中,欢迎大家关注我的公众号 CPP下午茶
,直接搜索即可添加,持续为大家推送 CPP 以及 CPP 周边相关优质技术文,共同进步,一起加油~
另外可以加入「前端下午茶交流qun」,vx 搜索 sherlocked_93
加我,备注 1,我拉你~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。