目前版本C++工程执行configure非常缓慢。为了提升性能,在robot层也需要做一些改造
1. 变更目的
1.1 目标
- configure 不构建:集成主工程时不在 CMake configure 阶段构建 Go 机器人;go-task 只驱动
手动选择的构建 target(不加 ALL),configure 永不因 Go/Java/Helm 缺失失败。
- 模板引擎参数化与 server-client 复用:
MAKO_GENERATOR_PY 可切换内置(robot-go 钉版)
与父工程 src/tools/generate-for-pb 版本;无论能否复用外层缓存,都无条件透传
--server-pid-file、--server-port-file、--server-auto-start、--client-mode,
为多次运行和未来全局 cleanup 编排提速。
- 按需子模块初始化:Taskfile 中
git submodule update --init 不带 --recursive;
使用外层 mako 时跳过内置 mako-generator 子模块初始化。
- Windows pwsh 化:Windows 下 Taskfile 用
pwsh -NoProfile(及脚本文件)替代 POSIX
工具链依赖;只替换真实的 POSIX 依赖,简单 stdout 捕获的 sh: 保留。
- Linux 独立运行零 PowerShell 依赖:Linux/macOS 路径不允许出现任何 pwsh 调用;
平台差异收敛到 platforms: 分支,Unix 分支只用 POSIX sh 与系统基础工具。
- 脚本对等(ps1/sh parity):
script/ 下每个承载非平凡逻辑的 .ps1 必须有同功能
.sh 对应物;Taskfile 只做参数装配与平台分发,避免逻辑双写漂移。
- go-task 自动下载:CMake 找不到本地 task 时查询并下载最新 release 二进制。
- 中间产物进构建目录: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
- 删除 configure 期
execute_process(task all)、set(ENV...) 与 Go/Java/Helm 版本探测;
只 find_program(TASK_EXECUTABLE),缺失仅 message(WARNING)。
- 找不到本地 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(选中时才报可操作错误)。
- 保留两个
maybe_populate_submodule(atframe-utils-go、robot-go,默认非 recursive)。
- 非
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(根)
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)。
submodule_update:git submodule update --init atframework/atframe-utils-go +
atframework/robot-go + task: robot:submodule_update。
- venv:检测"目录在但 pip 不可用"的残缺 venv,守卫(非空/非根)后删除重建;venv、
pb、staging、pid/port 全部从 ROBOT_BUILD_DIR 派生。
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。
_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
robot-go/Taskfile.yml:拆 submodule_update(xres-code-generator,显式
dir: "{{.TASKFILE_DIR}}")与 submodule-update-mako-generator(探测到有效外部
MAKO_GENERATOR_PY 时跳过);generate-code 透传 STAGING_DIR。
robot-go/config/Taskfile.yml:生成到 staging 后 publish-directory 稳定发布。
protocol/{public,private}/Taskfile.yml:pb 与 Go 代码生成改调
protocol-gen-{pb,code}.{ps1,sh};保持与 POSIX glob 一致的相对路径形式(描述符不变);
空 glob 组直接失败。
src/robot/generate-for-pb.yaml:删除硬编码 protocol_input_pb_file(pb 改 CLI
--pb-file)与全局 output_directory(规则已各有显式值)。
src/robot/.gitignore:增加 /generate-for-pb-run-server.log(server 在 client cwd
生成日志)。
3. 验收方法
日志与快照统一放 <BUILD_DIR>/_agent_tmp/robot-refactor/。
- 静态:
git diff --check;主仓与 robot-go 全部 submodule 命令无 --recursive;
ps1 语法解析;双平台 task --list 解析通过。
- configure:重跑 configure 日志无
task all/go build;go-task 缺失仅告警不阻断
(下载回退用隔离 cmake -P 脚本验证查询/下载/解压/可运行)。
- target 图:
cmake --build <BUILD_DIR> --target help 可见 robot-build;
ninja -n all 输出不含 robot-build/task.exe;缺 task 时占位 target 报错可操作。
- 端到端(Windows):
cmake --build <BUILD_DIR> --target robot-build -- -j 12 成功,
产出 robot.exe、pb、Go 协议包、config。
- server 复用与恢复:600 秒 idle timeout 内连续运行两次,第二次连接相同 pid/port
且全程只有一个 server、pid 不变(CMake 路径用父级 pid/port,独立路径用 robot-local
pid/port);显式杀 server 或等待 idle 后下一次自动重启;client 无法启动 server 时
非零退出并打印 pid/port 与实际命令。
- 内容与时间戳稳定:同输入连续两次运行,对 rpc_handle、config、protocol Go 文件做
SHA-256 与 mtime 对比,二者均不变(staging+publish 输出 Published 0 file(s))。
- 快速失败:注入无效
MAKO_GENERATOR_PY 时 precondition 打印实际路径并非零退出;
publish/递归删除对空值与盘符根做负向验证。
- Linux(WSL 或 CI):无 pwsh 环境下
task --list + task all 端到端成功(可用
独立 ROBOT_BUILD_DIR=build/wsl 等注入与 Windows 产物隔离),robot-local server
跨运行 pid 复用;与 Windows 产物做内容对比(.pb.go 注释可能因 Go 工具链版本
漂移而不同,属上游固有差异,记录即可)。
- 默认构建回归:
cmake --build <BUILD_DIR> --target all 不触发 robot 构建。
目前版本C++工程执行configure非常缓慢。为了提升性能,在robot层也需要做一些改造
1. 变更目的
1.1 目标
手动选择的构建 target(不加
ALL),configure 永不因 Go/Java/Helm 缺失失败。MAKO_GENERATOR_PY可切换内置(robot-go 钉版)与父工程
src/tools/generate-for-pb版本;无论能否复用外层缓存,都无条件透传--server-pid-file、--server-port-file、--server-auto-start、--client-mode,为多次运行和未来全局 cleanup 编排提速。
git submodule update --init不带--recursive;使用外层 mako 时跳过内置 mako-generator 子模块初始化。
pwsh -NoProfile(及脚本文件)替代 POSIX工具链依赖;只替换真实的 POSIX 依赖,简单 stdout 捕获的
sh:保留。平台差异收敛到
platforms:分支,Unix 分支只用 POSIX sh 与系统基础工具。script/下每个承载非平凡逻辑的.ps1必须有同功能.sh对应物;Taskfile 只做参数装配与平台分发,避免逻辑双写漂移。ROBOT_BUILD_DIR(CMake 注入
<CMAKE_BINARY_DIR>/robot);Unix 不再用$HOME/robot_venv;生成器输出内容稳定(未变化的输出不重写、时间戳不变)。
1.2 关键机制约束
根全局 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}}拼接,必须相对)。(pythonw/python 同安装归一化等价)。注入必须成组:
MAKO_GENERATOR_PY+MAKO_GENERATOR_PYTHON_BIN=${Python3_EXECUTABLE}+ 父级 pid/port + package prefix,缺解释器会静默失去复用并互丢 pid 文件形成 server ping-pong。
解释器;旧版 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天然一致)。$VAR/$true会被提前展开;内联 pwsh需
\$转义,跨 shell 传参用无$的 true/false 字符串。-File数组限制:多值参数统一;分隔单字符串,ps1-split、shIFS=';'拆分,两平台传参形式一致。
platforms(go-task 全平台执行所有条目):precondition 只用mvdan/sh 内置跨平台命令(
test -f),平台差异检查放进脚本内部。ROBOT_BUILD_DIR下 staging,再按内容稳定发布(hash 比较才拷贝 + 镜像清理 stale);protocol 发布范围限定生成的
protocol/子树,防止误删 Taskfile.yml 等非生成文件。2. 实现步骤
2.1
src/robot/CMakeLists.txtexecute_process(task all)、set(ENV...)与 Go/Java/Helm 版本探测;只
find_program(TASK_EXECUTABLE),缺失仅message(WARNING)。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(选中时才报可操作错误)。maybe_populate_submodule(atframe-utils-go、robot-go,默认非 recursive)。ALL的robot-buildtarget: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_DIRECTORYrobot 源码目录,USES_TERMINAL;不注册 common dependency,不伪造 OUTPUT/stamp。
2.2
src/robot/Taskfile.yml(根)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)。submodule_update:git submodule update --init atframework/atframe-utils-go+atframework/robot-go+task: robot:submodule_update。pb、staging、pid/port 全部从
ROBOT_BUILD_DIR派生。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。_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}。属于该 flow 的目录。
2.4 robot-go 与 protocol Taskfile
robot-go/Taskfile.yml:拆submodule_update(xres-code-generator,显式dir: "{{.TASKFILE_DIR}}")与submodule-update-mako-generator(探测到有效外部MAKO_GENERATOR_PY时跳过);generate-code透传STAGING_DIR。robot-go/config/Taskfile.yml:生成到 staging 后publish-directory稳定发布。protocol/{public,private}/Taskfile.yml:pb 与 Go 代码生成改调protocol-gen-{pb,code}.{ps1,sh};保持与 POSIX glob 一致的相对路径形式(描述符不变);空 glob 组直接失败。
src/robot/generate-for-pb.yaml:删除硬编码protocol_input_pb_file(pb 改 CLI--pb-file)与全局output_directory(规则已各有显式值)。src/robot/.gitignore:增加/generate-for-pb-run-server.log(server 在 client cwd生成日志)。
3. 验收方法
日志与快照统一放
<BUILD_DIR>/_agent_tmp/robot-refactor/。git diff --check;主仓与 robot-go 全部 submodule 命令无--recursive;ps1 语法解析;双平台
task --list解析通过。task all/go build;go-task 缺失仅告警不阻断(下载回退用隔离
cmake -P脚本验证查询/下载/解压/可运行)。cmake --build <BUILD_DIR> --target help可见robot-build;ninja -n all输出不含 robot-build/task.exe;缺 task 时占位 target 报错可操作。cmake --build <BUILD_DIR> --target robot-build -- -j 12成功,产出 robot.exe、pb、Go 协议包、config。
且全程只有一个 server、pid 不变(CMake 路径用父级 pid/port,独立路径用 robot-local
pid/port);显式杀 server 或等待 idle 后下一次自动重启;client 无法启动 server 时
非零退出并打印 pid/port 与实际命令。
SHA-256 与 mtime 对比,二者均不变(staging+publish 输出
Published 0 file(s))。MAKO_GENERATOR_PY时 precondition 打印实际路径并非零退出;publish/递归删除对空值与盘符根做负向验证。
task --list+task all端到端成功(可用独立
ROBOT_BUILD_DIR=build/wsl等注入与 Windows 产物隔离),robot-local server跨运行 pid 复用;与 Windows 产物做内容对比(
.pb.go注释可能因 Go 工具链版本漂移而不同,属上游固有差异,记录即可)。
cmake --build <BUILD_DIR> --target all不触发 robot 构建。