Files
2026-10-16 17:27:30 +08:00

83 lines
3.7 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# =============================================================================
# 修 console_scripts 的 shebang(真机 / 仿真两套构建产物都会踩的坑)
# =============================================================================
#
# 现象:
# source scripts/sim_env.sh && ros2 run arm_sim_gazebo sim_camera_adapter
# 进程列表里却是
# /home/cc/anaconda3/envs/ros_flexiv/bin/python3.11 ... sim_camera_adapter
# 即**仿真节点跑在真机的 conda 环境里**。
#
# 为什么:
# setuptools 的 console_scripts 入口脚本,shebang 用的是**构建那一刻**的
# sys.executable。本工作区只有一份源码,真机与仿真各有自己的 conda 环境
# (ros_flexiv / ros_gz_sim)和各自的 install 目录。如果在真机环境里跑过
# build_sim.sh(或反之),写进 install_sim/ 的脚本 shebang 就指向了另一个
# 环境。`ros2 run` 是**照 shebang 执行**的,不看当前 CONDA_PREFIX。
#
# 为什么危险:
# 两个环境都是 ROS 2 Humble + Python 3.11,所以多数时候"居然能跑",
# 只是 import 到的是另一个环境的包。表现为偶发的 ABI/`dlopen`/消息反序列化
# 报错,报错信息完全不提"shebang 指错环境"。
# 实测:LD_LIBRARY_PATH、PYTHONPATH 都清干净了,节点仍然跑在 ros_flexiv 里。
#
# 对策:
# 构建收尾时扫一遍本次产物,把指向"别的 conda 环境"的 shebang 改回
# **本环境**的 python。已指向本环境的文件不动(幂等)。
#
# 用法:
# fix_shebangs <install_dir> <expected_python_path>
# =============================================================================
# fix_shebangs <install_dir> <expected_python>
# 把 <install_dir> 下所有 console_scripts 里"指向其它 conda 环境"的 shebang
# 改写成 <expected_python>。返回 0;打印改了哪些文件(没改就不打印)。
fix_shebangs() {
local install_dir="$1"
local expected="$2"
if [[ ! -d "${install_dir}" || ! -x "${expected}" ]]; then
return 0
fi
# 只扫这两类位置:包自带的 console_scripts 目录、以及 bin/。
# 用 find 而不是递归 rg:要按"是不是可执行文件 + 首行是 shebang"判断。
local -a files=()
local f
while IFS= read -r -d '' f; do
files+=("${f}")
done < <(find "${install_dir}" \
\( -path "*/lib/*" -o -path "*/bin/*" \) \
-type f -perm -u+x -print0 2>/dev/null)
local fixed=0 first
for f in "${files[@]}"; do
# 读首行(最多 200 字节);不是 #! 开头就跳过(二进制、数据文件等)
first="$(head -c 200 "${f}" | head -1)"
[[ "${first:0:2}" == "#!" ]] || continue
# 只动"指向某个 conda 环境"的 shebang;/usr/bin/python3 这类系统解释器不动
[[ "${first}" == *"/envs/"*"python"* ]] || continue
[[ "${first}" == *"${expected}"* ]] && continue
# 保留原 shebang 里的参数(例如 `python3 -u`)
local interp="${first#\#!}" # 去掉 #!
interp="${interp%% *}" # 第一个 token = 解释器路径
local rest="${first#"#!${interp}"}" # 剩下的是参数(含前导空格)
# 就地重写首行:用 printf + tail 组装,避免 sed -i 在符号链接上的坑
local tmp="${f}.shebang.$$"
{
printf '#!%s%s\n' "${expected}" "${rest}"
tail -n +2 "${f}"
} > "${tmp}" && cat "${tmp}" > "${f}" && rm -f "${tmp}"
echo " 修正 shebang: ${f#$PWD/} → ${expected}"
fixed=$((fixed + 1))
done
if [[ "${fixed}" -gt 0 ]]; then
echo " (共修正 ${fixed} 个入口脚本:它们的 shebang 原本指向别的 conda 环境,"
echo " 会导致 ros2 run 起来的节点跑在错误的环境里)"
fi
return 0
}