Skip to content

iOS: put the stdlib and the python/ payload inside the .app and set PYTHONHOME #59

Closed

Description

@b-re-w

PythonPayload.ios.kt looks for <mainBundle.resourcePath>/python, but nothing attaches python/ to the .app (no Xcode folder-reference copy phase, no build-order dependency, no device/simulator proof). The stdlib is extracted to build/python-stdlib/ and passed to tests via SIMCTL_CHILD_PYTHONHOME only; an installed app gets no stdlib and no PYTHONHOME (a PYTHONHOME on the external volume can hang at 0% CPU, iosMain/README).

Scope: a Gradle task + documented Xcode build phase that copies the stdlib and the python/ payload (from toolchain's staging, or the app's own) into the app bundle; Python3.initialize on iOS sets PYTHONHOME to the bundled stdlib. Ownership: python-multiplatform owns interpreter/stdlib and the Xcode wiring; toolchain produces python/ (toolchain#20).

Completion: sample iOS app on the simulator imports a stdlib module and a payload module from the installed bundle with no SIMCTL env.

Activity

  1. b-re-w commented on Oct 3, 2026

    @b-re-w
    MemberAuthor

    Input from toolchain#20 research (PMM build session):

    • Loader path: NSBundle.mainBundle.resourcePath + "/python" = $TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/python (PythonPayload.ios.kt:44-49). toolchain's build/pythonStaging/ios/python/ (task stagePythonBundleIos) already has that layout; copy as is.
    • Copy as a folder reference, not a group (a group flattens packages; init.py files collide); run after the Gradle task; keep stdlib and payload inside the bundle.
    • Natural route: mirror Compose MP's resource copy ($BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/compose-resources) with a Gradle task the Xcode Run Script calls; toolchain offers a thin stagePythonBundleIosForXcode if a single entry point helps.
    • usage-example/src/iosMain/app.xcodeproj: one Run Script (embedAndSignAppleFrameworkForXcode); its iosApp group path=iosApp while Swift files are in swift/ — looks broken.
  2. b-re-w commented on Oct 3, 2026

    @b-re-w
    MemberAuthor

    Xcode phase contract (toolchain#43 stagePythonBundleIosForXcode prints one line PYTHON_PAYLOAD_DIR=<abs path> under -q and fails when there is no payload). The phase MUST NOT pipe Gradle into sed and rsync from the result unguarded: with a failing Gradle the substitution is empty and rsync -a --delete "/" ... copies the root filesystem. Use:

    set -euo pipefail
    out=$(./gradlew -q :app:stagePythonBundleIosForXcode)
    dir=$(printf '%s\n' "$out" | sed -n 's/^PYTHON_PAYLOAD_DIR=//p')
    [ -n "$dir" ] && [ -d "$dir" ] || { echo "error: no Python payload dir from Gradle" >&2; exit 1; }
    rsync -a --delete "$dir/" "$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/python/"
    
  3. b-re-w commented on Oct 3, 2026

    @b-re-w
    MemberAuthor

    Landed in develop via #89.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions