CPython opens the stdlib zip with its own stdio, so it needs a real path.
On the desktop res:// is a directory and globalize_path() is enough; in an
exported build res:// is inside the PCK, which nothing outside Godot reads.
make_stdlib_zip.py now also writes <out>.sha256
mtpython_stdlib_project copies python27.zip + .sha256 into project/
(gitignored), and both export presets' include_filter lists them, so
they enter the PCK — checked with --export-pack
extension/src/python_stdlib.{h,cpp} (Metin2Python.stdlib_path in
GDScript): reads the bytes out of the PCK, writes
user://python27.zip.part, hashes the file as written against the
shipped digest, then renames. A sandbox copy is reused only when it
matches, so a first start killed mid-copy and a zip replaced by a new
build both re-stage instead of feeding zipimport a torn file.
PythonHost::SetDefaultStdLibPath / DefaultStdLibPath() answer with that
path ($MT_PYTHON_STDLIB still wins). python_stdlib.cpp is the only unit
that knows res:// / user://; port_platform stays godot-free.
Also fixes the Windows gate, which step 3b broke: without mtpython the
MinGW build compiled UserInterface/StdAfx.h (it includes ScriptLib/StdAfx.h,
as the original PCH does). port/CMakeLists.txt excludes that header and
PythonPackModule.cpp with ScriptLib, and platform/CMakeLists.txt excludes
platform/ScriptLib/ the same way.
Not done: on-device staging. The macOS test drives the mobile path with
force_stage=true, and nothing in the app boot calls it yet — the
interpreter only starts in the process with 2V0.
gates: python_stdlib_test.gd PASS (in-place path, staging, sha256, bytes
equal res://, no .part, ZIPReader finds encodings/__init__.py, no re-copy
on a second call, corrupted copy re-staged) · macOS ctest 27/27 ·
mingw + android + ios port_platform compile clean · port_map.py check 0
errors · key leak check 8/8 none.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
226 lines
7.9 KiB
CMake
226 lines
7.9 KiB
CMake
# mtpython — CPython 2.7.18 as a static library for the embedded 40250 script layer
|
|
# (docs/PORT-PLAN.md 批次 2P step 1). Upstream source is the official Python-2.7.18 tarball
|
|
# (sha256 b62c0e79...def43), trimmed of Doc/Demo/Tools/Mac/PCbuild and the stdlib test trees;
|
|
# see docs/THIRD-PARTY.md for the two vendor patches.
|
|
#
|
|
# The source list and the built-in module table (config/config.c, config/Setup.static) are SHARED
|
|
# by every platform: they are exactly the objects the reference autotools build puts in
|
|
# libpython2.7.a. `pyconfig.h` is NOT shared — it is the result of probing one platform's type
|
|
# sizes and system calls, so each platform keeps its own under config/<platform>/.
|
|
#
|
|
# Windows is not built here yet: it needs PC/pyconfig.h, PC/getpathp.c, Python/dynload_win.c and a
|
|
# PC built-in table of its own (nt instead of posix, no fcntl/pwd). Upstream 2.7 supports MSVC there,
|
|
# while our Windows gate cross-compiles with MinGW, where PC/pyconfig.h's gnu-win32 branch leaves
|
|
# HAVE_UNISTD_H unset and posixmodule.c/dynload_win.c collide with the MinGW headers — so it needs a
|
|
# patch series, decided in PORT-PLAN 批次 2P step 4. See docs/THIRD-PARTY.md.
|
|
|
|
set(MT_PYTHON_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
# MT_PYTHON_PLATFORM is the reference build's MACHDEP, which becomes sys.platform.
|
|
if(ANDROID)
|
|
set(MT_PYTHON_CONFIG android)
|
|
set(MT_PYTHON_PLATFORM linux2)
|
|
elseif(IOS OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
|
set(MT_PYTHON_CONFIG ios)
|
|
set(MT_PYTHON_PLATFORM darwin)
|
|
elseif(APPLE)
|
|
set(MT_PYTHON_CONFIG macos)
|
|
set(MT_PYTHON_PLATFORM darwin)
|
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
set(MT_PYTHON_CONFIG linux)
|
|
set(MT_PYTHON_PLATFORM linux2)
|
|
else()
|
|
message(FATAL_ERROR "mtpython: no pyconfig.h for ${CMAKE_SYSTEM_NAME} yet (see the header of this file)")
|
|
endif()
|
|
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/config/${MT_PYTHON_CONFIG}/pyconfig.h")
|
|
message(FATAL_ERROR "mtpython: config/${MT_PYTHON_CONFIG}/pyconfig.h is missing; generate it with "
|
|
"tools/py_embed/gen_pyconfig.sh ${MT_PYTHON_CONFIG}")
|
|
endif()
|
|
|
|
add_library(mtpython STATIC
|
|
config/config.c
|
|
Modules/_bisectmodule.c
|
|
Modules/_codecsmodule.c
|
|
Modules/_collectionsmodule.c
|
|
Modules/_functoolsmodule.c
|
|
Modules/_heapqmodule.c
|
|
Modules/_localemodule.c
|
|
Modules/_math.c
|
|
Modules/_randommodule.c
|
|
Modules/_sre.c
|
|
Modules/_struct.c
|
|
Modules/_weakref.c
|
|
Modules/arraymodule.c
|
|
Modules/binascii.c
|
|
Modules/cPickle.c
|
|
Modules/cStringIO.c
|
|
Modules/datetimemodule.c
|
|
Modules/errnomodule.c
|
|
Modules/fcntlmodule.c
|
|
Modules/gcmodule.c
|
|
Modules/getbuildinfo.c
|
|
Modules/getpath.c
|
|
Modules/itertoolsmodule.c
|
|
Modules/main.c
|
|
Modules/mathmodule.c
|
|
Modules/operator.c
|
|
Modules/posixmodule.c
|
|
Modules/pwdmodule.c
|
|
Modules/selectmodule.c
|
|
Modules/signalmodule.c
|
|
Modules/stropmodule.c
|
|
Modules/symtablemodule.c
|
|
Modules/threadmodule.c
|
|
Modules/timemodule.c
|
|
Modules/xxsubtype.c
|
|
Modules/zipimport.c
|
|
Objects/abstract.c
|
|
Objects/boolobject.c
|
|
Objects/bufferobject.c
|
|
Objects/bytearrayobject.c
|
|
Objects/bytes_methods.c
|
|
Objects/capsule.c
|
|
Objects/cellobject.c
|
|
Objects/classobject.c
|
|
Objects/cobject.c
|
|
Objects/codeobject.c
|
|
Objects/complexobject.c
|
|
Objects/descrobject.c
|
|
Objects/dictobject.c
|
|
Objects/enumobject.c
|
|
Objects/exceptions.c
|
|
Objects/fileobject.c
|
|
Objects/floatobject.c
|
|
Objects/frameobject.c
|
|
Objects/funcobject.c
|
|
Objects/genobject.c
|
|
Objects/intobject.c
|
|
Objects/iterobject.c
|
|
Objects/listobject.c
|
|
Objects/longobject.c
|
|
Objects/memoryobject.c
|
|
Objects/methodobject.c
|
|
Objects/moduleobject.c
|
|
Objects/object.c
|
|
Objects/obmalloc.c
|
|
Objects/rangeobject.c
|
|
Objects/setobject.c
|
|
Objects/sliceobject.c
|
|
Objects/stringobject.c
|
|
Objects/structseq.c
|
|
Objects/tupleobject.c
|
|
Objects/typeobject.c
|
|
Objects/unicodectype.c
|
|
Objects/unicodeobject.c
|
|
Objects/weakrefobject.c
|
|
Parser/acceler.c
|
|
Parser/bitset.c
|
|
Parser/firstsets.c
|
|
Parser/grammar.c
|
|
Parser/grammar1.c
|
|
Parser/listnode.c
|
|
Parser/metagrammar.c
|
|
Parser/myreadline.c
|
|
Parser/node.c
|
|
Parser/parser.c
|
|
Parser/parsetok.c
|
|
Parser/pgen.c
|
|
Parser/tokenizer.c
|
|
Python/Python-ast.c
|
|
Python/_warnings.c
|
|
Python/asdl.c
|
|
Python/ast.c
|
|
Python/bltinmodule.c
|
|
Python/ceval.c
|
|
Python/codecs.c
|
|
Python/compile.c
|
|
Python/dtoa.c
|
|
Python/dynload_shlib.c
|
|
Python/errors.c
|
|
Python/formatter_string.c
|
|
Python/formatter_unicode.c
|
|
Python/frozen.c
|
|
Python/frozenmain.c
|
|
Python/future.c
|
|
Python/getargs.c
|
|
Python/getcompiler.c
|
|
Python/getcopyright.c
|
|
Python/getopt.c
|
|
Python/getplatform.c
|
|
Python/getversion.c
|
|
Python/graminit.c
|
|
Python/import.c
|
|
Python/importdl.c
|
|
Python/marshal.c
|
|
Python/modsupport.c
|
|
Python/mysnprintf.c
|
|
Python/mystrtoul.c
|
|
Python/peephole.c
|
|
Python/pyarena.c
|
|
Python/pyctype.c
|
|
Python/pyfpe.c
|
|
Python/pymath.c
|
|
Python/pystate.c
|
|
Python/pystrcmp.c
|
|
Python/pystrtod.c
|
|
Python/pythonrun.c
|
|
Python/random.c
|
|
Python/structmember.c
|
|
Python/symtable.c
|
|
Python/sysmodule.c
|
|
Python/thread.c
|
|
Python/traceback.c
|
|
)
|
|
|
|
# Python/mactoolboxglue.c is compiled only where pyconfig.h sets USE_TOOLBOX_OBJECT_GLUE (macOS).
|
|
if(MT_PYTHON_CONFIG STREQUAL macos)
|
|
target_sources(mtpython PRIVATE Python/mactoolboxglue.c)
|
|
endif()
|
|
|
|
target_include_directories(mtpython PUBLIC
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/config/${MT_PYTHON_CONFIG}"
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/Include"
|
|
)
|
|
target_include_directories(mtpython PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/Modules")
|
|
|
|
# The reference Makefile's PY_CFLAGS, plus the per-file defines it passes to getpath.c and
|
|
# getplatform.c. The interpreter runs with Py_IgnoreEnvironmentFlag/Py_NoSiteFlag and gets its
|
|
# sys.path from the host, so PREFIX/PYTHONPATH only feed getpath.c's unused defaults.
|
|
target_compile_definitions(mtpython PRIVATE
|
|
Py_BUILD_CORE
|
|
NDEBUG
|
|
PREFIX="/usr/local"
|
|
EXEC_PREFIX="/usr/local"
|
|
VERSION="2.7"
|
|
VPATH=""
|
|
PYTHONPATH=""
|
|
PLATFORM="${MT_PYTHON_PLATFORM}"
|
|
)
|
|
target_compile_options(mtpython PRIVATE -fno-strict-aliasing -fwrapv -w)
|
|
# The 2.7 headers still use `register`, which C++17 removed; every C++ consumer needs this (MSVC: /wd5033).
|
|
target_compile_options(mtpython INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-Wno-register>)
|
|
set_target_properties(mtpython PROPERTIES C_STANDARD 99 POSITION_INDEPENDENT_CODE ON)
|
|
if(NOT ANDROID AND NOT IOS AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
|
find_library(MT_PYTHON_DL dl)
|
|
if(MT_PYTHON_DL)
|
|
target_link_libraries(mtpython PUBLIC ${MT_PYTHON_DL})
|
|
endif()
|
|
endif()
|
|
find_package(Threads REQUIRED)
|
|
target_link_libraries(mtpython PUBLIC Threads::Threads m)
|
|
add_library(mt3p::python ALIAS mtpython)
|
|
|
|
# --- the stdlib the host puts on sys.path (批次 2P step 3) ---
|
|
# Built from the same vendored Lib/, so the interpreter and its library always match. MT_PYTHON_STDLIB_ZIP
|
|
# is where every consumer (the native tests now, the mobile staging in step 3c) picks it up.
|
|
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
|
set(MT_PYTHON_STDLIB_ZIP "${CMAKE_BINARY_DIR}/python27.zip" CACHE INTERNAL "stdlib zip for the embedded interpreter")
|
|
set(MT_PYTHON_STDLIB_SHA "${MT_PYTHON_STDLIB_ZIP}.sha256" CACHE INTERNAL "sha256 of MT_PYTHON_STDLIB_ZIP")
|
|
file(GLOB_RECURSE MT_PYTHON_STDLIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/Lib/*.py")
|
|
add_custom_command(OUTPUT "${MT_PYTHON_STDLIB_ZIP}" "${MT_PYTHON_STDLIB_SHA}"
|
|
COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/tools/py_embed/make_stdlib_zip.py"
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/Lib" "${MT_PYTHON_STDLIB_ZIP}"
|
|
DEPENDS "${CMAKE_SOURCE_DIR}/tools/py_embed/make_stdlib_zip.py" ${MT_PYTHON_STDLIB_SOURCES}
|
|
COMMENT "Packing python27.zip from the vendored Lib/")
|
|
add_custom_target(mtpython_stdlib ALL DEPENDS "${MT_PYTHON_STDLIB_ZIP}" "${MT_PYTHON_STDLIB_SHA}")
|