Skip to content

[depends][target][python] build as a real iOS platform - #28808

Merged
kambala-decapitator merged 1 commit into
xbmc:masterfrom
kambala-decapitator:python-ios
Aug 11, 2026
Merged

kambala-decapitator merged 1 commit into
xbmc:masterfrom
kambala-decapitator:python-ios

Conversation

@kambala-decapitator

Copy link
Copy Markdown
Contributor

Description

This change builds Python as a real iOS platform instead of just Darwin-like:

  • sys.platform reports ios instead of darwin
  • platform.platform() returns iPadOS-15.8.8-iPad5,4-arm64-64bit instead of macOS-15.8.8-iPad5,4-64bit for an iPad running iOS 15

As a positive side effect, Pycryptodome library (coming from script.module.pycryptodome) starts working on iOS. Previously it failed at loading native binary libs (it uses custom loading logic unlike PIL for example) with

EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
                                                    - NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
                                                   Error Type: <class 'ModuleNotFoundError'>
                                                   Error Contents: No module named '_posixsubprocess'
                                                   Traceback (most recent call last):
                                                     File "/var/containers/Bundle/Application/29AAD392-8750-432E-99FB-8ABD7CE94F82/Kodi.app/Frameworks/lib/python3.14/site-packages/Cryptodome/Util/_raw_api.py", line 85, in <module>
                                                       from cffi import FFI
                                                   ModuleNotFoundError: No module named 'cffi'

The new patch does the following:

  1. enforces platform to be iOS. Default platform detection doesn't work because python inspects host / host_alias which we set as aarch64-apple-darwin and overriding those isn't possible because values in config.site have the highest priority.
  2. strips requirement to build as a (dynamic) framework and related flags. There's no real requirement to package Python as a framework, probably apart from convenient packaging of python code.
  3. injects IPHONEOS_DEPLOYMENT_TARGET from environment. By default python is trying to infer the deployment target from host (which isn't possible in our case) and sets 13.0 as a fallback (the officially supported minimum iOS version). But we target 12.0 currently.
  4. removes exception when Python can't load the system objc library using its internal mechanism and forces lib path to a well-known location /usr/lib/libobjc.dylib. This happens on iOS 12 (and possibly 13 as well) due to the following python logic: try to read from disk from standard system locations (this always fails due to app sandboxing) or obtain lib path from dyld cache if possible (respective function _dyld_shared_cache_contains_path is available only on iOS >= 14). But a simple test showed that while you can't stat or check existence of the library file at /usr/lib (sandboxing), dlopen still succeeds in loading such a library.

Motivation and context

Preparation for TestFlight / AppStore. When Python detects that it was built for iOS (actually for Apple non-macOS if you look at the code), it enables AppleFrameworkLoader that can load binary libs from custom locations (for AppStore it must be <app bundle>/Frameworks). It requires proper packaging though and will be done in a following PR.

How has this been tested?

local test on iOS 12, 15 and 26 devices

What is the effect on users?

addons that rely on script.module.pycryptodome can be used on iOS now

Types of change

  • Bug fix (non-breaking change which fixes an issue)
  • Clean up (non-breaking change which removes non-working, unmaintained functionality)
  • Improvement (non-breaking change which improves existing functionality)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that will cause existing functionality to change)
  • Cosmetic change (non-breaking change that doesn't touch code)
  • Student submission (PR was done for educational purposes and will be treated as such)
  • None of the above (please explain below)

Checklist:

  • My code follows the Code Guidelines of this project
  • My change requires a change to the documentation, either Doxygen or wiki
  • I have updated the documentation accordingly
  • I have read the Contributing document
  • I have added tests to cover my change
  • All new and existing tests passed

@kodiai

kodiai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

Decision: APPROVE

Issues: none

Evidence:

  • Review prompt covered 3 changed files.
Review Details
  • Files reviewed: 3

  • Findings: 0 critical, 0 major, 0 medium, 0 minor

  • Lines changed: +157 -1

  • Profile: balanced (auto, lines changed: 158)

  • Contributor experience: profile-backed (using linked contributor profile guidance)

  • Review completed: 2026-08-01T11:12:33.514Z

  • Total wall-clock: 6m 29s

  • Phase timings:

    • queue wait: 0ms
    • workspace preparation: 12s
    • retrieval/context assembly: 21s
    • executor handoff: 3.0s
    • remote runtime: 5m 50s
    • publication: 115ms (degraded: captured before publication completed)
  • Tokens: 78 in / 15,377 out | 0.4282

  • Keyword parsing: No keywords detected

  • Budget behavior: complete (within-budget).

  • Prompt budget: 5 sections, 0 trimmed, 0 bypassed, 0 trimmed tokens.

  • Cache behavior: 2 observations, 1 hits, 1 misses, 0 degraded, 0 bypassed.

  • Continuation behavior: 0 observations, 0 compacted, 0 fallback, 0 degraded, 0 bypassed.

@clementperon

clementperon commented Aug 2, 2026 •

Copy link
Copy Markdown
Contributor

Don't want to make you rework the whole thing but this seems to be a bit too much hacky... I think we could reduce a bit the python patch.

first in tools/depends/target/config.site.in we don't enforce the host if it's provide by package

 if test "@cross_compiling@" = "yes"; then
 cross_compiling=yes
-host=@use_host@
-host_alias=@use_host@
+: ${host=@use_host@}
+: ${host_alias=@use_host@}
 fi

in tools/depends/target/python3/Makefile we force the host to match ios triplet

+  ifeq ($(findstring iphone,$(TARGET_PLATFORM)),iphone)
+    # Build as a real iOS platform (sys.platform == "ios") instead of Darwin.
+    PYTHON_HOST=$(subst -darwin,-ios$(APPLE_DEPLOYMENT_TARGET),$(HOST))
+    ifeq ($(TARGET_PLATFORM),iphonesimulator)
+      PYTHON_HOST:=$(PYTHON_HOST)-simulator
+    endif
+    EXTRA_CONFIGURE+= --host=$(PYTHON_HOST)
+  endif

then the python patch is much more smaller something like only to support the static compilation that should be upstream properly: remove the --enable-framework and avoid duplicate -mios-version-min :

--- a/configure.ac
+++ b/configure.ac
@@ -570,7 +570,6 @@
      case $enableval in
      no)
              case $ac_sys_system in
