
之前用 windows 开发,为了统一使用第三方库行为,我习惯 cmake + vcpkg 这套,直接用上 vcpkg.cmake 后在 cmake 中 find_package 就行。
而 linux 已经有自己的包管理器了,我直接 pacman 可以很方便的下载第三方库。但问题是有哪些统一行为能够在 cmake 引入 pacman 下载的内容(头文件+库文件)?
我能想到的是通过 pkg-config 去统一管理,在 cmake 中 find_package(PkgConfig),然后用 pkg-config 的东西去引入。
但当我通过 pacman 下载 boost 时( boost 和 boost-libs ),用 pkg-config 找不到对应的文件(例如我想引入 asio 库,但 pkg-config --list-all | grep asio 找不到相关的内容)。通过 pacman 下载的 boost 似乎没有提供 .pc 文件,导致 pkg-config 不知道这么个东西。
另外我能想到的是,手动的在 cmake 中 find_library 和 find_path 引入库文件和头文件,但这样太麻烦了(例如要使用 ffmpeg ,那我得分别手动搜索 libavformat 、libavcodec 、libavutil 、libswscale 的头文件和库文件),用 find_package 倒是可以很方便解决,但 pacman 下载的依赖似乎没有提供相关的 .cmake 文件?
似乎 pkg-config 不是终极解决方案,所以有什么方案能够统一引入依赖的行为。难道还要继续使用 vcpkg 吗?(确实好用,但看一些人的说法是 linux 上建议使用自带的包管理器)
1 w568w 1 天前 (我主要写 C ,没写过 C++,所以下面一部分说法可能不准确。) 这个问题其实有系统级和语言级的两层,一是 Linux 对 C/C++ 依赖的管理没有明确的定义,各个发行版自立山头;二是 C/C++ 的包管理本身确实很乱。 1. 对于前者,可以认为在依赖管理这件事上,Linux 没有规定什么做法是标准的,所以「每个系的发行版都是完全独立的体系」,不应该像 Windows 7/8/10/11 那样当成同一血脉的系统来看待。 尽管大家可以找出一些最大公约数(比如大多遵循 FHS 、使用 pkg-config 和 gcc ),但在实现上会有非常多细微的差别。大部分差别在开发过程中可以消解掉(例如使用 CMake 的 find_library/package 过程)但不是全部,而在打包和分发过程中则完全需要各个区别对待(比如 Debian 系、Gentoo 系和 Redhat 系,在分割软件包的粒度和指定依赖的方式上,做法都完全不同)。 此外,Linux 本身又是极度依赖 source-driven 的,需要时刻考虑用户利用现有环境进行开发的可能性。这就是为什么 Linux 下很难有 vcpkg 这样一个独立的、和系统无关的 C/C++ 包管理器。或者说即使有了,也不会好用,因为你最终还是要为每个发行版、编译器和依赖组合付出额外的成本去适配。 2. 对于后者,你的例子其实就是很好的典型。「通过 pacman 下载的 boost 似乎没有提供 .pc 文件」,是因为 boost 这个库本身只提供了 CMake 模块。你用 pacman -Ql boost 就能看到,boost 提供的是 /usr/lib/cmake/Boost-xxx/BoostConfig.cmake 配置文件,而不是 pkg-config 文件。 这种四世同堂的局面很多,不是每个包都会提供 pkg-config 来兜底(从功能性上来说,CMake Modules 无疑是更先进的)。这其实也是生态碎片化的体现:开发中的选择一旦多起来,开源作者都会习惯性选择自己最习惯的,而不是兼容性最好的。你问「有没有办法用统一的方式导入」,其实就和前端问「有没有办法在我的 React 项目里导入其他 UI 框架的控件」是一样的。当然这边的问题至少理论上是 solvable 的。 ---- 所以我能给的建议是什么呢? 1. 如果你专为某个发行版开发程序:完全本土化。使用那个发行版和系统包管理器,完全遵循那个发行版的逻辑。系统提供什么就使用什么方式引入; 2. 如果你为所有发行版开发程序:防御性编程,减少假设。同上,但是尽可能不要依赖某些假设(例如「一定有 pkg-config 」)。CMake 的 https://cmake.org/cmake/help/latest/guide/using-dependencies/index.html 介绍了通用的建议,主要是 尽可能使用 find_package 来引入依赖、使用 FetchContent 来从源码编译依赖 及 不要使用 FindPkgConfig 。 |
2 ysc3839 1 天前 via Android boost 的话直接用 cmake 的 find_package 就行了,不需要 pkg-config |
3 kekxv 1 天前 via iPhone 试试 bazel https://registry.bazel.build/ |
4 bwnjnOEI 1 天前 via iPhone 我用的 conan |
5 mz02005 1 天前 via iPhone 不是,你都用 vcpkg 了,还想如何? |
6 LindsayZhou 1 天前 em... 我不了解 C 开发,不过 asio 是这东西吗?它好像和 boost 不是同一个包,它带了 .pc 文件: https://archlinux.org/packages/extra/any/asio/ |
7 sir283 1 天前 手动找,或者自己拉源码 rebuild 一遍,生成 pkg-config ,就这样,下一个问题。 |
8 jsph 23 小时 20 分钟前 bazel |
9 bigtan 22 小时 14 分钟前 vcpkg 在 Linux 一样可以用啊 cmake 不都跨平台吗 |
10 tinybaby365 20 小时 29 分钟前 依然使用 cmake + vcpkg ,也可以 cmake + ExternalProject_Add 如果你想要你的程序不只是兼容特定的 Linux 发行版,你就不要使用 Linux 包管理器安装的-dev 或-devel 包。这一点上商业软件为了维护更少的包,基本上会采取这种做法,和 Linux 发行版里面自带软件的做法相反。 想要兼容更多的 Linux 发行版,你就要考虑编译环境的 glibc 版本(想要兼容更老的版本,就意味着不能使用 C++更新的标准) |
11 tinybaby365 20 小时 28 分钟前 @jsph bazel 是理想,小团队不现实 |
12 shylockhg 18 小时 24 分钟前 把所有 lib 放一个 cmake 工程用 external project 管理,编译安装 tar 打包,根据 libc 版本,区分不同 tar 包 |
14 shihira 10 小时 11 分钟前 或许比较邪教的 flake.nix ? |
15 pluswu1986 1 小时 2 分钟前 conan |
16 Fenicesun 54 分钟前 我都是把所有的依赖库源码放在 third_party 和自己工程一起编译 |
17 MrVito 42 分钟前 conan |