跳到主要内容

常见问题解答

什么是经典模式(classic mode)和清单模式(manifest mode)?

kmpkg 提供两种依赖管理方式:

  1. 清单模式:通过 kmpkg.json 文件(详见文档)声明直接依赖、版本约束和使用的注册表。该文件应纳入代码仓库,并可提交到版本控制系统。依赖项会安装在名为 kmpkg_installed 的子文件夹中,每个项目可拥有独立依赖集,无需系统级安装。运行 kmpkg install(无其他参数)即可启用清单模式,也可借助与 MSBuild 的自动集成CMake 项目的自动集成。大多数情况下,建议优先使用清单模式,因其能更精准地控制依赖。更多细节请参阅 清单模式文档
  2. 经典模式:传统的依赖管理方式,需通过 kmpkg 命令指定要安装、修改或移除的每个直接依赖项。依赖项存储在 kmpkg 安装目录中,多个项目可共享同一套依赖。更多细节请参阅 经典模式文档

我可以贡献新的库吗?

可以!首先阅读 贡献指南,再查看 维护者指南 了解更多细节。我们还提供了 向 kmpkg 添加端口的教程 帮助你快速上手。

如果想贡献但暂无具体目标库,可查看 新端口请求列表

kmpkg 能否创建预编译二进制包?kmpkg 使用的二进制格式是什么?

可以!若需生成二进制包用于其他环境,可参阅 export 命令文档

若需保留 kmpkg install 命令生成的二进制文件供后续复用,可使用 二进制缓存功能

如何更新库?

  • 若使用清单文件(kmpkg.json)管理依赖,需直接修改该文件。详情请参阅 版本控制参考文档
  • 若使用经典模式(无清单文件,通过命令管理包),请参阅 kmpkg update 命令文档。该命令会列出所有与当前端口文件不同步的包,之后需运行 kmpkg upgrade 命令 确认更新。

如何获取更多库?

库列表源自 ports\ 目录。你可根据自身或公司需求,自由添加/移除该目录中的库——详见打包 压缩文件GitHub 仓库 的示例。

建议直接从 GitHub 克隆仓库,通过 git pull 更新端口文件列表。

能否用该工具构建私有库?

可以。遵循 打包示例 创建自定义端口,再参阅 覆盖端口注册表 文档,学习如何管理私有端口。

你还可将私有库发布到自定义注册表中,详见 自定义注册表文档。注册表是端口的集合,类似 kmpkg 内置的开源库注册表。

能否用该工具使用预编译的私有库?

可以。库的 portfile.cmake 本质是一个脚本,用于将头文件和二进制文件放置到 ${CURRENT_PACKAGES_DIR} 的指定位置。因此,若要引入预编译二进制文件,只需编写端口文件直接下载并整理这些文件即可。

示例可参考 ports\opengl\portfile.cmake,该文件仅从 Windows SDK 中复制所需文件。

kmpkg 支持哪些目标平台?

我们通过持续集成测试的内置三元组(triplet)包括:

  • Windows 桌面(x86、x64、x64-static、arm64)
  • 通用 Windows 平台(x64、arm64)
  • Mac OS X(x64-static)
  • Linux(x64-static)
  • Android(x64、arm64、arm-neon)

这些目标平台在每个 kmpkg 版本中都会经过严格的兼容性测试。此外,社区还提供了更多三元组,支持 iOS、MinGW、WebAssembly、FreeBSD、OpenBSD 等更多平台和架构。

你也可根据需求自定义三元组,kmpkg 具有高度可定制性。

运行 kmpkg help triplet 可查看当前支持的三元组列表,更多细节请参阅 三元组文档

kmpkg 能否在 Linux/OS X 上运行?

可以!我们持续在 OS X 和 Ubuntu 22.04 上进行测试,同时已知用户已成功在 Arch、Fedora 和 FreeBSD 上使用。若在你常用的 Linux 发行版中遇到问题,可提交 issue 反馈,我们会尽力提供帮助!

如何更新 kmpkg?

执行 git pull 获取最新源代码,然后运行 bootstrap-kmpkg.bat(Windows)或 ./bootstrap-kmpkg.sh(Unix)更新 kmpkg。若你使用的是 Visual Studio 自带的 kmpkg,只需通过 Visual Studio 安装程序更新 Visual Studio 版本即可。

如何在一台机器上使用同一库的不同版本?

  • 建议使用 清单文件 管理单个项目的依赖,即使多个项目在同一台机器上,也能轻松管理包版本和库的来源注册表。
  • 若使用经典模式,在单个 kmpkg 实例中(例如一套 installed\packages\ports\ 等目录),同一库只能安装一个版本(否则头文件会冲突!)。对于有系统级包管理器使用经验的用户,kmpkg 中的包类似 X-devX-devel 包。若需为不同项目使用同一库的不同版本,建议创建多个 kmpkg 实例,并使用项目级集成机制。每个库的版本由 ports\ 目录中的文件指定,可通过标准 git 命令轻松操作(例如回滚到整套库的历史兼容版本)。若需单独固定某个库的版本,只需检出 ports\<package>\ 的对应版本即可。若你的应用对库版本高度敏感,建议将所需的端口文件与项目源代码一起提交到版本控制系统,并使用 --kmpkg-root 选项指定 kmpkg.exe 的工作目录。

kmpkg 如何保护我的隐私?

有关隐私的所有信息,请参阅 隐私文档

能否将自定义 CMake 工具链文件与 kmpkg 的工具链文件结合使用?

可以。若你已有自定义 CMake 工具链文件,只需在文件末尾包含 kmpkg 的工具链文件,例如添加 include(<kmpkg_root>\scripts\buildsystems\kmpkg.cmake) 指令。或者,也可将 scripts\buildsystems\kmpkg.cmake 的内容复制到现有工具链文件的末尾。

能否为重建库指定自定义编译标志?

可以。通过 自定义三元组,可借助 KMPKG_C_FLAGSKMPKG_CXX_FLAGS 变量修改编译标志。

也可 为单个端口自定义标志,示例如下:

if (PORT MATCHES "my-port")
set(KMPKG_CXX_FLAGS "-D_CRT_SECURE_NO_WARNINGS")
set(KMPKG_C_FLAGS "-D_CRT_SECURE_NO_WARNINGS")
endif()

kmpkg 是否支持自定义配置的集成?

支持。kmpkg 构建库时仅生成标准的 "Release" 和 "Debug" 配置,但你可为项目的自定义配置(以及标准配置)添加集成支持:

  1. 对于以 "Release"(或 "Debug")开头的自定义配置,kmpkg 会自动将其视为与标准 "Release"(或 "Debug")配置兼容,并相应地运行。
  2. 对于其他自定义配置,只需在项目文件(.vcxproj)中覆盖 MSBuild 的 $(KmpkgConfiguration) 宏,声明自定义配置与目标标准配置的兼容性。由于 MSBuild 的执行顺序限制,需在加载 kmpkg 集成之前添加该设置,建议将 $(KmpkgConfiguration) 宏添加到 "Globals" 属性组中。

示例:为 "MyRelease" 配置添加支持,需在项目文件中添加:

<PropertyGroup Label="Globals">
...
<KmpkgConfiguration Condition="'$(Configuration)' == 'MyRelease'">Release</KmpkgConfiguration>
</PropertyGroup>

注意:仅当自定义配置与目标标准配置兼容(例如链接相同的运行时库)时,才能生成可用的二进制文件。

无法使用全局用户级集成,能否使用项目级集成?

可以。可通过以下两种方式生成适用于项目级使用的 NuGet 包:

  • kmpkg integrate project 命令(轻量级链接)
  • kmpkg export --nuget 命令(打包所有依赖)

另一种底层实现方式(与 kmpkg integrate project 生成的 NuGet 包效果一致)是导入 <kmpkg_root>\scripts\buildsystems\msbuild\kmpkg.targets 文件。只需在 .vcxproj 文件中添加以下内容(将 <kmpkg_root> 替换为 kmpkg 的安装路径):

<Import Project="<kmpkg_root>\scripts\buildsystems\msbuild\kmpkg.targets" />

如何删除临时文件?

若仅需保留已安装的包,可安全删除 kmpkg 根目录下的以下目录:

  • packages
  • buildtrees
  • downloads

也可在运行 kmpkg install 命令 时,添加 --clean-after-build 标志,让 kmpkg 在构建完成后自动删除临时文件。

kmpkg 还会在根目录外使用其他临时位置,具体路径如下:

  • Windows:%LocalAppData%/kmpkg(存储 Visual Studio 集成文件、默认二进制缓存和注册表缓存)
  • Linux/macOS:$XDG_CACHE_HOME/kmpkg~/.cache/kmpkg(仅当 XDG_CACHE_HOME 未定义时)

