Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update documentation to reflect new install entry script.
  • Loading branch information
freakboy3742 committed Sep 17, 2025
commit d56a3deb8a2aaf79e4de233f3fd01820f559c485
121 changes: 26 additions & 95 deletions Doc/using/ios.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,22 +180,19 @@ To add Python to an iOS Xcode project:
of your project; however, you can use any other location that you want by
adjusting paths as needed.

3. Drag the ``Apple/iOS/Resources/dylib-Info-template.plist`` file into your project,
and ensure it is associated with the app target.

4. Add your application code as a folder in your Xcode project. In the
3. Add your application code as a folder in your Xcode project. In the
following instructions, we'll assume that your user code is in a folder
named ``app`` in the root of your project; you can use any other location by
adjusting paths as needed. Ensure that this folder is associated with your
app target.

5. Select the app target by selecting the root node of your Xcode project, then
4. Select the app target by selecting the root node of your Xcode project, then
the target name in the sidebar that appears.

6. In the "General" settings, under "Frameworks, Libraries and Embedded
5. In the "General" settings, under "Frameworks, Libraries and Embedded
Content", add ``Python.xcframework``, with "Embed & Sign" selected.

7. In the "Build Settings" tab, modify the following:
6. In the "Build Settings" tab, modify the following:

- Build Options

Expand All @@ -211,87 +208,24 @@ To add Python to an iOS Xcode project:

* Quoted Include In Framework Header: No

8. Add a build step that copies the Python standard library into your app. In
the "Build Phases" tab, add a new "Run Script" build step *before* the
"Embed Frameworks" step, but *after* the "Copy Bundle Resources" step. Name
the step "Install Target Specific Python Standard Library", disable the
"Based on dependency analysis" checkbox, and set the script content to:
7. Add a build step that processes the Python standard library, and your own
Python binary dependencies. In the "Build Phases" tab, add a new "Run
Script" build step *before* the "Embed Frameworks" step, but *after* the
"Copy Bundle Resources" step. Name the step "Process Python libraries",
disable the "Based on dependency analysis" checkbox, and set the script
content to:

.. code-block:: bash

set -e

mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib"
if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then
echo "Installing Python modules for iOS Simulator"
rsync -au --delete "$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
else
echo "Installing Python modules for iOS Device"
rsync -au --delete "$PROJECT_DIR/Python.xcframework/ios-arm64/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
fi
set -e
source $PROJECT_DIR/Python.xcframework/build/build_utils.sh
install_python Python.xcframework app

Note that the name of the simulator "slice" in the XCframework may be
different, depending the CPU architectures your ``XCFramework`` supports.
If you have placed your XCframework somewhere other than the root of your
project, modify the path to the first argument.

9. Add a second build step that processes the binary extension modules in the
standard library into "Framework" format. Add a "Run Script" build step
*directly after* the one you added in step 8, named "Prepare Python Binary
Modules". It should also have "Based on dependency analysis" unchecked, with
the following script content:

.. code-block:: bash

set -e

install_dylib () {
INSTALL_BASE=$1
FULL_EXT=$2

# The name of the extension file
EXT=$(basename "$FULL_EXT")
# The location of the extension file, relative to the bundle
RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/}
# The path to the extension file, relative to the install base
PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}
# The full dotted name of the extension module, constructed from the file path.
FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d "." -f 1 | tr "/" ".");
# A bundle identifier; not actually used, but required by Xcode framework packaging
FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-")
# The name of the framework folder.
FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework"

# If the framework folder doesn't exist, create it.
if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then
echo "Creating framework for $RELATIVE_EXT"
mkdir -p "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER"

cp "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist"
plutil -replace CFBundleExecutable -string "$FULL_MODULE_NAME" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist"
plutil -replace CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist"
fi

echo "Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME"
mv "$FULL_EXT" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME"
# Create a placeholder .fwork file where the .so was
echo "$FRAMEWORK_FOLDER/$FULL_MODULE_NAME" > ${FULL_EXT%.so}.fwork
# Create a back reference to the .so file location in the framework
echo "${RELATIVE_EXT%.so}.fwork" > "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin"
}

PYTHON_VER=$(ls -1 "$CODESIGNING_FOLDER_PATH/python/lib")
echo "Install Python $PYTHON_VER standard library extension modules..."
find "$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload" -name "*.so" | while read FULL_EXT; do
install_dylib python/lib/$PYTHON_VER/lib-dynload/ "$FULL_EXT"
done

# Clean up dylib template
rm -f "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist"

echo "Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)..."
find "$CODESIGNING_FOLDER_PATH/Frameworks" -name "*.framework" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der "{}" \;

10. Add Objective C code to initialize and use a Python interpreter in embedded
mode. You should ensure that:
8. Add Objective C code to initialize and use a Python interpreter in embedded
mode. You should ensure that:

* UTF-8 mode (:c:member:`PyPreConfig.utf8_mode`) is *enabled*;
* Buffered stdio (:c:member:`PyConfig.buffered_stdio`) is *disabled*;
Expand All @@ -310,22 +244,19 @@ To add Python to an iOS Xcode project:
Your app's bundle location can be determined using ``[[NSBundle mainBundle]
resourcePath]``.

Steps 8, 9 and 10 of these instructions assume that you have a single folder of
Steps 7 and 8 of these instructions assume that you have a single folder of
pure Python application code, named ``app``. If you have third-party binary
modules in your app, some additional steps will be required:

* You need to ensure that any folders containing third-party binaries are
either associated with the app target, or copied in as part of step 8. Step 8
should also purge any binaries that are not appropriate for the platform a
specific build is targeting (i.e., delete any device binaries if you're
building an app targeting the simulator).

* Any folders that contain third-party binaries must be processed into
framework form by step 9. The invocation of ``install_dylib`` that processes
the ``lib-dynload`` folder can be copied and adapted for this purpose.

* If you're using a separate folder for third-party packages, ensure that folder
is included as part of the :envvar:`PYTHONPATH` configuration in step 10.
either associated with the app target, or are explicitly copied as part of
step 7. Step 7 should also purge any binaries that are not appropriate for
the platform a specific build is targeting (i.e., delete any device binaries
if you're building an app targeting the simulator).

* If you're using a separate folder for third-party packages, ensure that
folder is added to the end of the call to ``install_python`` in step 7, and
as part of the :envvar:`PYTHONPATH` configuration in step 8.

* If any of the folders that contain third-party packages will contain ``.pth``
files, you should add that folder as a *site directory* (using
Expand Down