跳转到内容

在 CMake 中使用包

我们新增了一个独立项目 xrepo-cmake

它是一个基于 Xrepo/Xmake 的 C/C++ 包管理器的 CMake 包装器。

这允许使用 CMake 构建您的项目,同时用 Xrepo 管理依赖包。该项目部分灵感来自 cmake-conan

此项目的示例用例:

  • 想要使用 Xrepo 管理包的现有 CMake 项目。
  • 必须使用 CMake,但想使用 Xrepo 管理的新项目包。

APIs

xrepo_package

xrepo.cmake 提供xrepo_package函数来管理包。

cmake
xrepo_package(
    "foo 1.2.3"
    [CONFIGS feature1=true,feature2=false]
    [CONFIGS path/to/script.lua]
    [DEPS]
    [MODE debug|release]
    [ALIAS aliasname]
    [OUTPUT verbose|diagnosis|quiet]
    [DIRECTORY_SCOPE]
)

部分函数参数直接对应 Xrepo 命令选项。

xrepo_package 会将软件包安装目录添加到 CMAKE_PREFIX_PATH,因此 find_package 可以直接使用。如果 CMAKE_MINIMUM_REQUIRED_VERSION >= 3.1,cmake 的 pkgConfig 也会搜索软件包安装目录下的 pkgconfig 文件。

调用 xrepo_package(foo) 后,foo 包有三种使用方式:

  1. 如果包提供 cmake 配置文件,则调用 find_package(foo)
  2. 如果包没有提供 cmake 配置文件或者找不到模块
    • 以下变量可用于使用pacakge(cmake后的变量名 查找模块 标准变量名称)
      • foo_INCLUDE_DIRS
      • foo_LIBRARY_DIRS
      • foo_LIBRARIES
      • foo_DEFINITIONS
    • 如果指定了 DIRECTORY_SCOPE,则 xrepo_package 会运行以下代码
      cmake
      include_directories(${foo_INCLUDE_DIRS})
      link_directories(${foo_LIBRARY_DIRS})
  3. 也可以使用 xrepo_target_packages,详见下文。

注意:CONFIGS path/to/script.lua 用于对包配置进行精细控制。 例如:

  • 排除系统上的包。
  • 覆盖依赖包的默认配置,例如设置shared=true

如果指定了 DEPS,所有依赖库都将添加到 CMAKE_PREFIX_PATH,以及 include 和 libraries 那四个变量中。

xrepo_target_packages

将包的 includedirs 和 links/linkdirs 添加到指定目标。

cmake
xrepo_target_packages(
    target
    [NO_LINK_LIBRARIES]
    [PRIVATE|PUBLIC|INTERFACE]
    package1 package2 ...
)

使用来自官方存储库的包

Xrepo 官方仓库:xmake-repo

下面是一个使用 gflags 包版本 2.2.2 的 CMakeLists.txt 示例,由 Xrepo 管理。

集成 xrepo.cmake

cmake
cmake_minimum_required(VERSION 3.13.0)

project(foo)

# 如果 build 目录下不存在 xrepo.cmake,则下载。
if(NOT EXISTS "${CMAKE_BINARY_DIR}/xrepo.cmake")
    message(STATUS "Downloading xrepo.cmake from https://github.com/xmake-io/xrepo-cmake/")
    # mirror https://cdn.jsdelivr.net/gh/xmake-io/xrepo-cmake@main/xrepo.cmake
    file(DOWNLOAD "https://raw.githubusercontent.com/xmake-io/xrepo-cmake/main/xrepo.cmake"
                  "${CMAKE_BINARY_DIR}/xrepo.cmake"
                  TLS_VERIFY ON)
endif()

# 包含 xrepo.cmake 以便可以使用 xrepo_package 函数。
include(${CMAKE_BINARY_DIR}/xrepo.cmake)

添加包

cmake
xrepo_package("zlib")

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
xrepo_target_packages(example-bin zlib)

添加带有配置的包

cmake
xrepo_package("gflags 2.2.2" CONFIGS "shared=true,mt=true")

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
xrepo_target_packages(example-bin gflags)

添加带有 cmake 导入模块的包

cmake
xrepo_package("gflags 2.2.2" CONFIGS "shared=true,mt=true")

# `xrepo_package` 会将 gflags 安装目录添加到 CMAKE_PREFIX_PATH。
# `find_package(gflags)` 会从 CMAKE_PREFIX_PATH 包含的目录中找到 gflags 提供的 config-file 文件。
# 参考 https://cmake.org/cmake/help/latest/command/find_package.html#search-modes
find_package(gflags CONFIG COMPONENTS shared)

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
target_link_libraries(example-bin gflags)

添加自定义包

cmake
set(XREPO_XMAKEFILE ${CMAKE_CURRENT_SOURCE_DIR}/packages/xmake.lua)
xrepo_package("myzlib")

add_executable(example-bin "")
target_sources(example-bin PRIVATE
    src/main.cpp
)
xrepo_target_packages(example-bin myzlib)

在 packages/xmake.lua 中定义一个包:

lua
package("myzlib")
    -- ...

我们可以自定义一个包,具体定义方式见文档:自定义 Xrepo 包

使用来自第三个存储库的包

除了从官方维护的存储库安装软件包外,Xrepo 还可以安装来自第三方包管理器的包,例如 vcpkg、conan、conda、pacman、homebrew、apt、dub、cargo。

关于命令行的使用,我们可以参考文档:Xrepo命令用法.

我们也可以直接在 cmake 中使用它来安装来自第三方仓库的包,只需将仓库名称添加为命名空间即可。例如:vcpkg::zlibconan::pcre2

Conan

cmake
xrepo_package("conan::gflags/2.2.2")

Conda

cmake
xrepo_package("conda::gflags 2.2.2")

Vcpkg

cmake
xrepo_package("vcpkg::gflags")

Homebrew

cmake
xrepo_package("brew::gflags")