Xmake 是一个基于 Lua 的轻量级跨平台构建工具,关于 Xmake 与构建系统的介绍,我们已经在之前的文章中做了详细的介绍:C/C++ 构建系统,我用 xmake。
如果大家已经对 Xmake 已经有了大概的了解,就会知道,它不仅仅是一个构建工具,还内置了对 C/C++ 包管理的支持,我们也可以把 Xmake 理解为:
Xmake = Build backend + Project Generator + Package Manager
经过几年的持续迭代,Xmake 对 C/C++ 包管理的支持不断完善,也新增了不少实用的包管理特性,因此,在本文中,我们对其做一些总结,希望对大家有所帮助。
构建系统与包管理
C++ 的生态比较繁杂,这其中也有一定历史原因,不管如何,官方没有提供原生的包管理支持,对我们开发者来说,使用第三方 C++ 依赖库多少存在很多不便。
其实,现在已经有很多强大的 C/C++ 包管理器,最知名,用的最多的有:vcpkg, conan, conda 等等,它们虽然很强大,但是有一个共同的问题:构建工具对它们没有提供原生的支持。
由于 CMake 对它们没有提供内置支持,想在 CMake 中使用它们集成依赖包非常繁琐,并且集成和使用的方式都不一致。
在 CMake 中使用 Conan
在 CMake 中使用 conan 集成 C/C++ 包,我们需要提供额外的 CMake Wrapper 脚本,以类似插件的方式注入进自己的工程中去。
cmake_minimum_required(VERSION 3.5)
project(FormatOutput CXX)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
add_definitions("-std=c++11")
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.16.1/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake"
EXPECTED_HASH SHA256=396e16d0f5eabdc6a14afddbcfff62a54a7ee75c6da23f32f7a31bc85db23484
TLS_VERIFY ON)
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_configure(REQUIRES fmt/6.1.2
GENERATORS cmake_find_package)
conan_cmake_autodetect(settings)
conan_cmake_install(PATH_OR_REFERENCE .
BUILD missing
REMOTE conancenter
SETTINGS ${settings})
find_package(fmt)
add_executable(main main.cpp)
target_link_libraries(main fmt::fmt)
为了集成一个包,需要额外配置很多的脚本。
在 CMake 中使用 Vcpkg
在 CMake 中使用 vcpkg 集成包,我们也需要额外注入一个工具链脚本文件。
cmake -B [build directory] -S . -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake
cmake --build [build directory]
另外,还有一个问题,就是我们还需要额外自己调用 vcpkg install [packages]
命令,去安装包。
这其中每一个环节,对于用户来讲都需要额外的探索过程,没法做到真正的一键编译。
想象下,用户下载了一个集成了 vcpkg 包的 cmake 项目,想要编译通过,除了项目配置,还需要做哪些额外的事情:
- 安装 vcpkg
- 执行
vcpkg install xxx
安装里面需要的包 - 执行 cmake 传递 vcpkg.cmake 脚本给 cmake,进行工程配置
在 CMake 中使用 FetchContent
提供了 FetchContent 模式来管理依赖,但似乎是源码拉取,而且必须依赖也是基于 CMake 维护构建的,另外,我们需要对每个依赖项,配置 url, 版本等各种包信息。
cmake_minimum_required(VERSION 3.14)
project(fetchContent_example CXX)
include(FetchContent)
FetchContent_Declare(
DocTest
GIT_REPOSITORY "https://github.com/onqtam/doctest"
GIT_TAG "932a2ca50666138256dae56fbb16db3b1cae133a"
)
FetchContent_Declare(
Range-v3
GIT_REPOSITORY "https://github.com/ericniebler/range-v3"
GIT_TAG "4d6a463bca51bc316f9b565edd94e82388206093"
)
FetchContent_MakeAvailable(DocTest Range-v3)
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} doctest range-v3)
在 Meson 中使用依赖包
Meson 很强大,并且也提供了自带的包管理支持,但是想要在 Meson 中使用其他包管理器,例如 vcpkg/conan 等等同样很繁琐,并没有提供原生支持。
在 Xmake 中使用依赖包
Xmake 不仅提供了内置的 xmake-repo 内置的包管理仓库,可以直接集成使用里面的包,还支持以相同的集成方式,去快速集成 vcpkg/conan 等第三方的依赖包。
集成一个内置依赖包只需要几行配置:
add_requires("zlib 1.2.11")
target("test")
add_files("src/*.c")
add_packages("zlib")
集成一个 vcpkg 包,仅仅只需要加上对应的包管理器命名空间,集成方式完全相同:
add_requires("vcpkg::zlib 1.2.11")
target("test")
add_files("src/*.c")
add_packages("vcpkg::zlib")
集成一个 conan 包,或者 conda, homebrew, pacman, apt, clib 等第三方包,也只需要改成 conan::zlib
就行了,用户可以随意切换包源。
另外,Xmake 会自动帮你调用 vcpkg/conan install
安装命令去安装依赖包,然后集成它们,不需要用户做任何其他事情,仅仅只需要执行 xmake
一键编译。
C/C++ 包太少?
觉得 Xmake 内置的包仓库里面的包太少么?完全没关系,理论上,你可以通过 Xmake 使用整个 C/C++ 生态 90% 的常用依赖包,就是因为 Xmake 可以快速从各种其他包管理器中集成包来使用。
目前 Xmake 支持的包源有以下这些:
- Official package repository xmake-repo (tbox >1.6.1)
- Official package manager Xrepo
- User-built repositories
- Conan (conan::openssl/1.1.1g)
- Conda (conda::libpng 1.3.67)
- Vcpkg (vcpkg:ffmpeg)
- Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)
- Pacman on archlinux/msys2 (pacman::libcurl)
- Apt on ubuntu/debian (apt::zlib1g-dev)
- Clib (clib::clibs/bytes@0.0.4)
- Dub (dub::log 0.4.3)
- Portage on Gentoo/Linux (portage::libhandy)
- Nimble for nimlang (nimble::zip >1.3)
- Cargo for rust (cargo::base64 0.13.0)
基本上,这些仓库基本已经覆盖了 C/C++ 用户日常所需的所有包。
作者从写这篇文章开始,统计了下 vcpkg/conan/xmake-repo 仓库的包数量:
- vcpkg: 1859
- conan: 1218
- xmake-repo: 651
可以看到,目前 Xmake 内置仓库的包数量,已经快要接近 vcpkg/conan 了,也不少了,我们也在不断的收录新的包进来。
但是这完全没有关系,因为我们可以使用任意包仓库中的包。
如果在 CMake 中使用 vcpkg,我们只能使用 1859 个包。
如果在 CMake 中使用 conan,我们只能使用 1218 个包。
而如果在 Xmake 中使用包,我们可以使用 651 (xmake-repo) + vcpkg/conan (1k+) + more (conda, homebrew, pacman, apt, clib …) 中的包。
甚至,C/C++ 包不够,其他语言的包也可以拿过来用,例如:Xmake 也支持从 dub/cargo 等 Dlang/Rust 的包管理器中拉取包,给 C/C++ 项目使用。
<