xmake v2.2.5, 更加完善的 C/C++ 包依赖管理

本贴最后更新于 2060 天前,其中的信息可能已经时移俗易

此版本耗时四个多月,对包依赖管理进行了重构改进,官方仓库新增了 mysql,ffmpeg 等常用依赖包,并且新增了大量新特性。

最近我打算对 xmake 的包仓库 xmake-repo 扩充一些常用的 C/C++ 包。

大家有哪些经常使用到的包,都可以提到 Issue #10 · xmake-io/xmake-repo 里面去,我之后会优先入库进去,提供给用户快速集成和使用依赖包。

关于新特性的详细说明见文章下文。

第三方包管理器支持

新版本对内置的包管理进行了重构,已经支持的非常完善了,我们可以通过

add_requires("libuv master", "ffmpeg", "zlib 1.20.*")`

方便的安装使用依赖包,但是官方的包仓库 xmake-repo 目前收录的包还非常少,因此为了扩充 xmake 的包仓库,
xmake 新增了对第三方包管理器的内置支持,通过包命名空间显式指定其他包管理器中的包,目前支持对 conan::brew::vcpkg:: 包管理中的包进行安装。

安装 homebrew 的依赖包

add_requires("brew::zlib", {alias = "zlib"}})
add_requires("brew::pcre2/libpcre2-8", {alias = "pcre2"}})

target("test")
    set_kind("binary")
    add_files("src/*.c") 
    add_packages("pcre2", "zlib")

安装 vcpkg 的依赖包

add_requires("vcpkg::zlib", "vcpkg::pcre2")

target("test")
    set_kind("binary")
    add_files("src/*.c") 
    add_packages("vcpkg::zlib", "vcpkg::pcre2")

不过需要注意的是,使用 vcpkg,需要先对 vcpkg 与 xmake 进行集成才行,详细操作如下:

windows 上用户装完 vcpkg 后,执行 $ vcpkg integrate install,xmake 就能自动从系统中检测到 vcpkg 的根路径,然后自动适配里面包。

当然,我们也可以手动指定 vcpkg 的根路径来支持:

$ xmake f --vcpkg=f:\vcpkg

安装 conan 的依赖包

新版本实现了对 conan 的 generator,来集成获取 conan 中的包信息,我们在 xmake 中使用也是非常的方便,并且可以传递 conan 包的所有配置参数。

add_requires("conan::zlib/1.2.11@conan/stable", {alias = "zlib", debug = true})
add_requires("conan::OpenSSL/1.0.2n@conan/stable", {alias = "openssl", configs = {options = "OpenSSL:shared=True"}})

target("test")
    set_kind("binary")
    add_files("src/*.c") 
    add_packages("openssl", "zlib")

执行 xmake 进行编译后:

ruki:test_package ruki$ xmake
checking for the architecture ... x86_64
checking for the Xcode directory ... /Applications/Xcode.app
checking for the SDK version of Xcode ... 10.14
note: try installing these packages (pass -y to skip confirm)?
  -> conan::zlib/1.2.11@conan/stable  (debug)
  -> conan::OpenSSL/1.0.2n@conan/stable  
please input: y (y/n)

  => installing conan::zlib/1.2.11@conan/stable .. ok
  => installing conan::OpenSSL/1.0.2n@conan/stable .. ok

[  0%]: ccache compiling.release src/main.c
[100%]: linking.release test

内置依赖包查找支持

之前的版本提供了 lib.detect.find_package 来对依赖库进行查找,但是这需要通过 import 后才能使用,并且一次只能查找一个包,比较繁琐:

target("test")
    set_kind("binary")
    add_files("src/*.c")
    on_load(function (target)
        import("lib.detect.find_package")
        target:add(find_package("openssl"))
        target:add(find_package("zlib"))
    end)

而新版本中通过内置 find_packages 接口,对 lib.detect.find_package 进行了进一步的封装,来提升易用性:

target("test")
    set_kind("binary")
    add_files("src/*.c")
    on_load(function (target)
        target:add(find_packages("openssl", "zlib"))
    end)

并且还支持从指定的第三方包管理器中进行查找:

find_packages("conan::OpenSSL/1.0.2n@conan/stable", "brew::zlib")

参数配置依赖包安装

新版本中对内置的包管理进行了大规模重构和升级,并且对参数可配置编译安装依赖包进行了更好的支持,我们可以在包仓库中定义一些编译安装配置参数,来定制安装包。

例如, 我们以 pcre2 的包为例:


package("pcre2")

    set_homepage("https://www.pcre.org/")
    set_description("A Perl Compatible Regular Expressions Library")

    set_urls("https://ftp.pcre.org/pub/pcre/pcre2-$(version).zip",
             "ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre2-$(version).zip")

    add_versions("10.23", "6301a525a8a7e63a5fac0c2fbfa0374d3eb133e511d886771e097e427707094a")
    add_versions("10.30", "3677ce17854fffa68fce6b66442858f48f0de1f537f18439e4bd2771f8b4c7fb")
    add_versions("10.31", "b4b40695a5347a770407d492c1749e35ba3970ca03fe83eb2c35d44343a5a444")

    add_configs("shared", {description = "Enable shared library.", default = false, type = "boolean"})
    add_configs("jit", {description = "Enable jit.", default = true, type = "boolean"})
    add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values = {"8", "16", "32"}})

上面我们通过 add_configs 定义了三个条件配置参数,使得用户在集成使用 pcre2 库的时候,可以定制化选择是否需要启用 jit 版本、bit 位宽版本等,例如:

add_requires("pcre2", {configs = {jit = true, bitwidth = 8}})

而且,配置参数是强约束检测的,如果传的值不对,会提示报错,避免传递无效的参数进来,像 bitwidth 参数配置,被限制了只能在 values = {"8", "16", "32"} 里面取值。

那么,用户如何知道我们的包当前支持哪些配置参数呢,很简单,我们可以通过下面的命令,快速查看 pcre2 包的所有信息:

$ xmake require --info pcre2

输出结果如下:

add_requires("pcre2", {configs = {debug = true}})

由于这个太过于常用,xmake 提供了更方便的配置支持:

add_requires("pcre2", {debug = true})

另外 requires: 里面的内容,就是当前依赖包的配置状态,方便用户查看当前使用了哪个模式的包。

预处理模板配置文件

xmake 提供了三个新的接口 api,用于在编译前,添加一些需要预处理的配置文件,用于替代 set_config_header 等老接口。

  • add_configfiles
  • set_configdir
  • set_configvar

其中 add_configfiles 相当于 cmake 中的 configure_file 接口,xmake 中参考了它的 api 设计,并且在其基础上进行了扩展支持,提供更多的灵活性。

此接口相比以前的 set_config_header 更加的通用,不仅用于处理 config.h 的自动生成和预处理,还可以处理各种文件类型,而 set_config_header 仅用于处理头文件,并且不支持模板变量替换。

先来一个简单的例子:

target("test")
    set_kind("binary")
    add_files("src/*.c")
    set_configdir("$(buildir)/config")
    add_configfiles("src/config.h.in")

上面的设置,会在编译前,自动的将 config.h.in 这个头文件配置模板,经过预处理后,生成输出到指定的 build/config/config.h

这个接口的一个最重要的特性就是,可以在预处理的时候,对里面的一些模板变量进行预处理替换,例如:

config.h.in

#define VAR1 "${VAR1}"
#define VAR2 "${VAR2}"
#define HELLO "${HELLO}"
set_configvar("VAR1", "1")

target("test")
    set_kind("binary")
    add_files("main.c")

    set_configvar("VAR2", 2)
    add_configfiles("config.h.in", {variables = {hello = "xmake"}})
    add_configfiles("*.man", {copyonly = true})

通过 set_configvar 接口设置模板变量,裹着通过 {variables = {xxx = ""}} 中设置的变量进行替换处理。

预处理后的文件 config.h 内容为:

#define VAR1 "1"
#define VAR2 "2"
#define HELLO "xmake"

{copyonly = true} 设置,会强制将 *.man 作为普通文件处理,仅在预处理阶段 copy 文件,不进行变量替换。

默认的模板变量匹配模式为 ${var},当然我们也可以设置其他的匹配模式,例如,改为 @var@ 匹配规则:

target("test")
    add_configfiles("config.h.in", {pattern = "@(.-)@"})

我们也有提供了一些内置的变量,即使不通过此接口设置,也是可以进行默认变量替换的:

${VERSION} -> 1.6.3
${VERSION_MAJOR} -> 1
${VERSION_MINOR} -> 6
${VERSION_ALTER} -> 3
${VERSION_BUILD} -> set_version("1.6.3", {build = "%Y%m%d%H%M"}) -> 201902031421
${PLAT} and ${plat} -> MACOS and macosx
${ARCH} and ${arch} -> ARM and arm
${MODE} and ${mode} -> DEBUG/RELEASE and debug/release
${DEBUG} and ${debug} -> 1 or 0
${OS} and ${os} -> IOS or ios

例如:

config.h.in

#define CONFIG_VERSION "${VERSION}"
#define CONFIG_VERSION_MAJOR ${VERSION_MAJOR}
#define CONFIG_VERSION_MINOR ${VERSION_MINOR}
#define CONFIG_VERSION_ALTER ${VERSION_ALTER}
#define CONFIG_VERSION_BUILD ${VERSION_BUILD}

config.h

#define CONFIG_VERSION "1.6.3"
#define CONFIG_VERSION_MAJOR 1
#define CONFIG_VERSION_MINOR 6
#define CONFIG_VERSION_ALTER 3
#define CONFIG_VERSION_BUILD 201902031401

我们还可以对 #define 定义进行一些变量状态控制处理:

config.h.in

${define FOO_ENABLE}
set_configvar("FOO_ENABLE", 1) -- or pass true
set_configvar("FOO_STRING", "foo")

通过上面的变量设置后,${define xxx} 就会替换成:

#define FOO_ENABLE 1
#define FOO_STRING "foo"

或者(设置为 0 禁用的时候)

/* #undef FOO_ENABLE */
/* #undef FOO_STRING */

这种方式,对于一些自动检测生成 config.h 非常有用,比如配合 option 来做自动检测:

option("foo")
    set_default(true)
    set_description("Enable Foo")
    set_configvar("FOO_ENABLE", 1) -- 或者传递true,启用FOO_ENABLE变量
    set_configvar("FOO_STRING", "foo")

target("test")
    add_configfiles("config.h.in")

    -- 如果启用foo选项 -> 天剑 FOO_ENABLE 和 FOO_STRING 定义
    add_options("foo") 

config.h.in

${define FOO_ENABLE}
${define FOO_STRING}

config.h

#define FOO_ENABLE 1
#define FOO_STRING "foo"

关于 option 选项检测,以及 config.h 的自动生成,有一些辅助函数,可以看下:Issue #342 · xmake-io/xmake

除了 #define,如果想要对其他非 #define xxx 也做状态切换处理,可以使用 ${default xxx 0} 模式,设置默认值,例如:

HAVE_SSE2 equ ${default VAR_HAVE_SSE2 0}

通过 set_configvar("HAVE_SSE2", 1) 启用变量后,变为 HAVE_SSE2 equ 1,如果没有设置变量,则使用默认值:HAVE_SSE2 equ 0

关于这个的详细说明,见:https://github.com/xmake-io/xmake/issues/320

更加方便的特性检测

我们通过 add_configfiles 配合 option 检测,可以做到检测一些头文件、接口函数、类型、编译器特性是否存在,如果存在则自动写入 config.h 中,例如:

option("foo")
    set_default(true)
    set_description("Has pthread library")
    add_cincludes("pthread.h")
    add_cfuncs("pthread_create")
    add_links("pthread")
    set_configvar("HAS_PTHREAD", 1) 

target("test")
    add_configfiles("config.h.in")
    add_options("pthread") 

config.h.in

${define HAS_PTHREAD}

config.h

#define HAS_PTHREAD 1

上面的配置,我们通过 option 检测 pthread.h 里面的接口以及 link 库是否都存在,如果能正常使用 pthread 库,那么自动在 config.h 中定义 HAS_PTHREAD,并且 test target 中追加上相关的 links。

上面的 option 可以支持各种检测,但是配置上少许复杂繁琐了些,为了让 xmake.lua 更加的简洁直观,对于一些常用检测,xmake 通过扩展 includes 接口,
提供了一些内置封装好的辅助接口函数,来快速实现上面的 option 检测,写入 config.h 的功能。

上面的代码我们可以简化为:

includes("check_cfuncs.lua")
target("test")
    add_configfiles("config.h.in")
    configvar_check_cfuncs("HAS_PTHREAD", "pthread_create", {includes = "pthread.h", links = "pthread"})

除了 configvar_check_cfuncs,我们还有 check_cfuncs 函数,仅吧检测结果直接在编译时候追加,不再写入 configfiles 文件中。

我们再来看个综合性的例子:

includes("check_links.lua")
includes("check_ctypes.lua")
includes("check_cfuncs.lua")
includes("check_features.lua")
includes("check_csnippets.lua")
includes("check_cincludes.lua")

target("test")
    set_kind("binary")
    add_files("*.c")
    add_configfiles("config.h.in")

    configvar_check_ctypes("HAS_WCHAR", "wchar_t")
    configvar_check_cincludes("HAS_STRING_H", "string.h")
    configvar_check_cincludes("HAS_STRING_AND_STDIO_H", {"string.h", "stdio.h"})
    configvar_check_ctypes("HAS_WCHAR_AND_FLOAT", {"wchar_t", "float"})
    configvar_check_links("HAS_PTHREAD", {"pthread", "m", "dl"})
    configvar_check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");")
    configvar_check_cfuncs("HAS_SETJMP", "setjmp", {includes = {"signal.h", "setjmp.h"}})
    configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr")
    configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})

config.h.in

${define HAS_STRING_H}
${define HAS_STRING_AND_STDIO_H}
${define HAS_WCHAR}
${define HAS_WCHAR_AND_FLOAT}
${define HAS_PTHREAD}
${define HAS_STATIC_ASSERT}
${define HAS_SETJMP}
${define HAS_CONSTEXPR}
${define HAS_CONSEXPR_AND_STATIC_ASSERT}

config.h

/* #undef HAS_STRING_H */
#define HAS_STRING_AND_STDIO_H 1
/* #undef HAS_WCHAR */
/* #undef HAS_WCHAR_AND_FLOAT */
#define HAS_PTHREAD 1
#define HAS_STATIC_ASSERT 1
#define HAS_SETJMP 1
/* #undef HAS_CONSTEXPR */
#define HAS_CONSEXPR_AND_STATIC_ASSERT 1

可以看到,xmake 还提供了其他的辅助函数,用于检测:c/c++ 类型,c/c++ 代码片段,c/c++ 函数接口,链接库,头文件是否存在,甚至是 c/c++ 编译器特性支持力度等。

关于这块的更加完整的说明,可以看下:https://github.com/xmake-io/xmake/issues/342

配置自定义安装文件

对于 xmake install/uninstall 命令,xmake 新增了 add_installfiles 接口来设置一些安装文件,比起 on_install,此接口用起来更加的方便简洁,基本能够满足大部分安装需求。

比如我们可以指定安装各种类型的文件到安装目录:

target("test")
    add_installfiles("src/*.h")
    add_installfiles("doc/*.md")

默认在 linux 等系统上,我们会安装到 /usr/local/*.h, /usr/local/*.md,不过我们也可以指定安装到特定子目录:

target("test")
    add_installfiles("src/*.h", {prefixdir = "include"})
    add_installfiles("doc/*.md", {prefixdir = "share/doc"})

上面的设置,我们会安装到 /usr/local/include/*.h, /usr/local/share/doc/*.md

我们也可以通过 () 去提取源文件中的子目录来安装,例如:

target("test")
    add_installfiles("src/(tbox/*.h)", {prefixdir = "include"})
    add_installfiles("doc/(tbox/*.md)", {prefixdir = "share/doc"})

我们把 src/tbox/*.h 中的文件,提取 tbox/*.h 子目录结构后,在进行安装:/usr/local/include/tbox/*.h, /usr/local/share/doc/tbox/*.md

当然,用户也可以通过 set_installdir 接口,来配合使用。

关于此接口的详细说明,见:Issue #318 · xmake-io/xmake

CMakelists.txt 导出

新版本对 xmake project 工程生成插件进行了扩展,新增了对 CMakelists.txt 文件的导出支持,方便使用 xmake 的用户可以快速导出 CMakelists.txt 提供给 cmake,
以及 CLion 等一些支持 cmake 的工具使用,使用方式如下:

$ xmake project -k cmakelists

即可在当前工程目录下,生成对应的 CMakelists.txt 文件。

更新内容

新特性

  • 添加 string.serializestring.deserialize 去序列化,反序列化对象,函数以及其他类型
  • 添加 xmake g --menu 去图形化配置全局选项
  • #283: 添加 target:installdir()set_installdir() 接口
  • #260: 添加 add_platformdirs 接口,用户现在可以自定义扩展编译平台
  • #310: 新增主题设置支持,用户可随意切换和扩展主题样式
  • #318: 添加 add_installfiles 接口到 target 去自定义安装文件
  • #339: 改进 add_requiresfind_package 使其支持对第三方包管理的集成支持
  • #327: 实现对 conan 包管理的集成支持
  • 添加内置 API find_packages("pcre2", "zlib") 去同时查找多个依赖包,不需要通过 import 导入即可直接调用
  • #320: 添加模板配置文件相关接口,add_configfilesset_configvar
  • #179: 扩展 xmake project 插件,新增 CMakelist.txt 生成支持
  • #361: 增加对 vs2019 preview 的支持
  • #368: 支持 private, public, interface 属性设置去继承 target 配置
  • #284: 通过 add_configs() 添加和传递用户自定义配置到 package()
  • #319: 添加 add_headerfiles 接口去改进头文件的设置
  • #342: 为 includes() 添加一些内置的辅助函数,例如:check_cfuncs

改进

  • 针对远程依赖包,改进版本和调试模式切换
  • #264: 支持在 windows 上更新 dev/master 版本,xmake update dev
  • #293: 添加 xmake f/g --mingw=xxx 配置选线,并且改进 find_mingw 检测
  • #301: 改进编译预处理头文件以及依赖头文件生成,编译速度提升 30%
  • #322: 添加 option.add_features, option.add_cxxsnippetsoption.add_csnippets
  • 移除 xmake 1.x 的一些废弃接口, 例如:add_option_xxx
  • #327: 改进 lib.detect.find_package 增加对 conan 包管理器的支持
  • 改进 lib.detect.find_package 并且添加内建的 find_packages("zlib 1.x", "openssl", {xxx = ...}) 接口
  • 标记 set_modes() 作为废弃接口, 我们使用 add_rules("mode.debug", "mode.release") 来替代它
  • #353: 改进 target:set, target:add 并且添加 target:del 去动态修改 target 配置
  • #356: 添加 qt_add_static_plugins() 接口去支持静态 Qt sdk
  • #351: 生成 vs201x 插件增加对 yasm 的支持
  • 重构改进整个远程依赖包管理器,更加快速、稳定、可靠,并提供更多的常用包

Bugs 修复

  • 修复无法通过 set_optimize() 设置优化选项,如果存在 add_rules("mode.release") 的情况下
  • #289: 修复在 windows 下解压 gzip 文件失败
  • #296: 修复 option.add_includedirs 对 cuda 编译不生效
  • #321: 修复 PATH 环境改动后查找工具不对问题

原文:https://tboox.org/cn/2019/03/29/xmake-update-v2.2.5/

  • xmake
    6 引用 • 10 回帖 • 1 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    85 引用 • 165 回帖 • 1 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...