V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
waruqi
V2EX  ›  程序员

Xmake v3.0.5 发布:多行进度输出、XML 模块、异步 OS API 和 Swift 互操作

  •  
  •   waruqi ·
    waruqi · 17 小时 22 分钟前 · 549 次点击

    新特性介绍

    新版本中,我们引入了多个重要特性,显著提升了开发体验。重点包括多行进度输出(支持主题配置,提供更好的构建可见性)、全面的XML 模块(用于解析和编码 XML 数据)、异步 OS API(提升 I/O 性能)以及Swift 互操作支持(实现 Swift 与 C++/Objective-C 代码的无缝集成)。同时,我们也对工具链配置、TTY 处理进行了重大改进,并进行了各种性能优化。

    下载地址: GitHub Releases | 源码仓库

    支持多行刷新进度输出

    我们改进了进度输出,支持多行刷新,在长时间运行的构建过程中提供显著更好的视觉体验。构建输出现在不再只更新单行进度,而是显示多个并发构建任务及其各自的进度,使得监控并行编译变得更加容易。

    输出现在显示并行构建的多行进度,每个编译任务都有实时状态更新:

    progress

    您可以通过两种方式启用多行进度输出:

    1. 通过主题配置:使用 soong 主题,它默认包含多行进度:

      $ xmake g --theme=soong
      
    2. 通过项目策略:在 xmake.lua 中直接启用:

      set_policy("build.progress_style", "multirow")
      

    这提供了更好的并行构建进度可见性,更容易识别编译缓慢的单元,并为包含大量源文件或具有多个编译单元的并行构建的大型项目改善了整体用户体验。

    更多详情,请参考:#6974

    添加 Swift 与 C++/Objective-C 互操作支持

    我们新增了全面的 Swift 互操作支持,实现了 Swift 与 C++/Objective-C 代码之间的无缝双向互操作性。当设置了 swift.interop 目标值时,swift.interop 规则会自动启用,使得在同一个项目中混合使用 Swift 和 C++ 代码变得非常容易。

    Swift 互操作支持包括:

    • Swift-C++ 双向互操作性
    • 自动生成 C++ 头文件,使 C++ 可以调用 Swift 函数
    • 支持 Objective-C 和 C++ 两种互操作模式
    • Swift 静态库归档工具集,增强编译工作流

    目标值配置:

    您可以使用以下目标值来配置 Swift 互操作:

    set_values("swift.modulename", "SwiftFibonacci")           -- 设置 Swift 模块名
    set_values("swift.interop", "cxx")                         -- 启用互操作:"objc" 或 "cxx"
    set_values("swift.interop.headername", "fibonacci-Swift.h") -- 定义输出头文件名
    set_values("swift.interop.cxxmain", true)                  -- 强制 -parse-as-library 以避免重复的 main 符号
    

    完整示例:Swift-C++ 互操作

    以下是一个完整的示例,演示 Swift-C++ 双向互操作:

    fibonacci.swift:

    // fibonacci.swift
    public func fibonacciSwift(_ x: CInt) -> CInt {
      print("x [swift]: \(x)")
      if x <= 1 {
        return 1
      }
      return fibonacciSwift(x - 1) + fibonacciSwift(x - 2)
    }
    

    main.cpp:

    // main.cpp
    #include <fibonacci-Swift.h>
    #include <iostream>
    
    int main(int argc, char ** argv) {
      std::cout << SwiftFibonacci::fibonacciSwift(5) << std::endl;
      return 0;
    }
    

    xmake.lua:

    -- xmake.lua
    target("cxx_interop")
        set_kind("binary")
        set_languages("cxx20")
        add_files("lib/**.swift", {public = true})
        add_files("src/**.cpp")
        set_values("swift.modulename", "SwiftFibonacci")
        set_values("swift.interop", "cxx")
        set_values("swift.interop.headername", "fibonacci-Swift.h")
        set_values("swift.interop.cxxmain", true)
    

    构建输出:

    $ xmake
    checking for platform ... macosx
    checking for architecture ... x86_64
    checking for Xcode directory ... /Applications/Xcode.app
    [  3%]: <cxx_interop> generating.swift.header fibonacci-Swift.h
    [ 38%]: cache compiling.release src/fibonacci.cpp
    [ 56%]: compiling.release lib/fibonacci/fibonacci.swift
    [ 76%]: linking.release cxx_interop
    [100%]: build ok, spent 1.785s
    
    $ xmake run
    x [swift]: 5
    x [swift]: 4
    ...
    8
    

    当设置 swift.interop 时,xmake 会自动生成 C++ 头文件,使 C++ 代码能够调用 Swift 函数。您可以使用 swift.modulename 定义 Swift 模块名,该名称将成为 C++ 中的命名空间。选择 "objc" 进行 Objective-C 互操作,或选择 "cxx" 进行 C++ 互操作。当 Swift 和 C++ 都有 main 函数时,使用 swift.interop.cxxmain 来避免重复的 main 符号。

    这个特性特别适用于:

    • 逐步将现有 C++ 项目迁移到 Swift
    • 在 Swift 应用程序中使用高性能 C++ 库
    • 为 C++ API 创建 Swift 包装器
    • 构建利用两种语言的跨平台应用程序
    • 从 C++ 应用程序无缝调用 Swift 代码

    更多详情,请参考:#6967

    添加 XML 模块支持

    我们引入了一个新的 core.base.xml 模块,提供了一个轻量级的 DOM 风格 XML 工具包,可在 Xmake 的沙箱环境中工作。它专注于可预测的数据结构、类似 JSON 的易用性,以及可选的流式解析,使您可以在不构建整个树的情况下解析大型 XML 文档。

    XML 模块特性:

    • 使用普通 Lua 表的 DOM 风格节点结构
    • 用于大文件的流式解析器(xml.scan
    • 类似 XPath 的查询(xml.find
    • 便捷的文件 I/O 辅助函数(xml.loadfilexml.savefile
    • 支持注释、CDATA 、DOCTYPE 和未引用的属性
    • 可自定义缩进的格式化输出

    节点结构:

    XML 节点是具有以下结构的普通 Lua 表:

    {
        name     = "element-name" | nil,  -- 仅用于元素节点
        kind     = "element" | "text" | "comment" | "cdata" | "doctype" | "document",
        attrs    = { key = value, ... } or nil,
        text     = string or nil,
        children = { child1, child2, ... } or nil,
        prolog   = { comment/doctype nodes before root } or nil
    }
    

    基本用法:

    import("core.base.xml")
    
    -- 解析 XML 字符串
    local doc = assert(xml.decode([[
    <?xml version="1.0"?>
    <root id="1">
      <item id="foo">hello</item>
    </root>
    ]]))
    
    -- 查找并修改节点
    local item = assert(xml.find(doc, "//item[@id='foo']"))
    item.attrs.lang = "en"             -- 直接修改属性
    item.children = {xml.text("world")} -- 替换现有文本节点
    
    -- 添加注释
    table.insert(doc.children, xml.comment("generated by xmake"))
    
    -- 使用格式化输出编码
    local pretty = assert(xml.encode(doc, {pretty = true}))
    assert(xml.savefile("out.xml", doc, {pretty = true}))
    

    文件操作:

    import("core.base.xml")
    
    -- 从文件加载
    local plist = assert(xml.loadfile("Info.plist"))
    
    -- 修改并保存
    local dict = assert(xml.find(plist, "plist/dict"))
    -- ... 修改节点 ...
    assert(xml.savefile("Info.plist", plist, {pretty = true, indent = 2}))
    

    用于大文件的流式解析器:

    import("core.base.xml")
    
    local found
    xml.scan(plist_text, function(node)
        if node.name == "key" and xml.text_of(node) == "NSPrincipalClass" then
            found = node
            return false -- 提前终止
        end
    end)
    

    xml.scan 在节点完成时遍历它们;返回 false 会立即停止扫描。这对于只需要几个条目的大文件非常理想。

    类似 XPath 的查询:

    import("core.base.xml")
    
    local doc = assert(xml.loadfile("config.xml"))
    
    -- 通过路径查找
    local element = xml.find(doc, "/root/item")
    
    -- 通过属性查找
    local item = xml.find(doc, "//item[@id='foo']")
    
    -- 通过文本内容查找
    local node = xml.find(doc, "//string[text()='value']")
    
    -- 获取文本内容
    local text = xml.text_of(node)
    

    节点创建辅助函数:

    import("core.base.xml")
    
    local textnode   = xml.text("hello")
    local empty      = xml.empty("br", {class = "line"})
    local comment    = xml.comment("generated by xmake")
    local cdata_node = xml.cdata("if (value < 1) {...}")
    local doctype    = xml.doctype('plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"')
    

    选项:

    选项 适用于 描述
    trim_text = true xml.decode, xml.scan 去除文本节点中的前导/尾随空格
    keep_whitespace_nodes = true xml.decode, xml.scan 保留仅包含空白字符的文本节点
    pretty = true / indent / indentchar xml.encode, xml.savefile 启用格式化并控制缩进

    使用场景:

    • 读取和修改 IDE 项目配置( Info.plist 、.vcxproj 等)
    • 生成基于 XML 的项目文件
    • 处理构建元数据和报告
    • 使用流式解析高效解析大型 XML 文件
    • 在 XML 和 Lua 数据结构之间转换

    更多详情,请参考:#7025

    添加目标信息的 JSON 输出格式

    我们为 xmake show 命令添加了 JSON 输出格式支持,使得以编程方式提取目标信息变得更加容易。这个特性实现了与 IDE 、构建自动化工具和需要解析 xmake 项目元数据的自定义脚本的无缝集成。

    JSON 输出包含全面的目标信息:

    • 目标名称、类型和文件路径
    • 源文件和头文件
    • 编译器标志和宏定义
    • 链接库和链接器标志
    • 包含目录和依赖项
    • 配置选项和规则

    您可以使用 --json 获得紧凑输出,或使用 --pretty-json 获得格式化输出:

    $ xmake show -t target --json
    {"targets":[{"name":"test","kind":"binary","files":["src/main.cpp"],"links":["pthread"],"defines":["DEBUG"]}]}
    
    $ xmake show -t target --pretty-json
    {
      "targets": [
        {
          "name": "test",
          "kind": "binary",
          "files": ["src/main.cpp"],
          "links": ["pthread"],
          "defines": ["DEBUG"],
          "includedirs": ["include"],
          "cxxflags": ["-std=c++17"],
          "deps": ["mylib"]
        }
      ]
    }
    

    您可以提取目标信息用于 IDE 集成或在脚本中使用:

    # 提取目标信息用于 IDE 集成
    xmake show -t target --pretty-json > project_info.json
    
    # 在脚本中使用
    TARGET_INFO=$(xmake show -t target --json)
    TARGET_NAME=$(echo $TARGET_INFO | jq -r '.targets[0].name')
    

    这对于以下场景特别有用:

    • IDE 集成( VS Code 、CLion 等)
    • 自动化构建系统和 CI/CD 流水线
    • 自定义项目分析工具
    • 文档生成

    更多详情,请参考:#7024

    支持指定 CUDA SDK 版本

    我们添加了通过 --cuda_sdkver 命令行选项指定 CUDA SDK 版本的支持,让您对 CUDA 编译有精确的控制。这在处理多个 CUDA 安装或需要针对特定 CUDA 版本以确保兼容性时非常重要。

    您可以通过命令行参数指定 CUDA SDK 版本:

    $ xmake f --cuda_sdkver=11.8
    $ xmake
    

    支持的版本值包括:

    • 11.8 - 指定 CUDA 11.8 版本
    • 11.x - 指定 CUDA 11.x 系列版本
    • auto - 自动检测(默认值)

    这个特性特别适用于:

    • 需要特定 CUDA 版本以确保兼容性的项目
    • 多版本 CUDA 开发环境
    • 确保在不同系统上一致的 CUDA 编译

    更多详情,请参考:#6964

    添加 GCC 15 工具链支持

    我们添加了对最新 GCC 15 工具链的支持,确保与最新的编译器特性和改进的兼容性。

    $ xmake f --toolchain=gcc-15
    

    更多详情,请参考:#6929

    添加 Solaris 平台支持

    我们新增了对 Solaris 平台的支持,包括 i386 和 x86_64 架构。这使得 xmake 可以在 Solaris 系统上进行构建,进一步扩展了跨平台支持。同时,我们也新增了对其他 BSD 系统的支持,包括 NetBSD 、OpenBSD 和 DragonflyBSD 。

    $ xmake f -p solaris -a i386
    $ xmake f -p solaris -a x86_64
    

    更多详情,请参考:#7055#7054

    添加 os API 异步支持

    我们为 os API 添加了异步支持,允许在 xmake 脚本中进行非阻塞的文件和进程操作。这使得能够并发执行 I/O 操作,在处理多个文件操作或长时间运行的进程时显著提高性能。

    支持的 API:

    以下 API 现在支持异步操作:

    • os.rm - 删除文件
    • os.rmdir - 删除目录
    • os.cp - 复制文件
    • os.files - 查找文件
    • os.filedirs - 查找文件和目录
    • os.dirs - 查找目录
    • os.match - 匹配文件模式
    • lib.detect.find_file - 查找文件
    • lib.detect.find_library - 查找库
    • lib.detect.find_path - 查找路径
    • lib.detect.find_directory - 查找目录

    异步模式:

    有两种异步模式可用:

    1. **async = true**(阻塞):操作可以与其他协程任务一起调度。您需要等待返回值。
    2. **async = true, detach = true**(非阻塞):操作在后台线程中执行,因此您不需要等待返回值。

    使用示例:

    import("lib.detect.find_file")
    
    function main()
        -- 在空闲的后台线程中删除文件,我们不需要等待它
        os.rm("/tmp/xxx.txt", {async = true, detach = true})
    
        -- 异步等待并获取返回值
        local files = os.files("src/*.c", {async = true})
    
        -- 异步等待并查找文件
        local file = find_file("*.txt", "/tmp/", {async = true})
    end
    

    这实现了非阻塞 I/O 操作,在并行读取多个配置文件或并发处理大型文件列表时显著提高性能。它对于异步运行外部工具、实现并行构建步骤以及提高插件和规则性能也很有用。

    更多详情,请参考:#6989#6868

    改进

    改进工具链配置语法

    我们改进了工具链配置语法,支持内联配置选项,使工具链设置更加简洁和声明式。新语法提供了三种主要的简化格式:

    简化的工具链配置格式:

    1. 仅工具链名称clanggcc
    2. 工具链 @包clang@llvm-10@muslcczig
    3. 工具链[配置]@包mingw[clang]@llvm-mingwmsvc[vs=2025,..]

    快速切换工具链配置:

    您现在可以使用内联语法快速切换工具链配置:

    -- 等价于:set_toolchains("mingw", {clang = true})
    set_toolchains("mingw[clang]")
    
    -- 命令行用法
    -- xmake f --toolchain=mingw[clang]
    

    示例:

    -- 简单工具链
    set_toolchains("clang")
    
    -- 带包的工具链
    set_toolchains("clang@llvm-10")
    set_toolchains("@muslcc")
    set_toolchains("zig")
    
    -- 带配置和包的工具链
    set_toolchains("mingw[clang]@llvm-mingw")
    set_toolchains("msvc[vs=2025]")
    
    -- 多个配置
    set_toolchains("mingw[clang]", {sdk = "/path/to/llvm-mingw"})
    

    其他改进:

    • 为 llvm-mingw 工具链添加了 clang 支持:

      xmake f --toolchain=mingw[clang] --sdk=/xxx/llvm-mingw
      
      set_toolchains("mingw[clang]@llvm-mingw")
      
    • 为旧版本 NDK 工具链添加了 gcc 支持:

      xmake f -p android --toolchain=ndk[gcc] --ndk=/xxxx
      

    这使得工具链配置更加简洁和可读,支持声明式工具链设置,并更易于管理多个工具链变体。它对于快速切换工具链、每个目标的工具链配置、CI/CD 流水线设置以及交叉编译工具链规范特别有用。

    更多详情,请参考:#6924讨论 #6903讨论 #6879

    改进文件读取性能

    我们显著改进了文件读取性能,特别是对于大文件和包含大量源文件的项目。

    改进包括更好的缓冲策略和优化的 I/O 操作。

    更多详情,请参考:#6942

    添加 xmake test 实时输出支持

    我们为 xmake test 添加了实时输出支持,允许测试输出在测试运行时实时显示,而不是等到测试完成后再缓冲输出。这对于长时间运行的测试或产生连续输出的测试特别有用,因为它提供了即时的测试进度反馈。

    要为测试启用实时输出,在测试配置中设置 realtime_output = true

    target("test")
        set_kind("binary")
        add_tests("stub_n", {realtime_output = true, files = "tests/stub_n*.cpp", defines = "STUB_N"})
    

    当启用 realtime_output 时,测试输出将在测试运行时直接流式传输到终端,使得实时监控测试进度和调试问题变得更加容易。

    更多详情,请参考:#6993

    改进 TTY 处理和输出

    我们改进了 core.base.tty 模块的 TTY 处理和输出格式。新增了以下接口:

    • tty.cursor_move_up(n) / tty.cursor_move_down(n) - 垂直移动光标
    • tty.cursor_move_left(n) / tty.cursor_move_right(n) - 水平移动光标
    • tty.cursor_move_to_col(n) - 移动到指定列
    • tty.cursor_save() / tty.cursor_restore() - 保存和恢复光标位置
    • tty.cursor_hide() / tty.cursor_show() - 控制光标可见性
    • tty.cr() - 移动到行首(回车)
    • tty.erase_line() - 清除整行
    • tty.erase_line_to_end() - 清除从光标到行尾
    • tty.has_vtansi() - 检查终端是否支持 ANSI 控制码

    更多详情,请参考:#6970

    添加 Ghostty 终端检测支持

    我们添加了对 Ghostty 终端的检测支持,确保在这个现代终端模拟器中具有正确的输出格式和颜色支持。

    更多详情,请参考:#6987

    改进图模块性能

    我们改进了图模块的性能,该模块用于依赖解析和构建图生成。

    这些改进使得项目配置和依赖分析速度更快。

    更多详情,请参考:#7027

    更新日志

    新特性

    • #6929: 添加 GCC 15 工具链支持
    • #6967: 添加 Swift 与 C++/Objective-C 互操作支持
    • #6964: 支持通过 cuda_sdkver 指定 CUDA SDK 版本
    • #6963: 添加交叉编译的 libtool 补丁支持
    • #6974: 支持多行刷新进度输出
    • #7024: 为 xmake show -t target 添加 JSON 输出格式
    • #7025: 添加 XML 模块,支持解析和编码
    • #6989: 添加 os API 异步支持
    • #7055: 添加 Solaris 平台支持( i386, x86_64 )
    • #7054: 添加对其他 BSD 系统的支持( NetBSD, OpenBSD, DragonflyBSD )

    改进

    • #6924: 改进工具链配置,支持 add_toolchains("name[configs]") 语法
    • #6942: 改进文件读取性能
    • #6970: 改进 TTY 处理和输出
    • #6977: 重构 Xcode 工具链,集成到 Apple 设备的 LLVM 工具链中
    • #6987: 添加 Ghostty 终端检测支持
    • #7003: 限制包配置中的构建环境获取
    • #7004: 使用 -r 标志时跳过重建包和 std 模块
    • #7019: 改进 xmake.sh/configure 脚本,添加 Ninja 生成器支持
    • #7022: 使 zig-cc 工具链继承自 clang
    • #7027: 改进图模块性能
    • #7031: 改进 require 解析
    • #7032: 改进符号提取
    • #7037: 改进 xmake format
    • #7038: 改进 clang-tidy 输出处理

    Bugs 修复

    • #6926: 修复 Windows 上加载 Unicode 主脚本路径的问题
    • #6931: 修复 C++ 模块:当工具链版本未安装时回退到系统范围的 clang-scan-deps
    • #6937: 修复目标作业处理
    • #6954: 修复 vsxmake/vs 生成器的模块支持
    • #6955: 修复包中的构建号排序
    • #6956: 修复使用不支持 depfile 的 zigcc 链接器时的构建失败
    • #6959: 修复使用 zigcc 与 autotools 进行动态链接的问题
    • #6983: 修复模块:为模块重用去除 sanitizer 标志
    • #6984: 修复已安装的 CMake 导入文件中的 libdir 路径
    • #6992: 修复模块:为 clang get_cpp_library_name 添加所有支持的平台
    • #6993: 修复 xmake test 模块
    • #6996: 修复 Nimble find_package 以使用最新的包列表格式
    • #6999: 修复 rootdir 处理
    • #7002: 修复 asn1c:将生成的输出作为系统头文件包含
    • #7012: 修复稀疏检出处理
    • #7013: 修复打包时移除依赖的问题
    • #7016: 修复 vsxmake 中的项目默认配置
    • #7017: 修复 lock_packages 拼写错误
    • #7018: 修复构建顺序:仅在禁用依赖链接继承时禁用
    • #7035: 通过更新 tbox 修复进程重定向问题
    2 条回复    2025-11-28 09:46:20 +08:00
    momo1999
        1
    momo1999  
       16 小时 30 分钟前
    现在 xmake.io 网站不好找版本信息和更新日志了。
    waruqi
        2
    waruqi  
    OP
       16 小时 15 分钟前
    @momo1999 在 github 上看,每次同步到文档站 太麻烦
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   1082 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 18:01 · PVG 02:01 · LAX 10:01 · JFK 13:01
    ♥ Do have faith in what you're doing.