若你配置了本地二进制缓存或资源缓存,也可根据需要定期清理。

kmpkg 内部如何使用 CMake?

kmpkg 将 CMake 用作内部构建脚本语言,原因如下:

  • CMake 是跨平台开源库中极为常用的构建系统,在 C++ 项目中普及度高。
  • 在 Windows 上易于获取,无需系统级安装。
  • 语法清晰,便于不熟悉的用户理解。

kmpkg 是否支持从公共或私有服务器下载预编译二进制文件?

建议使用首选构建配置构建一次库,然后通过 二进制缓存功能 复用二进制文件,避免重复构建。这在团队协作、本地构建与持续集成环境(多机器、容器、虚拟机等)中尤为实用。

支持哪些 MSVC 工具集?

支持 Visual Studio 2015 Update 3 及以上版本。

启用全局用户级集成后,Visual Studio 为何无法使用我的库?

启用全局用户级集成(kmpkg integrate install)会修改部分项目属性的默认值:

  • 未启用集成时,“C/C++/常规/附加包含目录”和“链接器/常规/附加库目录”通常为空。
  • 启用集成后,空值会覆盖 kmpkg 提供的增强默认值,导致无法找到头文件/库。

如需恢复默认行为,需将这些属性设置为“从父级或项目默认值继承”。

为何不使用 NuGet?

NuGet 是 .NET 库的包管理器,严重依赖 MSBuild,在以下三个方面无法满足原生 C++ 用户的特定需求:

  1. 编译配置多样性:C++ 编译选项组合繁多,提供完整的预编译二进制包几乎不可能;且完整二进制包的下载体积庞大,需拆分为多个包,导致搜索困难。
  2. 二进制 vs 源代码:NuGet 设计初衷是提供小型预编译二进制文件,但原生代码开发中,开发者需要访问源代码以确保 ABI 兼容性、性能、完整性和可调试性。
  3. 按 DLL 版本控制 vs 按应用版本控制:NuGet 以项目为中心,适用于 ABI 稳定的托管语言(基础库升级不会影响上层依赖)。但原生语言 ABI 脆弱,稳健的策略是每个库都针对最终应用的精确依赖进行显式构建——这在 NuGet 中难以保证,导致生态系统高度分散且版本独立。

为何不使用 Conan?

Conan.io 是基于 Python 开发的跨平台 C++ 包管理器,采用公共联邦制、项目中心架构。我们的核心差异如下:

  1. 公共联邦制 vs 私有联邦制:Conan 依赖个人发布独立的包副本,易导致大量包存在不同问题;用户需在 20+ 个 Boost 1.56 公共包中筛选可用版本,效率低下。我们主张“单一协作维护版本”,确保绝大多数场景可用,同时允许用户自由修改私有版本——这能形成高质量、经过充分互测的包集合,为私有修改提供坚实基础。
  2. 按库版本控制 vs 按应用版本控制:库级独立版本控制会导致每个构建环境独一无二,无法利用或贡献稳定的生态系统。我们通过“平台级版本控制”(类似系统包管理器),将所有库作为整体版本管理,集中测试常见库版本组合,最大化生态系统的质量和稳定性;同时避免库依赖版本与应用需求冲突(例如“库需 OpenSSL Z 但应用依赖 Boost X,而 X 仅支持 OpenSSL Y”)。
  3. 跨平台 vs 单平台:虽然跨平台是理想目标,但 apt-get、yum、homebrew 等系统包管理器的系统集成度和稳定性极高——在自动化脚本中用 kmpkg install boost 替代 apt-get install libboost-all-devbrew install boost 仅需一行代码,无需在这些成熟工具的优势场景中替代它们。
  4. Python 实现 vs C++/CMake 实现:Python 是优秀的语言,但包管理器对工作流至关重要,透明度和熟悉度是关键。因此,我们选择 C++/CMake 作为实现语言(C++ 包管理器应为 C++ 开发者设计)——无需学习其他编程语言即可理解包管理器的工作原理。

为何不使用 Chocolatey?

Chocolatey 是优秀的应用管理工具,但目前并非为获取可再发行的开发资源和调试支持而设计。相比之下,kmpkg 专注于提供构建应用所需的库,并支持通过任何平台(包括 Chocolatey)交付最终产品。