build_secure.sh 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env bash
  2. # ============================================================
  3. # build_secure.sh — 用 Nuitka 把 lambdagent / agentpaas 编成原生 .so,
  4. # 再重打包成「编译后 wheel」放进 dist-secure/。
  5. #
  6. # 与普通 wheel 的区别:解开 .whl 只有机器码 .so,没有 .py 源码。
  7. # 产物是「平台 + Python 小版本」绑定的(如 cp311 + macOS arm64),
  8. # 换架构/换 Python 小版本需在对应环境重新构建。
  9. #
  10. # 用法: scripts/build_secure.sh [PYTHON]
  11. # PYTHON 默认 python3;必须是「原生架构 + 3.10+ + 带头文件」的解释器,
  12. # 且该 Python 的版本即决定产出 wheel 的 cpXXX 标签。
  13. #
  14. # 前置: C 编译器(macOS: xcode-select --install)
  15. # ============================================================
  16. set -e
  17. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  18. PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
  19. cd "$PROJECT_DIR"
  20. RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
  21. info() { echo -e "${BLUE}[INFO]${NC} $1"; }
  22. ok() { echo -e "${GREEN}[OK]${NC} $1"; }
  23. warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
  24. fail() { echo -e "${RED}[FAIL]${NC} $1"; exit 1; }
  25. PYTHON="${1:-python3}"
  26. command -v "$PYTHON" >/dev/null 2>&1 || fail "未找到 Python: $PYTHON"
  27. # ── 架构/版本/头文件检查 ──────────────────────────────────
  28. read -r PYVER PYARCH HAVE_H <<EOF
  29. $("$PYTHON" - <<'PY'
  30. import platform, sysconfig, os
  31. inc = sysconfig.get_path('include')
  32. print(f"{platform.python_version()} {platform.machine()} {int(os.path.exists(os.path.join(inc,'Python.h')))}")
  33. PY
  34. )
  35. EOF
  36. info "构建解释器: $PYTHON (Python $PYVER, $PYARCH)"
  37. HOSTARCH="$(uname -m)"
  38. if [ "$PYARCH" != "$HOSTARCH" ]; then
  39. warn "Python 架构($PYARCH) ≠ 主机架构($HOSTARCH)。"
  40. warn "多半是 Rosetta 下的 x86_64 Python,会编出错架构的 .so。"
  41. warn "请改用原生 $HOSTARCH 的 Python(如 Homebrew 的 python3.11)。"
  42. fail "架构不匹配,已中止。"
  43. fi
  44. [ "$HAVE_H" = "1" ] || fail "缺 Python.h 头文件,无法编译。请装带头文件的 Python(如 Homebrew)。"
  45. # ── 构建专用 venv(装 nuitka,不污染用户环境)──────────────
  46. BUILD_VENV="$PROJECT_DIR/.nuitka-venv"
  47. if [ ! -x "$BUILD_VENV/bin/python" ]; then
  48. info "创建构建环境 .nuitka-venv ..."
  49. "$PYTHON" -m venv "$BUILD_VENV"
  50. fi
  51. BPY="$BUILD_VENV/bin/python"
  52. "$BPY" -m pip install -q --upgrade pip nuitka packaging wheel
  53. # ── 1) 普通 wheel(保留正确的依赖元数据,repack 会复用)────
  54. info "构建基准 wheel(取依赖元数据)..."
  55. mkdir -p dist
  56. rm -f dist/lambdagent-*.whl dist/agentpaas-*.whl
  57. "$BPY" -m pip wheel --no-deps ./lambdagent -w dist/ --quiet
  58. "$BPY" -m pip wheel --no-deps ./agentpaas -w dist/ --quiet
  59. # ── 2) Nuitka 编译两个包为整包 .so ────────────────────────
  60. NOUT="$PROJECT_DIR/build_nuitka"
  61. rm -rf "$NOUT"; mkdir -p "$NOUT"
  62. COMMON_FLAGS=(--include-package-data=. --python-flag=no_docstrings --remove-output --assume-yes-for-downloads)
  63. info "Nuitka 编译 lambdagent(可能数分钟)..."
  64. "$BPY" -m nuitka --module lambdagent/src/lambdagent \
  65. --include-package=lambdagent --include-package-data=lambdagent \
  66. --python-flag=no_docstrings --remove-output --assume-yes-for-downloads \
  67. --output-dir="$NOUT"
  68. info "Nuitka 编译 agentpaas(可能数分钟)..."
  69. "$BPY" -m nuitka --module agentpaas/src/agentpaas \
  70. --include-package=agentpaas --include-package-data=agentpaas \
  71. --python-flag=no_docstrings --remove-output --assume-yes-for-downloads \
  72. --output-dir="$NOUT"
  73. LG_SO=$(ls "$NOUT"/lambdagent.*.so 2>/dev/null | head -1)
  74. AP_SO=$(ls "$NOUT"/agentpaas.*.so 2>/dev/null | head -1)
  75. [ -f "$LG_SO" ] && [ -f "$AP_SO" ] || fail "未找到编译产物 .so"
  76. # ── 3) 平台 tag ───────────────────────────────────────────
  77. TAG=$("$BPY" -c "from packaging.tags import sys_tags; t=next(iter(sys_tags())); print(f'{t.interpreter}-{t.abi}-{t.platform}')")
  78. info "目标 wheel 标签: $TAG"
  79. # ── 4) 重打包成 .so wheel ─────────────────────────────────
  80. mkdir -p dist-secure
  81. rm -f dist-secure/lambdagent-*.whl dist-secure/agentpaas-*.whl
  82. "$BPY" scripts/repack_wheel_so.py --wheel dist/lambdagent-*.whl --so "$LG_SO" --package lambdagent --tag "$TAG" --out dist-secure/
  83. "$BPY" scripts/repack_wheel_so.py --wheel dist/agentpaas-*.whl --so "$AP_SO" --package agentpaas --tag "$TAG" --out dist-secure/
  84. echo ""
  85. ok "编译版 wheel 已生成 → dist-secure/"
  86. for w in dist-secure/*.whl; do
  87. npy=$(unzip -l "$w" | grep -cE '\.py$'); nso=$(unzip -l "$w" | grep -cE '\.so$')
  88. echo " $(basename "$w") [.py=$npy .so=$nso]"
  89. done
  90. echo ""
  91. echo " 下一步: ./setup.sh --package # 会优先用 dist-secure/ 里的编译 wheel 组装发行包"
  92. echo ""
  93. warn "提醒: 编译版 wheel 绑定 $TAG —— 用户的 Python 小版本与架构需匹配。"
  94. warn " 逻辑已编成机器码不可反编译,但日志/prompt 等字符串常量仍可被 strings 提取(开源版 Nuitka 限制)。"