mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 06:47:29 +00:00
fix(csrc): 交叉门禁改用 clang --target,去掉会卡死的 apt 下载 + 修两处假通过
## 卡死真因(这次可观测了)
上一版加了 `timeout` 硬超时后,日志终于能看出卡在哪:
15:47:33 Fetched 12.5 MB in 1s (9972 kB/s) ← update 很快
15:47:38 Get:2 gcc-13-aarch64-linux-gnu-base 51.9 kB
15:47:39 Get:3 cpp-13-aarch64-linux-gnu 10.8 MB ← 下到这儿卡住
15:50:37 ##[error]apt-get install 超时/失败(180s)
**根因:为了跑一道 `-fsyntax-only` 的语法门禁,去下载 10MB+ 的交叉 GCC 工具链,
在 runner 上拉不动。**
## 改法:用 clang 自带的交叉前端
这道门禁只做 `-fsyntax-only`(不链接、不运行)。clang 支持
`--target=aarch64-linux-gnu`,会**真的切到 aarch64 目标**:
$ clang -fsyntax-only arch2.c → error: "not aarch64 target"
$ clang --target=aarch64-linux-gnu ... → 通过(__aarch64__ 生效)
指针宽度、endianness、C 扩展支持都按目标架构算 —— 足以暴露本门禁要抓的
那类问题。而 clang 在 ubuntu-latest 镜像里**已预装**(实测确认,只列出
`gcc-aarch64-linux-gnu` 一项需要安装)。
优先级:`CC_ARM64`(显式)> `clang --target` > `aarch64-linux-gnu-gcc` > SKIP
## 顺带修掉两处**本来就存在**的假通过
这两处不是本轮引入的,是新写的存在性校验暴露出来的:
### ① `cmd | head` 吞掉编译器退出码
for src in ...; do
if ! $CC ... -fsyntax-only $src 2>&1 | head -20; then ok=0; fi
done
管道退出码是 `head` 的(恒 0)。实测:`CC_ARM64=nonexistent-xyz make csrc-cross`
竟然输出「0 告警、编译通过 ✓」—— 编译器根本没执行。
修法:改用 `${PIPESTATUS[0]}`,取编译器的真实退出码。
### ② `PIPESTATUS` 需要 bash,Make 默认是 dash
`/bin/sh` 在 Debian/Ubuntu 上是 dash,不支持 `PIPESTATUS`(报 Bad substitution)。
必须显式 `SHELL := /bin/bash`,否则上面的修法静默失效。
### 风险自证(三条路径实测)
| 场景 | 结果 |
|---|---|
| 正常(clang-target) | ✅ 0 告警、编译通过 ✓ |
| `CC_ARM64` 指向不存在的命令 | ✅ `[FAIL] CC_ARM64=nonexistent-xyz 不存在` → Error 1 |
| 真的写坏 C 源码 | ✅ 编译器报错 + `[FAIL] arm64 交叉编译失败` → Error 1 |
## CI 侧
- 安装步骤不再要求 `gcc-aarch64-linux-gnu` ⇒ **依赖已预装,直接跳过 apt-get,完全不碰网络**
- 工具链确认步骤只校验 `cmake` + `clang`
- `[SKIP]` 拦截、`timeout` 硬超时、去 `-qq` 全部保留(对付将来别的原因导致的卡死)
This commit is contained in:
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@ -192,13 +192,21 @@ jobs:
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
set -uo pipefail
|
||||
# ★ 不再需要 gcc-aarch64-linux-gnu(2026-10-22)。
|
||||
#
|
||||
# 实测:装它要从源拉 10MB+ 的 cpp-13 等依赖,在 runner 上卡住超时
|
||||
# (15:47:39 开始下 cpp-13-aarch64,180s 后仍未完成)。
|
||||
# 而 csrc-cross 只需要 `-fsyntax-only`,clang 自带交叉前端即可:
|
||||
# `clang --target=aarch64-linux-gnu` 会真的切到 aarch64 目标
|
||||
# (__aarch64__ 宏生效、指针宽度按该架构算),足以暴露本门禁要抓的
|
||||
# 架构问题。Makefile 的 csrc-cross 已按
|
||||
# CC_ARM64 > clang --target > aarch64-gcc > SKIP 的优先级挑选。
|
||||
need=""
|
||||
command -v cmake >/dev/null || need="$need cmake"
|
||||
command -v clang >/dev/null || need="$need clang"
|
||||
command -v aarch64-linux-gnu-gcc >/dev/null || need="$need gcc-aarch64-linux-gnu"
|
||||
command -v cmake >/dev/null || need="$need cmake"
|
||||
command -v clang >/dev/null || need="$need clang"
|
||||
|
||||
if [ -z "$need" ]; then
|
||||
echo "✅ 三件套已存在,跳过 apt-get:$(command -v cmake clang aarch64-linux-gnu-gcc | tr '\n' ' ')"
|
||||
echo "✅ 依赖已存在,跳过 apt-get:$(command -v cmake clang | tr '\n' ' ')"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@ -239,7 +247,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
miss=""
|
||||
for t in cmake clang aarch64-linux-gnu-gcc; do
|
||||
for t in cmake clang; do
|
||||
if command -v "$t" >/dev/null 2>&1; then
|
||||
echo " ✅ $t: $(command -v "$t")"
|
||||
else
|
||||
|
||||
57
Makefile
57
Makefile
@ -1,3 +1,7 @@
|
||||
# 门禁脚本需要 bash 的 PIPESTATUS(/bin/sh=dash 不支持)。
|
||||
# 没有它就无法区分"编译器失败"与"head 成功" —— 实测会让门禁假通过。
|
||||
SHELL := /bin/bash
|
||||
|
||||
.PHONY: test-gui all build build-plain build-cli build-gui clean install test run build-static build-linux-arm64 lint fmt sync-client-versions check-client-versions check-starmap-shared check-client-protocol csrc csrc-test csrc-lint csrc-abi csrc-headers csrc-sanitize csrc-cross csrc-fuzz check-csrc check-csrc-full
|
||||
# HOMED_TAGS 默认带 onnxruntime:发行版**默认启用**本地向量空间(与
|
||||
# deploy/packaging/build.sh 保持一致)。
|
||||
@ -255,21 +259,56 @@ csrc-fuzz:
|
||||
# C 侧的架构相关问题(endianness 假设、指针宽度、size_t vs int 宽度、
|
||||
# -fsanitize 不可用)只有真的用目标编译器编一遍才会暴露。
|
||||
# 与 deploy/packaging/build.sh 的 arm64 目标共用同一套 CC 变量。
|
||||
#
|
||||
# ## 为什么首选 clang --target,而不是 aarch64-linux-gnu-gcc(2026-10-22)
|
||||
#
|
||||
# 这道门禁只做 `-fsyntax-only`(不链接、不运行),而 clang 自带交叉前端:
|
||||
# `clang --target=aarch64-linux-gnu` 会真的切到 aarch64 目标(`__aarch64__`
|
||||
# 宏生效、指针宽度按该架构计算),足以暴露本门禁要抓的那类问题
|
||||
# (endianness 假设、指针/size_t 宽度、不支持的 C 扩展)。
|
||||
#
|
||||
# 而装 `gcc-aarch64-linux-gnu` 需要从源拉 10MB+ 的 cpp-13 等依赖 ——
|
||||
# 实测在 CI runner 上会卡住超时(见 .github/workflows/ci.yml 的加固说明)。
|
||||
# 既然只需要语法层验证,就不该为它引入一个会卡死的下载依赖。
|
||||
#
|
||||
# 优先级:CC_ARM64(显式指定) > clang --target > aarch64-linux-gnu-gcc > SKIP
|
||||
#
|
||||
# ★ 两个假通过陷阱(实测踩到,勿删):
|
||||
# 1. 显式 CC_ARM64 指向不存在的命令时,`cmd | head` 的退出码是 head 的(恒 0),
|
||||
# command-not-found(127) 被吞 ⇒ 门禁显示"通过"。所以循环里改用 PIPESTATUS[0],
|
||||
# 且对显式指定的编译器先做 command -v 校验。
|
||||
# 2. 上述 PIPESTATUS 需要 bash;Make 默认 /bin/sh=dash 不支持(见文件顶 SHELL)。
|
||||
.PHONY: csrc-cross
|
||||
csrc-cross:
|
||||
@echo "== C 侧交叉编译(linux/arm64)=="
|
||||
@CC_ARM64=$${CC_ARM64:-aarch64-linux-gnu-gcc}; \
|
||||
if ! command -v $$CC_ARM64 >/dev/null 2>&1; then \
|
||||
echo " [SKIP] $$CC_ARM64 不存在(未装交叉工具链)"; exit 0; \
|
||||
fi; \
|
||||
ok=1; \
|
||||
for src in $(CSRC_SRCS); do \
|
||||
if ! $$CC_ARM64 $(CSRC_CFLAGS) -Werror -fsyntax-only $$src 2>&1 | head -20; then \
|
||||
ok=0; \
|
||||
@ok=1; \
|
||||
if [ -n "$${CC_ARM64:-}" ]; then \
|
||||
if ! command -v "$$CC_ARM64" >/dev/null 2>&1; then \
|
||||
echo " [FAIL] CC_ARM64=$$CC_ARM64 不存在"; exit 1; \
|
||||
fi; \
|
||||
CC="$$CC_ARM64"; MODE="explicit"; \
|
||||
elif command -v clang >/dev/null 2>&1; then \
|
||||
CC="clang --target=aarch64-linux-gnu"; MODE="clang-target"; \
|
||||
elif command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
|
||||
CC="aarch64-linux-gnu-gcc"; MODE="cross-gcc"; \
|
||||
else \
|
||||
echo " [SKIP] 无 clang、无 aarch64-linux-gnu-gcc(未装任何交叉前端)"; exit 0; \
|
||||
fi; \
|
||||
\
|
||||
if [ "$$MODE" = "clang-target" ]; then \
|
||||
printf 'int main(void){return 0;}\n' > /tmp/_archchk.c; \
|
||||
if ! clang --target=aarch64-linux-gnu -fsyntax-only /tmp/_archchk.c 2>/dev/null; then \
|
||||
echo " [SKIP] clang 不支持 --target=aarch64-linux-gnu(版本过旧)"; exit 0; \
|
||||
fi; \
|
||||
fi; \
|
||||
\
|
||||
for src in $(CSRC_SRCS); do \
|
||||
$$CC $(CSRC_CFLAGS) -Werror -fsyntax-only $$src 2>&1 | head -20; \
|
||||
rc=$${PIPESTATUS[0]}; \
|
||||
if [ "$$rc" != "0" ]; then ok=0; fi; \
|
||||
done; \
|
||||
if [ "$$ok" = "1" ]; then \
|
||||
echo " $$CC_ARM64: 0 告警、编译通过 ✓($(words $(CSRC_SRCS)) 个源文件)"; \
|
||||
echo " $$CC [$$MODE]: 0 告警、编译通过 ✓($(words $(CSRC_SRCS)) 个源文件)"; \
|
||||
else \
|
||||
echo " [FAIL] arm64 交叉编译失败"; exit 1; \
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user