From 00f4463f40e5732724e8b22e85fb9819badf8e7d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sat, 25 Jul 2026 14:39:55 -0700 Subject: [PATCH 1/2] Bump to 4.4.0: dart_bridge as a dynamic framework on Apple platforms Fixes built iOS apps crashing at startup with 'Failed to lookup symbol serious_python_run: dlsym(RTLD_DEFAULT, serious_python_run): symbol not found'. dart_bridge's FFI entry points (serious_python_run, DartBridge_*, PyInit_dart_bridge) are resolved at runtime via dlsym -- from Dart through DynamicLibrary.process() and from Python through 'import dart_bridge'. It previously shipped as a static archive linked into the host app executable, and an iOS executable exports nothing to the dynamic symbol table by default (release builds also strip local symbols), so those lookups failed. Only release/archive device builds were affected: debug/simulator don't dead-strip. Android was never affected -- its dart_bridge is a dynamic .so. dart_bridge 1.6.0 now builds dart_bridge.xcframework as a dynamic framework (flet-dev/dart-bridge#11), so it is embedded + signed into the app like Python.xcframework and its symbols stay exported. Removes what a loaded image no longer needs: the SwiftPM -all_load/-force_load retention, the CocoaPods -all_load, and the plugin's dead-strip keep-alive references. Re-pins the bundled python-build snapshot to 20260725 (dart_bridge 1.5.1 -> 1.6.0, Pyodide 3.14 314.0.2 -> 314.0.3). Python versions (3.12.13 / 3.13.14 / 3.14.6) are unchanged and all platform runtimes are byte-identical to 20260720. Also bumps .fvmrc to Flutter 3.44.8. --- .fvmrc | 2 +- src/serious_python/CHANGELOG.md | 5 ++ .../lib/src/python_versions.dart | 8 ++-- src/serious_python/pubspec.yaml | 2 +- src/serious_python_android/CHANGELOG.md | 4 ++ .../android/build.gradle.kts | 2 +- .../android/python_versions.properties | 6 +-- src/serious_python_android/pubspec.yaml | 2 +- src/serious_python_darwin/CHANGELOG.md | 5 ++ .../darwin/python_versions.properties | 6 +-- .../darwin/serious_python_darwin.podspec | 16 ++++--- .../serious_python_darwin/Package.swift | 48 +++++-------------- .../SeriousPythonPlugin.swift | 39 +++------------ src/serious_python_darwin/pubspec.yaml | 2 +- src/serious_python_linux/CHANGELOG.md | 4 ++ .../linux/python_versions.properties | 6 +-- src/serious_python_linux/pubspec.yaml | 2 +- .../CHANGELOG.md | 4 ++ .../pubspec.yaml | 2 +- src/serious_python_windows/CHANGELOG.md | 4 ++ src/serious_python_windows/pubspec.yaml | 2 +- .../windows/python_versions.properties | 6 +-- 22 files changed, 79 insertions(+), 98 deletions(-) diff --git a/.fvmrc b/.fvmrc index 5913bec0..4b28f0a5 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.44.4" + "flutter": "3.44.8" } \ No newline at end of file diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 92538239..37d7b18d 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.4.0 + +* **iOS/macOS:** fix built iOS apps crashing at startup with `Failed to lookup symbol 'serious_python_run'`. `dart_bridge` now ships as a dynamic framework, so the FFI entry points Dart and Python resolve via `dlsym` stay exported; previously it was static-linked into the app executable, which exports nothing. Release/device builds only. See `serious_python_darwin` 4.4.0. +* Bundled python-build snapshot re-pinned to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**, which carries the dynamic-framework change above; Pyodide 3.14 **314.0.2 → 314.0.3**). Python versions (**3.12.13 / 3.13.14 / 3.14.6**) are unchanged. + ## 4.3.6 * **Android:** PEP 734 subinterpreters (Python 3.14's `concurrent.interpreters` / `InterpreterPoolExecutor`) now work in built apps. Previously the main interpreter could import them, but every *subinterpreter* failed to import any relocated C extension (`ModuleNotFoundError: _struct` / `_interpqueues` / ...) — which broke the whole feature (its cross-interpreter transport pickles → `_struct`, and its queues need `_interpqueues`). The native-module finder lives on `sys.meta_path`, which is per-interpreter, and was installed only in the main interpreter. See `serious_python_android` 4.3.6. diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart index e35cce2e..0aafcdcd 100644 --- a/src/serious_python/lib/src/python_versions.dart +++ b/src/serious_python/lib/src/python_versions.dart @@ -1,5 +1,5 @@ // GENERATED by `dart run serious_python:gen_version_tables` from python-build's -// manifest.json (release 20260720). Do not edit by hand — edit python-build's +// manifest.json (release 20260725). Do not edit by hand — edit python-build's // manifest.json, cut a release, bump `pythonReleaseDate`, and regenerate. const pythonVersionEnvironmentVariable = "SERIOUS_PYTHON_VERSION"; @@ -10,8 +10,8 @@ const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION"; const dartBridgeVersionEnvironmentVariable = "DART_BRIDGE_VERSION"; /// python-build release the bundled runtimes come from (YYYYMMDD). -const pythonReleaseDate = "20260720"; -const dartBridgeVersion = "1.5.1"; +const pythonReleaseDate = "20260725"; +const dartBridgeVersion = "1.6.0"; const defaultPythonVersion = "3.14"; class PythonRelease { @@ -56,7 +56,7 @@ const pythonReleases = { "3.14": PythonRelease( standaloneVersion: "3.14.6", standaloneReleaseDate: "20260623", - pyodideVersion: "314.0.2", + pyodideVersion: "314.0.3", pyodidePlatformTag: "pyemscripten-2026.0-wasm32", androidAbis: ["arm64-v8a", "x86_64", "armeabi-v7a"], prerelease: false, diff --git a/src/serious_python/pubspec.yaml b/src/serious_python/pubspec.yaml index 572ca8d8..2db670c3 100644 --- a/src/serious_python/pubspec.yaml +++ b/src/serious_python/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python description: A cross-platform plugin for adding embedded Python runtime to your Flutter apps. homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 4.3.6 +version: 4.4.0 platforms: ios: diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index e8760e7c..1787bcfe 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.4.0 + +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). 1.6.0 changes only how `dart_bridge` is packaged for Apple platforms (static library → dynamic framework, see `serious_python_darwin` 4.4.0); the Android runtime is byte-identical to 20260720. + ## 4.3.6 * **PEP 734 subinterpreters now work** (Python 3.14 `concurrent.interpreters` / `InterpreterPoolExecutor`) — enabling true multi-core CPU parallelism inside a single process, which `multiprocessing` cannot provide on Android. Previously the main interpreter imported the machinery fine, but every subinterpreter raised `ModuleNotFoundError` for `_struct` / `_interpqueues` / any other C extension, so `InterpreterPoolExecutor` and the low-level API were unusable. Cause: Android relocates C extensions (native-mmap packaging) and resolves them through `_SorefFinder` on `sys.meta_path`; `sys.meta_path` is per-interpreter, and `install()` only ran in the main interpreter, so a freshly created subinterpreter had a `meta_path` without the finder. Fix: `_sp_bootstrap.install()` now also wraps `concurrent.interpreters.create()` so every new interpreter installs the finder before use. The install runs via `Interpreter.exec()` — a source string, which is pickle-free (unlike `Interpreter.call()`), so it works *before* `_struct` is importable in the child. Because `InterpreterPoolExecutor` builds its workers via `concurrent.interpreters.create()`, the pool is fixed transparently with no user-code change. A no-op before 3.14; iOS/desktop were unaffected. diff --git a/src/serious_python_android/android/build.gradle.kts b/src/serious_python_android/android/build.gradle.kts index 8f14855e..c2038256 100644 --- a/src/serious_python_android/android/build.gradle.kts +++ b/src/serious_python_android/android/build.gradle.kts @@ -21,7 +21,7 @@ buildscript { } group = "com.flet.serious_python_android" -version = "4.3.6" +version = "4.4.0" rootProject.allprojects { repositories { diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index 1816c017..7cd2e7f2 100644 --- a/src/serious_python_android/android/python_versions.properties +++ b/src/serious_python_android/android/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260720). Do not edit by hand. +# python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.5.1 -python_build_release_date=20260720 +dart_bridge_version=1.6.0 +python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 diff --git a/src/serious_python_android/pubspec.yaml b/src/serious_python_android/pubspec.yaml index ca194240..d88072ac 100644 --- a/src/serious_python_android/pubspec.yaml +++ b/src/serious_python_android/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_android description: Android implementation of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 4.3.6 +version: 4.4.0 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/src/serious_python_darwin/CHANGELOG.md b/src/serious_python_darwin/CHANGELOG.md index c34af698..0c0726cf 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.4.0 + +* **iOS/macOS: `dart_bridge` now ships as a dynamic framework**, fixing built iOS apps crashing at startup with `Failed to lookup symbol 'serious_python_run': dlsym(RTLD_DEFAULT, serious_python_run): symbol not found`. `dart_bridge`'s FFI entry points (`serious_python_run`, `DartBridge_InitDartApiDL`, `DartBridge_EnqueueMessage`, `PyInit_dart_bridge`) are resolved at runtime via `dlsym` — from Dart through `DynamicLibrary.process()` and from Python through `import dart_bridge`. It previously shipped as a **static** archive linked into the host app *executable*, and an iOS executable exports nothing to the dynamic symbol table by default (the release build also strips local symbols), so those lookups failed. Only release/archive (device) builds were affected — debug/simulator builds don't dead-strip, so the failure did not reproduce there. Android was never affected: its `dart_bridge` is a dynamic `.so`, which exports its symbols. `dart_bridge` **1.6.0** now builds `dart_bridge.xcframework` as a dynamic framework (see flet-dev/dart-bridge#11), so it is embedded + signed into the app like `Python.xcframework` and its symbols stay exported. The SwiftPM `-all_load` / `-force_load` retention, the CocoaPods `-all_load`, and the plugin's dead-strip keep-alive references are all removed — a loaded image needs none of them. +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). Python versions (**3.12.13 / 3.13.14 / 3.14.6**) are unchanged and the iOS/macOS CPython runtimes are byte-identical to 20260720. + ## 4.3.6 * Re-pins the bundled python-build snapshot to **20260720** (`dart_bridge` **1.5.0 → 1.5.1**). 1.5.1 is a Windows-only UTF-8 startup fix (see `serious_python_windows` 4.3.6); the iOS/macOS runtimes are functionally unchanged from 20260719. diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index 1816c017..7cd2e7f2 100644 --- a/src/serious_python_darwin/darwin/python_versions.properties +++ b/src/serious_python_darwin/darwin/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260720). Do not edit by hand. +# python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.5.1 -python_build_release_date=20260720 +dart_bridge_version=1.6.0 +python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 diff --git a/src/serious_python_darwin/darwin/serious_python_darwin.podspec b/src/serious_python_darwin/darwin/serious_python_darwin.podspec index b7483634..06910f01 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin.podspec +++ b/src/serious_python_darwin/darwin/serious_python_darwin.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'serious_python_darwin' - s.version = '4.3.6' + s.version = '4.4.0' s.summary = 'A cross-platform plugin for adding embedded Python runtime to your Flutter apps.' s.description = <<-DESC A cross-platform plugin for adding embedded Python runtime to your Flutter apps. @@ -13,11 +13,10 @@ Pod::Spec.new do |s| s.license = { :file => '../LICENSE' } s.author = { 'Appveyor Systems Inc.' => 'hello@flet.dev' } s.source = { :path => '.' } - # dart_bridge.xcframework (vendored below) contains static .a archives. - # CocoaPods 1.16+ refuses to install vendored xcframeworks with static - # libraries unless the consuming pod is itself declared as a static - # framework. Python.xcframework is also static, so this was always - # implicitly the case — just being explicit now. + # This pod's own Swift code links as a static framework. The vendored + # xcframeworks below (Python, dart_bridge) are dynamic frameworks — they are + # embedded and signed into the host app, and their symbols stay exported so + # the dlsym lookups Dart and Python perform at runtime resolve. s.static_framework = true s.source_files = ['serious_python_darwin/Sources/serious_python_darwin/**/*.swift'] s.ios.dependency 'Flutter' @@ -26,9 +25,12 @@ Pod::Spec.new do |s| s.osx.deployment_target = '11.0' # Flutter.framework does not contain a i386 slice. + # `-all_load` is no longer needed: it existed to retain the static + # libdart_bridge.a against -dead_strip, and dart_bridge now ships as a dynamic + # framework whose symbols are exported from its own loaded image. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', - 'OTHER_LDFLAGS' => '-ObjC -all_load -lc++' + 'OTHER_LDFLAGS' => '-ObjC -lc++' } s.swift_version = '5.0' diff --git a/src/serious_python_darwin/darwin/serious_python_darwin/Package.swift b/src/serious_python_darwin/darwin/serious_python_darwin/Package.swift index f6988e9a..1c0bfcf5 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin/Package.swift +++ b/src/serious_python_darwin/darwin/serious_python_darwin/Package.swift @@ -44,36 +44,20 @@ func staged(_ rel: String) -> Bool { var binaryTargets: [Target] = [] var deps: [Target.Dependency] = [.product(name: "FlutterFramework", package: "FlutterFramework")] -// dart_bridge: static archive, link-only. Its FFI exports are resolved at runtime -// via dlsym (Dart's `DynamicLibrary.process()` and Python's `import dart_bridge`), -// so the whole archive must be retained against the linker's -dead_strip. We -// force-load JUST this archive rather than using a global -all_load: SwiftPM -// applies a target's linkerSettings to the FINAL app executable link, so a global -// -all_load there would force-load EVERY static archive on the link line — -// including plugins that statically bundle the same third-party code (e.g. -// flet-video/media_kit and flet-rive both embed miniaudio), which then collide -// with thousands of duplicate symbols. -force_load on dart_bridge alone mirrors -// what the CocoaPods podspec did via `pod_target_xcconfig` (scoped to this pod's -// own inputs — only dart_bridge among them is a static archive). On macOS the -// xcframework has a single universal slice with a stable path, so we resolve it -// here. On iOS, plugin pods link as dynamic frameworks (no static-archive -// collision) and device/simulator use different slice paths, so the -// slice-agnostic -all_load is kept there (see linkerSettings below). -var macosDartBridgeForceLoad: [String] = [] +// dart_bridge: DYNAMIC framework -> embedded + auto-signed in the app. Its FFI +// entry points (serious_python_run, DartBridge_*, PyInit_dart_bridge) are +// EXPORTED from the loaded framework, so the dlsym lookups that Dart +// (`DynamicLibrary.process()`) and Python (`import dart_bridge`) perform resolve +// at runtime. A static library would instead be linked into the app executable, +// which does not export its symbols (and the release build strips them), so +// dlsym would fail with "Failed to lookup symbol 'serious_python_run'". Shipping +// it dynamic mirrors the Android `.so` (CMake SHARED) that already works — see +// flet-dev/dart-bridge apple/build_xcframework.sh. No -all_load/-force_load or +// keep-alive is needed anymore: the framework is a loaded image, not archive +// members that must be pulled in and kept against -dead_strip. if staged("dart_bridge.xcframework") { binaryTargets.append(.binaryTarget(name: "dart_bridge", path: "dart_bridge.xcframework")) deps.append("dart_bridge") - let xc = pkgDir.appendingPathComponent("dart_bridge.xcframework") - if let slices = try? FileManager.default.contentsOfDirectory( - at: xc, includingPropertiesForKeys: nil) { - for slice in slices.sorted(by: { $0.lastPathComponent < $1.lastPathComponent }) - where slice.lastPathComponent.hasPrefix("macos") { - let lib = slice.appendingPathComponent("libdart_bridge.a") - if FileManager.default.fileExists(atPath: lib.path) { - macosDartBridgeForceLoad = ["-force_load", lib.path] - } - } - } } // Python.framework: dynamic -> embedded + auto-signed. iOS and macOS ship separate // xcframeworks, so each is platform-conditional. @@ -119,15 +103,9 @@ let package = Package( .copy("Resources/app"), ], linkerSettings: [ + // dart_bridge is now a dynamic framework (embedded, symbols + // exported), so no -all_load / -force_load is needed to retain it. .unsafeFlags(["-ObjC"]), - // iOS: slice-agnostic -all_load. Plugin pods link as dynamic - // frameworks, so dart_bridge is the only static archive in scope — - // nothing else to double-load. (device/simulator slice paths differ, - // so a single -force_load path isn't possible here.) - .unsafeFlags(["-all_load"], .when(platforms: [.iOS])), - // macOS: force-load ONLY dart_bridge (resolved above), never a global - // -all_load — see the note where macosDartBridgeForceLoad is built. - .unsafeFlags(macosDartBridgeForceLoad, .when(platforms: [.macOS])), .linkedLibrary("c++"), ] ), diff --git a/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift b/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift index bc9ba68e..b24022ed 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift +++ b/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift @@ -5,27 +5,13 @@ import UIKit import FlutterMacOS #endif -// Keep-alive references to dart_bridge.xcframework's C entry points. Dart -// resolves them via `DynamicLibrary.process()` at runtime; without these -// static references the host app's linker `-dead_strip` pass could drop -// them even though `-all_load` pulled the archive members in. -@_silgen_name("serious_python_run") -private func _sp_run_keepalive(_ cfg: OpaquePointer?) -> Int32 -@_silgen_name("DartBridge_InitDartApiDL") -private func _sp_init_keepalive(_ data: UnsafeMutableRawPointer?) -> Int -@_silgen_name("DartBridge_EnqueueMessage") -private func _sp_enqueue_keepalive(_ data: UnsafePointer?, _ len: Int) - -// multiprocessing child-interception entry points, -// dlsym'd by the host app's main.swift before NSApplicationMain. -@_silgen_name("serious_python_is_mp_invocation") -private func _sp_is_mp_keepalive( - _ argc: Int32, _ argv: UnsafeMutablePointer?>? -) -> Int32 -@_silgen_name("serious_python_main") -private func _sp_main_keepalive( - _ argc: Int32, _ argv: UnsafeMutablePointer?>? -) -> Int32 +// dart_bridge's C entry points (serious_python_run, DartBridge_*, +// serious_python_{is_mp_invocation,main}) used to need keep-alive references +// here: it shipped as a static archive linked into the host app executable, +// which exports nothing, so the dlsym lookups Dart (`DynamicLibrary.process()`) +// and the macOS host's main.swift perform could fail. dart_bridge now ships as a +// dynamic framework (embedded + signed) whose symbols are exported from its own +// loaded image, so no keep-alive is required — see dart-bridge 1.6.0. /// Thin Flutter plugin: surfaces the python.bundle resource path to Dart. /// All Python lifecycle now lives in `serious_python_run` @@ -42,17 +28,6 @@ public class SeriousPythonPlugin: NSObject, FlutterPlugin { let channel = FlutterMethodChannel(name: "serious_python", binaryMessenger: messenger) let instance = SeriousPythonPlugin() registrar.addMethodCallDelegate(instance, channel: channel) - - // Static reference to dart_bridge symbols — see top-of-file note. - // The branch is unreachable at runtime (the registrar argument is - // always non-nil), but the linker only sees a live call site. - if unsafeBitCast(registrar, to: Int.self) == 0 { - _ = _sp_run_keepalive(nil) - _ = _sp_init_keepalive(nil) - _sp_enqueue_keepalive(nil, 0) - _ = _sp_is_mp_keepalive(0, nil) - _ = _sp_main_keepalive(0, nil) - } } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { diff --git a/src/serious_python_darwin/pubspec.yaml b/src/serious_python_darwin/pubspec.yaml index e7c7d4a8..8a0da963 100644 --- a/src/serious_python_darwin/pubspec.yaml +++ b/src/serious_python_darwin/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_darwin description: iOS and macOS implementations of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 4.3.6 +version: 4.4.0 environment: # The Swift Package Manager build path needs Flutter 3.44 / Dart 3.11 (the diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index a79a2877..a4ed070f 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.4.0 + +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). 1.6.0 is an Apple-only packaging change (see `serious_python_darwin` 4.4.0); the Linux runtime is byte-identical to 20260720. + ## 4.3.6 * Re-pins the bundled python-build snapshot to **20260720** (`dart_bridge` **1.5.0 → 1.5.1**). 1.5.1 is a Windows-only UTF-8 startup fix (see `serious_python_windows` 4.3.6); the Linux runtime is functionally unchanged from 20260719. diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index 1816c017..7cd2e7f2 100644 --- a/src/serious_python_linux/linux/python_versions.properties +++ b/src/serious_python_linux/linux/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260720). Do not edit by hand. +# python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.5.1 -python_build_release_date=20260720 +dart_bridge_version=1.6.0 +python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 diff --git a/src/serious_python_linux/pubspec.yaml b/src/serious_python_linux/pubspec.yaml index e7545477..860c1811 100644 --- a/src/serious_python_linux/pubspec.yaml +++ b/src/serious_python_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_linux description: Linux implementations of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 4.3.6 +version: 4.4.0 environment: sdk: '>=3.1.3 <4.0.0' diff --git a/src/serious_python_platform_interface/CHANGELOG.md b/src/serious_python_platform_interface/CHANGELOG.md index 4b5b560f..7b585aba 100644 --- a/src/serious_python_platform_interface/CHANGELOG.md +++ b/src/serious_python_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.4.0 + +* Version bump aligning with the `serious_python_*` 4.4.0 release. + ## 4.3.6 * Version bump aligning with the `serious_python_*` 4.3.6 release (Windows UTF-8 startup fix via `dart_bridge` 1.5.1). No interface changes. diff --git a/src/serious_python_platform_interface/pubspec.yaml b/src/serious_python_platform_interface/pubspec.yaml index 22a7291a..75dd5a0e 100644 --- a/src/serious_python_platform_interface/pubspec.yaml +++ b/src/serious_python_platform_interface/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_platform_interface description: A common platform interface for the serious_python plugin. homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 4.3.6 +version: 4.4.0 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/src/serious_python_windows/CHANGELOG.md b/src/serious_python_windows/CHANGELOG.md index 156a29b2..dcc7b692 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.4.0 + +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). 1.6.0 is an Apple-only packaging change (see `serious_python_darwin` 4.4.0); the Windows runtime is byte-identical to 20260720. + ## 4.3.6 * **Fix Windows startup when app paths or environment values contain non-ASCII characters.** Dart FFI strings arrive as UTF-8, but the Windows boundary passed them straight to the ANSI CRT (`_putenv_s`, `fopen`), corrupting paths/env values through the process code page. The runtime now converts UTF-8 → UTF-16 and uses the wide CRT APIs (`_wputenv_s`, `_wfopen_s`), enables Python UTF-8 mode before `Py_Initialize()`, sets `PYTHONUTF8=1` for multiprocessing helpers, and treats embedded env-setup failures as fatal. Delivered via `dart_bridge` **1.5.1** (bundled python-build snapshot re-pinned to **20260720**). ([flet-dev/flet#6641](https://github.com/flet-dev/flet/issues/6641)) diff --git a/src/serious_python_windows/pubspec.yaml b/src/serious_python_windows/pubspec.yaml index 8524b9f4..bd5f7b75 100644 --- a/src/serious_python_windows/pubspec.yaml +++ b/src/serious_python_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: serious_python_windows description: Windows implementations of the serious_python plugin homepage: https://flet.dev repository: https://github.com/flet-dev/serious-python -version: 4.3.6 +version: 4.4.0 environment: sdk: '>=3.1.3 <4.0.0' diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index 1816c017..7cd2e7f2 100644 --- a/src/serious_python_windows/windows/python_versions.properties +++ b/src/serious_python_windows/windows/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260720). Do not edit by hand. +# python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.5.1 -python_build_release_date=20260720 +dart_bridge_version=1.6.0 +python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 From e0e030574c1cfbe0619a52400f1b0608b341e92a Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sat, 25 Jul 2026 15:23:38 -0700 Subject: [PATCH 2/2] Re-pin dart_bridge to 1.6.1 (macOS framework symlink fix) python-build's 20260725 manifest was updated in place to dart_bridge 1.6.1, so regenerate the version tables against it. 1.6.1 zips the Apple xcframework with -y so the macOS slice's versioned framework symlinks (Versions/Current -> A, dart_bridge and Resources -> Versions/Current/...) survive publishing. Under 1.6.0 they were followed and stored as real files/directories, producing a malformed bundle that macOS codesign rejected ('Couldn't resolve framework symlink for .../Versions/Current', 'code object is not signed at all'). iOS was unaffected -- its slices use a flat layout with no symlinks. See flet-dev/dart-bridge#12. Binaries are unchanged from 1.6.0; only the artifact packaging differs. --- src/serious_python/CHANGELOG.md | 2 +- src/serious_python/lib/src/python_versions.dart | 2 +- src/serious_python_android/CHANGELOG.md | 2 +- src/serious_python_android/android/python_versions.properties | 2 +- src/serious_python_darwin/CHANGELOG.md | 4 ++-- src/serious_python_darwin/darwin/python_versions.properties | 2 +- src/serious_python_linux/CHANGELOG.md | 2 +- src/serious_python_linux/linux/python_versions.properties | 2 +- src/serious_python_windows/CHANGELOG.md | 2 +- src/serious_python_windows/windows/python_versions.properties | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 37d7b18d..99229084 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,7 +1,7 @@ ## 4.4.0 * **iOS/macOS:** fix built iOS apps crashing at startup with `Failed to lookup symbol 'serious_python_run'`. `dart_bridge` now ships as a dynamic framework, so the FFI entry points Dart and Python resolve via `dlsym` stay exported; previously it was static-linked into the app executable, which exports nothing. Release/device builds only. See `serious_python_darwin` 4.4.0. -* Bundled python-build snapshot re-pinned to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**, which carries the dynamic-framework change above; Pyodide 3.14 **314.0.2 → 314.0.3**). Python versions (**3.12.13 / 3.13.14 / 3.14.6**) are unchanged. +* Bundled python-build snapshot re-pinned to **20260725** (`dart_bridge` **1.5.1 → 1.6.1**, which carries the dynamic-framework change above; Pyodide 3.14 **314.0.2 → 314.0.3**). Python versions (**3.12.13 / 3.13.14 / 3.14.6**) are unchanged. ## 4.3.6 diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart index 0aafcdcd..6aa21de5 100644 --- a/src/serious_python/lib/src/python_versions.dart +++ b/src/serious_python/lib/src/python_versions.dart @@ -11,7 +11,7 @@ const dartBridgeVersionEnvironmentVariable = "DART_BRIDGE_VERSION"; /// python-build release the bundled runtimes come from (YYYYMMDD). const pythonReleaseDate = "20260725"; -const dartBridgeVersion = "1.6.0"; +const dartBridgeVersion = "1.6.1"; const defaultPythonVersion = "3.14"; class PythonRelease { diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 1787bcfe..d9686c0f 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -1,6 +1,6 @@ ## 4.4.0 -* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). 1.6.0 changes only how `dart_bridge` is packaged for Apple platforms (static library → dynamic framework, see `serious_python_darwin` 4.4.0); the Android runtime is byte-identical to 20260720. +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.1**). 1.6.1 changes only how `dart_bridge` is packaged for Apple platforms (static library → dynamic framework, see `serious_python_darwin` 4.4.0); the Android runtime is byte-identical to 20260720. ## 4.3.6 diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index 7cd2e7f2..e2f008ff 100644 --- a/src/serious_python_android/android/python_versions.properties +++ b/src/serious_python_android/android/python_versions.properties @@ -1,7 +1,7 @@ # GENERATED by `dart run serious_python:gen_version_tables` from # python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.6.0 +dart_bridge_version=1.6.1 python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a diff --git a/src/serious_python_darwin/CHANGELOG.md b/src/serious_python_darwin/CHANGELOG.md index 0c0726cf..c9da7a18 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -1,7 +1,7 @@ ## 4.4.0 -* **iOS/macOS: `dart_bridge` now ships as a dynamic framework**, fixing built iOS apps crashing at startup with `Failed to lookup symbol 'serious_python_run': dlsym(RTLD_DEFAULT, serious_python_run): symbol not found`. `dart_bridge`'s FFI entry points (`serious_python_run`, `DartBridge_InitDartApiDL`, `DartBridge_EnqueueMessage`, `PyInit_dart_bridge`) are resolved at runtime via `dlsym` — from Dart through `DynamicLibrary.process()` and from Python through `import dart_bridge`. It previously shipped as a **static** archive linked into the host app *executable*, and an iOS executable exports nothing to the dynamic symbol table by default (the release build also strips local symbols), so those lookups failed. Only release/archive (device) builds were affected — debug/simulator builds don't dead-strip, so the failure did not reproduce there. Android was never affected: its `dart_bridge` is a dynamic `.so`, which exports its symbols. `dart_bridge` **1.6.0** now builds `dart_bridge.xcframework` as a dynamic framework (see flet-dev/dart-bridge#11), so it is embedded + signed into the app like `Python.xcframework` and its symbols stay exported. The SwiftPM `-all_load` / `-force_load` retention, the CocoaPods `-all_load`, and the plugin's dead-strip keep-alive references are all removed — a loaded image needs none of them. -* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). Python versions (**3.12.13 / 3.13.14 / 3.14.6**) are unchanged and the iOS/macOS CPython runtimes are byte-identical to 20260720. +* **iOS/macOS: `dart_bridge` now ships as a dynamic framework**, fixing built iOS apps crashing at startup with `Failed to lookup symbol 'serious_python_run': dlsym(RTLD_DEFAULT, serious_python_run): symbol not found`. `dart_bridge`'s FFI entry points (`serious_python_run`, `DartBridge_InitDartApiDL`, `DartBridge_EnqueueMessage`, `PyInit_dart_bridge`) are resolved at runtime via `dlsym` — from Dart through `DynamicLibrary.process()` and from Python through `import dart_bridge`. It previously shipped as a **static** archive linked into the host app *executable*, and an iOS executable exports nothing to the dynamic symbol table by default (the release build also strips local symbols), so those lookups failed. Only release/archive (device) builds were affected — debug/simulator builds don't dead-strip, so the failure did not reproduce there. Android was never affected: its `dart_bridge` is a dynamic `.so`, which exports its symbols. `dart_bridge` **1.6.1** now builds `dart_bridge.xcframework` as a dynamic framework (see flet-dev/dart-bridge#11 and #12), so it is embedded + signed into the app like `Python.xcframework` and its symbols stay exported. The SwiftPM `-all_load` / `-force_load` retention, the CocoaPods `-all_load`, and the plugin's dead-strip keep-alive references are all removed — a loaded image needs none of them. +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.1**). Python versions (**3.12.13 / 3.13.14 / 3.14.6**) are unchanged and the iOS/macOS CPython runtimes are byte-identical to 20260720. ## 4.3.6 diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index 7cd2e7f2..e2f008ff 100644 --- a/src/serious_python_darwin/darwin/python_versions.properties +++ b/src/serious_python_darwin/darwin/python_versions.properties @@ -1,7 +1,7 @@ # GENERATED by `dart run serious_python:gen_version_tables` from # python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.6.0 +dart_bridge_version=1.6.1 python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index a4ed070f..37103e59 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -1,6 +1,6 @@ ## 4.4.0 -* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). 1.6.0 is an Apple-only packaging change (see `serious_python_darwin` 4.4.0); the Linux runtime is byte-identical to 20260720. +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.1**). 1.6.1 is an Apple-only packaging change (see `serious_python_darwin` 4.4.0); the Linux runtime is byte-identical to 20260720. ## 4.3.6 diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index 7cd2e7f2..e2f008ff 100644 --- a/src/serious_python_linux/linux/python_versions.properties +++ b/src/serious_python_linux/linux/python_versions.properties @@ -1,7 +1,7 @@ # GENERATED by `dart run serious_python:gen_version_tables` from # python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.6.0 +dart_bridge_version=1.6.1 python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a diff --git a/src/serious_python_windows/CHANGELOG.md b/src/serious_python_windows/CHANGELOG.md index dcc7b692..ab546ebf 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -1,6 +1,6 @@ ## 4.4.0 -* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.0**). 1.6.0 is an Apple-only packaging change (see `serious_python_darwin` 4.4.0); the Windows runtime is byte-identical to 20260720. +* Re-pins the bundled python-build snapshot to **20260725** (`dart_bridge` **1.5.1 → 1.6.1**). 1.6.1 is an Apple-only packaging change (see `serious_python_darwin` 4.4.0); the Windows runtime is byte-identical to 20260720. ## 4.3.6 diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index 7cd2e7f2..e2f008ff 100644 --- a/src/serious_python_windows/windows/python_versions.properties +++ b/src/serious_python_windows/windows/python_versions.properties @@ -1,7 +1,7 @@ # GENERATED by `dart run serious_python:gen_version_tables` from # python-build manifest.json (release 20260725). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.6.0 +dart_bridge_version=1.6.1 python_build_release_date=20260725 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a