Files
mtgodot-poc/tools/py_embed/make_stdlib_zip.py
T
shenleiandClaude Opus 5 2b873f190f port(2P step 3a/3b): stdlib on sys.path + the pack module
step 3a — 标准库:
  tools/py_embed/make_stdlib_zip.py packs the vendored Lib/ into
  <build>/python27.zip (397 modules, 6876547 bytes, ZIP_STORED — the zlib
  module is trimmed out of our CPython, so zipimport cannot inflate).
  The mtpython_stdlib target builds it; py_embed_test and the launcher test
  both run against it.
  platform/ScriptLib/PythonHost sets the embedding flags before
  Py_Initialize and, after it, puts the zip on sys.path and re-registers
  encodings.search_function with codecs — 2.7 builds the codec registry
  once, at startup, so replacing sys.path afterwards needs it back.

step 3b — pack 模块:
  UserInterface/PythonPackModule.cpp copied verbatim; packExist/packGet/
  initpack read root/ and uiscript/ through CEterPackManager, i.e. through
  asset_io. The CHINA_CRYPT_KEY block in that unit is CAccountConnector's
  and is kept #if 0 until the login slice (2V1). UserInterface/StdAfx.h is
  a documented partial mirror — the original is the whole client's PCH.

The launcher test now runs initpack() as RunMainScript does (its first
line), reads system.py / uiscript / locale text back out of the packs, and
confirms cp1252 decoding works off the zip. system.py still stops at
"No module named app" — the C++ modules are the 2V0 slice.

gates: port_map.py check 0 errors · key leak check 8/8 none · macOS ctest
27/27 · android + ios port_platform compile clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 09:16:37 +09:00

60 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Pack the vendored CPython 2.7.18 Lib/ into the python27.zip the host puts on sys.path.
make_stdlib_zip.py <Lib dir> <out.zip>
40250 shipped a real python27 installation, so `import encodings` found Lib/ through the
interpreter's prefix. The embedded interpreter has no prefix (Py_FrozenFlag, no site), so the host
supplies the stdlib as this one file — the arrangement validated on the device by
tools/py_embed_android/build-and-run.sh (PORT-PLAN 批次 2P step 3).
Entries are STORED, never deflated: the zlib module is not in the vendored Modules/ (see
docs/THIRD-PARTY.md), so zipimport could not inflate them. Only .py goes in; zipimport reads
source as happily as bytecode, and .pyc would pin the magic number to the build host's interpreter.
Written deterministically (sorted, fixed timestamp) so the file's sha256 identifies its contents —
3c checks that hash when staging the zip into a mobile sandbox.
"""
from __future__ import annotations
import sys
import zipfile
from pathlib import Path
# Test suites, the Tk/2to3/bsddb/pip trees and the platform-specific stubs: none of the 40250 scripts
# or their imports reach them, and they are most of the size.
SKIP_DIRS = {"test", "tests", "lib-tk", "idlelib", "lib2to3", "bsddb", "ensurepip", "curses",
"distutils", "unittest", "wsgiref", "multiprocessing", "compiler"}
def main() -> int:
if len(sys.argv) != 3:
print(__doc__, file=sys.stderr)
return 2
lib, out = Path(sys.argv[1]), Path(sys.argv[2])
if not (lib / "os.py").is_file():
print(f"make_stdlib_zip: {lib} is not a CPython Lib/ directory", file=sys.stderr)
return 1
members = []
for path in sorted(lib.rglob("*.py")):
rel = path.relative_to(lib)
if rel.parts[0].startswith("plat-") or SKIP_DIRS.intersection(rel.parts[:-1]):
continue
members.append((rel, path))
out.parent.mkdir(parents=True, exist_ok=True)
tmp = out.with_suffix(".zip.tmp")
with zipfile.ZipFile(tmp, "w", zipfile.ZIP_STORED) as zf:
for rel, path in members:
info = zipfile.ZipInfo(rel.as_posix(), date_time=(1980, 1, 1, 0, 0, 0))
info.external_attr = 0o644 << 16
zf.writestr(info, path.read_bytes())
tmp.replace(out)
print(f"make_stdlib_zip: {out} ({len(members)} modules, {out.stat().st_size} bytes)")
return 0
if __name__ == "__main__":
raise SystemExit(main())