-                     iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
                      *)
@@ -680,7 +679,6 @@
              esac
      ],[
      case $ac_sys_system in
-             iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
              *)
@@ -986,13 +984,6 @@
-dnl Add the compiler flag for the iOS minimum supported OS version.
-AS_CASE([$ac_sys_system],
-  [iOS], [
-    AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"])
-    AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"])
-  ],
-)
@@ -3658,7 +3649,7 @@
              elif test $ac_sys_system = "iOS"; then
-                     LINKFORSHARED="… $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
+                     LINKFORSHARED="… $LINKFORSHARED "
@@ -6413,10 +6404,4 @@
-# On iOS the shared libraries must be linked with the Python framework
-if test "$ac_sys_system" = "iOS"; then
-  MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)"
-fi

@kambala-decapitator

Copy link
Copy Markdown
Contributor Author

first in tools/depends/target/config.site.in we don't enforce the host if it's provide by package

was hesitant to touch that, but if everyone is ok with it, I'll change happily. Yeah, once we can pass proper host, the patch would be smaller.

@clementperon

Copy link
Copy Markdown
Contributor

first in tools/depends/target/config.site.in we don't enforce the host if it's provide by package

was hesitant to touch that, but if everyone is ok with it, I'll change happily. Yeah, once we can pass proper host, the patch would be smaller.

Maybe to clean for v23 as the impact is much more broader @garbear

@garbear

garbear commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

We need a policy decision on this.

It's correct, true? Correctness is required.

It only affects iOS, true? Fallout is minimized.

It's an insufficient improvement, true? Insufficiency isn't a blocker for B2.

The risk of this patch, weighted against the improvement it offers, makes the risk worth it, right?

@kambala-decapitator

Copy link
Copy Markdown
Contributor Author

@garbear

It's correct, true?

Seems so

It only affects iOS, true?

Yes

It's an insufficient improvement, true?

Sorry, not sure I understand the meaning of sufficiency in this case

The risk of this patch, weighted against the improvement it offers, makes the risk worth it, right?

I'd say so

@kambala-decapitator
kambala-decapitator merged commit 0032182 into xbmc:master Aug 11, 2026
2 checks passed
@kambala-decapitator
kambala-decapitator deleted the python-ios branch August 11, 2026 05:52
@clementperon

Copy link
Copy Markdown
Contributor

@kambala-decapitator this break the iOS simulator 😢

@clementperon

Copy link
Copy Markdown
Contributor

@kambala-decapitator cpython upstream:
gh-156112: Load the ObjC runtime by name when find_library() cannot resolve it: python/cpython#156113
And
gh-156109: Allow static, non-framework iOS builds: python/cpython#156110

@kambala-decapitator

Copy link
Copy Markdown
Contributor Author

@clementperon thanks! I wasn't really interested in upstreaming those :)

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants