Skip to content

针对C++工程集成优化构建系统性能 #1

Description

@owent

目前版本C++工程执行configure非常缓慢。为了提升性能,在robot层也需要做一些改造

1. 变更目的

1.1 目标

  1. configure 不构建:集成主工程时不在 CMake configure 阶段构建 Go 机器人;go-task 只驱动
    手动选择的构建 target(不加 ALL),configure 永不因 Go/Java/Helm 缺失失败。
  2. 模板引擎参数化与 server-client 复用:MAKO_GENERATOR_PY 可切换内置(robot-go 钉版)
    与父工程 src/tools/generate-for-pb 版本;无论能否复用外层缓存,都无条件透传
    --server-pid-file、--server-port-file、--server-auto-start、--client-mode,
    为多次运行和未来全局 cleanup 编排提速。
  3. 按需子模块初始化:Taskfile 中 git submodule update --init 不带 --recursive;
    使用外层 mako 时跳过内置 mako-generator 子模块初始化。
  4. Windows pwsh 化:Windows 下 Taskfile 用 pwsh -NoProfile(及脚本文件)替代 POSIX
    工具链依赖;只替换真实的 POSIX 依赖,简单 stdout 捕获的 sh: 保留。
  5. Linux 独立运行零 PowerShell 依赖:Linux/macOS 路径不允许出现任何 pwsh 调用;
    平台差异收敛到 platforms: 分支,Unix 分支只用 POSIX sh 与系统基础工具。
  6. 脚本对等(ps1/sh parity):script/ 下每个承载非平凡逻辑的 .ps1 必须有同功能
    .sh 对应物;Taskfile 只做参数装配与平台分发,避免逻辑双写漂移。
  7. go-task 自动下载:CMake 找不到本地 task 时查询并下载最新 release 二进制。
  8. 中间产物进构建目录:pb、venv、工具、staging、pid/port 一律落在 ROBOT_BUILD_DIR
    (CMake 注入 <CMAKE_BINARY_DIR>/robot);Unix 不再用 $HOME/robot_venv;生成器输出
    内容稳定(未变化的输出不重写、时间戳不变)。

1.2 关键机制约束

  • go-task 变量优先级(3.51/3.52 实测):调用 vars > 根全局 vars > dotenv > OS 环境变量;
    根全局 var 自动传播到 included Taskfile。因此 ENV_BUILD_TARGET_DIR/
    ENV_BUILD_TOOLS_DOWNLOAD_DIR 不能留在 build-tools.env(dotenv 会压掉 env 注入),
    改为根 Taskfile 用自引用 env-default 模式声明,CMake 注入相对 src/robot 的路径
    (下游 atframe-utils 用 {{.PROJECT_ROOT}}/{{.ToolsDir}} 拼接,必须相对)。
  • server 复用绑定解释器:generator_ipc 校验 server 进程镜像与 client 解释器一致
    (pythonw/python 同安装归一化等价)。注入必须成组:MAKO_GENERATOR_PY +
    MAKO_GENERATOR_PYTHON_BIN=${Python3_EXECUTABLE} + 父级 pid/port + package prefix,
    缺解释器会静默失去复用并互丢 pid 文件形成 server ping-pong。
  • Python 3.14 venv redirector:Windows 上 venv python 是 redirector,真实镜像是基座
    解释器;旧版 generator_ipc 按 realpath(sys.executable) 校验必败。独立路径(内置旧版
    生成器)由 rpc-handle.ps1 解析 sys._base_executable 作为 client、venv site-packages
    走 PYTHONPATH;检测到 MAKO_GENERATOR_PYTHON_BIN 环境注入(CMake 路径)时不启用 shim。
    POSIX 无需 shim(venv 是符号链接,realpath 与 /proc/<pid>/exe 天然一致)。
  • mvdan/sh 预解析:Taskfile cmd 先经 mvdan/sh,$VAR/$true 会被提前展开;内联 pwsh
    需 \$ 转义,跨 shell 传参用无 $ 的 true/false 字符串。
  • pwsh -File 数组限制:多值参数统一 ; 分隔单字符串,ps1 -split、sh IFS=';' 拆分,
    两平台传参形式一致。
  • preconditions 不支持 platforms(go-task 全平台执行所有条目):precondition 只用
    mvdan/sh 内置跨平台命令(test -f),平台差异检查放进脚本内部。
  • 相对路径 pid/port 按 client cwd 归一化:注入与默认一律用绝对路径。
  • protoc 无条件重写输出:协议 Go 代码与 config 先生成到 ROBOT_BUILD_DIR 下 staging,
    再按内容稳定发布(hash 比较才拷贝 + 镜像清理 stale);protocol 发布范围限定生成的
    protocol/ 子树,防止误删 Taskfile.yml 等非生成文件。

