构建:修复 GTest 链接失败——显式指定 Linux GTest 配置,避免从 PATH 探测到 Windows Anaconda 的 .lib

This commit is contained in:
zjk
2026-08-18 19:45:50 +08:00
parent a6da5e3ae9
commit f3dd9e2c5a
20 changed files with 4629 additions and 6 deletions
+306
View File
@@ -0,0 +1,306 @@
#!/bin/bash
#=======================================================================
# FILE: scripts/run_host_sim.sh
# DESC: 运行与测试 pPowerMangerHost(模拟 pPowerManger 上位机的网页程序)
#
# 用法:
# ./scripts/run_host_sim.sh run 启动 MOOSDB + pPowerManger
# + pPowerMangerHost(前台运行,
# Ctrl-C 退出并清理)
# ./scripts/run_host_sim.sh test 自动化测试 pPowerMangerHost:
# 网页 HTTP / WebSocket 反馈 /
# 指令下发到 MOOSDB
# ./scripts/run_host_sim.sh build 仅编译需要的目标
# ./scripts/run_host_sim.sh stop 清理残留进程
# ./scripts/run_host_sim.sh help 显示帮助
#
# 环境变量(可覆盖):
# SERVER_HOST MOOSDB 地址(默认 localhost)
# SERVER_PORT MOOSDB 端口(默认 9000)
# WEB_PORT 网页监听端口(默认 18080)
# WITH_POWERMANGER run 模式是否同时启动 pPowerManger(默认 1)
#=======================================================================
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BIN_DIR="${ROOT}/bin"
MOOS_TEMPLATE="${ROOT}/src/pPowerMangerHost/pPowerMangerHost.moos"
SERVER_HOST="${SERVER_HOST:-localhost}"
SERVER_PORT="${SERVER_PORT:-9000}"
WEB_PORT="${WEB_PORT:-18080}"
WITH_POWERMANGER="${WITH_POWERMANGER:-1}"
MOOSDB_BIN="${MOOSDB_BIN:-$(command -v MOOSDB || true)}"
POKE_BIN="$(command -v uPokeDB || true)"
PM_BIN="${BIN_DIR}/pPowerManger"
HOST_BIN="${BIN_DIR}/pPowerMangerHost"
MOOSDB_PID=""
PM_PID=""
HOST_PID=""
WORKDIR=""
MISSION=""
info() { printf '\033[1;36m[host-sim]\033[0m %s\n' "$*"; }
ok() { printf '\033[1;32m[host-sim]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[host-sim]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[host-sim]\033[0m %s\n' "$*"; }
usage() {
sed -n '2,23p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
exit 0
}
# 生成临时 mission 文件(同时含 pPowerManger 与 pPowerMangerHost 两个配置块)
make_mission() {
WORKDIR="$(mktemp -d)"
MISSION="${WORKDIR}/host_sim.moos"
cat > "${MISSION}" <<EOF
ServerHost = ${SERVER_HOST}
ServerPort = ${SERVER_PORT}
Community = h100hostsim
ProcessConfig = pPowerManger
{
AppTick = 4
CommsTick = 4
}
ProcessConfig = pPowerMangerHost
{
AppTick = 4
CommsTick = 4
WEB_PORT = ${WEB_PORT}
}
EOF
}
kill_proc() {
[ -n "$1" ] && kill "$1" 2>/dev/null && wait "$1" 2>/dev/null
}
cleanup() {
kill_proc "${HOST_PID}"
kill_proc "${PM_PID}"
kill_proc "${MOOSDB_PID}"
[ -n "${WORKDIR}" ] && rm -rf "${WORKDIR}"
}
build_targets() {
info "编译 pPowerManger / pPowerMangerHost ..."
mkdir -p "${ROOT}/build"
cd "${ROOT}/build"
cmake -DCMAKE_BUILD_TYPE=Release "${ROOT}" >/dev/null 2>&1 || { err "cmake 失败"; return 1; }
make -j2 pPowerManger pPowerMangerHost >/dev/null 2>&1 || { err "make 失败"; return 1; }
cd "${ROOT}"
ok "编译完成"
}
check_binaries() {
local missing=0
[ -n "${MOOSDB_BIN}" ] || { err "未找到 MOOSDB(请加入 PATH)"; missing=1; }
[ -x "${HOST_BIN}" ] || { err "未找到 ${HOST_BIN}(请先运行: $0 build)"; missing=1; }
if [ "${WITH_POWERMANGER}" = "1" ]; then
[ -x "${PM_BIN}" ] || { err "未找到 ${PM_BIN}(请先运行: $0 build)"; missing=1; }
fi
return "${missing}"
}
start_moosdb() {
make_mission
info "启动 MOOSDB (${SERVER_HOST}:${SERVER_PORT}) ..."
"${MOOSDB_BIN}" --moos_no_colour "${MISSION}" > "${WORKDIR}/moosdb.log" 2>&1 &
MOOSDB_PID=$!
sleep 1
kill -0 "${MOOSDB_PID}" 2>/dev/null || { err "MOOSDB 未存活"; return 1; }
}
start_pm() {
info "启动 pPowerManger ..."
( cd "${WORKDIR}" && exec "${PM_BIN}" "${MISSION}" ) > "${WORKDIR}/pm.log" 2>&1 &
PM_PID=$!
sleep 1
kill -0 "${PM_PID}" 2>/dev/null || warn "pPowerManger 未存活(无 CCU 硬件属正常)"
}
start_host() {
info "启动 pPowerMangerHost (网页端口 ${WEB_PORT}) ..."
( cd "${WORKDIR}" && exec "${HOST_BIN}" "${MISSION}" ) > "${WORKDIR}/host.log" 2>&1 &
HOST_PID=$!
sleep 2
kill -0 "${HOST_PID}" 2>/dev/null || { err "pPowerMangerHost 未存活"; return 1; }
}
#-----------------------------------------------------------------------
# 测试项
#-----------------------------------------------------------------------
test_http() {
info "测试: 网页 HTTP (http://${SERVER_HOST}:${WEB_PORT}/) ..."
local code
code="$(curl -s -o /dev/null -w '%{http_code}' "http://${SERVER_HOST}:${WEB_PORT}/" 2>/dev/null || echo 000)"
if [ "${code}" = "200" ]; then
ok "网页 HTTP 200 通过"
return 0
else
err "网页 HTTP 失败 (code=${code})"
return 1
fi
}
# 反馈链路:向 MOOSDB 注入一条假的反馈变量 → 宿主订阅后应经 WS 推给浏览器
test_monitor_loop() {
info "测试: 反馈链路 (MOOSDB -> pPowerMangerHost -> WebSocket) ..."
if [ -z "${POKE_BIN}" ]; then
warn "未找到 uPokeDB,跳过反馈链路测试"
return 0
fi
if ! python3 -c "import websockets" >/dev/null 2>&1; then
warn "未安装 python3 websockets,跳过反馈链路测试"
return 0
fi
local fb_key="uPower_pmState_fb"
local fb_val='{"workCondition_uint8":9,"currentMod_uint8":1,"powerState_uint8":1,"faultLevel_uint8":0,"soc_uint16":88,"sustainableTime_int64":3600,"leakage_uint8":0,"info_str":"host-sim-test"}'
# 先让 WS 客户端连接等待快照,再注入反馈
FB_KEY="${fb_key}" python3 - "${WEB_PORT}" > "${WORKDIR}/ws_fb.log" 2>&1 <<'PY' &
import asyncio, json, os, sys
import websockets
PORT = int(sys.argv[1])
KEY = os.environ["FB_KEY"]
async def main():
uri = f"ws://localhost:{PORT}/ws"
async with websockets.connect(uri) as ws:
try:
while True:
msg = await asyncio.wait_for(ws.recv(), timeout=8)
snap = json.loads(msg)
if isinstance(snap, dict) and KEY in snap:
print(f"FEEDBACK_OK {KEY}")
return
except asyncio.TimeoutError:
pass
print("FEEDBACK_TIMEOUT")
asyncio.run(main())
PY
WS_PID=$!
sleep 1
"${POKE_BIN}" --host="${SERVER_HOST}" --port="${SERVER_PORT}" "${fb_key}=${fb_val}" >/dev/null 2>&1
wait "${WS_PID}" 2>/dev/null
if grep -q "FEEDBACK_OK" "${WORKDIR}/ws_fb.log" 2>/dev/null; then
ok "反馈链路通过(${fb_key} 已推送到浏览器)"
return 0
else
err "反馈链路失败(WS 未收到 ${fb_key})"
cat "${WORKDIR}/ws_fb.log" >&2
return 1
fi
}
# 指令下发:网页 WS 下发 -> 宿主 Notify -> MOOSDB -> (宿主订阅回环) -> 推回浏览器
# 利用宿主订阅了 uPower_pmState_fb,下发该变量后经 MOOSDB 回环,能收到即证明
# 指令确实进入了 MOOSDB。
test_command_notify() {
info "测试: 指令下发 (WebSocket -> pPowerMangerHost -> MOOSDB) ..."
if ! python3 -c "import websockets" >/dev/null 2>&1; then
warn "未安装 python3 websockets,跳过指令下发校验"
return 0
fi
python3 - "${WEB_PORT}" > "${WORKDIR}/ws_cmd.log" 2>&1 <<'PY'
import asyncio, json, sys
import websockets
PORT = int(sys.argv[1])
KEY = "uPower_pmState_fb"
TAG = "cmd-loopback-test"
async def main():
uri = f"ws://localhost:{PORT}/ws"
async with websockets.connect(uri) as ws:
await ws.send(json.dumps({"key": KEY, "value": {"info_str": TAG, "workCondition_uint8": 7}}))
try:
while True:
msg = await asyncio.wait_for(ws.recv(), timeout=8)
snap = json.loads(msg)
if isinstance(snap, dict) and KEY in snap:
obj = json.loads(snap[KEY])
if obj.get("info_str") == TAG:
print("CMD_OK")
return
except asyncio.TimeoutError:
pass
print("CMD_TIMEOUT")
asyncio.run(main())
PY
local r=$?
if [ ${r} -eq 0 ] && grep -q "CMD_OK" "${WORKDIR}/ws_cmd.log" 2>/dev/null; then
ok "指令下发到 MOOSDB 通过(uPower_pmState_fb 已回环)"
return 0
else
err "指令下发校验失败:未收到回环快照"
cat "${WORKDIR}/ws_cmd.log" >&2
return 1
fi
}
#-----------------------------------------------------------------------
# 命令入口
#-----------------------------------------------------------------------
cmd_run() {
check_binaries || return 1
start_moosdb || return 1
[ "${WITH_POWERMANGER}" = "1" ] && start_pm
start_host || return 1
info "全部启动完成。"
info "浏览器访问: http://${SERVER_HOST}:${WEB_PORT}/"
info "按 Ctrl-C 退出并清理。"
echo ""
trap 'info "退出清理..."; cleanup; exit 0' INT TERM
while kill -0 "${HOST_PID}" 2>/dev/null; do sleep 1; done
info "pPowerMangerHost 已退出。"
cleanup
}
cmd_test() {
check_binaries || return 1
start_moosdb || return 1
start_host || return 1
local pass=0 fail=0 r
test_http; r=$?; [ $r -eq 0 ] && pass=$((pass+1)) || fail=$((fail+1))
test_monitor_loop; r=$?; [ $r -eq 0 ] && pass=$((pass+1)) || fail=$((fail+1))
test_command_notify;r=$?; [ $r -eq 0 ] && pass=$((pass+1)) || fail=$((fail+1))
echo ""
info "==== 测试结果: 通过 ${pass} / 失败 ${fail} ===="
cleanup
[ "${fail}" -eq 0 ]
}
cmd_stop() {
pkill -f "${HOST_BIN}" 2>/dev/null
pkill -f "${PM_BIN}" 2>/dev/null
pkill -x MOOSDB 2>/dev/null
ok "已清理残留进程"
}
case "${1:-run}" in
run) cmd_run ;;
test) cmd_test ;;
build) build_targets ;;
stop) cmd_stop ;;
help|-h|--help) usage ;;
*) usage ;;
esac