2. 实现步骤

2.1 src/robot/CMakeLists.txt

  1. 删除 configure 期 execute_process(task all)、set(ENV...) 与 Go/Java/Helm 版本探测;
    只 find_program(TASK_EXECUTABLE),缺失仅 message(WARNING)。
  2. 找不到本地 task 时:查询 api.github.com/repos/go-task/task/releases/latest 取 tag,
    下载 task_<os>_<arch>.{zip|tar.gz} 解压到 PROJECT_INSTALL_TOOLS_DIR/go-task;
    任一失败仅告警。最终仍无 task 时创建同名占位 robot-build(选中时才报可操作错误)。
  3. 保留两个 maybe_populate_submodule(atframe-utils-go、robot-go,默认非 recursive)。
  4. 非 ALL 的 robot-build target:cmake -E env 注入 INSTALL_PATH、
    ROBOT_BUILD_DIR=<CMAKE_BINARY_DIR>/robot、PYTHON_VENV_PATH、相对路径
    ENV_BUILD_TARGET_DIR/ENV_BUILD_TOOLS_DOWNLOAD_DIR,以及成组注入
    MAKO_GENERATOR_PY/MAKO_GENERATOR_PYTHON_BIN/MAKO_GENERATOR_SERVER_PID_FILE/
    MAKO_GENERATOR_SERVER_PORT_FILE/MAKO_GENERATOR_PACKAGE_PREFIX;
    WORKING_DIRECTORY robot 源码目录,USES_TERMINAL;不注册 common dependency,
    不伪造 OUTPUT/stamp。

2.2 src/robot/Taskfile.yml(根)

  1. build-tools.env 移除 ENV_BUILD_TARGET_DIR/ENV_BUILD_TOOLS_DOWNLOAD_DIR(保留版本
    pin);根全局 vars 以自引用 env-default 声明二者(默认 build/build/tools),
    ROBOT_BUILD_DIR 默认 {{.ROOT_DIR}}/build;OS 相关变量改纯模板(EXE_EXT、PYTHON_CMD)。
  2. submodule_update:git submodule update --init atframework/atframe-utils-go +
    atframework/robot-go + task: robot:submodule_update。
  3. venv:检测"目录在但 pip 不可用"的残缺 venv,守卫(非空/非根)后删除重建;venv、
    pb、staging、pid/port 全部从 ROBOT_BUILD_DIR 派生。
  4. rpc_handle:新增 MAKO_GENERATOR_PY/MAKO_GENERATOR_SERVER_PID_FILE/
    MAKO_GENERATOR_SERVER_PORT_FILE(默认内置脚本与 ROBOT_BUILD_DIR 下文件)、
    MAKO_GENERATOR_PYTHON_BIN(默认 venv python,CMake 注入父级解释器);precondition
    为单一跨平台 test -f 检查生成器与 pb;调用 script/rpc-handle.{ps1,sh},无条件带
    四个 IPC 参数与 --project-dir {{.ROOT_DIR}}、--pb-file <ROBOT_BUILD_DIR>/pb/ALL.pb、
    可选 --add-package-prefix。
  5. _generate-protocol/_generate-config:pb 输出到 {{.ROBOT_BUILD_DIR}}/pb,
    staging 传 {{.ROBOT_BUILD_DIR}}/_staging/{protocol-public,protocol-private,config}。

2.3 脚本集合(对等)

  • src/robot/script/:prepare-python-venv.ps1、prepare-python.{ps1,sh}、
    protocol-gen-pb.{ps1,sh}、protocol-gen-code.{ps1,sh}、publish-directory.{ps1,sh}、
    rpc-handle.{ps1,sh}。
  • src/robot/atframework/robot-go/config/:generate-config-code.{ps1,sh}、
    publish-directory.{ps1,sh}。
  • 递归删除前统一守卫:拒绝空值、盘符根/文件系统根;publish 镜像语义只作用于确认
    属于该 flow 的目录。

2.4 robot-go 与 protocol Taskfile

  1. robot-go/Taskfile.yml:拆 submodule_update(xres-code-generator,显式
    dir: "{{.TASKFILE_DIR}}")与 submodule-update-mako-generator(探测到有效外部
    MAKO_GENERATOR_PY 时跳过);generate-code 透传 STAGING_DIR。
  2. robot-go/config/Taskfile.yml:生成到 staging 后 publish-directory 稳定发布。
  3. protocol/{public,private}/Taskfile.yml:pb 与 Go 代码生成改调
    protocol-gen-{pb,code}.{ps1,sh};保持与 POSIX glob 一致的相对路径形式(描述符不变);
    空 glob 组直接失败。
  4. src/robot/generate-for-pb.yaml:删除硬编码 protocol_input_pb_file(pb 改 CLI
    --pb-file)与全局 output_directory(规则已各有显式值)。
  5. src/robot/.gitignore:增加 /generate-for-pb-run-server.log(server 在 client cwd
    生成日志)。

3. 验收方法

日志与快照统一放 <BUILD_DIR>/_agent_tmp/robot-refactor/。

  1. 静态:git diff --check;主仓与 robot-go 全部 submodule 命令无 --recursive;
    ps1 语法解析;双平台 task --list 解析通过。
  2. configure:重跑 configure 日志无 task all/go build;go-task 缺失仅告警不阻断
    (下载回退用隔离 cmake -P 脚本验证查询/下载/解压/可运行)。
  3. target 图:cmake --build <BUILD_DIR> --target help 可见 robot-build;
    ninja -n all 输出不含 robot-build/task.exe;缺 task 时占位 target 报错可操作。
  4. 端到端(Windows):cmake --build <BUILD_DIR> --target robot-build -- -j 12 成功,
    产出 robot.exe、pb、Go 协议包、config。
  5. server 复用与恢复:600 秒 idle timeout 内连续运行两次,第二次连接相同 pid/port
    且全程只有一个 server、pid 不变(CMake 路径用父级 pid/port,独立路径用 robot-local
    pid/port);显式杀 server 或等待 idle 后下一次自动重启;client 无法启动 server 时
    非零退出并打印 pid/port 与实际命令。
  6. 内容与时间戳稳定:同输入连续两次运行,对 rpc_handle、config、protocol Go 文件做
    SHA-256 与 mtime 对比,二者均不变(staging+publish 输出 Published 0 file(s))。
  7. 快速失败:注入无效 MAKO_GENERATOR_PY 时 precondition 打印实际路径并非零退出;
    publish/递归删除对空值与盘符根做负向验证。
  8. Linux(WSL 或 CI):无 pwsh 环境下 task --list + task all 端到端成功(可用
    独立 ROBOT_BUILD_DIR=build/wsl 等注入与 Windows 产物隔离),robot-local server
    跨运行 pid 复用;与 Windows 产物做内容对比(.pb.go 注释可能因 Go 工具链版本
    漂移而不同,属上游固有差异,记录即可)。
  9. 默认构建回归:cmake --build <BUILD_DIR> --target all 不触发 robot 构建。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions