From 8458555ddd7bea7336a1f2f4247499f1e3ff6094 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:01:43 -0700 Subject: [PATCH 001/114] Add serious_python_bridge plugin: dart_bridge C source + Python extension Restructured from the abandoned dart-bridge repo, scoped to the byte-transport primitives only. The plugin is independently consumable and shares its version + release cadence with the other serious_python* packages. - native/dart_bridge.c: drop DartBridge_RunPython and its threading machinery; keep the Dart-callable core (DartBridge_InitDartApiDL, DartBridge_EnqueueMessage) and the Python-callable shim (set_enqueue_handler_func, send_bytes) - send_bytes now detects an uninitialized Dart API DL and raises RuntimeError instead of segfaulting on a NULL Dart_PostCObject_DL function pointer - native/dart_api/: vendored Dart SDK headers needed by Dart_InitializeApiDL - python/: setup.py + pyproject.toml building the dart_bridge Python extension; cibuildwheel matrix gated to cp312/cp313/cp314 matching ci.yml - .gitignore: cover compiled extension artifacts (*.so, *.pyd, *.dylib, *.dll, *.egg-info/, *.egg/) --- .gitignore | 8 +- .../native/dart_api/dart_api.h | 4186 +++++++++++++++++ .../native/dart_api/dart_api_dl.c | 79 + .../native/dart_api/dart_api_dl.h | 172 + .../native/dart_api/dart_native_api.h | 224 + .../native/dart_api/dart_tools_api.h | 627 +++ .../native/dart_api/dart_version.h | 16 + .../dart_api/internal/dart_api_dl_impl.h | 21 + .../native/dart_bridge.c | 124 + src/serious_python_bridge/python/MANIFEST.in | 4 + .../python/pyproject.toml | 33 + src/serious_python_bridge/python/setup.py | 16 + 12 files changed, 5509 insertions(+), 1 deletion(-) create mode 100644 src/serious_python_bridge/native/dart_api/dart_api.h create mode 100644 src/serious_python_bridge/native/dart_api/dart_api_dl.c create mode 100644 src/serious_python_bridge/native/dart_api/dart_api_dl.h create mode 100644 src/serious_python_bridge/native/dart_api/dart_native_api.h create mode 100644 src/serious_python_bridge/native/dart_api/dart_tools_api.h create mode 100644 src/serious_python_bridge/native/dart_api/dart_version.h create mode 100644 src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h create mode 100644 src/serious_python_bridge/native/dart_bridge.c create mode 100644 src/serious_python_bridge/python/MANIFEST.in create mode 100644 src/serious_python_bridge/python/pyproject.toml create mode 100644 src/serious_python_bridge/python/setup.py diff --git a/.gitignore b/.gitignore index b4ec5742..d74c253c 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,10 @@ dist/ # Python .venv/ -__pypackages__/ \ No newline at end of file +__pypackages__/ +*.so +*.pyd +*.dylib +*.dll +*.egg-info/ +*.egg/ \ No newline at end of file diff --git a/src/serious_python_bridge/native/dart_api/dart_api.h b/src/serious_python_bridge/native/dart_api/dart_api.h new file mode 100644 index 00000000..1d83c903 --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/dart_api.h @@ -0,0 +1,4186 @@ +/* + * Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef RUNTIME_INCLUDE_DART_API_H_ +#define RUNTIME_INCLUDE_DART_API_H_ + +/** \mainpage Dart Embedding API Reference + * + * This reference describes the Dart Embedding API, which is used to embed the + * Dart Virtual Machine within C/C++ applications. + * + * This reference is generated from the header include/dart_api.h. + */ + +/* __STDC_FORMAT_MACROS has to be defined before including to + * enable platform independent printf format specifiers. */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include +#include +#include + +#if defined(__Fuchsia__) +#include +#endif + +#ifdef __cplusplus +#define DART_EXTERN_C extern "C" +#else +#define DART_EXTERN_C extern +#endif + +#if defined(__CYGWIN__) +#error Tool chain and platform not supported. +#elif defined(_WIN32) +#if defined(DART_SHARED_LIB) +#define DART_EXPORT DART_EXTERN_C __declspec(dllexport) +#else +#define DART_EXPORT DART_EXTERN_C +#endif +#else +#if __GNUC__ >= 4 +#if defined(DART_SHARED_LIB) +#define DART_EXPORT \ + DART_EXTERN_C __attribute__((visibility("default"))) __attribute((used)) +#else +#define DART_EXPORT DART_EXTERN_C +#endif +#else +#error Tool chain not supported. +#endif +#endif + +#if __GNUC__ +#define DART_API_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#define DART_API_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif _MSC_VER +#define DART_API_WARN_UNUSED_RESULT _Check_return_ +#define DART_API_DEPRECATED(msg) __declspec(deprecated(msg)) +#else +#define DART_API_WARN_UNUSED_RESULT +#define DART_API_DEPRECATED(msg) +#endif + +/* + * ======= + * Handles + * ======= + */ + +/** + * An isolate is the unit of concurrency in Dart. Each isolate has + * its own memory and thread of control. No state is shared between + * isolates. Instead, isolates communicate by message passing. + * + * Each thread keeps track of its current isolate, which is the + * isolate which is ready to execute on the current thread. The + * current isolate may be NULL, in which case no isolate is ready to + * execute. Most of the Dart apis require there to be a current + * isolate in order to function without error. The current isolate is + * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate. + */ +typedef struct _Dart_Isolate* Dart_Isolate; +typedef struct _Dart_IsolateGroup* Dart_IsolateGroup; + +/** + * An object reference managed by the Dart VM garbage collector. + * + * Because the garbage collector may move objects, it is unsafe to + * refer to objects directly. Instead, we refer to objects through + * handles, which are known to the garbage collector and updated + * automatically when the object is moved. Handles should be passed + * by value (except in cases like out-parameters) and should never be + * allocated on the heap. + * + * Most functions in the Dart Embedding API return a handle. When a + * function completes normally, this will be a valid handle to an + * object in the Dart VM heap. This handle may represent the result of + * the operation or it may be a special valid handle used merely to + * indicate successful completion. Note that a valid handle may in + * some cases refer to the null object. + * + * --- Error handles --- + * + * When a function encounters a problem that prevents it from + * completing normally, it returns an error handle (See Dart_IsError). + * An error handle has an associated error message that gives more + * details about the problem (See Dart_GetError). + * + * There are four kinds of error handles that can be produced, + * depending on what goes wrong: + * + * - Api error handles are produced when an api function is misused. + * This happens when a Dart embedding api function is called with + * invalid arguments or in an invalid context. + * + * - Unhandled exception error handles are produced when, during the + * execution of Dart code, an exception is thrown but not caught. + * Prototypically this would occur during a call to Dart_Invoke, but + * it can occur in any function which triggers the execution of Dart + * code (for example, Dart_ToString). + * + * An unhandled exception error provides access to an exception and + * stacktrace via the functions Dart_ErrorGetException and + * Dart_ErrorGetStackTrace. + * + * - Compilation error handles are produced when, during the execution + * of Dart code, a compile-time error occurs. As above, this can + * occur in any function which triggers the execution of Dart code. + * + * - Fatal error handles are produced when the system wants to shut + * down the current isolate. + * + * --- Propagating errors --- + * + * When an error handle is returned from the top level invocation of + * Dart code in a program, the embedder must handle the error as they + * see fit. Often, the embedder will print the error message produced + * by Dart_Error and exit the program. + * + * When an error is returned while in the body of a native function, + * it can be propagated up the call stack by calling + * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException. + * Errors should be propagated unless there is a specific reason not + * to. If an error is not propagated then it is ignored. For + * example, if an unhandled exception error is ignored, that + * effectively "catches" the unhandled exception. Fatal errors must + * always be propagated. + * + * When an error is propagated, any current scopes created by + * Dart_EnterScope will be exited. + * + * Using Dart_SetReturnValue to propagate an exception is somewhat + * more convenient than using Dart_PropagateError, and should be + * preferred for reasons discussed below. + * + * Dart_PropagateError and Dart_ThrowException do not return. Instead + * they transfer control non-locally using a setjmp-like mechanism. + * This can be inconvenient if you have resources that you need to + * clean up before propagating the error. + * + * When relying on Dart_PropagateError, we often return error handles + * rather than propagating them from helper functions. Consider the + * following contrived example: + * + * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) { + * 2 intptr_t* length = 0; + * 3 result = Dart_StringLength(arg, &length); + * 4 if (Dart_IsError(result)) { + * 5 return result; + * 6 } + * 7 return Dart_NewBoolean(length > 100); + * 8 } + * 9 + * 10 void NativeFunction_isLongString(Dart_NativeArguments args) { + * 11 Dart_EnterScope(); + * 12 AllocateMyResource(); + * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); + * 14 Dart_Handle result = isLongStringHelper(arg); + * 15 if (Dart_IsError(result)) { + * 16 FreeMyResource(); + * 17 Dart_PropagateError(result); + * 18 abort(); // will not reach here + * 19 } + * 20 Dart_SetReturnValue(result); + * 21 FreeMyResource(); + * 22 Dart_ExitScope(); + * 23 } + * + * In this example, we have a native function which calls a helper + * function to do its work. On line 5, the helper function could call + * Dart_PropagateError, but that would not give the native function a + * chance to call FreeMyResource(), causing a leak. Instead, the + * helper function returns the error handle to the caller, giving the + * caller a chance to clean up before propagating the error handle. + * + * When an error is propagated by calling Dart_SetReturnValue, the + * native function will be allowed to complete normally and then the + * exception will be propagated only once the native call + * returns. This can be convenient, as it allows the C code to clean + * up normally. + * + * The example can be written more simply using Dart_SetReturnValue to + * propagate the error. + * + * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) { + * 2 intptr_t* length = 0; + * 3 result = Dart_StringLength(arg, &length); + * 4 if (Dart_IsError(result)) { + * 5 return result + * 6 } + * 7 return Dart_NewBoolean(length > 100); + * 8 } + * 9 + * 10 void NativeFunction_isLongString(Dart_NativeArguments args) { + * 11 Dart_EnterScope(); + * 12 AllocateMyResource(); + * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); + * 14 Dart_SetReturnValue(isLongStringHelper(arg)); + * 15 FreeMyResource(); + * 16 Dart_ExitScope(); + * 17 } + * + * In this example, the call to Dart_SetReturnValue on line 14 will + * either return the normal return value or the error (potentially + * generated on line 3). The call to FreeMyResource on line 15 will + * execute in either case. + * + * --- Local and persistent handles --- + * + * Local handles are allocated within the current scope (see + * Dart_EnterScope) and go away when the current scope exits. Unless + * otherwise indicated, callers should assume that all functions in + * the Dart embedding api return local handles. + * + * Persistent handles are allocated within the current isolate. They + * can be used to store objects across scopes. Persistent handles have + * the lifetime of the current isolate unless they are explicitly + * deallocated (see Dart_DeletePersistentHandle). + * The type Dart_Handle represents a handle (both local and persistent). + * The type Dart_PersistentHandle is a Dart_Handle and it is used to + * document that a persistent handle is expected as a parameter to a call + * or the return value from a call is a persistent handle. + * + * FinalizableHandles are persistent handles which are auto deleted when + * the object is garbage collected. It is never safe to use these handles + * unless you know the object is still reachable. + * + * WeakPersistentHandles are persistent handles which are automatically set + * to point Dart_Null when the object is garbage collected. They are not auto + * deleted, so it is safe to use them after the object has become unreachable. + */ +typedef struct _Dart_Handle* Dart_Handle; +typedef Dart_Handle Dart_PersistentHandle; +typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle; +typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle; +// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the +// version when changing this struct. + +typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer); + +/** + * Is this an error handle? + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsError(Dart_Handle handle); + +/** + * Is this an api error handle? + * + * Api error handles are produced when an api function is misused. + * This happens when a Dart embedding api function is called with + * invalid arguments or in an invalid context. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsApiError(Dart_Handle handle); + +/** + * Is this an unhandled exception error handle? + * + * Unhandled exception error handles are produced when, during the + * execution of Dart code, an exception is thrown but not caught. + * This can occur in any function which triggers the execution of Dart + * code. + * + * See Dart_ErrorGetException and Dart_ErrorGetStackTrace. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle handle); + +/** + * Is this a compilation error handle? + * + * Compilation error handles are produced when, during the execution + * of Dart code, a compile-time error occurs. This can occur in any + * function which triggers the execution of Dart code. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle); + +/** + * Is this a fatal error handle? + * + * Fatal error handles are produced when the system wants to shut down + * the current isolate. + * + * Requires there to be a current isolate. + */ +DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle); + +/** + * Gets the error message from an error handle. + * + * Requires there to be a current isolate. + * + * \return A C string containing an error message if the handle is + * error. An empty C string ("") if the handle is valid. This C + * String is scope allocated and is only valid until the next call + * to Dart_ExitScope. +*/ +DART_EXPORT const char* Dart_GetError(Dart_Handle handle); + +/** + * Is this an error handle for an unhandled exception? + */ +DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle); + +/** + * Gets the exception Object from an unhandled exception error handle. + */ +DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle); + +/** + * Gets the stack trace Object from an unhandled exception error handle. + */ +DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle); + +/** + * Produces an api error handle with the provided error message. + * + * Requires there to be a current isolate. + * + * \param error the error message. + */ +DART_EXPORT Dart_Handle Dart_NewApiError(const char* error); +DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error); + +/** + * Produces a new unhandled exception error handle. + * + * Requires there to be a current isolate. + * + * \param exception An instance of a Dart object to be thrown or + * an ApiError or CompilationError handle. + * When an ApiError or CompilationError handle is passed in + * a string object of the error message is created and it becomes + * the Dart object to be thrown. + */ +DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception); + +/** + * Propagates an error. + * + * If the provided handle is an unhandled exception error, this + * function will cause the unhandled exception to be rethrown. This + * will proceed in the standard way, walking up Dart frames until an + * appropriate 'catch' block is found, executing 'finally' blocks, + * etc. + * + * If the error is not an unhandled exception error, we will unwind + * the stack to the next C frame. Intervening Dart frames will be + * discarded; specifically, 'finally' blocks will not execute. This + * is the standard way that compilation errors (and the like) are + * handled by the Dart runtime. + * + * In either case, when an error is propagated any current scopes + * created by Dart_EnterScope will be exited. + * + * See the additional discussion under "Propagating Errors" at the + * beginning of this file. + * + * \param handle An error handle (See Dart_IsError) + * + * On success, this function does not return. On failure, the + * process is terminated. + */ +DART_EXPORT void Dart_PropagateError(Dart_Handle handle); + +/** + * Converts an object to a string. + * + * May generate an unhandled exception error. + * + * \return The converted string if no error occurs during + * the conversion. If an error does occur, an error handle is + * returned. + */ +DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object); + +/** + * Checks to see if two handles refer to identically equal objects. + * + * If both handles refer to instances, this is equivalent to using the top-level + * function identical() from dart:core. Otherwise, returns whether the two + * argument handles refer to the same object. + * + * \param obj1 An object to be compared. + * \param obj2 An object to be compared. + * + * \return True if the objects are identically equal. False otherwise. + */ +DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2); + +/** + * Allocates a handle in the current scope from a persistent handle. + */ +DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object); + +/** + * Allocates a handle in the current scope from a weak persistent handle. + * + * This will be a handle to Dart_Null if the object has been garbage collected. + */ +DART_EXPORT Dart_Handle +Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object); + +/** + * Allocates a persistent handle for an object. + * + * This handle has the lifetime of the current isolate unless it is + * explicitly deallocated by calling Dart_DeletePersistentHandle. + * + * Requires there to be a current isolate. + */ +DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object); + +/** + * Assign value of local handle to a persistent handle. + * + * Requires there to be a current isolate. + * + * \param obj1 A persistent handle whose value needs to be set. + * \param obj2 An object whose value needs to be set to the persistent handle. + */ +DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1, + Dart_Handle obj2); + +/** + * Deallocates a persistent handle. + * + * Requires there to be a current isolate group. + */ +DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object); + +/** + * Allocates a weak persistent handle for an object. + * + * This handle has the lifetime of the current isolate. The handle can also be + * explicitly deallocated by calling Dart_DeleteWeakPersistentHandle. + * + * If the object becomes unreachable the callback is invoked with the peer as + * argument. The callback can be executed on any thread, will have a current + * isolate group, but will not have a current isolate. The callback can only + * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This + * gives the embedder the ability to cleanup data associated with the object. + * The handle will point to the Dart_Null object after the finalizer has been + * run. It is illegal to call into the VM with any other Dart_* functions from + * the callback. If the handle is deleted before the object becomes + * unreachable, the callback is never invoked. + * + * Requires there to be a current isolate. + * + * \param object An object with identity. + * \param peer A pointer to a native object or NULL. This value is + * provided to callback when it is invoked. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A function pointer that will be invoked sometime + * after the object is garbage collected, unless the handle has been deleted. + * A valid callback needs to be specified it cannot be NULL. + * + * \return The weak persistent handle or NULL. NULL is returned in case of bad + * parameters. + */ +DART_EXPORT Dart_WeakPersistentHandle +Dart_NewWeakPersistentHandle(Dart_Handle object, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Deletes the given weak persistent [object] handle. + * + * Requires there to be a current isolate group. + */ +DART_EXPORT void Dart_DeleteWeakPersistentHandle( + Dart_WeakPersistentHandle object); + +/** + * Allocates a finalizable handle for an object. + * + * This handle has the lifetime of the current isolate group unless the object + * pointed to by the handle is garbage collected, in this case the VM + * automatically deletes the handle after invoking the callback associated + * with the handle. The handle can also be explicitly deallocated by + * calling Dart_DeleteFinalizableHandle. + * + * If the object becomes unreachable the callback is invoked with the + * the peer as argument. The callback can be executed on any thread, will have + * an isolate group, but will not have a current isolate. The callback can only + * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. + * This gives the embedder the ability to cleanup data associated with the + * object and clear out any cached references to the handle. All references to + * this handle after the callback will be invalid. It is illegal to call into + * the VM with any other Dart_* functions from the callback. If the handle is + * deleted before the object becomes unreachable, the callback is never + * invoked. + * + * Requires there to be a current isolate. + * + * \param object An object with identity. + * \param peer A pointer to a native object or NULL. This value is + * provided to callback when it is invoked. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A function pointer that will be invoked sometime + * after the object is garbage collected, unless the handle has been deleted. + * A valid callback needs to be specified it cannot be NULL. + * + * \return The finalizable handle or NULL. NULL is returned in case of bad + * parameters. + */ +DART_EXPORT Dart_FinalizableHandle +Dart_NewFinalizableHandle(Dart_Handle object, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Deletes the given finalizable [object] handle. + * + * The caller has to provide the actual Dart object the handle was created from + * to prove the object (and therefore the finalizable handle) is still alive. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_DeleteFinalizableHandle(Dart_FinalizableHandle object, + Dart_Handle strong_ref_to_object); + +/* + * ========================== + * Initialization and Globals + * ========================== + */ + +/** + * Gets the version string for the Dart VM. + * + * The version of the Dart VM can be accessed without initializing the VM. + * + * \return The version string for the embedded Dart VM. + */ +DART_EXPORT const char* Dart_VersionString(void); + +/** + * Isolate specific flags are set when creating a new isolate using the + * Dart_IsolateFlags structure. + * + * Current version of flags is encoded in a 32-bit integer with 16 bits used + * for each part. + */ + +#define DART_FLAGS_CURRENT_VERSION (0x0000000d) + +typedef struct { + int32_t version; + bool enable_asserts; + bool use_field_guards; + bool use_osr; + bool obfuscate; + bool load_vmservice_library; + bool null_safety; + bool is_system_isolate; + bool is_service_isolate; + bool is_kernel_isolate; + bool snapshot_is_dontneed_safe; + bool branch_coverage; + bool coverage; +} Dart_IsolateFlags; + +/** + * Initialize Dart_IsolateFlags with correct version and default values. + */ +DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); + +/** + * An isolate creation and initialization callback function. + * + * This callback, provided by the embedder, is called when the VM + * needs to create an isolate. The callback should create an isolate + * by calling Dart_CreateIsolateGroup and load any scripts required for + * execution. + * + * This callback may be called on a different thread than the one + * running the parent isolate. + * + * When the function returns NULL, it is the responsibility of this + * function to ensure that Dart_ShutdownIsolate has been called if + * required (for example, if the isolate was created successfully by + * Dart_CreateIsolateGroup() but the root library fails to load + * successfully, then the function should call Dart_ShutdownIsolate + * before returning). + * + * When the function returns NULL, the function should set *error to + * a malloc-allocated buffer containing a useful error message. The + * caller of this function (the VM) will make sure that the buffer is + * freed. + * + * \param script_uri The uri of the main source file or snapshot to load. + * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for + * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the + * library tag handler of the parent isolate. + * The callback is responsible for loading the program by a call to + * Dart_LoadScriptFromKernel. + * \param main The name of the main entry point this isolate will + * eventually run. This is provided for advisory purposes only to + * improve debugging messages. The main function is not invoked by + * this function. + * \param package_root Ignored. + * \param package_config Uri of the package configuration file (either in format + * of .packages or .dart_tool/package_config.json) for this isolate + * to resolve package imports against. If this parameter is not passed the + * package resolution of the parent isolate should be used. + * \param flags Default flags for this isolate being spawned. Either inherited + * from the spawning isolate or passed as parameters when spawning the + * isolate from Dart code. + * \param isolate_data The isolate data which was passed to the + * parent isolate when it was created by calling Dart_CreateIsolateGroup(). + * \param error A structure into which the embedder can place a + * C string containing an error message in the case of failures. + * + * \return The embedder returns NULL if the creation and + * initialization was not successful and the isolate if successful. + */ +typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)( + const char* script_uri, + const char* main, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* isolate_data, + char** error); + +/** + * An isolate initialization callback function. + * + * This callback, provided by the embedder, is called when the VM has created an + * isolate within an existing isolate group (i.e. from the same source as an + * existing isolate). + * + * The callback should setup native resolvers and might want to set a custom + * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as + * runnable. + * + * This callback may be called on a different thread than the one + * running the parent isolate. + * + * When the function returns `false`, it is the responsibility of this + * function to ensure that `Dart_ShutdownIsolate` has been called. + * + * When the function returns `false`, the function should set *error to + * a malloc-allocated buffer containing a useful error message. The + * caller of this function (the VM) will make sure that the buffer is + * freed. + * + * \param child_isolate_data The callback data to associate with the new + * child isolate. + * \param error A structure into which the embedder can place a + * C string containing an error message in the case the initialization fails. + * + * \return The embedder returns true if the initialization was successful and + * false otherwise (in which case the VM will terminate the isolate). + */ +typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data, + char** error); + +/** + * An isolate shutdown callback function. + * + * This callback, provided by the embedder, is called before the vm + * shuts down an isolate. The isolate being shutdown will be the current + * isolate. It is safe to run Dart code. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. + */ +typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data, + void* isolate_data); + +/** + * An isolate cleanup callback function. + * + * This callback, provided by the embedder, is called after the vm + * shuts down an isolate. There will be no current isolate and it is *not* + * safe to run Dart code. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. + */ +typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data, + void* isolate_data); + +/** + * An isolate group cleanup callback function. + * + * This callback, provided by the embedder, is called after the vm + * shuts down an isolate group. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * + */ +typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data); + +/** + * A thread start callback function. + * This callback, provided by the embedder, is called after a thread in the + * vm thread pool starts. + * This function could be used to adjust thread priority or attach native + * resources to the thread. + */ +typedef void (*Dart_ThreadStartCallback)(void); + +/** + * A thread death callback function. + * This callback, provided by the embedder, is called before a thread in the + * vm thread pool exits. + * This function could be used to dispose of native resources that + * are associated and attached to the thread, in order to avoid leaks. + */ +typedef void (*Dart_ThreadExitCallback)(void); + +/** + * Opens a file for reading or writing. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param name The name of the file to open. + * \param write A boolean variable which indicates if the file is to + * opened for writing. If there is an existing file it needs to truncated. + */ +typedef void* (*Dart_FileOpenCallback)(const char* name, bool write); + +/** + * Read contents of file. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param data Buffer allocated in the callback into which the contents + * of the file are read into. It is the responsibility of the caller to + * free this buffer. + * \param file_length A variable into which the length of the file is returned. + * In the case of an error this value would be -1. + * \param stream Handle to the opened file. + */ +typedef void (*Dart_FileReadCallback)(uint8_t** data, + intptr_t* file_length, + void* stream); + +/** + * Write data into file. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param data Buffer which needs to be written into the file. + * \param length Length of the buffer. + * \param stream Handle to the opened file. + */ +typedef void (*Dart_FileWriteCallback)(const void* data, + intptr_t length, + void* stream); + +/** + * Closes the opened file. + * + * Callback provided by the embedder for file operations. If the + * embedder does not allow file operations this callback can be + * NULL. + * + * \param stream Handle to the opened file. + */ +typedef void (*Dart_FileCloseCallback)(void* stream); + +typedef bool (*Dart_EntropySource)(uint8_t* buffer, intptr_t length); + +/** + * Callback provided by the embedder that is used by the vmservice isolate + * to request the asset archive. The asset archive must be an uncompressed tar + * archive that is stored in a Uint8List. + * + * If the embedder has no vmservice isolate assets, the callback can be NULL. + * + * \return The embedder must return a handle to a Uint8List containing an + * uncompressed tar archive or null. + */ +typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(void); + +/** + * The current version of the Dart_InitializeFlags. Should be incremented every + * time Dart_InitializeFlags changes in a binary incompatible way. + */ +#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000008) + +/** Forward declaration */ +struct Dart_CodeObserver; + +/** + * Callback provided by the embedder that is used by the VM to notify on code + * object creation, *before* it is invoked the first time. + * This is useful for embedders wanting to e.g. keep track of PCs beyond + * the lifetime of the garbage collected code objects. + * Note that an address range may be used by more than one code object over the + * lifecycle of a process. Clients of this function should record timestamps for + * these compilation events and when collecting PCs to disambiguate reused + * address ranges. + */ +typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer, + const char* name, + uintptr_t base, + uintptr_t size); + +typedef struct Dart_CodeObserver { + void* data; + + Dart_OnNewCodeCallback on_new_code; +} Dart_CodeObserver; + +/** + * Optional callback provided by the embedder that is used by the VM to + * implement registration of kernel blobs for the subsequent Isolate.spawnUri + * If no callback is provided, the registration of kernel blobs will throw + * an error. + * + * \param kernel_buffer A buffer which contains a kernel program. Callback + * should copy the contents of `kernel_buffer` as + * it may be freed immediately after registration. + * \param kernel_buffer_size The size of `kernel_buffer`. + * + * \return A C string representing URI which can be later used + * to spawn a new isolate. This C String should be scope allocated + * or owned by the embedder. + * Returns NULL if embedder runs out of memory. + */ +typedef const char* (*Dart_RegisterKernelBlobCallback)( + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); + +/** + * Optional callback provided by the embedder that is used by the VM to + * unregister kernel blobs. + * If no callback is provided, the unregistration of kernel blobs will throw + * an error. + * + * \param kernel_blob_uri URI of the kernel blob to unregister. + */ +typedef void (*Dart_UnregisterKernelBlobCallback)(const char* kernel_blob_uri); + +/** + * Describes how to initialize the VM. Used with Dart_Initialize. + */ +typedef struct { + /** + * Identifies the version of the struct used by the client. + * should be initialized to DART_INITIALIZE_PARAMS_CURRENT_VERSION. + */ + int32_t version; + + /** + * A buffer containing snapshot data, or NULL if no snapshot is provided. + * + * If provided, the buffer must remain valid until Dart_Cleanup returns. + */ + const uint8_t* vm_snapshot_data; + + /** + * A buffer containing a snapshot of precompiled instructions, or NULL if + * no snapshot is provided. + * + * If provided, the buffer must remain valid until Dart_Cleanup returns. + */ + const uint8_t* vm_snapshot_instructions; + + /** + * A function to be called during isolate group creation. + * See Dart_IsolateGroupCreateCallback. + */ + Dart_IsolateGroupCreateCallback create_group; + + /** + * A function to be called during isolate + * initialization inside an existing isolate group. + * See Dart_InitializeIsolateCallback. + */ + Dart_InitializeIsolateCallback initialize_isolate; + + /** + * A function to be called right before an isolate is shutdown. + * See Dart_IsolateShutdownCallback. + */ + Dart_IsolateShutdownCallback shutdown_isolate; + + /** + * A function to be called after an isolate was shutdown. + * See Dart_IsolateCleanupCallback. + */ + Dart_IsolateCleanupCallback cleanup_isolate; + + /** + * A function to be called after an isolate group is + * shutdown. See Dart_IsolateGroupCleanupCallback. + */ + Dart_IsolateGroupCleanupCallback cleanup_group; + + Dart_ThreadStartCallback thread_start; + Dart_ThreadExitCallback thread_exit; + Dart_FileOpenCallback file_open; + Dart_FileReadCallback file_read; + Dart_FileWriteCallback file_write; + Dart_FileCloseCallback file_close; + Dart_EntropySource entropy_source; + + /** + * A function to be called by the service isolate when it requires the + * vmservice assets archive. See Dart_GetVMServiceAssetsArchive. + */ + Dart_GetVMServiceAssetsArchive get_service_assets; + + bool start_kernel_isolate; + + /** + * An external code observer callback function. The observer can be invoked + * as early as during the Dart_Initialize() call. + */ + Dart_CodeObserver* code_observer; + + /** + * Kernel blob registration callback function. See Dart_RegisterKernelBlobCallback. + */ + Dart_RegisterKernelBlobCallback register_kernel_blob; + + /** + * Kernel blob unregistration callback function. See Dart_UnregisterKernelBlobCallback. + */ + Dart_UnregisterKernelBlobCallback unregister_kernel_blob; + +#if defined(__Fuchsia__) + /** + * The resource needed to use zx_vmo_replace_as_executable. Can be + * ZX_HANDLE_INVALID if the process has ambient-replace-as-executable or if + * executable memory is not needed (e.g., this is an AOT runtime). + */ + zx_handle_t vmex_resource; +#endif +} Dart_InitializeParams; + +/** + * Initializes the VM. + * + * \param params A struct containing initialization information. The version + * field of the struct must be DART_INITIALIZE_PARAMS_CURRENT_VERSION. + * + * \return NULL if initialization is successful. Returns an error message + * otherwise. The caller is responsible for freeing the error message. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_Initialize( + Dart_InitializeParams* params); + +/** + * Cleanup state in the VM before process termination. + * + * \return NULL if cleanup is successful. Returns an error message otherwise. + * The caller is responsible for freeing the error message. + * + * NOTE: This function must not be called on a thread that was created by the VM + * itself. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_Cleanup(void); + +/** + * Sets command line flags. Should be called before Dart_Initialize. + * + * \param argc The length of the arguments array. + * \param argv An array of arguments. + * + * \return NULL if successful. Returns an error message otherwise. + * The caller is responsible for freeing the error message. + * + * NOTE: This call does not store references to the passed in c-strings. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_SetVMFlags( + int argc, + const char** argv); + +/** + * Returns true if the named VM flag is of boolean type, specified, and set to + * true. + * + * \param flag_name The name of the flag without leading punctuation + * (example: "enable_asserts"). + */ +DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); + +/* + * ======== + * Isolates + * ======== + */ + +/** + * Creates a new isolate. The new isolate becomes the current isolate. + * + * A snapshot can be used to restore the VM quickly to a saved state + * and is useful for fast startup. If snapshot data is provided, the + * isolate will be started using that snapshot data. Requires a core snapshot or + * an app snapshot created by Dart_CreateSnapshot or + * Dart_CreatePrecompiledSnapshot* from a VM with the same version. + * + * Requires there to be no current isolate. + * + * \param script_uri The main source file or snapshot this isolate will load. + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a + * child isolate is created by Isolate.spawn. The embedder should use a URI + * that allows it to load the same program into such a child isolate. + * \param name A short name for the isolate to improve debugging messages. + * Typically of the format 'foo.dart:main()'. + * \param isolate_snapshot_data Buffer containing the snapshot data of the + * isolate or NULL if no snapshot is provided. If provided, the buffer must + * remain valid until the isolate shuts down. + * \param isolate_snapshot_instructions Buffer containing the snapshot + * instructions of the isolate or NULL if no snapshot is provided. If + * provided, the buffer must remain valid until the isolate shuts down. + * \param flags Pointer to VM specific flags or NULL for default flags. + * \param isolate_group_data Embedder group data. This data can be obtained + * by calling Dart_IsolateGroupData and will be passed to the + * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and + * Dart_IsolateGroupCleanupCallback. + * \param isolate_data Embedder data. This data will be passed to + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from + * this parent isolate. + * \param error Returns NULL if creation is successful, an error message + * otherwise. The caller is responsible for calling free() on the error + * message. + * + * \return The new isolate on success, or NULL if isolate creation failed. + */ +DART_EXPORT Dart_Isolate +Dart_CreateIsolateGroup(const char* script_uri, + const char* name, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instructions, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); +/** + * Creates a new isolate inside the isolate group of [group_member]. + * + * Requires there to be no current isolate. + * + * \param group_member An isolate from the same group into which the newly created + * isolate should be born into. Other threads may not have entered / enter this + * member isolate. + * \param name A short name for the isolate for debugging purposes. + * \param shutdown_callback A callback to be called when the isolate is being + * shutdown (may be NULL). + * \param cleanup_callback A callback to be called when the isolate is being + * cleaned up (may be NULL). + * \param child_isolate_data The embedder-specific data associated with this isolate. + * \param error Set to NULL if creation is successful, set to an error + * message otherwise. The caller is responsible for calling free() on the + * error message. + * + * \return The newly created isolate on success, or NULL if isolate creation + * failed. + * + * If successful, the newly created isolate will become the current isolate. + */ +DART_EXPORT Dart_Isolate +Dart_CreateIsolateInGroup(Dart_Isolate group_member, + const char* name, + Dart_IsolateShutdownCallback shutdown_callback, + Dart_IsolateCleanupCallback cleanup_callback, + void* child_isolate_data, + char** error); + +/* TODO(turnidge): Document behavior when there is already a current + * isolate. */ + +/** + * Creates a new isolate from a Dart Kernel file. The new isolate + * becomes the current isolate. + * + * Requires there to be no current isolate. + * + * \param script_uri The main source file or snapshot this isolate will load. + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a + * child isolate is created by Isolate.spawn. The embedder should use a URI that + * allows it to load the same program into such a child isolate. + * \param name A short name for the isolate to improve debugging messages. + * Typically of the format 'foo.dart:main()'. + * \param kernel_buffer A buffer which contains a kernel/DIL program. Must + * remain valid until isolate shutdown. + * \param kernel_buffer_size The size of `kernel_buffer`. + * \param flags Pointer to VM specific flags or NULL for default flags. + * \param isolate_group_data Embedder group data. This data can be obtained + * by calling Dart_IsolateGroupData and will be passed to the + * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and + * Dart_IsolateGroupCleanupCallback. + * \param isolate_data Embedder data. This data will be passed to + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from + * this parent isolate. + * \param error Returns NULL if creation is successful, an error message + * otherwise. The caller is responsible for calling free() on the error + * message. + * + * \return The new isolate on success, or NULL if isolate creation failed. + */ +DART_EXPORT Dart_Isolate +Dart_CreateIsolateGroupFromKernel(const char* script_uri, + const char* name, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); +/** + * Shuts down the current isolate. After this call, the current isolate is NULL. + * Any current scopes created by Dart_EnterScope will be exited. Invokes the + * shutdown callback and any callbacks of remaining weak persistent handles. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_ShutdownIsolate(void); +/* TODO(turnidge): Document behavior when there is no current isolate. */ + +/** + * Returns the current isolate. Will return NULL if there is no + * current isolate. + */ +DART_EXPORT Dart_Isolate Dart_CurrentIsolate(void); + +/** + * Returns the callback data associated with the current isolate. This + * data was set when the isolate got created or initialized. + */ +DART_EXPORT void* Dart_CurrentIsolateData(void); + +/** + * Returns the callback data associated with the given isolate. This + * data was set when the isolate got created or initialized. + */ +DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate); + +/** + * Returns the current isolate group. Will return NULL if there is no + * current isolate group. + */ +DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup(void); + +/** + * Returns the callback data associated with the current isolate group. This + * data was passed to the isolate group when it was created. + */ +DART_EXPORT void* Dart_CurrentIsolateGroupData(void); + +/** + * Gets an id that uniquely identifies current isolate group. + * + * It is the responsibility of the caller to free the returned ID. + */ +typedef int64_t Dart_IsolateGroupId; +DART_EXPORT Dart_IsolateGroupId Dart_CurrentIsolateGroupId(void); + +/** + * Returns the callback data associated with the specified isolate group. This + * data was passed to the isolate when it was created. + * The embedder is responsible for ensuring the consistency of this data + * with respect to the lifecycle of an isolate group. + */ +DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate); + +/** + * Returns the debugging name for the current isolate. + * + * This name is unique to each isolate and should only be used to make + * debugging messages more comprehensible. + */ +DART_EXPORT Dart_Handle Dart_DebugName(void); + +/** + * Returns the debugging name for the current isolate. + * + * This name is unique to each isolate and should only be used to make + * debugging messages more comprehensible. + * + * The returned string is scope allocated and is only valid until the next call + * to Dart_ExitScope. + */ +DART_EXPORT const char* Dart_DebugNameToCString(void); + +/** + * Returns the ID for an isolate which is used to query the service protocol. + * + * It is the responsibility of the caller to free the returned ID. + */ +DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate); + +/** + * Enters an isolate. After calling this function, + * the current isolate will be set to the provided isolate. + * + * Requires there to be no current isolate. Multiple threads may not be in + * the same isolate at once. + */ +DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate); + +/** + * Kills the given isolate. + * + * This function has the same effect as dart:isolate's + * Isolate.kill(priority:immediate). + * It can interrupt ordinary Dart code but not native code. If the isolate is + * in the middle of a long running native function, the isolate will not be + * killed until control returns to Dart. + * + * Does not require a current isolate. It is safe to kill the current isolate if + * there is one. + */ +DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate); + +/** + * Notifies the VM that the embedder expects to be idle until |deadline|. The VM + * may use this time to perform garbage collection or other tasks to avoid + * delays during execution of Dart code in the future. + * + * |deadline| is measured in microseconds against the system's monotonic time. + * This clock can be accessed via Dart_TimelineGetMicros(). + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_NotifyIdle(int64_t deadline); + +typedef void (*Dart_HeapSamplingReportCallback)(void* context, void* data); + +typedef void* (*Dart_HeapSamplingCreateCallback)( + Dart_Isolate isolate, + Dart_IsolateGroup isolate_group, + const char* cls_name, + intptr_t allocation_size); +typedef void (*Dart_HeapSamplingDeleteCallback)(void* data); + +/** + * Starts the heap sampling profiler for each thread in the VM. + */ +DART_EXPORT void Dart_EnableHeapSampling(void); + +/* + * Stops the heap sampling profiler for each thread in the VM. + */ +DART_EXPORT void Dart_DisableHeapSampling(void); + +/* Registers callbacks are invoked once per sampled allocation upon object + * allocation and garbage collection. + * + * |create_callback| can be used to associate additional data with the sampled + * allocation, such as a stack trace. This data pointer will be passed to + * |delete_callback| to allow for proper disposal when the object associated + * with the allocation sample is collected. + * + * The provided callbacks must not call into the VM and should do as little + * work as possible to avoid performance penalities during object allocation and + * garbage collection. + * + * NOTE: It is a fatal error to set either callback to null once they have been + * initialized. + */ +DART_EXPORT void Dart_RegisterHeapSamplingCallback( + Dart_HeapSamplingCreateCallback create_callback, + Dart_HeapSamplingDeleteCallback delete_callback); + +/* + * Reports the surviving allocation samples for all live isolate groups in the + * VM. + * + * When the callback is invoked: + * - |context| will be the context object provided when invoking + * |Dart_ReportSurvivingAllocations|. This can be safely set to null if not + * required. + * - |heap_size| will be equal to the size of the allocated object associated + * with the sample. + * - |cls_name| will be a C String representing + * the class name of the allocated object. This string is valid for the + * duration of the call to Dart_ReportSurvivingAllocations and can be + * freed by the VM at any point after the method returns. + * - |data| will be set to the data associated with the sample by + * |Dart_HeapSamplingCreateCallback|. + * + * If |force_gc| is true, a full GC will be performed before reporting the + * allocations. + */ +DART_EXPORT void Dart_ReportSurvivingAllocations( + Dart_HeapSamplingReportCallback callback, + void* context, + bool force_gc); + +/* + * Sets the average heap sampling rate based on a number of |bytes| for each + * thread. + * + * In other words, approximately every |bytes| allocated will create a sample. + * Defaults to 512 KiB. + */ +DART_EXPORT void Dart_SetHeapSamplingPeriod(intptr_t bytes); + +/** + * Notifies the VM that the embedder expects the application's working set has + * recently shrunk significantly and is not expected to rise in the near future. + * The VM may spend O(heap-size) time performing clean up work. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_NotifyDestroyed(void); + +/** + * Notifies the VM that the system is running low on memory. + * + * Does not require a current isolate. Only valid after calling Dart_Initialize. + */ +DART_EXPORT void Dart_NotifyLowMemory(void); + +typedef enum { + /** + * Balanced + */ + Dart_PerformanceMode_Default, + /** + * Optimize for low latency, at the expense of throughput and memory overhead + * by performing work in smaller batches (requiring more overhead) or by + * delaying work (requiring more memory). An embedder should not remain in + * this mode indefinitely. + */ + Dart_PerformanceMode_Latency, + /** + * Optimize for high throughput, at the expense of latency and memory overhead + * by performing work in larger batches with more intervening growth. + */ + Dart_PerformanceMode_Throughput, + /** + * Optimize for low memory, at the expensive of throughput and latency by more + * frequently performing work. + */ + Dart_PerformanceMode_Memory, +} Dart_PerformanceMode; + +/** + * Set the desired performance trade-off. + * + * Requires a current isolate. + * + * Returns the previous performance mode. + */ +DART_EXPORT Dart_PerformanceMode +Dart_SetPerformanceMode(Dart_PerformanceMode mode); + +/** + * Starts the CPU sampling profiler. + */ +DART_EXPORT void Dart_StartProfiling(void); + +/** + * Stops the CPU sampling profiler. + * + * Note that some profile samples might still be taken after this function + * returns due to the asynchronous nature of the implementation on some + * platforms. + */ +DART_EXPORT void Dart_StopProfiling(void); + +/** + * Notifies the VM that the current thread should not be profiled until a + * matching call to Dart_ThreadEnableProfiling is made. + * + * NOTE: By default, if a thread has entered an isolate it will be profiled. + * This function should be used when an embedder knows a thread is about + * to make a blocking call and wants to avoid unnecessary interrupts by + * the profiler. + */ +DART_EXPORT void Dart_ThreadDisableProfiling(void); + +/** + * Notifies the VM that the current thread should be profiled. + * + * NOTE: It is only legal to call this function *after* calling + * Dart_ThreadDisableProfiling. + * + * NOTE: By default, if a thread has entered an isolate it will be profiled. + */ +DART_EXPORT void Dart_ThreadEnableProfiling(void); + +/** + * Register symbol information for the Dart VM's profiler and crash dumps. + * + * This consumes the output of //topaz/runtime/dart/profiler_symbols, which + * should be treated as opaque. + */ +DART_EXPORT void Dart_AddSymbols(const char* dso_name, + void* buffer, + intptr_t buffer_size); + +/** + * Exits an isolate. After this call, Dart_CurrentIsolate will + * return NULL. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_ExitIsolate(void); +/* TODO(turnidge): We don't want users of the api to be able to exit a + * "pure" dart isolate. Implement and document. */ + +/** + * Creates a full snapshot of the current isolate heap. + * + * A full snapshot is a compact representation of the dart vm isolate heap + * and dart isolate heap states. These snapshots are used to initialize + * the vm isolate on startup and fast initialization of an isolate. + * A Snapshot of the heap is created before any dart code has executed. + * + * Requires there to be a current isolate. Not available in the precompiled + * runtime (check Dart_IsPrecompiledRuntime). + * + * \param vm_snapshot_data_buffer Returns a pointer to a buffer containing the + * vm snapshot. This buffer is scope allocated and is only valid + * until the next call to Dart_ExitScope. + * \param vm_snapshot_data_size Returns the size of vm_snapshot_data_buffer. + * \param isolate_snapshot_data_buffer Returns a pointer to a buffer containing + * the isolate snapshot. This buffer is scope allocated and is only valid + * until the next call to Dart_ExitScope. + * \param isolate_snapshot_data_size Returns the size of + * isolate_snapshot_data_buffer. + * \param is_core Create a snapshot containing core libraries. + * Such snapshot should be agnostic to null safety mode. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer, + intptr_t* vm_snapshot_data_size, + uint8_t** isolate_snapshot_data_buffer, + intptr_t* isolate_snapshot_data_size, + bool is_core); + +/** + * Returns whether the buffer contains a kernel file. + * + * \param buffer Pointer to a buffer that might contain a kernel binary. + * \param buffer_size Size of the buffer. + * + * \return Whether the buffer contains a kernel binary (full or partial). + */ +DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size); + +/** + * Make isolate runnable. + * + * When isolates are spawned, this function is used to indicate that + * the creation and initialization (including script loading) of the + * isolate is complete and the isolate can start. + * This function expects there to be no current isolate. + * + * \param isolate The isolate to be made runnable. + * + * \return NULL if successful. Returns an error message otherwise. The caller + * is responsible for freeing the error message. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable( + Dart_Isolate isolate); + +/* + * ================== + * Messages and Ports + * ================== + */ + +/** + * A port is used to send or receive inter-isolate messages + */ +typedef int64_t Dart_Port; +typedef struct { + int64_t port_id; + int64_t origin_id; +} Dart_PortEx; + +/** + * ILLEGAL_PORT is a port number guaranteed never to be associated with a valid + * port. + */ +#define ILLEGAL_PORT ((Dart_Port)0) + +/** + * A message notification callback. + * + * This callback allows the embedder to provide a custom wakeup mechanism for + * the delivery of inter-isolate messages. This function is called once per + * message on an arbitrary thread. It is the responsibility of the embedder to + * eventually call Dart_HandleMessage once per callback received with the + * destination isolate set as the current isolate to process the message. + */ +typedef void (*Dart_MessageNotifyCallback)(Dart_Isolate destination_isolate); + +/** + * Allows embedders to provide a custom wakeup mechanism for the delivery of + * inter-isolate messages. This setting only applies to the current isolate. + * + * This mechanism is optional: if not provided, the isolate will be scheduled on + * a VM-managed thread pool. An embedder should provide this callback if it + * wants to run an isolate on a specific thread or to interleave handling of + * inter-isolate messages with other event sources. + * + * Most embedders will only call this function once, before isolate + * execution begins. If this function is called after isolate + * execution begins, the embedder is responsible for threading issues. + */ +DART_EXPORT void Dart_SetMessageNotifyCallback( + Dart_MessageNotifyCallback message_notify_callback); +/* TODO(turnidge): Consider moving this to isolate creation so that it + * is impossible to mess up. */ + +/** + * Query the current message notify callback for the isolate. + * + * \return The current message notify callback for the isolate. + */ +DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback(void); + +/** + * The VM's default message handler supports pausing an isolate before it + * processes the first message and right after the it processes the isolate's + * final message. This can be controlled for all isolates by two VM flags: + * + * `--pause-isolates-on-start` + * `--pause-isolates-on-exit` + * + * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be + * used to control this behaviour on a per-isolate basis. + * + * When an embedder is using a Dart_MessageNotifyCallback the embedder + * needs to cooperate with the VM so that the service protocol can report + * accurate information about isolates and so that tools such as debuggers + * work reliably. + * + * The following functions can be used to implement pausing on start and exit. + */ + +/** + * If the VM flag `--pause-isolates-on-start` was passed this will be true. + * + * \return A boolean value indicating if pause on start was requested. + */ +DART_EXPORT bool Dart_ShouldPauseOnStart(void); + +/** + * Override the VM flag `--pause-isolates-on-start` for the current isolate. + * + * \param should_pause Should the isolate be paused on start? + * + * NOTE: This must be called before Dart_IsolateMakeRunnable. + */ +DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause); + +/** + * Is the current isolate paused on start? + * + * \return A boolean value indicating if the isolate is paused on start. + */ +DART_EXPORT bool Dart_IsPausedOnStart(void); + +/** + * Called when the embedder has paused the current isolate on start and when + * the embedder has resumed the isolate. + * + * \param paused Is the isolate paused on start? + */ +DART_EXPORT void Dart_SetPausedOnStart(bool paused); + +/** + * If the VM flag `--pause-isolates-on-exit` was passed this will be true. + * + * \return A boolean value indicating if pause on exit was requested. + */ +DART_EXPORT bool Dart_ShouldPauseOnExit(void); + +/** + * Override the VM flag `--pause-isolates-on-exit` for the current isolate. + * + * \param should_pause Should the isolate be paused on exit? + * + */ +DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause); + +/** + * Is the current isolate paused on exit? + * + * \return A boolean value indicating if the isolate is paused on exit. + */ +DART_EXPORT bool Dart_IsPausedOnExit(void); + +/** + * Called when the embedder has paused the current isolate on exit and when + * the embedder has resumed the isolate. + * + * \param paused Is the isolate paused on exit? + */ +DART_EXPORT void Dart_SetPausedOnExit(bool paused); + +/** + * Called when the embedder has caught a top level unhandled exception error + * in the current isolate. + * + * NOTE: It is illegal to call this twice on the same isolate without first + * clearing the sticky error to null. + * + * \param error The unhandled exception error. + */ +DART_EXPORT void Dart_SetStickyError(Dart_Handle error); + +/** + * Does the current isolate have a sticky error? + */ +DART_EXPORT bool Dart_HasStickyError(void); + +/** + * Gets the sticky error for the current isolate. + * + * \return A handle to the sticky error object or null. + */ +DART_EXPORT Dart_Handle Dart_GetStickyError(void); + +/** + * Handles the next pending message for the current isolate. + * + * May generate an unhandled exception error. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_HandleMessage(void); + +/** + * Handles any pending messages for the vm service for the current + * isolate. + * + * This function may be used by an embedder at a breakpoint to avoid + * pausing the vm service. + * + * This function can indirectly cause the message notify callback to + * be called. + * + * \return true if the vm service requests the program resume + * execution, false otherwise + */ +DART_EXPORT bool Dart_HandleServiceMessages(void); + +/** + * Does the current isolate have pending service messages? + * + * \return true if the isolate has pending service messages, false otherwise. + */ +DART_EXPORT bool Dart_HasServiceMessages(void); + +/** + * Processes any incoming messages for the current isolate. + * + * This function may only be used when the embedder has not provided + * an alternate message delivery mechanism with + * Dart_SetMessageCallbacks. It is provided for convenience. + * + * This function waits for incoming messages for the current + * isolate. As new messages arrive, they are handled using + * Dart_HandleMessage. The routine exits when all ports to the + * current isolate are closed. + * + * \return A valid handle if the run loop exited successfully. If an + * exception or other error occurs while processing messages, an + * error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_RunLoop(void); + +/** + * Lets the VM run message processing for the isolate. + * + * This function expects there to a current isolate and the current isolate + * must not have an active api scope. The VM will take care of making the + * isolate runnable (if not already), handles its message loop and will take + * care of shutting the isolate down once it's done. + * + * \param errors_are_fatal Whether uncaught errors should be fatal. + * \param on_error_port A port to notify on uncaught errors (or ILLEGAL_PORT). + * \param on_exit_port A port to notify on exit (or ILLEGAL_PORT). + * \param error A non-NULL pointer which will hold an error message if the call + * fails. The error has to be free()ed by the caller. + * + * \return If successful the VM takes ownership of the isolate and takes care + * of its message loop. If not successful the caller retains ownership of the + * isolate. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT bool Dart_RunLoopAsync( + bool errors_are_fatal, + Dart_Port on_error_port, + Dart_Port on_exit_port, + char** error); + +/* TODO(turnidge): Should this be removed from the public api? */ + +/** + * Gets the main port id for the current isolate. + */ +DART_EXPORT Dart_Port Dart_GetMainPortId(void); + +/** + * Does the current isolate have live ReceivePorts? + * + * A ReceivePort is live when it has not been closed. + */ +DART_EXPORT bool Dart_HasLivePorts(void); + +/** + * Posts a message for some isolate. The message is a serialized + * object. + * + * Requires there to be a current isolate. + * + * For posting messages outside of an isolate see \ref Dart_PostCObject. + * + * \param port_id The destination port. + * \param object An object from the current isolate. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object); + +/** + * Returns a new SendPort with the provided port id. + * + * If there is a possibility of a port closing since port_id was acquired + * for a SendPort, one should use Dart_NewSendPortEx and + * Dart_SendPortGetIdEx. + * + * \param port_id The destination port. + * + * \return A new SendPort if no errors occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id); + +/** + * Returns a new SendPort with the provided port id and origin id. + * + * \param portex_id The destination composte port id. + * + * \return A new SendPort if no errors occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewSendPortEx(Dart_PortEx portex_id); + +/** + * Gets the SendPort id for the provided SendPort. + * \param port A SendPort object whose id is desired. + * \param port_id Returns the id of the SendPort. + * \return Success if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port, + Dart_Port* port_id); + +/** + * Gets the SendPort and Origin ids for the provided SendPort. + * \param port A SendPort object whose id is desired. + * \param portex_id Returns composite id of the SendPort. + * \return Success if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_SendPortGetIdEx(Dart_Handle port, + Dart_PortEx* portex_id); +/* + * ====== + * Scopes + * ====== + */ + +/** + * Enters a new scope. + * + * All new local handles will be created in this scope. Additionally, + * some functions may return "scope allocated" memory which is only + * valid within this scope. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_EnterScope(void); + +/** + * Exits a scope. + * + * The previous scope (if any) becomes the current scope. + * + * Requires there to be a current isolate. + */ +DART_EXPORT void Dart_ExitScope(void); + +/** + * The Dart VM uses "zone allocation" for temporary structures. Zones + * support very fast allocation of small chunks of memory. The chunks + * cannot be deallocated individually, but instead zones support + * deallocating all chunks in one fast operation. + * + * This function makes it possible for the embedder to allocate + * temporary data in the VMs zone allocator. + * + * Zone allocation is possible: + * 1. when inside a scope where local handles can be allocated + * 2. when processing a message from a native port in a native port + * handler + * + * All the memory allocated this way will be reclaimed either on the + * next call to Dart_ExitScope or when the native port handler exits. + * + * \param size Size of the memory to allocate. + * + * \return A pointer to the allocated memory. NULL if allocation + * failed. Failure might due to is no current VM zone. + */ +DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size); + +/* + * ======= + * Objects + * ======= + */ + +/** + * Returns the null object. + * + * \return A handle to the null object. + */ +DART_EXPORT Dart_Handle Dart_Null(void); + +/** + * Is this object null? + */ +DART_EXPORT bool Dart_IsNull(Dart_Handle object); + +/** + * Returns the empty string object. + * + * \return A handle to the empty string object. + */ +DART_EXPORT Dart_Handle Dart_EmptyString(void); + +/** + * Returns types that are not classes, and which therefore cannot be looked up + * as library members by Dart_GetType. + * + * \return A handle to the dynamic, void or Never type. + */ +DART_EXPORT Dart_Handle Dart_TypeDynamic(void); +DART_EXPORT Dart_Handle Dart_TypeVoid(void); +DART_EXPORT Dart_Handle Dart_TypeNever(void); + +/** + * Checks if the two objects are equal. + * + * The result of the comparison is returned through the 'equal' + * parameter. The return value itself is used to indicate success or + * failure, not equality. + * + * May generate an unhandled exception error. + * + * \param obj1 An object to be compared. + * \param obj2 An object to be compared. + * \param equal Returns the result of the equality comparison. + * + * \return A valid handle if no error occurs during the comparison. + */ +DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1, + Dart_Handle obj2, + bool* equal); + +/** + * Is this object an instance of some type? + * + * The result of the test is returned through the 'instanceof' parameter. + * The return value itself is used to indicate success or failure. + * + * \param object An object. + * \param type A type. + * \param instanceof Return true if 'object' is an instance of type 'type'. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object, + Dart_Handle type, + bool* instanceof); + +/** + * Query object type. + * + * \param object Some Object. + * + * \return true if Object is of the specified type. + */ +DART_EXPORT bool Dart_IsInstance(Dart_Handle object); +DART_EXPORT bool Dart_IsNumber(Dart_Handle object); +DART_EXPORT bool Dart_IsInteger(Dart_Handle object); +DART_EXPORT bool Dart_IsDouble(Dart_Handle object); +DART_EXPORT bool Dart_IsBoolean(Dart_Handle object); +DART_EXPORT bool Dart_IsString(Dart_Handle object); +DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */ +DART_EXPORT bool Dart_IsList(Dart_Handle object); +DART_EXPORT bool Dart_IsMap(Dart_Handle object); +DART_EXPORT bool Dart_IsLibrary(Dart_Handle object); +DART_EXPORT bool Dart_IsType(Dart_Handle handle); +DART_EXPORT bool Dart_IsFunction(Dart_Handle handle); +DART_EXPORT bool Dart_IsVariable(Dart_Handle handle); +DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle); +DART_EXPORT bool Dart_IsClosure(Dart_Handle object); +DART_EXPORT bool Dart_IsTypedData(Dart_Handle object); +DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle object); +DART_EXPORT bool Dart_IsFuture(Dart_Handle object); + +/* + * ========= + * Instances + * ========= + */ + +/* + * For the purposes of the embedding api, not all objects returned are + * Dart language objects. Within the api, we use the term 'Instance' + * to indicate handles which refer to true Dart language objects. + * + * TODO(turnidge): Reorganize the "Object" section above, pulling down + * any functions that more properly belong here. */ + +/** + * Gets the type of a Dart language object. + * + * \param instance Some Dart object. + * + * \return If no error occurs, the type is returned. Otherwise an + * error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance); + +/** + * Returns the name for the provided class type. + * + * \return A valid string handle if no error occurs during the + * operation. + */ +DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type); + +/** + * Returns the name for the provided function or method. + * + * \return A valid string handle if no error occurs during the + * operation. + */ +DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function); + +/** + * Returns a handle to the owner of a function. + * + * The owner of an instance method or a static method is its defining + * class. The owner of a top-level function is its defining + * library. The owner of the function of a non-implicit closure is the + * function of the method or closure that defines the non-implicit + * closure. + * + * \return A valid handle to the owner of the function, or an error + * handle if the argument is not a valid handle to a function. + */ +DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function); + +/** + * Determines whether a function handle refers to a static function + * of method. + * + * For the purposes of the embedding API, a top-level function is + * implicitly declared static. + * + * \param function A handle to a function or method declaration. + * \param is_static Returns whether the function or method is declared static. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function, + bool* is_static); + +/** + * Is this object a closure resulting from a tear-off (closurized method)? + * + * Returns true for closures produced when an ordinary method is accessed + * through a getter call. Returns false otherwise, in particular for closures + * produced from local function declarations. + * + * \param object Some Object. + * + * \return true if Object is a tear-off. + */ +DART_EXPORT bool Dart_IsTearOff(Dart_Handle object); + +/** + * Retrieves the function of a closure. + * + * \return A handle to the function of the closure, or an error handle if the + * argument is not a closure. + */ +DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure); + +/** + * Returns a handle to the library which contains class. + * + * \return A valid handle to the library with owns class, null if the class + * has no library or an error handle if the argument is not a valid handle + * to a class type. + */ +DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type); + +/* + * ============================= + * Numbers, Integers and Doubles + * ============================= + */ + +/** + * Does this Integer fit into a 64-bit signed integer? + * + * \param integer An integer. + * \param fits Returns true if the integer fits into a 64-bit signed integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer, + bool* fits); + +/** + * Does this Integer fit into a 64-bit unsigned integer? + * + * \param integer An integer. + * \param fits Returns true if the integer fits into a 64-bit unsigned integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer, + bool* fits); + +/** + * Returns an Integer with the provided value. + * + * \param value The value of the integer. + * + * \return The Integer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value); + +/** + * Returns an Integer with the provided value. + * + * \param value The unsigned value of the integer. + * + * \return The Integer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value); + +/** + * Returns an Integer with the provided value. + * + * \param value The value of the integer represented as a C string + * containing a hexadecimal number. + * + * \return The Integer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value); + +/** + * Gets the value of an Integer. + * + * The integer must fit into a 64-bit signed integer, otherwise an error occurs. + * + * \param integer An Integer. + * \param value Returns the value of the Integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, + int64_t* value); + +/** + * Gets the value of an Integer. + * + * The integer must fit into a 64-bit unsigned integer, otherwise an + * error occurs. + * + * \param integer An Integer. + * \param value Returns the value of the Integer. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer, + uint64_t* value); + +/** + * Gets the value of an integer as a hexadecimal C string. + * + * \param integer An Integer. + * \param value Returns the value of the Integer as a hexadecimal C + * string. This C string is scope allocated and is only valid until + * the next call to Dart_ExitScope. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer, + const char** value); + +/** + * Returns a Double with the provided value. + * + * \param value A double. + * + * \return The Double object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewDouble(double value); + +/** + * Gets the value of a Double + * + * \param double_obj A Double + * \param value Returns the value of the Double. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value); + +/** + * Returns a closure of static function 'function_name' in the class 'class_name' + * in the exported namespace of specified 'library'. + * + * \param library Library object + * \param cls_type Type object representing a Class + * \param function_name Name of the static function in the class + * + * \return A valid Dart instance if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library, + Dart_Handle cls_type, + Dart_Handle function_name); + +/* + * ======== + * Booleans + * ======== + */ + +/** + * Returns the True object. + * + * Requires there to be a current isolate. + * + * \return A handle to the True object. + */ +DART_EXPORT Dart_Handle Dart_True(void); + +/** + * Returns the False object. + * + * Requires there to be a current isolate. + * + * \return A handle to the False object. + */ +DART_EXPORT Dart_Handle Dart_False(void); + +/** + * Returns a Boolean with the provided value. + * + * \param value true or false. + * + * \return The Boolean object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewBoolean(bool value); + +/** + * Gets the value of a Boolean + * + * \param boolean_obj A Boolean + * \param value Returns the value of the Boolean. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value); + +/* + * ======= + * Strings + * ======= + */ + +/** + * Gets the length of a String. + * + * \param str A String. + * \param length Returns the length of the String. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length); + +/** + * Gets the length of UTF-8 encoded representation for a string. + * + * \param str A String. + * \param length Returns the length of UTF-8 encoded representation for string. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringUTF8Length(Dart_Handle str, + intptr_t* length); + +/** + * Returns a String built from the provided C string + * (There is an implicit assumption that the C string passed in contains + * UTF-8 encoded characters and '\0' is considered as a termination + * character). + * + * \param str A C String + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str); +/* TODO(turnidge): Document what happens when we run out of memory + * during this call. */ + +/** + * Returns a String built from an array of UTF-8 encoded characters. + * + * \param utf8_array An array of UTF-8 encoded characters. + * \param length The length of the codepoints array. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array, + intptr_t length); + +/** + * Returns a String built from an array of UTF-16 encoded characters. + * + * \param utf16_array An array of UTF-16 encoded characters. + * \param length The length of the codepoints array. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array, + intptr_t length); + +/** + * Returns a String built from an array of UTF-32 encoded characters. + * + * \param utf32_array An array of UTF-32 encoded characters. + * \param length The length of the codepoints array. + * + * \return The String object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array, + intptr_t length); + +/** + * Gets the C string representation of a String. + * (It is a sequence of UTF-8 encoded values with a '\0' termination.) + * + * \param str A string. + * \param cstr Returns the String represented as a C string. + * This C string is scope allocated and is only valid until + * the next call to Dart_ExitScope. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str, + const char** cstr); + +/** + * Gets a UTF-8 encoded representation of a String. + * + * Any unpaired surrogate code points in the string will be converted as + * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need + * to preserve unpaired surrogates, use the Dart_StringToUTF16 function. + * + * \param str A string. + * \param utf8_array Returns the String represented as UTF-8 code + * units. This UTF-8 array is scope allocated and is only valid + * until the next call to Dart_ExitScope. + * \param length Used to return the length of the array which was + * actually used. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str, + uint8_t** utf8_array, + intptr_t* length); + +/** + * Copies the UTF-8 encoded representation of a String into specified buffer. + * + * Any unpaired surrogate code points in the string will be converted as + * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). + * + * \param str A string. + * \param utf8_array Buffer into which the UTF-8 encoded representation of + * the string is copied into. + * The buffer is allocated and managed by the caller. + * \param length Specifies the length of the buffer passed in. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_CopyUTF8EncodingOfString(Dart_Handle str, + uint8_t* utf8_array, + intptr_t length); + +/** + * Gets the data corresponding to the string object. This function returns + * the data only for Latin-1 (ISO-8859-1) string objects. For all other + * string objects it returns an error. + * + * \param str A string. + * \param latin1_array An array allocated by the caller, used to return + * the string data. + * \param length Used to pass in the length of the provided array. + * Used to return the length of the array which was actually used. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str, + uint8_t* latin1_array, + intptr_t* length); + +/** + * Gets the UTF-16 encoded representation of a string. + * + * \param str A string. + * \param utf16_array An array allocated by the caller, used to return + * the array of UTF-16 encoded characters. + * \param length Used to pass in the length of the provided array. + * Used to return the length of the array which was actually used. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str, + uint16_t* utf16_array, + intptr_t* length); + +/** + * Gets the storage size in bytes of a String. + * + * \param str A String. + * \param size Returns the storage size in bytes of the String. + * This is the size in bytes needed to store the String. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size); + +/** + * Retrieves some properties associated with a String. + * Properties retrieved are: + * - character size of the string (one or two byte) + * - length of the string + * - peer pointer of string if it is an external string. + * \param str A String. + * \param char_size Returns the character size of the String. + * \param str_len Returns the length of the String. + * \param peer Returns the peer pointer associated with the String or 0 if + * there is no peer pointer for it. + * \return Success if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str, + intptr_t* char_size, + intptr_t* str_len, + void** peer); + +/* + * ===== + * Lists + * ===== + */ + +/** + * Returns a List of the desired length. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewList(intptr_t length); + +/** + * Returns a List of the desired length with the desired element type. + * + * \param element_type Handle to a nullable type object. E.g., from + * Dart_GetType or Dart_GetNullableType. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type, + intptr_t length); + +/** + * Returns a List of the desired length with the desired element type, filled + * with the provided object. + * + * \param element_type Handle to a type object. E.g., from Dart_GetType. + * + * \param fill_object Handle to an object of type 'element_type' that will be + * used to populate the list. This parameter can only be Dart_Null() if the + * length of the list is 0 or 'element_type' is a nullable type. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type, + Dart_Handle fill_object, + intptr_t length); + +/** + * Gets the length of a List. + * + * May generate an unhandled exception error. + * + * \param list A List. + * \param length Returns the length of the List. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* length); + +/** + * Gets the Object at some index of a List. + * + * If the index is out of bounds, an error occurs. + * + * May generate an unhandled exception error. + * + * \param list A List. + * \param index A valid index into the List. + * + * \return The Object in the List at the specified index if no error + * occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index); + +/** +* Gets a range of Objects from a List. +* +* If any of the requested index values are out of bounds, an error occurs. +* +* May generate an unhandled exception error. +* +* \param list A List. +* \param offset The offset of the first item to get. +* \param length The number of items to get. +* \param result A pointer to fill with the objects. +* +* \return Success if no error occurs during the operation. +*/ +DART_EXPORT Dart_Handle Dart_ListGetRange(Dart_Handle list, + intptr_t offset, + intptr_t length, + Dart_Handle* result); + +/** + * Sets the Object at some index of a List. + * + * If the index is out of bounds, an error occurs. + * + * May generate an unhandled exception error. + * + * \param list A List. + * \param index A valid index into the List. + * \param value The Object to put in the List. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list, + intptr_t index, + Dart_Handle value); + +/** + * May generate an unhandled exception error. + */ +DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list, + intptr_t offset, + uint8_t* native_array, + intptr_t length); + +/** + * May generate an unhandled exception error. + */ +DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list, + intptr_t offset, + const uint8_t* native_array, + intptr_t length); + +/* + * ==== + * Maps + * ==== + */ + +/** + * Gets the Object at some key of a Map. + * + * May generate an unhandled exception error. + * + * \param map A Map. + * \param key An Object. + * + * \return The value in the map at the specified key, null if the map does not + * contain the key, or an error handle. + */ +DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key); + +/** + * Returns whether the Map contains a given key. + * + * May generate an unhandled exception error. + * + * \param map A Map. + * + * \return A handle on a boolean indicating whether map contains the key. + * Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key); + +/** + * Gets the list of keys of a Map. + * + * May generate an unhandled exception error. + * + * \param map A Map. + * + * \return The list of key Objects if no error occurs. Otherwise returns an + * error handle. + */ +DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map); + +/* + * ========== + * Typed Data + * ========== + */ + +typedef enum { + Dart_TypedData_kByteData = 0, + Dart_TypedData_kInt8, + Dart_TypedData_kUint8, + Dart_TypedData_kUint8Clamped, + Dart_TypedData_kInt16, + Dart_TypedData_kUint16, + Dart_TypedData_kInt32, + Dart_TypedData_kUint32, + Dart_TypedData_kInt64, + Dart_TypedData_kUint64, + Dart_TypedData_kFloat32, + Dart_TypedData_kFloat64, + Dart_TypedData_kInt32x4, + Dart_TypedData_kFloat32x4, + Dart_TypedData_kFloat64x2, + Dart_TypedData_kInvalid +} Dart_TypedData_Type; + +/** + * Return type if this object is a TypedData object. + * + * \return kInvalid if the object is not a TypedData object or the appropriate + * Dart_TypedData_Type. + */ +DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object); + +/** + * Return type if this object is an external TypedData object. + * + * \return kInvalid if the object is not an external TypedData object or + * the appropriate Dart_TypedData_Type. + */ +DART_EXPORT Dart_TypedData_Type +Dart_GetTypeOfExternalTypedData(Dart_Handle object); + +/** + * Returns a TypedData object of the desired length and type. + * + * \param type The type of the TypedData object. + * \param length The length of the TypedData object (length in type units). + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type, + intptr_t length); + +/** + * Returns a TypedData object which references an external data array. + * + * \param type The type of the data array. + * \param data A data array. This array must not move. + * \param length The length of the data array (length in type units). + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type, + void* data, + intptr_t length); + +/** + * Returns a TypedData object which references an external data array. + * + * \param type The type of the data array. + * \param data A data array. This array must not move. + * \param length The length of the data array (length in type units). + * \param peer A pointer to a native object or NULL. This value is + * provided to callback when it is invoked. + * \param external_allocation_size The number of externally allocated + * bytes for peer. Used to inform the garbage collector. + * \param callback A function pointer that will be invoked sometime + * after the object is garbage collected, unless the handle has been deleted. + * A valid callback needs to be specified it cannot be NULL. + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle +Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type, + void* data, + intptr_t length, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); +DART_EXPORT Dart_Handle Dart_NewUnmodifiableExternalTypedDataWithFinalizer( + Dart_TypedData_Type type, + const void* data, + intptr_t length, + void* peer, + intptr_t external_allocation_size, + Dart_HandleFinalizer callback); + +/** + * Returns a ByteBuffer object for the typed data. + * + * \param typed_data The TypedData object. + * + * \return The ByteBuffer object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data); + +/** + * Acquires access to the internal data address of a TypedData object. + * + * \param object The typed data object whose internal data address is to + * be accessed. + * \param type The type of the object is returned here. + * \param data The internal data address is returned here. + * \param len Size of the typed array is returned here. + * + * Notes: + * When the internal address of the object is acquired any calls to a + * Dart API function that could potentially allocate an object or run + * any Dart code will return an error. + * + * Any Dart API functions for accessing the data should not be called + * before the corresponding release. In particular, the object should + * not be acquired again before its release. This leads to undefined + * behavior. + * + * \return Success if the internal data address is acquired successfully. + * Otherwise, returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, + Dart_TypedData_Type* type, + void** data, + intptr_t* len); + +/** + * Releases access to the internal data address that was acquired earlier using + * Dart_TypedDataAcquireData. + * + * \param object The typed data object whose internal data address is to be + * released. + * + * \return Success if the internal data address is released successfully. + * Otherwise, returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object); + +/** + * Returns the TypedData object associated with the ByteBuffer object. + * + * \param byte_buffer The ByteBuffer object. + * + * \return The TypedData object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle byte_buffer); + +/* + * ============================================================ + * Invoking Constructors, Methods, Closures and Field accessors + * ============================================================ + */ + +/** + * Invokes a constructor, creating a new object. + * + * This function allows hidden constructors (constructors with leading + * underscores) to be called. + * + * \param type Type of object to be constructed. + * \param constructor_name The name of the constructor to invoke. Use + * Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor. + * This name should not include the name of the class. + * \param number_of_arguments Size of the arguments array. + * \param arguments An array of arguments to the constructor. + * + * \return If the constructor is called and completes successfully, + * then the new object. If an error occurs during execution, then an + * error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_New(Dart_Handle type, + Dart_Handle constructor_name, + int number_of_arguments, + Dart_Handle* arguments); + +/** + * Allocate a new object without invoking a constructor. + * + * \param type The type of an object to be allocated. + * + * \return The new object. If an error occurs during execution, then an + * error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_Allocate(Dart_Handle type); + +/** + * Allocate a new object without invoking a constructor, and sets specified + * native fields. + * + * \param type The type of an object to be allocated. + * \param num_native_fields The number of native fields to set. + * \param native_fields An array containing the value of native fields. + * + * \return The new object. If an error occurs during execution, then an + * error handle is returned. + */ +DART_EXPORT Dart_Handle +Dart_AllocateWithNativeFields(Dart_Handle type, + intptr_t num_native_fields, + const intptr_t* native_fields); + +/** + * Invokes a method or function. + * + * The 'target' parameter may be an object, type, or library. If + * 'target' is an object, then this function will invoke an instance + * method. If 'target' is a type, then this function will invoke a + * static method. If 'target' is a library, then this function will + * invoke a top-level function from that library. + * NOTE: This API call cannot be used to invoke methods of a type object. + * + * This function ignores visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param target An object, type, or library. + * \param name The name of the function or method to invoke. + * \param number_of_arguments Size of the arguments array. + * \param arguments An array of arguments to the function. + * + * \return If the function or method is called and completes + * successfully, then the return value is returned. If an error + * occurs during execution, then an error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_Invoke(Dart_Handle target, + Dart_Handle name, + int number_of_arguments, + Dart_Handle* arguments); +/* TODO(turnidge): Document how to invoke operators. */ + +/** + * Invokes a Closure with the given arguments. + * + * May generate an unhandled exception error. + * + * \return If no error occurs during execution, then the result of + * invoking the closure is returned. If an error occurs during + * execution, then an error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_InvokeClosure(Dart_Handle closure, + int number_of_arguments, + Dart_Handle* arguments); + +/** + * Invokes a Generative Constructor on an object that was previously + * allocated using Dart_Allocate/Dart_AllocateWithNativeFields. + * + * The 'object' parameter must be an object. + * + * This function ignores visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param object An object. + * \param name The name of the constructor to invoke. + * Use Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor. + * \param number_of_arguments Size of the arguments array. + * \param arguments An array of arguments to the function. + * + * \return If the constructor is called and completes + * successfully, then the object is returned. If an error + * occurs during execution, then an error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_InvokeConstructor(Dart_Handle object, + Dart_Handle name, + int number_of_arguments, + Dart_Handle* arguments); + +/** + * Gets the value of a field. + * + * The 'container' parameter may be an object, type, or library. If + * 'container' is an object, then this function will access an + * instance field. If 'container' is a type, then this function will + * access a static field. If 'container' is a library, then this + * function will access a top-level variable. + * NOTE: This API call cannot be used to access fields of a type object. + * + * This function ignores field visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param container An object, type, or library. + * \param name A field name. + * + * \return If no error occurs, then the value of the field is + * returned. Otherwise an error handle is returned. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_GetField(Dart_Handle container, Dart_Handle name); + +/** + * Sets the value of a field. + * + * The 'container' parameter may actually be an object, type, or + * library. If 'container' is an object, then this function will + * access an instance field. If 'container' is a type, then this + * function will access a static field. If 'container' is a library, + * then this function will access a top-level variable. + * NOTE: This API call cannot be used to access fields of a type object. + * + * This function ignores field visibility (leading underscores in names). + * + * May generate an unhandled exception error. + * + * \param container An object, type, or library. + * \param name A field name. + * \param value The new field value. + * + * \return A valid handle if no error occurs. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value); + +/* + * ========== + * Exceptions + * ========== + */ + +/* + * TODO(turnidge): Remove these functions from the api and replace all + * uses with Dart_NewUnhandledExceptionError. */ + +/** + * Throws an exception. + * + * This function causes a Dart language exception to be thrown. This + * will proceed in the standard way, walking up Dart frames until an + * appropriate 'catch' block is found, executing 'finally' blocks, + * etc. + * + * If an error handle is passed into this function, the error is + * propagated immediately. See Dart_PropagateError for a discussion + * of error propagation. + * + * If successful, this function does not return. Note that this means + * that the destructors of any stack-allocated C++ objects will not be + * called. If there are no Dart frames on the stack, an error occurs. + * + * \return An error handle if the exception was not thrown. + * Otherwise the function does not return. + */ +DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception); + +/** + * Rethrows an exception. + * + * Rethrows an exception, unwinding all dart frames on the stack. If + * successful, this function does not return. Note that this means + * that the destructors of any stack-allocated C++ objects will not be + * called. If there are no Dart frames on the stack, an error occurs. + * + * \return An error handle if the exception was not thrown. + * Otherwise the function does not return. + */ +DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception, + Dart_Handle stacktrace); + +/* + * =========================== + * Native fields and functions + * =========================== + */ + +/** + * Gets the number of native instance fields in an object. + */ +DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj, + int* count); + +/** + * Gets the value of a native field. + * + * TODO(turnidge): Document. + */ +DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, + int index, + intptr_t* value); + +/** + * Sets the value of a native field. + * + * TODO(turnidge): Document. + */ +DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, + int index, + intptr_t value); + +/** + * The arguments to a native function. + * + * This object is passed to a native function to represent its + * arguments and return value. It allows access to the arguments to a + * native function by index. It also allows the return value of a + * native function to be set. + */ +typedef struct _Dart_NativeArguments* Dart_NativeArguments; + +/** + * Extracts current isolate group data from the native arguments structure. + */ +DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args); + +typedef enum { + Dart_NativeArgument_kBool = 0, + Dart_NativeArgument_kInt32, + Dart_NativeArgument_kUint32, + Dart_NativeArgument_kInt64, + Dart_NativeArgument_kUint64, + Dart_NativeArgument_kDouble, + Dart_NativeArgument_kString, + Dart_NativeArgument_kInstance, + Dart_NativeArgument_kNativeFields, +} Dart_NativeArgument_Type; + +typedef struct _Dart_NativeArgument_Descriptor { + uint8_t type; + uint8_t index; +} Dart_NativeArgument_Descriptor; + +typedef union _Dart_NativeArgument_Value { + bool as_bool; + int32_t as_int32; + uint32_t as_uint32; + int64_t as_int64; + uint64_t as_uint64; + double as_double; + struct { + Dart_Handle dart_str; + void* peer; + } as_string; + struct { + intptr_t num_fields; + intptr_t* values; + } as_native_fields; + Dart_Handle as_instance; +} Dart_NativeArgument_Value; + +enum { + kNativeArgNumberPos = 0, + kNativeArgNumberSize = 8, + kNativeArgTypePos = kNativeArgNumberPos + kNativeArgNumberSize, + kNativeArgTypeSize = 8, +}; + +#define BITMASK(size) ((1 << size) - 1) +#define DART_NATIVE_ARG_DESCRIPTOR(type, position) \ + (((type & BITMASK(kNativeArgTypeSize)) << kNativeArgTypePos) | \ + (position & BITMASK(kNativeArgNumberSize))) + +/** + * Gets the native arguments based on the types passed in and populates + * the passed arguments buffer with appropriate native values. + * + * \param args the Native arguments block passed into the native call. + * \param num_arguments length of argument descriptor array and argument + * values array passed in. + * \param arg_descriptors an array that describes the arguments that + * need to be retrieved. For each argument to be retrieved the descriptor + * contains the argument number (0, 1 etc.) and the argument type + * described using Dart_NativeArgument_Type, e.g: + * DART_NATIVE_ARG_DESCRIPTOR(Dart_NativeArgument_kBool, 1) indicates + * that the first argument is to be retrieved and it should be a boolean. + * \param arg_values array into which the native arguments need to be + * extracted into, the array is allocated by the caller (it could be + * stack allocated to avoid the malloc/free performance overhead). + * + * \return Success if all the arguments could be extracted correctly, + * returns an error handle if there were any errors while extracting the + * arguments (mismatched number of arguments, incorrect types, etc.). + */ +DART_EXPORT Dart_Handle +Dart_GetNativeArguments(Dart_NativeArguments args, + int num_arguments, + const Dart_NativeArgument_Descriptor* arg_descriptors, + Dart_NativeArgument_Value* arg_values); + +/** + * Gets the native argument at some index. + */ +DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, + int index); +/* TODO(turnidge): Specify the behavior of an out-of-bounds access. */ + +/** + * Gets the number of native arguments. + */ +DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args); + +/** + * Gets all the native fields of the native argument at some index. + * \param args Native arguments structure. + * \param arg_index Index of the desired argument in the structure above. + * \param num_fields size of the intptr_t array 'field_values' passed in. + * \param field_values intptr_t array in which native field values are returned. + * \return Success if the native fields where copied in successfully. Otherwise + * returns an error handle. On success the native field values are copied + * into the 'field_values' array, if the argument at 'arg_index' is a + * null object then 0 is copied as the native field values into the + * 'field_values' array. + */ +DART_EXPORT Dart_Handle +Dart_GetNativeFieldsOfArgument(Dart_NativeArguments args, + int arg_index, + int num_fields, + intptr_t* field_values); + +/** + * Gets the native field of the receiver. + */ +DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args, + intptr_t* value); + +/** + * Gets a string native argument at some index. + * \param args Native arguments structure. + * \param arg_index Index of the desired argument in the structure above. + * \param peer Returns the peer pointer if the string argument has one. + * \return Success if the string argument has a peer, if it does not + * have a peer then the String object is returned. Otherwise returns + * an error handle (argument is not a String object). + */ +DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args, + int arg_index, + void** peer); + +/** + * Gets an integer native argument at some index. + * \param args Native arguments structure. + * \param index Index of the desired argument in the structure above. + * \param value Returns the integer value if the argument is an Integer. + * \return Success if no error occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args, + int index, + int64_t* value); + +/** + * Gets a boolean native argument at some index. + * \param args Native arguments structure. + * \param index Index of the desired argument in the structure above. + * \param value Returns the boolean value if the argument is a Boolean. + * \return Success if no error occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args, + int index, + bool* value); + +/** + * Gets a double native argument at some index. + * \param args Native arguments structure. + * \param index Index of the desired argument in the structure above. + * \param value Returns the double value if the argument is a double. + * \return Success if no error occurs. Otherwise returns an error handle. + */ +DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args, + int index, + double* value); + +/** + * Sets the return value for a native function. + * + * If retval is an Error handle, then error will be propagated once + * the native functions exits. See Dart_PropagateError for a + * discussion of how different types of errors are propagated. + */ +DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, + Dart_Handle retval); + +DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args, + Dart_WeakPersistentHandle rval); + +DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args, + bool retval); + +DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args, + int64_t retval); + +DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args, + double retval); + +/** + * A native function. + */ +typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments); + +/** + * Native entry resolution callback. + * + * For libraries and scripts which have native functions, the embedder + * can provide a native entry resolver. This callback is used to map a + * name/arity to a Dart_NativeFunction. If no function is found, the + * callback should return NULL. + * + * The parameters to the native resolver function are: + * \param name a Dart string which is the name of the native function. + * \param num_of_arguments is the number of arguments expected by the + * native function. + * \param auto_setup_scope is a boolean flag that can be set by the resolver + * to indicate if this function needs a Dart API scope (see Dart_EnterScope/ + * Dart_ExitScope) to be setup automatically by the VM before calling into + * the native function. By default most native functions would require this + * to be true but some light weight native functions which do not call back + * into the VM through the Dart API may not require a Dart scope to be + * setup automatically. + * + * \return A valid Dart_NativeFunction which resolves to a native entry point + * for the native function. + * + * See Dart_SetNativeResolver. + */ +typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name, + int num_of_arguments, + bool* auto_setup_scope); +/* TODO(turnidge): Consider renaming to NativeFunctionResolver or + * NativeResolver. */ + +/** + * Native entry symbol lookup callback. + * + * For libraries and scripts which have native functions, the embedder + * can provide a callback for mapping a native entry to a symbol. This callback + * maps a native function entry PC to the native function name. If no native + * entry symbol can be found, the callback should return NULL. + * + * The parameters to the native reverse resolver function are: + * \param nf A Dart_NativeFunction. + * + * \return A const UTF-8 string containing the symbol name or NULL. + * + * See Dart_SetNativeResolver. + */ +typedef const uint8_t* (*Dart_NativeEntrySymbol)(Dart_NativeFunction nf); + +/** + * FFI Native C function pointer resolver callback. + * + * See Dart_SetFfiNativeResolver. + */ +typedef void* (*Dart_FfiNativeResolver)(const char* name, uintptr_t args_n); + +/* + * =========== + * Environment + * =========== + */ + +/** + * An environment lookup callback function. + * + * \param name The name of the value to lookup in the environment. + * + * \return A valid handle to a string if the name exists in the + * current environment or Dart_Null() if not. + */ +typedef Dart_Handle (*Dart_EnvironmentCallback)(Dart_Handle name); + +/** + * Sets the environment callback for the current isolate. This + * callback is used to lookup environment values by name in the + * current environment. This enables the embedder to supply values for + * the const constructors bool.fromEnvironment, int.fromEnvironment + * and String.fromEnvironment. + */ +DART_EXPORT Dart_Handle +Dart_SetEnvironmentCallback(Dart_EnvironmentCallback callback); + +/** + * Sets the callback used to resolve native functions for a library. + * + * \param library A library. + * \param resolver A native entry resolver. + * + * \return A valid handle if the native resolver was set successfully. + */ +DART_EXPORT Dart_Handle +Dart_SetNativeResolver(Dart_Handle library, + Dart_NativeEntryResolver resolver, + Dart_NativeEntrySymbol symbol); +/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */ + +/** + * Returns the callback used to resolve native functions for a library. + * + * \param library A library. + * \param resolver a pointer to a Dart_NativeEntryResolver + * + * \return A valid handle if the library was found. + */ +DART_EXPORT Dart_Handle +Dart_GetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver* resolver); + +/** + * Returns the callback used to resolve native function symbols for a library. + * + * \param library A library. + * \param resolver a pointer to a Dart_NativeEntrySymbol. + * + * \return A valid handle if the library was found. + */ +DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library, + Dart_NativeEntrySymbol* resolver); + +/** + * Sets the callback used to resolve FFI native functions for a library. + * The resolved functions are expected to be a C function pointer of the + * correct signature (as specified in the `@Native()` function + * annotation in Dart code). + * + * NOTE: This is an experimental feature and might change in the future. + * + * \param library A library. + * \param resolver A native function resolver. + * + * \return A valid handle if the native resolver was set successfully. + */ +DART_EXPORT Dart_Handle +Dart_SetFfiNativeResolver(Dart_Handle library, Dart_FfiNativeResolver resolver); + +/** + * Callback provided by the embedder that is used by the VM to resolve asset + * paths. + * + * The VM is responsible for looking up the asset path with the asset id in the + * kernel mapping. The embedder is responsible for providing the asset mapping + * during kernel compilation and using the asset path to return a library handle + * in this function. + * + * \param path The string in the asset path as passed in native_assets.yaml + * during kernel compilation. + * + * \param error Returns NULL if successful, an error message otherwise. The + * caller is responsible for calling free() on the error message. + * + * \return The library handle. If |error| is not-null, the return value is + * undefined. + */ +typedef void* (*Dart_NativeAssetsDlopenCallback)(const char* path, + char** error); +typedef void* (*Dart_NativeAssetsDlopenCallbackNoPath)(char** error); + +/** + * Callback provided by the embedder that is used by the VM to resolve asset + * ids. + * + * The embedder can freely chose how to bundle asset id to asset path mappings + * and how to perform this lookup. + * + * If the embedder provides this callback, it must also provide + * `Dart_NativeAssetsAvailableAssets`. + * + * If provided, takes prescedence over `Dart_NativeAssetsDlopenCallback`. + * + * \param path The asset id requested in the `@Native` external function. + * + * \param error Returns NULL if successful, an error message otherwise. The + * caller is responsible for calling free() on the error message. + * + * \return The library handle. If |error| is not-null, the return value is + * undefined. + */ +typedef void* (*Dart_NativeAssetsDlopenAssetId)(const char* asset_id, + char** error); + +/** + * Callback provided by the embedder that is used by the VM to request a + * description of the available assets + * + * \return A malloced string containing all asset ids. The caller must free this + * string. + */ +typedef char* (*Dart_NativeAssetsAvailableAssets)(); + +/** + * Callback provided by the embedder that is used by the VM to lookup symbols + * in native code assets. + * If no callback is provided, using `@Native`s with `native_asset.yaml`s will + * fail. + * + * \param handle The library handle returned from a + * `Dart_NativeAssetsDlopenCallback` or + * `Dart_NativeAssetsDlopenCallbackNoPath`. + * + * \param symbol The symbol to look up. Is a string. + * + * \param error Returns NULL if creation is successful, an error message + * otherwise. The caller is responsible for calling free() on the error + * message. + * + * \return The symbol address. If |error| is not-null, the return value is + * undefined. + */ +typedef void* (*Dart_NativeAssetsDlsymCallback)(void* handle, + const char* symbol, + char** error); + +typedef struct { + Dart_NativeAssetsDlopenCallback dlopen_absolute; + Dart_NativeAssetsDlopenCallback dlopen_relative; + Dart_NativeAssetsDlopenCallback dlopen_system; + Dart_NativeAssetsDlopenCallbackNoPath dlopen_process; + Dart_NativeAssetsDlopenCallbackNoPath dlopen_executable; + Dart_NativeAssetsDlsymCallback dlsym; + Dart_NativeAssetsDlopenAssetId dlopen; + Dart_NativeAssetsAvailableAssets available_assets; +} NativeAssetsApi; + +/** + * Initializes native asset resolution for the current isolate group. + * + * The caller is responsible for ensuring this is called right after isolate + * group creation, and before running any dart code (or spawning isolates). + * + * @param native_assets_api The callbacks used by native assets resolution. + * The VM does not take ownership of the parameter, + * it can be freed immediately after the call. + */ +DART_EXPORT void Dart_InitializeNativeAssetsResolver( + NativeAssetsApi* native_assets_api); + +/* + * ===================== + * Scripts and Libraries + * ===================== + */ + +typedef enum { + Dart_kCanonicalizeUrl = 0, + Dart_kImportTag, + Dart_kKernelTag, +} Dart_LibraryTag; + +/** + * The library tag handler is a multi-purpose callback provided by the + * embedder to the Dart VM. The embedder implements the tag handler to + * provide the ability to load Dart scripts and imports. + * + * -- TAGS -- + * + * Dart_kCanonicalizeUrl + * + * This tag indicates that the embedder should canonicalize 'url' with + * respect to 'library'. For most embedders, this is resolving the `url` + * relative to the `library`s url (see `Dart_LibraryUrl`). + * + * Dart_kImportTag + * + * This tag is used to load a library from IsolateMirror.loadUri. The embedder + * should call Dart_LoadLibraryFromKernel to provide the library to the VM. The + * return value should be an error or library (the result from + * Dart_LoadLibraryFromKernel). + * + * Dart_kKernelTag + * + * This tag is used to load the intermediate file (kernel) generated by + * the Dart front end. This tag is typically used when a 'hot-reload' + * of an application is needed and the VM is 'use dart front end' mode. + * The dart front end typically compiles all the scripts, imports and part + * files into one intermediate file hence we don't use the source/import or + * script tags. The return value should be an error or a TypedData containing + * the kernel bytes. + * + */ +typedef Dart_Handle (*Dart_LibraryTagHandler)( + Dart_LibraryTag tag, + Dart_Handle library_or_package_map_url, + Dart_Handle url); + +/** + * Sets library tag handler for the current isolate. This handler is + * used to handle the various tags encountered while loading libraries + * or scripts in the isolate. + * + * \param handler Handler code to be used for handling the various tags + * encountered while loading libraries or scripts in the isolate. + * + * \return If no error occurs, the handler is set for the isolate. + * Otherwise an error handle is returned. + * + * TODO(turnidge): Document. + */ +DART_EXPORT Dart_Handle +Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler); + +/** + * Handles deferred loading requests. When this handler is invoked, it should + * eventually load the deferred loading unit with the given id and call + * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is + * recommended that the loading occur asynchronously, but it is permitted to + * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the + * handler returns. + * + * If an error is returned, it will be propagated through + * `prefix.loadLibrary()`. This is useful for synchronous + * implementations, which must propagate any unwind errors from + * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler + * should return a non-error such as `Dart_Null()`. + */ +typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id); + +/** + * Sets the deferred load handler for the current isolate. This handler is + * used to handle loading deferred imports in an AppJIT or AppAOT program. + */ +DART_EXPORT Dart_Handle +Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler); + +/** + * Notifies the VM that a deferred load completed successfully. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadComplete(intptr_t loading_unit_id, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions); + +/** + * Notifies the VM that a deferred load failed. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete with an error. + * + * If `transient` is true, future invocations of `prefix.loadLibrary()` will + * trigger new load requests. If false, futures invocation will complete with + * the same error. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadCompleteError(intptr_t loading_unit_id, + const char* error_message, + bool transient); + +/** + * Loads the root library for the current isolate. + * + * Requires there to be no current root library. + * + * \param kernel_buffer A buffer which contains a kernel binary (see + * pkg/kernel/binary.md). Must remain valid until isolate group shutdown. + * \param kernel_size Length of the passed in buffer. + * + * \return A handle to the root library, or an error. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer, intptr_t kernel_size); + +/** + * Gets the library for the root script for the current isolate. + * + * If the root script has not yet been set for the current isolate, + * this function returns Dart_Null(). This function never returns an + * error handle. + * + * \return Returns the root Library for the current isolate or Dart_Null(). + */ +DART_EXPORT Dart_Handle Dart_RootLibrary(void); + +/** + * Sets the root library for the current isolate. + * + * \return Returns an error handle if `library` is not a library handle. + */ +DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library); + +/** + * Lookup or instantiate a legacy type by name and type arguments from a + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parametric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Lookup or instantiate a nullable type by name and type arguments from + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parametric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Lookup or instantiate a non-nullable type by name and type arguments from + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parametric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle +Dart_GetNonNullableType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Creates a nullable version of the provided type. + * + * \param type The type to be converted to a nullable type. + * + * \return If no error occurs, a nullable type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type); + +/** + * Creates a non-nullable version of the provided type. + * + * \param type The type to be converted to a non-nullable type. + * + * \return If no error occurs, a non-nullable type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type); + +/** + * A type's nullability. + * + * \param type A Dart type. + * \param result An out parameter containing the result of the check. True if + * the type is of the specified nullability, false otherwise. + * + * \return Returns an error handle if type is not of type Type. + */ +DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result); +DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result); + +/** + * Lookup a class or interface by name from a Library. + * + * \param library The library containing the class or interface. + * \param class_name The name of the class or interface. + * + * \return If no error occurs, the class or interface is + * returned. Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, + Dart_Handle class_name); +/* TODO(asiva): The above method needs to be removed once all uses + * of it are removed from the embedder code. */ + +/** + * Returns an import path to a Library, such as "file:///test.dart" or + * "dart:core". + */ +DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library); + +/** + * Returns a URL from which a Library was loaded. + */ +DART_EXPORT Dart_Handle Dart_LibraryResolvedUrl(Dart_Handle library); + +/** + * \return An array of libraries. + */ +DART_EXPORT Dart_Handle Dart_GetLoadedLibraries(void); + +DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url); +/* TODO(turnidge): Consider returning Dart_Null() when the library is + * not found to distinguish that from a true error case. */ + +/** + * Report an loading error for the library. + * + * \param library The library that failed to load. + * \param error The Dart error instance containing the load error. + * + * \return If the VM handles the error, the return value is + * a null handle. If it doesn't handle the error, the error + * object is returned. + */ +DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library, + Dart_Handle error); + +/** + * Called by the embedder to load a partial program. Does not set the root + * library. + * + * \param kernel_buffer A buffer which contains a kernel binary (see + * pkg/kernel/binary.md). Must remain valid until isolate shutdown. + * \param kernel_buffer_size Length of the passed in buffer. + * + * \return A handle to the main library of the compilation unit, or an error. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadLibrary(Dart_Handle kernel_buffer); + +/** + * Indicates that all outstanding load requests have been satisfied. + * This finalizes all the new classes loaded and optionally completes + * deferred library futures. + * + * Requires there to be a current isolate. + * + * \param complete_futures Specify true if all deferred library + * futures should be completed, false otherwise. + * + * \return Success if all classes have been finalized and deferred library + * futures are completed. Otherwise, returns an error. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_FinalizeLoading(bool complete_futures); + +/* + * ===== + * Peers + * ===== + */ + +/** + * The peer field is a lazily allocated field intended for storage of + * an uncommonly used values. Most instances types can have a peer + * field allocated. The exceptions are subtypes of Null, num, and + * bool. + */ + +/** + * Returns the value of peer field of 'object' in 'peer'. + * + * \param object An object. + * \param peer An out parameter that returns the value of the peer + * field. + * + * \return Returns an error if 'object' is a subtype of Null, num, or + * bool. + */ +DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer); + +/** + * Sets the value of the peer field of 'object' to the value of + * 'peer'. + * + * \param object An object. + * \param peer A value to store in the peer field. + * + * \return Returns an error if 'object' is a subtype of Null, num, or + * bool. + */ +DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer); + +/* + * ====== + * Kernel + * ====== + */ + +/** + * Experimental support for Dart to Kernel parser isolate. + * + * TODO(hausner): Document finalized interface. + * + */ + +// TODO(33433): Remove kernel service from the embedding API. + +typedef enum { + Dart_KernelCompilationStatus_Unknown = -1, + Dart_KernelCompilationStatus_Ok = 0, + Dart_KernelCompilationStatus_Error = 1, + Dart_KernelCompilationStatus_Crash = 2, + Dart_KernelCompilationStatus_MsgFailed = 3, +} Dart_KernelCompilationStatus; + +typedef struct { + Dart_KernelCompilationStatus status; + char* error; + uint8_t* kernel; + intptr_t kernel_size; +} Dart_KernelCompilationResult; + +typedef enum { + Dart_KernelCompilationVerbosityLevel_Error = 0, + Dart_KernelCompilationVerbosityLevel_Warning, + Dart_KernelCompilationVerbosityLevel_Info, + Dart_KernelCompilationVerbosityLevel_All, +} Dart_KernelCompilationVerbosityLevel; + +DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate); +DART_EXPORT bool Dart_KernelIsolateIsRunning(void); +DART_EXPORT Dart_Port Dart_KernelPort(void); + +/** + * Compiles the given `script_uri` to a kernel file. + * + * \param platform_kernel A buffer containing the kernel of the platform (e.g. + * `vm_platform_strong.dill`). The VM does not take ownership of this memory. + * + * \param platform_kernel_size The length of the platform_kernel buffer. + * + * \param snapshot_compile Set to `true` when the compilation is for a snapshot. + * This is used by the frontend to determine if compilation related information + * should be printed to console (e.g., null safety mode). + * + * \param embed_sources Set to `true` when sources should be embedded in the + * kernel file. + * + * \param verbosity Specifies the logging behavior of the kernel compilation + * service. + * + * \return Returns the result of the compilation. + * + * On a successful compilation the returned [Dart_KernelCompilationResult] has + * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size` + * fields are set. The caller takes ownership of the malloc()ed buffer. + * + * On a failed compilation the `error` might be set describing the reason for + * the failed compilation. The caller takes ownership of the malloc()ed + * error. + * + * Requires there to be a current isolate. + */ +DART_EXPORT Dart_KernelCompilationResult +Dart_CompileToKernel(const char* script_uri, + const uint8_t* platform_kernel, + const intptr_t platform_kernel_size, + bool incremental_compile, + bool snapshot_compile, + bool embed_sources, + const char* package_config, + Dart_KernelCompilationVerbosityLevel verbosity); + +typedef struct { + const char* uri; + const char* source; +} Dart_SourceFile; + +DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(void); + +/** + * Sets the kernel buffer which will be used to load Dart SDK sources + * dynamically at runtime. + * + * \param platform_kernel A buffer containing kernel which has sources for the + * Dart SDK populated. Note: The VM does not take ownership of this memory. + * + * \param platform_kernel_size The length of the platform_kernel buffer. + */ +DART_EXPORT void Dart_SetDartLibrarySourcesKernel( + const uint8_t* platform_kernel, + const intptr_t platform_kernel_size); + +/** + * Always return true as the VM only supports strong null safety. + */ +DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri, + const char* package_config, + const char* original_working_directory, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); + +#define DART_KERNEL_ISOLATE_NAME "kernel-service" + +/* + * ======= + * Service + * ======= + */ + +#define DART_VM_SERVICE_ISOLATE_NAME "vm-service" + +/** + * Returns true if isolate is the service isolate. + * + * \param isolate An isolate + * + * \return Returns true if 'isolate' is the service isolate. + */ +DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate); + +/** + * Writes the CPU profile to the timeline as a series of 'instant' events. + * + * Note that this is an expensive operation. + * + * \param main_port The main port of the Isolate whose profile samples to write. + * \param error An optional error, must be free()ed by caller. + * + * \return Returns true if the profile is successfully written and false + * otherwise. + */ +DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error); + +/* + * ============== + * Precompilation + * ============== + */ + +/** + * Compiles all functions reachable from entry points and marks + * the isolate to disallow future compilation. + * + * Entry points should be specified using `@pragma("vm:entry-point")` + * annotation. + * + * \return An error handle if a compilation error or runtime error running const + * constructors was encountered. + */ +DART_EXPORT Dart_Handle Dart_Precompile(void); + +typedef void (*Dart_CreateLoadingUnitCallback)( + void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data); +typedef void (*Dart_StreamingWriteCallback)(void* callback_data, + const uint8_t* buffer, + intptr_t size); +typedef void (*Dart_StreamingCloseCallback)(void* callback_data); + +DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id); + +// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name. +// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual +// symbol names in the objects are given by the '...AsmSymbol' definitions. +#if defined(__APPLE__) +#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId" +#define kVmSnapshotDataCSymbol "kDartVmSnapshotData" +#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions" +#define kVmSnapshotBssCSymbol "kDartVmSnapshotBss" +#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions" +#define kIsolateSnapshotBssCSymbol "kDartIsolateSnapshotBss" +#else +#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId" +#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData" +#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions" +#define kVmSnapshotBssCSymbol "_kDartVmSnapshotBss" +#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions" +#define kIsolateSnapshotBssCSymbol "_kDartIsolateSnapshotBss" +#endif + +#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId" +#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData" +#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions" +#define kVmSnapshotBssAsmSymbol "_kDartVmSnapshotBss" +#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsAsmSymbol \ + "_kDartIsolateSnapshotInstructions" +#define kIsolateSnapshotBssAsmSymbol "_kDartIsolateSnapshotBss" + +/** + * Creates a precompiled snapshot. + * - A root library must have been loaded. + * - Dart_Precompile must have been called. + * + * Outputs an assembly file defining the symbols listed in the definitions + * above. + * + * The assembly should be compiled as a static or shared library and linked or + * loaded by the embedder. Running this snapshot requires a VM compiled with + * DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and + * kDartVmSnapshotInstructions should be passed to Dart_Initialize. The + * kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be + * passed to Dart_CreateIsolateGroup. + * + * The callback will be invoked one or more times to provide the assembly code. + * + * If stripped is true, then the assembly code will not include DWARF + * debugging sections. + * + * If debug_callback_data is provided, debug_callback_data will be used with + * the callback to provide separate debugging information. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, + void* callback_data, + bool stripped, + void* debug_callback_data); +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssemblies( + Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); + +/** + * Creates a precompiled snapshot. + * - A root library must have been loaded. + * - Dart_Precompile must have been called. + * + * Outputs an ELF shared library defining the symbols + * - _kDartVmSnapshotData + * - _kDartVmSnapshotInstructions + * - _kDartIsolateSnapshotData + * - _kDartIsolateSnapshotInstructions + * + * The shared library should be dynamically loaded by the embedder. + * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT. + * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to + * Dart_Initialize. The kDartIsolateSnapshotData and + * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate. + * + * The callback will be invoked one or more times to provide the binary output. + * + * If stripped is true, then the binary output will not include DWARF + * debugging sections. + * + * If debug_callback_data is provided, debug_callback_data will be used with + * the callback to provide separate debugging information. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback, + void* callback_data, + bool stripped, + void* debug_callback_data); +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); + +/** + * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes + * kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does + * not strip DWARF information from the generated assembly or allow for + * separate debug information. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, + void* callback_data); + +/** + * Sorts the class-ids in depth first traversal order of the inheritance + * tree. This is a costly operation, but it can make method dispatch + * more efficient and is done before writing snapshots. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(void); + +/** + * Creates a snapshot that caches compiled code and type feedback for faster + * startup and quicker warmup in a subsequent process. + * + * Outputs a snapshot in two pieces. The pieces should be passed to + * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the + * current VM. The instructions piece must be loaded with read and execute + * permissions; the data piece may be loaded as read-only. + * + * - Requires the VM to have not been started with --precompilation. + * - Not supported when targeting IA32. + * - The VM writing the snapshot and the VM reading the snapshot must be the + * same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must + * be targeting the same architecture, and must both be in checked mode or + * both in unchecked mode. + * + * The buffers are scope allocated and are only valid until the next call to + * Dart_ExitScope. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer, + intptr_t* isolate_snapshot_data_size, + uint8_t** isolate_snapshot_instructions_buffer, + intptr_t* isolate_snapshot_instructions_size); + +/** + * Get obfuscation map for precompiled code. + * + * Obfuscation map is encoded as a JSON array of pairs (original name, + * obfuscated name). + * + * \return Returns an error handler if the VM was built in a mode that does not + * support obfuscation. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length); + +/** + * Returns whether the VM only supports running from precompiled snapshots and + * not from any other kind of snapshot or from source (that is, the VM was + * compiled with DART_PRECOMPILED_RUNTIME). + */ +DART_EXPORT bool Dart_IsPrecompiledRuntime(void); + +/** + * Print a native stack trace. Used for crash handling. + * + * If context is NULL, prints the current stack trace. Otherwise, context + * should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler + * running on the current thread. + */ +DART_EXPORT void Dart_DumpNativeStackTrace(void* context); + +/** + * Indicate that the process is about to abort, and the Dart VM should not + * attempt to cleanup resources. + */ +DART_EXPORT void Dart_PrepareToAbort(void); + +/** + * Callback provided by the embedder that is used by the VM to + * produce footnotes appended to DWARF stack traces. + * + * Whenever VM formats a stack trace as a string it would call this callback + * passing raw program counters for each frame in the stack trace. + * + * Embedder can then return a string which if not-null will be appended to the + * formatted stack trace. + * + * Returned string is expected to be `malloc()` allocated. VM takes ownership + * of the returned string and will `free()` it. + * + * \param addresses raw program counter addresses for each frame + * \param count number of elements in the addresses array + */ +typedef char* (*Dart_DwarfStackTraceFootnoteCallback)(void* addresses[], + intptr_t count); + +/** + * Configure DWARF stack trace footnote callback. + */ +DART_EXPORT void Dart_SetDwarfStackTraceFootnoteCallback( + Dart_DwarfStackTraceFootnoteCallback callback); + +#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/dart_api_dl.c b/src/serious_python_bridge/native/dart_api/dart_api_dl.c new file mode 100644 index 00000000..48fb54e7 --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/dart_api_dl.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#include "dart_api_dl.h" /* NOLINT */ +#include "dart_version.h" /* NOLINT */ +#include "internal/dart_api_dl_impl.h" /* NOLINT */ + +#include +#include + +#define DART_API_DL_DEFINITIONS(name, R, A) name##_Type name##_DL = NULL; + +DART_API_ALL_DL_SYMBOLS(DART_API_DL_DEFINITIONS) +DART_API_DEPRECATED_DL_SYMBOLS(DART_API_DL_DEFINITIONS) + +#undef DART_API_DL_DEFINITIONS + +typedef void* DartApiEntry_function; + +DartApiEntry_function FindFunctionPointer(const DartApiEntry* entries, + const char* name) { + while (entries->name != NULL) { + if (strcmp(entries->name, name) == 0) return entries->function; + entries++; + } + return NULL; +} + +DART_EXPORT void Dart_UpdateExternalSize_Deprecated( + Dart_WeakPersistentHandle object, intptr_t external_size) { + printf("Dart_UpdateExternalSize is a nop, it has been deprecated\n"); +} + +DART_EXPORT void Dart_UpdateFinalizableExternalSize_Deprecated( + Dart_FinalizableHandle object, + Dart_Handle strong_ref_to_object, + intptr_t external_allocation_size) { + printf("Dart_UpdateFinalizableExternalSize is a nop, " + "it has been deprecated\n"); +} + +intptr_t Dart_InitializeApiDL(void* data) { + DartApi* dart_api_data = (DartApi*)data; + + if (dart_api_data->major != DART_API_DL_MAJOR_VERSION) { + // If the DartVM we're running on does not have the same version as this + // file was compiled against, refuse to initialize. The symbols are not + // compatible. + return -1; + } + // Minor versions are allowed to be different. + // If the DartVM has a higher minor version, it will provide more symbols + // than we initialize here. + // If the DartVM has a lower minor version, it will not provide all symbols. + // In that case, we leave the missing symbols un-initialized. Those symbols + // should not be used by the Dart and native code. The client is responsible + // for checking the minor version number himself based on which symbols it + // is using. + // (If we would error out on this case, recompiling native code against a + // newer SDK would break all uses on older SDKs, which is too strict.) + + const DartApiEntry* dart_api_function_pointers = dart_api_data->functions; + +#define DART_API_DL_INIT(name, R, A) \ + name##_DL = \ + (name##_Type)(FindFunctionPointer(dart_api_function_pointers, #name)); + DART_API_ALL_DL_SYMBOLS(DART_API_DL_INIT) +#undef DART_API_DL_INIT + +#define DART_API_DEPRECATED_DL_INIT(name, R, A) \ + name##_DL = name##_Deprecated; + DART_API_DEPRECATED_DL_SYMBOLS(DART_API_DEPRECATED_DL_INIT) +#undef DART_API_DEPRECATED_DL_INIT + + return 0; +} diff --git a/src/serious_python_bridge/native/dart_api/dart_api_dl.h b/src/serious_python_bridge/native/dart_api/dart_api_dl.h new file mode 100644 index 00000000..2b4c8d4f --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/dart_api_dl.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef RUNTIME_INCLUDE_DART_API_DL_H_ +#define RUNTIME_INCLUDE_DART_API_DL_H_ + +#include "dart_api.h" /* NOLINT */ +#include "dart_native_api.h" /* NOLINT */ + +/** \mainpage Dynamically Linked Dart API + * + * This exposes a subset of symbols from dart_api.h and dart_native_api.h + * available in every Dart embedder through dynamic linking. + * + * All symbols are postfixed with _DL to indicate that they are dynamically + * linked and to prevent conflicts with the original symbol. + * + * Link `dart_api_dl.c` file into your library and invoke + * `Dart_InitializeApiDL` with `NativeApi.initializeApiDLData`. + * + * Returns 0 on success. + */ + +DART_EXPORT intptr_t Dart_InitializeApiDL(void* data); + +// ============================================================================ +// IMPORTANT! Never update these signatures without properly updating +// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION. +// +// Verbatim copy of `dart_native_api.h` and `dart_api.h` symbol names and types +// to trigger compile-time errors if the symbols in those files are updated +// without updating these. +// +// Function return and argument types, and typedefs are carbon copied. Structs +// are typechecked nominally in C/C++, so they are not copied, instead a +// comment is added to their definition. +typedef int64_t Dart_Port_DL; +typedef struct { + int64_t port_id; + int64_t origin_id; +} Dart_PortEx_DL; + +typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id, + Dart_CObject* message); + +// dart_native_api.h symbols can be called on any thread. +#define DART_NATIVE_API_DL_SYMBOLS(F) \ + /***** dart_native_api.h *****/ \ + /* Dart_Port */ \ + F(Dart_PostCObject, bool, (Dart_Port_DL port_id, Dart_CObject * message)) \ + F(Dart_PostInteger, bool, (Dart_Port_DL port_id, int64_t message)) \ + F(Dart_NewNativePort, Dart_Port_DL, \ + (const char* name, Dart_NativeMessageHandler_DL handler, \ + bool handle_concurrently)) \ + F(Dart_CloseNativePort, bool, (Dart_Port_DL native_port_id)) + +// dart_api.h symbols can only be called on Dart threads. +#define DART_API_DL_SYMBOLS(F) \ + /***** dart_api.h *****/ \ + /* Errors */ \ + F(Dart_IsError, bool, (Dart_Handle handle)) \ + F(Dart_IsApiError, bool, (Dart_Handle handle)) \ + F(Dart_IsUnhandledExceptionError, bool, (Dart_Handle handle)) \ + F(Dart_IsCompilationError, bool, (Dart_Handle handle)) \ + F(Dart_IsFatalError, bool, (Dart_Handle handle)) \ + F(Dart_GetError, const char*, (Dart_Handle handle)) \ + F(Dart_ErrorHasException, bool, (Dart_Handle handle)) \ + F(Dart_ErrorGetException, Dart_Handle, (Dart_Handle handle)) \ + F(Dart_ErrorGetStackTrace, Dart_Handle, (Dart_Handle handle)) \ + F(Dart_NewApiError, Dart_Handle, (const char* error)) \ + F(Dart_NewCompilationError, Dart_Handle, (const char* error)) \ + F(Dart_NewUnhandledExceptionError, Dart_Handle, (Dart_Handle exception)) \ + F(Dart_PropagateError, void, (Dart_Handle handle)) \ + /* Dart_Handle, Dart_PersistentHandle, Dart_WeakPersistentHandle */ \ + F(Dart_HandleFromPersistent, Dart_Handle, (Dart_PersistentHandle object)) \ + F(Dart_HandleFromWeakPersistent, Dart_Handle, \ + (Dart_WeakPersistentHandle object)) \ + F(Dart_NewPersistentHandle, Dart_PersistentHandle, (Dart_Handle object)) \ + F(Dart_SetPersistentHandle, void, \ + (Dart_PersistentHandle obj1, Dart_Handle obj2)) \ + F(Dart_DeletePersistentHandle, void, (Dart_PersistentHandle object)) \ + F(Dart_NewWeakPersistentHandle, Dart_WeakPersistentHandle, \ + (Dart_Handle object, void* peer, intptr_t external_allocation_size, \ + Dart_HandleFinalizer callback)) \ + F(Dart_DeleteWeakPersistentHandle, void, (Dart_WeakPersistentHandle object)) \ + F(Dart_NewFinalizableHandle, Dart_FinalizableHandle, \ + (Dart_Handle object, void* peer, intptr_t external_allocation_size, \ + Dart_HandleFinalizer callback)) \ + F(Dart_DeleteFinalizableHandle, void, \ + (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object)) \ + /* Isolates */ \ + F(Dart_CurrentIsolate, Dart_Isolate, (void)) \ + F(Dart_ExitIsolate, void, (void)) \ + F(Dart_EnterIsolate, void, (Dart_Isolate)) \ + /* Dart_Port */ \ + F(Dart_Post, bool, (Dart_Port_DL port_id, Dart_Handle object)) \ + F(Dart_NewSendPort, Dart_Handle, (Dart_Port_DL port_id)) \ + F(Dart_NewSendPortEx, Dart_Handle, (Dart_PortEx_DL portex_id)) \ + F(Dart_SendPortGetId, Dart_Handle, \ + (Dart_Handle port, Dart_Port_DL * port_id)) \ + F(Dart_SendPortGetIdEx, Dart_Handle, \ + (Dart_Handle port, Dart_PortEx_DL * portex_id)) \ + /* Scopes */ \ + F(Dart_EnterScope, void, (void)) \ + F(Dart_ExitScope, void, (void)) \ + /* Objects */ \ + F(Dart_IsNull, bool, (Dart_Handle)) \ + F(Dart_Null, Dart_Handle, (void)) + +// dart_api.h symbols that have been deprecated but are retained here +// until we can make a breaking change bumping the major version number +// (DART_API_DL_MAJOR_VERSION) +#define DART_API_DEPRECATED_DL_SYMBOLS(F) \ + F(Dart_UpdateExternalSize, void, \ + (Dart_WeakPersistentHandle object, intptr_t external_allocation_size)) \ + F(Dart_UpdateFinalizableExternalSize, void, \ + (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object, \ + intptr_t external_allocation_size)) + +#define DART_API_ALL_DL_SYMBOLS(F) \ + DART_NATIVE_API_DL_SYMBOLS(F) \ + DART_API_DL_SYMBOLS(F) +// IMPORTANT! Never update these signatures without properly updating +// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION. +// +// End of verbatim copy. +// ============================================================================ + +// Copy of definition of DART_EXPORT without 'used' attribute. +// +// The 'used' attribute cannot be used with DART_API_ALL_DL_SYMBOLS because +// they are not function declarations, but variable declarations with a +// function pointer type. +// +// The function pointer variables are initialized with the addresses of the +// functions in the VM. If we were to use function declarations instead, we +// would need to forward the call to the VM adding indirection. +#if defined(__CYGWIN__) +#error Tool chain and platform not supported. +#elif defined(_WIN32) +#if defined(DART_SHARED_LIB) +#define DART_EXPORT_DL DART_EXTERN_C __declspec(dllexport) +#else +#define DART_EXPORT_DL DART_EXTERN_C +#endif +#else +#if __GNUC__ >= 4 +#if defined(DART_SHARED_LIB) +#define DART_EXPORT_DL DART_EXTERN_C __attribute__((visibility("default"))) +#else +#define DART_EXPORT_DL DART_EXTERN_C +#endif +#else +#error Tool chain not supported. +#endif +#endif + +#define DART_API_DL_DECLARATIONS(name, R, A) \ + typedef R(*name##_Type) A; \ + DART_EXPORT_DL name##_Type name##_DL; + +DART_API_ALL_DL_SYMBOLS(DART_API_DL_DECLARATIONS) +DART_API_DEPRECATED_DL_SYMBOLS(DART_API_DL_DECLARATIONS) + +#undef DART_API_DL_DECLARATIONS + +#undef DART_EXPORT_DL + +#endif /* RUNTIME_INCLUDE_DART_API_DL_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/dart_native_api.h b/src/serious_python_bridge/native/dart_api/dart_native_api.h new file mode 100644 index 00000000..dbdaeb32 --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/dart_native_api.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef RUNTIME_INCLUDE_DART_NATIVE_API_H_ +#define RUNTIME_INCLUDE_DART_NATIVE_API_H_ + +#include "dart_api.h" /* NOLINT */ + +/* + * ========================================== + * Message sending/receiving from native code + * ========================================== + */ + +/** + * A Dart_CObject is used for representing Dart objects as native C + * data outside the Dart heap. These objects are totally detached from + * the Dart heap. Only a subset of the Dart objects have a + * representation as a Dart_CObject. + * + * The string encoding in the 'value.as_string' is UTF-8. + * + * All the different types from dart:typed_data are exposed as type + * kTypedData. The specific type from dart:typed_data is in the type + * field of the as_typed_data structure. The length in the + * as_typed_data structure is always in bytes. + * + * The data for kTypedData is copied on message send and ownership remains with + * the caller. The ownership of data for kExternalTyped is passed to the VM on + * message send and returned when the VM invokes the + * Dart_HandleFinalizer callback; a non-NULL callback must be provided. + * + * Note that Dart_CObject_kNativePointer is intended for internal use by + * dart:io implementation and has no connection to dart:ffi Pointer class. + * It represents a pointer to a native resource of a known type. + * The receiving side will only see this pointer as an integer and will not + * see the specified finalizer. + * The specified finalizer will only be invoked if the message is not delivered. + */ +typedef enum { + Dart_CObject_kNull = 0, + Dart_CObject_kBool, + Dart_CObject_kInt32, + Dart_CObject_kInt64, + Dart_CObject_kDouble, + Dart_CObject_kString, + Dart_CObject_kArray, + Dart_CObject_kTypedData, + Dart_CObject_kExternalTypedData, + Dart_CObject_kSendPort, + Dart_CObject_kCapability, + Dart_CObject_kNativePointer, + Dart_CObject_kUnsupported, + Dart_CObject_kUnmodifiableExternalTypedData, + Dart_CObject_kNumberOfTypes +} Dart_CObject_Type; +// This enum is versioned by DART_API_DL_MAJOR_VERSION, only add at the end +// and bump the DART_API_DL_MINOR_VERSION. + +typedef struct _Dart_CObject { + Dart_CObject_Type type; + union { + bool as_bool; + int32_t as_int32; + int64_t as_int64; + double as_double; + const char* as_string; + struct { + Dart_Port id; + Dart_Port origin_id; + } as_send_port; + struct { + int64_t id; + } as_capability; + struct { + intptr_t length; + struct _Dart_CObject** values; + } as_array; + struct { + Dart_TypedData_Type type; + intptr_t length; /* in elements, not bytes */ + const uint8_t* values; + } as_typed_data; + struct { + Dart_TypedData_Type type; + intptr_t length; /* in elements, not bytes */ + uint8_t* data; + void* peer; + Dart_HandleFinalizer callback; + } as_external_typed_data; + struct { + intptr_t ptr; + intptr_t size; + Dart_HandleFinalizer callback; + } as_native_pointer; + } value; +} Dart_CObject; +// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when +// changing this struct. + +/** + * Posts a message on some port. The message will contain the Dart_CObject + * object graph rooted in 'message'. + * + * While the message is being sent the state of the graph of Dart_CObject + * structures rooted in 'message' should not be accessed, as the message + * generation will make temporary modifications to the data. When the message + * has been sent the graph will be fully restored. + * + * If true is returned, the message was enqueued, and finalizers for external + * typed data will eventually run, even if the receiving isolate shuts down + * before processing the message. If false is returned, the message was not + * enqueued and ownership of external typed data in the message remains with the + * caller. + * + * This function may be called on any thread when the VM is running (that is, + * after Dart_Initialize has returned and before Dart_Cleanup has been called). + * + * \param port_id The destination port. + * \param message The message to send. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message); + +/** + * Posts a message on some port. The message will contain the integer 'message'. + * + * \param port_id The destination port. + * \param message The message to send. + * + * \return True if the message was posted. + */ +DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message); + +/** + * A native message handler. + * + * This handler is associated with a native port by calling + * Dart_NewNativePort. + * + * The message received is decoded into the message structure. The + * lifetime of the message data is controlled by the caller. All the + * data references from the message are allocated by the caller and + * will be reclaimed when returning to it. + */ +typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id, + Dart_CObject* message); + +/** + * Creates a new native port. When messages are received on this + * native port, then they will be dispatched to the provided native + * message handler. + * + * \param name The name of this port in debugging messages. + * \param handler The C handler to run when messages arrive on the port. + * \param handle_concurrently Is it okay to process requests on this + * native port concurrently? + * + * \return If successful, returns the port id for the native port. In + * case of error, returns ILLEGAL_PORT. + */ +DART_EXPORT Dart_Port Dart_NewNativePort(const char* name, + Dart_NativeMessageHandler handler, + bool handle_concurrently); + +/** + * Creates a new native port. When messages are received on this + * native port, then they will be dispatched to the provided native + * message handler using up to |max_concurrency| concurrent threads. + * + * \param name The name of this port in debugging messages. + * \param handler The C handler to run when messages arrive on the port. + * \param max_concurrency Size of the thread pool used by the native port. + * + * \return If successful, returns the port id for the native port. In + * case of error, returns ILLEGAL_PORT. + */ +DART_EXPORT Dart_Port +Dart_NewConcurrentNativePort(const char* name, + Dart_NativeMessageHandler handler, + intptr_t max_concurrency); + +/** + * Closes the native port with the given id. + * + * The port must have been allocated by a call to Dart_NewNativePort. + * + * \param native_port_id The id of the native port to close. + * + * \return Returns true if the port was closed successfully. + */ +DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id); + +/* + * ================== + * Verification Tools + * ================== + */ + +/** + * Forces all loaded classes and functions to be compiled eagerly in + * the current isolate.. + * + * TODO(turnidge): Document. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll(void); + +/** + * Finalizes all classes. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle +Dart_FinalizeAllClasses(void); + +/* This function is intentionally undocumented. + * + * It should not be used outside internal tests. + */ +DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg); + +#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/dart_tools_api.h b/src/serious_python_bridge/native/dart_api/dart_tools_api.h new file mode 100644 index 00000000..367e1eb5 --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/dart_tools_api.h @@ -0,0 +1,627 @@ +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef RUNTIME_INCLUDE_DART_TOOLS_API_H_ +#define RUNTIME_INCLUDE_DART_TOOLS_API_H_ + +#include "dart_api.h" /* NOLINT */ + +/** \mainpage Dart Tools Embedding API Reference + * + * This reference describes the Dart embedding API for tools. Tools include + * a debugger, service protocol, and timeline. + * + * NOTE: The APIs described in this file are unstable and subject to change. + * + * This reference is generated from the header include/dart_tools_api.h. + */ + +/* + * ======== + * Debugger + * ======== + */ + +/** + * ILLEGAL_ISOLATE_ID is a number guaranteed never to be associated with a + * valid isolate. + */ +#define ILLEGAL_ISOLATE_ID ILLEGAL_PORT + +/** + * ILLEGAL_ISOLATE_GROUP_ID is a number guaranteed never to be associated with a + * valid isolate group. + */ +#define ILLEGAL_ISOLATE_GROUP_ID 0 + +/* + * ======= + * Service + * ======= + */ + +/** + * A service request callback function. + * + * These callbacks, registered by the embedder, are called when the VM receives + * a service request it can't handle and the service request command name + * matches one of the embedder registered handlers. + * + * The return value of the callback indicates whether the response + * should be used as a regular result or an error result. + * Specifically, if the callback returns true, a regular JSON-RPC + * response is built in the following way: + * + * { + * "jsonrpc": "2.0", + * "result": , + * "id": , + * } + * + * If the callback returns false, a JSON-RPC error is built like this: + * + * { + * "jsonrpc": "2.0", + * "error": , + * "id": , + * } + * + * \param method The rpc method name. + * \param param_keys Service requests can have key-value pair parameters. The + * keys and values are flattened and stored in arrays. + * \param param_values The values associated with the keys. + * \param num_params The length of the param_keys and param_values arrays. + * \param user_data The user_data pointer registered with this handler. + * \param result A C string containing a valid JSON object. The returned + * pointer will be freed by the VM by calling free. + * + * \return True if the result is a regular JSON-RPC response, false if the + * result is a JSON-RPC error. + */ +typedef bool (*Dart_ServiceRequestCallback)(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + +/** + * Register a Dart_ServiceRequestCallback to be called to handle + * requests for the named rpc on a specific isolate. The callback will + * be invoked with the current isolate set to the request target. + * + * \param method The name of the method that this callback is responsible for. + * \param callback The callback to invoke. + * \param user_data The user data passed to the callback. + * + * NOTE: If multiple callbacks with the same name are registered, only + * the last callback registered will be remembered. + */ +DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback( + const char* method, + Dart_ServiceRequestCallback callback, + void* user_data); + +/** + * Register a Dart_ServiceRequestCallback to be called to handle + * requests for the named rpc. The callback will be invoked without a + * current isolate. + * + * \param method The name of the command that this callback is responsible for. + * \param callback The callback to invoke. + * \param user_data The user data passed to the callback. + * + * NOTE: If multiple callbacks with the same name are registered, only + * the last callback registered will be remembered. + */ +DART_EXPORT void Dart_RegisterRootServiceRequestCallback( + const char* method, + Dart_ServiceRequestCallback callback, + void* user_data); + +/** + * Embedder information which can be requested by the VM for internal or + * reporting purposes. + * + * The pointers in this structure are not going to be cached or freed by the VM. + */ + +#define DART_EMBEDDER_INFORMATION_CURRENT_VERSION (0x00000001) + +typedef struct { + int32_t version; + const char* name; // [optional] The name of the embedder + int64_t current_rss; // [optional] the current RSS of the embedder + int64_t max_rss; // [optional] the maximum RSS of the embedder +} Dart_EmbedderInformation; + +/** + * Callback provided by the embedder that is used by the VM to request + * information. + * + * \return Returns a pointer to a Dart_EmbedderInformation structure. + * The embedder keeps the ownership of the structure and any field in it. + * The embedder must ensure that the structure will remain valid until the + * next invocation of the callback. + */ +typedef void (*Dart_EmbedderInformationCallback)( + Dart_EmbedderInformation* info); + +/** + * Register a Dart_ServiceRequestCallback to be called to handle + * requests for the named rpc. The callback will be invoked without a + * current isolate. + * + * \param method The name of the command that this callback is responsible for. + * \param callback The callback to invoke. + * \param user_data The user data passed to the callback. + * + * NOTE: If multiple callbacks are registered, only the last callback registered + * will be remembered. + */ +DART_EXPORT void Dart_SetEmbedderInformationCallback( + Dart_EmbedderInformationCallback callback); + +/** + * Invoke a vm-service method and wait for its result. + * + * \param request_json The utf8-encoded json-rpc request. + * \param request_json_length The length of the json-rpc request. + * + * \param response_json The returned utf8-encoded json response, must be + * free()ed by caller. + * \param response_json_length The length of the returned json response. + * \param error An optional error, must be free()ed by caller. + * + * \return Whether the call was successfully performed. + * + * NOTE: This method does not need a current isolate and must not have the + * vm-isolate being the current isolate. It must be called after + * Dart_Initialize() and before Dart_Cleanup(). + */ +DART_EXPORT bool Dart_InvokeVMServiceMethod(uint8_t* request_json, + intptr_t request_json_length, + uint8_t** response_json, + intptr_t* response_json_length, + char** error); + +/* + * ======== + * Event Streams + * ======== + */ + +/** + * A callback invoked when the VM service gets a request to listen to + * some stream. + * + * \return Returns true iff the embedder supports the named stream id. + */ +typedef bool (*Dart_ServiceStreamListenCallback)(const char* stream_id); + +/** + * A callback invoked when the VM service gets a request to cancel + * some stream. + */ +typedef void (*Dart_ServiceStreamCancelCallback)(const char* stream_id); + +/** + * Adds VM service stream callbacks. + * + * \param listen_callback A function pointer to a listen callback function. + * A listen callback function should not be already set when this function + * is called. A NULL value removes the existing listen callback function + * if any. + * + * \param cancel_callback A function pointer to a cancel callback function. + * A cancel callback function should not be already set when this function + * is called. A NULL value removes the existing cancel callback function + * if any. + * + * \return Success if the callbacks were added. Otherwise, returns an + * error handle. + */ +DART_EXPORT char* Dart_SetServiceStreamCallbacks( + Dart_ServiceStreamListenCallback listen_callback, + Dart_ServiceStreamCancelCallback cancel_callback); + +/** + * Sends a data event to clients of the VM Service. + * + * A data event is used to pass an array of bytes to subscribed VM + * Service clients. For example, in the standalone embedder, this is + * function used to provide WriteEvents on the Stdout and Stderr + * streams. + * + * If the embedder passes in a stream id for which no client is + * subscribed, then the event is ignored. + * + * \param stream_id The id of the stream on which to post the event. + * + * \param event_kind A string identifying what kind of event this is. + * For example, 'WriteEvent'. + * + * \param bytes A pointer to an array of bytes. + * + * \param bytes_length The length of the byte array. + * + * \return NULL if the arguments are well formed. Otherwise, returns an + * error string. The caller is responsible for freeing the error message. + */ +DART_EXPORT char* Dart_ServiceSendDataEvent(const char* stream_id, + const char* event_kind, + const uint8_t* bytes, + intptr_t bytes_length); + +/* + * ======== + * Reload support + * ======== + * + * These functions are used to implement reloading in the Dart VM. + * This is an experimental feature, so embedders should be prepared + * for these functions to change. + */ + +/** + * A callback which determines whether the file at some url has been + * modified since some time. If the file cannot be found, true should + * be returned. + */ +typedef bool (*Dart_FileModifiedCallback)(const char* url, int64_t since); + +DART_EXPORT char* Dart_SetFileModifiedCallback( + Dart_FileModifiedCallback file_modified_callback); + +/** + * Returns true if isolate is currently reloading. + */ +DART_EXPORT bool Dart_IsReloading(); + +/* + * ======== + * Timeline + * ======== + */ + +/** + * Enable tracking of specified timeline category. This is operational + * only when systrace timeline functionality is turned on. + * + * \param categories A comma separated list of categories that need to + * be enabled, the categories are + * "all" : All categories + * "API" - Execution of Dart C API functions + * "Compiler" - Execution of Dart JIT compiler + * "CompilerVerbose" - More detailed Execution of Dart JIT compiler + * "Dart" - Execution of Dart code + * "Debugger" - Execution of Dart debugger + * "Embedder" - Execution of Dart embedder code + * "GC" - Execution of Dart Garbage Collector + * "Isolate" - Dart Isolate lifecycle execution + * "VM" - Execution in Dart VM runtime code + * "" - None + * + * When "all" is specified all the categories are enabled. + * When a comma separated list of categories is specified, the categories + * that are specified will be enabled and the rest will be disabled. + * When "" is specified all the categories are disabled. + * The category names are case sensitive. + * eg: Dart_EnableTimelineCategory("all"); + * Dart_EnableTimelineCategory("GC,API,Isolate"); + * Dart_EnableTimelineCategory("GC,Debugger,Dart"); + * + * \return True if the categories were successfully enabled, False otherwise. + */ +DART_EXPORT bool Dart_SetEnabledTimelineCategory(const char* categories); + +/** + * Returns a timestamp in microseconds. This timestamp is suitable for + * passing into the timeline system, and uses the same monotonic clock + * as dart:developer's Timeline.now. + * + * \return A timestamp that can be passed to the timeline system. + */ +DART_EXPORT int64_t Dart_TimelineGetMicros(); + +/** + * Returns a raw timestamp in from the monotonic clock. + * + * \return A raw timestamp from the monotonic clock. + */ +DART_EXPORT int64_t Dart_TimelineGetTicks(); + +/** + * Returns the frequency of the monotonic clock. + * + * \return The frequency of the monotonic clock. + */ +DART_EXPORT int64_t Dart_TimelineGetTicksFrequency(); + +typedef enum { + Dart_Timeline_Event_Begin, // Phase = 'B'. + Dart_Timeline_Event_End, // Phase = 'E'. + Dart_Timeline_Event_Instant, // Phase = 'i'. + Dart_Timeline_Event_Duration, // Phase = 'X'. + Dart_Timeline_Event_Async_Begin, // Phase = 'b'. + Dart_Timeline_Event_Async_End, // Phase = 'e'. + Dart_Timeline_Event_Async_Instant, // Phase = 'n'. + Dart_Timeline_Event_Counter, // Phase = 'C'. + Dart_Timeline_Event_Flow_Begin, // Phase = 's'. + Dart_Timeline_Event_Flow_Step, // Phase = 't'. + Dart_Timeline_Event_Flow_End, // Phase = 'f'. +} Dart_Timeline_Event_Type; + +/** + * Add a timeline event to the embedder stream. + * + * Note regarding flow events: events must be associated with flow IDs in two + * different ways to allow flow events to be serialized correctly in both + * Chrome's JSON trace event format and Perfetto's proto trace format. Events + * of type |Dart_Timeline_Event_Flow_Begin|, |Dart_Timeline_Event_Flow_Step|, + * and |Dart_Timeline_Event_Flow_End| must be reported to support serialization + * in Chrome's trace format. The |flow_ids| argument must be supplied when + * reporting events of type |Dart_Timeline_Event_Begin|, + * |Dart_Timeline_Event_Duration|, |Dart_Timeline_Event_Instant|, + * |Dart_Timeline_Event_Async_Begin|, and |Dart_Timeline_Event_Async_Instant| to + * support serialization in Perfetto's proto format. + * + * The Dart VM can use various underlying recorders depending on configuration + * and operating system. Many recorders do not support all event types; + * unsupported event types are siliently dropped. Some recorders do not accept + * timestamps as input, instead implicitly using the time the event is recorded. + * For maximum compatibility, record events with the Begin and End types as they + * occur instead of using the Duration type or buffering. + * + * \param label The name of the event. Its lifetime must extend at least until + * Dart_Cleanup. + * \param timestamp0 The first timestamp of the event. + * \param timestamp1_or_id When reporting an event of type + * |Dart_Timeline_Event_Duration|, the second (end) timestamp of the event + * should be passed through |timestamp1_or_id|. When reporting an event of + * type |Dart_Timeline_Event_Async_Begin|, |Dart_Timeline_Event_Async_End|, + * or |Dart_Timeline_Event_Async_Instant|, the async ID associated with the + * event should be passed through |timestamp1_or_id|. When reporting an + * event of type |Dart_Timeline_Event_Flow_Begin|, + * |Dart_Timeline_Event_Flow_Step|, or |Dart_Timeline_Event_Flow_End|, the + * flow ID associated with the event should be passed through + * |timestamp1_or_id|. When reporting an event of type + * |Dart_Timeline_Event_Begin| or |Dart_Timeline_Event_End|, the event ID + * associated with the event should be passed through |timestamp1_or_id|. + * Note that this event ID will only be used by the MacOS recorder. The + * argument to |timestamp1_or_id| will not be used when reporting events of + * other types. + * \param flow_id_count The number of flow IDs associated with this event. + * \param flow_ids An array of flow IDs associated with this event. The array + * may be reclaimed when this call returns. + * \param argument_count The number of argument names and values. + * \param argument_names An array of names of the arguments. The lifetime of the + * names must extend at least until Dart_Cleanup. The array may be reclaimed + * when this call returns. + * \param argument_values An array of values of the arguments. The values and + * the array may be reclaimed when this call returns. + */ +DART_EXPORT void Dart_RecordTimelineEvent(const char* label, + int64_t timestamp0, + int64_t timestamp1_or_id, + intptr_t flow_id_count, + const int64_t* flow_ids, + Dart_Timeline_Event_Type type, + intptr_t argument_count, + const char** argument_names, + const char** argument_values); + +/** + * Associates a name with the current thread. This name will be used to name + * threads in the timeline. Can only be called after a call to Dart_Initialize. + * + * \param name The name of the thread. + */ +DART_EXPORT void Dart_SetThreadName(const char* name); + +typedef struct { + const char* name; + const char* value; +} Dart_TimelineRecorderEvent_Argument; + +#define DART_TIMELINE_RECORDER_CURRENT_VERSION (0x00000002) + +typedef struct { + /* Set to DART_TIMELINE_RECORDER_CURRENT_VERSION */ + int32_t version; + + /* The event's type / phase. */ + Dart_Timeline_Event_Type type; + + /* The event's timestamp according to the same clock as + * Dart_TimelineGetMicros. For a duration event, this is the beginning time. + */ + int64_t timestamp0; + + /** + * For a duration event, this is the end time. For an async event, this is the + * async ID. For a flow event, this is the flow ID. For a begin or end event, + * this is the event ID (which is only referenced by the MacOS recorder). + */ + int64_t timestamp1_or_id; + + /* The current isolate of the event, as if by Dart_GetMainPortId, or + * ILLEGAL_PORT if the event had no current isolate. */ + Dart_Port isolate; + + /* The current isolate group of the event, as if by + * Dart_CurrentIsolateGroupId, or ILLEGAL_PORT if the event had no current + * isolate group. */ + Dart_IsolateGroupId isolate_group; + + /* The callback data associated with the isolate if any. */ + void* isolate_data; + + /* The callback data associated with the isolate group if any. */ + void* isolate_group_data; + + /* The name / label of the event. */ + const char* label; + + /* The stream / category of the event. */ + const char* stream; + + intptr_t argument_count; + Dart_TimelineRecorderEvent_Argument* arguments; +} Dart_TimelineRecorderEvent; + +/** + * Callback provided by the embedder to handle the completion of timeline + * events. + * + * \param event A timeline event that has just been completed. The VM keeps + * ownership of the event and any field in it (i.e., the embedder should copy + * any values it needs after the callback returns). + */ +typedef void (*Dart_TimelineRecorderCallback)( + Dart_TimelineRecorderEvent* event); + +/** + * Register a `Dart_TimelineRecorderCallback` to be called as timeline events + * are completed. + * + * The callback will be invoked without a current isolate. + * + * The callback will be invoked on the thread completing the event. Because + * `Dart_RecordTimelineEvent` may be called by any thread, the callback may be + * called on any thread. + * + * The callback may be invoked at any time after `Dart_Initialize` is called and + * before `Dart_Cleanup` returns. + * + * If multiple callbacks are registered, only the last callback registered + * will be remembered. Providing a NULL callback will clear the registration + * (i.e., a NULL callback produced a no-op instead of a crash). + * + * Setting a callback is insufficient to receive events through the callback. The + * VM flag `timeline_recorder` must also be set to `callback`. + */ +DART_EXPORT void Dart_SetTimelineRecorderCallback( + Dart_TimelineRecorderCallback callback); + +/* + * ======= + * Metrics + * ======= + */ + +/** + * Return metrics gathered for the VM and individual isolates. + */ +DART_EXPORT int64_t +Dart_IsolateGroupHeapOldUsedMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapOldCapacityMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapOldExternalMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapNewUsedMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapNewCapacityMetric(Dart_IsolateGroup group); // Byte +DART_EXPORT int64_t +Dart_IsolateGroupHeapNewExternalMetric(Dart_IsolateGroup group); // Byte + +/* + * ======== + * UserTags + * ======== + */ + +/* + * Gets the current isolate's currently set UserTag instance. + * + * \return The currently set UserTag instance. + */ +DART_EXPORT Dart_Handle Dart_GetCurrentUserTag(); + +/* + * Gets the current isolate's default UserTag instance. + * + * \return The default UserTag with label 'Default' + */ +DART_EXPORT Dart_Handle Dart_GetDefaultUserTag(); + +/* + * Creates a new UserTag instance. + * + * \param label The name of the new UserTag. + * + * \return The newly created UserTag instance or an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label); + +/* + * Updates the current isolate's UserTag to a new value. + * + * \param user_tag The UserTag to be set as the current UserTag. + * + * \return The previously set UserTag instance or an error handle. + */ +DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag); + +/* + * Returns the label of a given UserTag instance. + * + * \param user_tag The UserTag from which the label will be retrieved. + * + * \return The UserTag's label. NULL if the user_tag is invalid. The caller is + * responsible for freeing the returned label. + */ +DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_GetUserTagLabel( + Dart_Handle user_tag); + +/* + * ======= + * Heap Snapshot + * ======= + */ + +/** + * Callback provided by the caller of `Dart_WriteHeapSnapshot` which is + * used to write out chunks of the requested heap snapshot. + * + * \param context An opaque context which was passed to `Dart_WriteHeapSnapshot` + * together with this callback. + * + * \param buffer Pointer to the buffer containing a chunk of the snapshot. + * The callback owns the buffer and needs to `free` it. + * + * \param size Number of bytes in the `buffer` to be written. + * + * \param is_last Set to `true` for the last chunk. The callback will not + * be invoked again after it was invoked once with `is_last` set to `true`. + */ +typedef void (*Dart_HeapSnapshotWriteChunkCallback)(void* context, + uint8_t* buffer, + intptr_t size, + bool is_last); + +/** + * Generate heap snapshot of the current isolate group and stream it into the + * given `callback`. VM would produce snapshot in chunks and send these chunks + * one by one back to the embedder by invoking the provided `callback`. + * + * This API enables embedder to stream snapshot into a file or socket without + * allocating a buffer to hold the whole snapshot in memory. + * + * The isolate group will be paused for the duration of this operation. + * + * \param write Callback used to write chunks of the heap snapshot. + * + * \param context Opaque context which would be passed on each invocation of + * `write` callback. + * + * \returns `nullptr` if the operation is successful otherwise error message. + * Caller owns error message string and needs to `free` it. + */ +DART_EXPORT char* Dart_WriteHeapSnapshot( + Dart_HeapSnapshotWriteChunkCallback write, + void* context); + +#endif // RUNTIME_INCLUDE_DART_TOOLS_API_H_ diff --git a/src/serious_python_bridge/native/dart_api/dart_version.h b/src/serious_python_bridge/native/dart_api/dart_version.h new file mode 100644 index 00000000..5ca0b683 --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/dart_version.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef RUNTIME_INCLUDE_DART_VERSION_H_ +#define RUNTIME_INCLUDE_DART_VERSION_H_ + +// On breaking changes the major version is increased. +// On backwards compatible changes the minor version is increased. +// The versioning covers the symbols exposed in dart_api_dl.h +#define DART_API_DL_MAJOR_VERSION 2 +#define DART_API_DL_MINOR_VERSION 5 + +#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h b/src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h new file mode 100644 index 00000000..e4a56893 --- /dev/null +++ b/src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#ifndef RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ +#define RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ + +typedef struct { + const char* name; + void (*function)(void); +} DartApiEntry; + +typedef struct { + const int major; + const int minor; + const DartApiEntry* const functions; +} DartApi; + +#endif /* RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_bridge.c b/src/serious_python_bridge/native/dart_bridge.c new file mode 100644 index 00000000..062e3aec --- /dev/null +++ b/src/serious_python_bridge/native/dart_bridge.c @@ -0,0 +1,124 @@ +#define PY_SSIZE_T_CLEAN +#include +#include +#include +#include "dart_api/dart_api_dl.h" + +#if defined(_WIN32) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT __attribute__((visibility("default"))) +#endif + +// --------------------------------------------------------------------------- +// Core: symbols called from Dart via FFI. On platforms with the shared-lib +// split these live in libflet_bridge; on iOS they're linked statically into +// the serious_python framework. +// --------------------------------------------------------------------------- + +static PyObject* global_enqueue_handler_func = NULL; + +EXPORT intptr_t DartBridge_InitDartApiDL(void* data) { + return Dart_InitializeApiDL(data); +} + +EXPORT void DartBridge_EnqueueMessage(const char* data, size_t len) { + PyGILState_STATE gstate = PyGILState_Ensure(); + + if (!global_enqueue_handler_func) { + fprintf(stderr, "[dart_bridge] enqueue handler is not registered\n"); + PyGILState_Release(gstate); + return; + } + + PyObject* arg = PyBytes_FromStringAndSize(data, len); + if (!arg) { + PyErr_Print(); + PyGILState_Release(gstate); + return; + } + + PyObject* result = PyObject_CallFunctionObjArgs(global_enqueue_handler_func, arg, NULL); + if (!result) { + PyErr_Print(); + } + + Py_XDECREF(arg); + Py_XDECREF(result); + PyGILState_Release(gstate); +} + +// --------------------------------------------------------------------------- +// Shim: Python-callable methods exposed by the `dart_bridge` module. +// --------------------------------------------------------------------------- + +static PyObject* set_enqueue_handler_func(PyObject* self, PyObject* args) { + PyObject* func; + + if (!PyArg_ParseTuple(args, "O:set_enqueue_handler_func", &func)) { + return NULL; + } + + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return NULL; + } + + Py_XINCREF(func); + Py_XDECREF(global_enqueue_handler_func); + global_enqueue_handler_func = func; + + Py_RETURN_NONE; +} + +static PyObject* send_bytes(PyObject* self, PyObject* args) { + int64_t port; + const char* buffer; + Py_ssize_t length; + + if (!PyArg_ParseTuple(args, "Ly#", &port, &buffer, &length)) { + return NULL; + } + + if (port == 0) { + PyErr_SetString(PyExc_RuntimeError, "Dart port is 0 (invalid)"); + return NULL; + } + + // Dart_PostCObject_DL is a function pointer populated by Dart_InitializeApiDL. + // Calling it before init segfaults; surface a clean error instead. + if (Dart_PostCObject_DL == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Dart API DL not initialized (call DartBridge_InitDartApiDL from Dart first)"); + return NULL; + } + + Dart_CObject obj; + obj.type = Dart_CObject_kTypedData; + obj.value.as_typed_data.type = Dart_TypedData_kUint8; + obj.value.as_typed_data.length = (int32_t)length; + obj.value.as_typed_data.values = (void*)buffer; + + if (!Dart_PostCObject_DL(port, &obj)) { + PyErr_SetString(PyExc_RuntimeError, "Dart_PostCObject_DL failed"); + return NULL; + } + + Py_RETURN_TRUE; +} + +static PyMethodDef methods[] = { + {"send_bytes", send_bytes, METH_VARARGS, "Post a bytes payload to a Dart ReceivePort."}, + {"set_enqueue_handler_func", set_enqueue_handler_func, METH_VARARGS, + "Register the Python callable that receives bytes posted from Dart."}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "dart_bridge", NULL, -1, methods +}; + +PyMODINIT_FUNC PyInit_dart_bridge(void) { + return PyModule_Create(&moduledef); +} diff --git a/src/serious_python_bridge/python/MANIFEST.in b/src/serious_python_bridge/python/MANIFEST.in new file mode 100644 index 00000000..4ff3dbf2 --- /dev/null +++ b/src/serious_python_bridge/python/MANIFEST.in @@ -0,0 +1,4 @@ +include ../native/dart_bridge.c +include ../native/dart_api/*.h +include ../native/dart_api/*.c +include ../native/dart_api/internal/*.h diff --git a/src/serious_python_bridge/python/pyproject.toml b/src/serious_python_bridge/python/pyproject.toml new file mode 100644 index 00000000..c5bc4b5e --- /dev/null +++ b/src/serious_python_bridge/python/pyproject.toml @@ -0,0 +1,33 @@ +[build-system] +requires = ["setuptools>=61.0.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "dart_bridge" +version = "0.0.0" +description = "Python C extension exposing the dart_bridge module — bidirectional Dart ↔ Python byte transport for serious_python_bridge." +readme = "../README.md" +authors = [ + { name = "Flet Team", email = "hello@flet.dev" }, +] +requires-python = ">=3.12" +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: C", + "Operating System :: POSIX", + "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows", + "Topic :: Software Development :: Libraries :: Python Modules", +] +keywords = ["dart", "ffi", "bridge", "serious_python", "flet"] + +[project.urls] +Homepage = "https://github.com/flet-dev/serious-python" +Issues = "https://github.com/flet-dev/serious-python/issues" + +[tool.cibuildwheel] +build = "cp312-* cp313-* cp314-*" +skip = ["pp*", "*-musllinux_*"] diff --git a/src/serious_python_bridge/python/setup.py b/src/serious_python_bridge/python/setup.py new file mode 100644 index 00000000..7d5826fa --- /dev/null +++ b/src/serious_python_bridge/python/setup.py @@ -0,0 +1,16 @@ +from setuptools import Extension, setup + +NATIVE_ROOT = "../native" + +setup( + ext_modules=[ + Extension( + "dart_bridge", + sources=[ + f"{NATIVE_ROOT}/dart_bridge.c", + f"{NATIVE_ROOT}/dart_api/dart_api_dl.c", + ], + include_dirs=[NATIVE_ROOT], + ) + ], +) From 2b7733c3ed6808a280f592f42dd225581706bbba Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:08:19 -0700 Subject: [PATCH 002/114] Add registerPythonExtension API to serious_python_darwin Generic hook for plugins shipping statically linked Python C extensions (intended primarily for iOS, where dlopen of late-loaded extensions is forbidden, but available on macOS too so callers don't need platform conditionals). Callers register (name, PyInit_*) pairs; the plugin calls PyImport_AppendInittab on each entry before every Py_Initialize, so the existing Py_Initialize/Py_Finalize cycle works correctly. - Names are strdup'd into stable storage (PyImport_AppendInittab does not copy and requires lifetime >= interpreter) - NSLock-guarded registration list, safe to call from any thread - No bridge-specific code: serious_python_darwin stays agnostic, any future static Python extension can register the same way --- .../darwin/Classes/SeriousPythonPlugin.swift | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift b/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift index 0c233a3c..201be1c1 100644 --- a/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift +++ b/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift @@ -8,7 +8,48 @@ import FlutterMacOS import Python public class SeriousPythonPlugin: NSObject, FlutterPlugin { - + + public typealias PyInitFunction = @convention(c) () -> UnsafeMutablePointer? + + private struct PythonExtensionEntry { + // PyImport_AppendInittab does not copy the name string; the storage must + // outlive the interpreter. We strdup on register and intentionally leak. + let name: UnsafeMutablePointer + let initFn: PyInitFunction + } + + private static var registeredExtensions: [PythonExtensionEntry] = [] + private static let registrationLock = NSLock() + + /// Register a statically linked Python C extension to be made available as a + /// built-in module on every Py_Initialize. Intended for iOS, where dlopen of + /// late-loaded .so extensions is forbidden, but available on macOS too so + /// callers don't need platform conditionals. + /// + /// Must be called before serious_python's first runPython invocation. Calling + /// twice with the same name is the caller's responsibility to avoid. + public static func registerPythonExtension(name: String, initFn: PyInitFunction) { + registrationLock.lock() + defer { registrationLock.unlock() } + guard let copied = strdup(name) else { + NSLog("[SeriousPython] strdup failed for extension name \(name)") + return + } + registeredExtensions.append(PythonExtensionEntry(name: copied, initFn: initFn)) + } + + private func applyRegisteredExtensions() { + SeriousPythonPlugin.registrationLock.lock() + let entries = SeriousPythonPlugin.registeredExtensions + SeriousPythonPlugin.registrationLock.unlock() + + for entry in entries { + if PyImport_AppendInittab(entry.name, entry.initFn) != 0 { + NSLog("[SeriousPython] PyImport_AppendInittab failed for \(String(cString: entry.name))") + } + } + } + public static func register(with registrar: FlutterPluginRegistrar) { // Workaround for https://github.com/flutter/flutter/issues/118103. #if os(iOS) @@ -110,27 +151,29 @@ public class SeriousPythonPlugin: NSObject, FlutterPlugin { } @objc func runPythonFile(appPath: String) { + applyRegisteredExtensions() Py_Initialize() - + // run app let file = fopen(appPath, "r") let result = PyRun_SimpleFileEx(file, appPath, 1) if (result != 0) { print("Python program completed with error.") } - + Py_Finalize() } @objc func runPythonScript(script: String) { + applyRegisteredExtensions() Py_Initialize() - + // run app let result = PyRun_SimpleString(script) if (result != 0) { print("Python script completed with error.") } - + Py_Finalize() } } From 9a33d58dcb76d151e75c5056c220ae52a0847489 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:22:42 -0700 Subject: [PATCH 003/114] Scaffold serious_python_bridge Flutter plugin: pubspec + Dart PythonBridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Standard FFI Flutter plugin layout, sibling to serious_python_*. Pure FFI on Linux/Windows/Android; iOS+macOS additionally declare pluginClass + sharedDarwinSource for the Swift code that will call SeriousPython.registerPythonExtension (added in a later step). - lib/serious_python_bridge.dart: PythonBridge singleton wrapping the native symbols (DartBridge_InitDartApiDL, DartBridge_EnqueueMessage) and Python's send_bytes reply path via a ReceivePort. Generic byte-transport API (Stream messages, send(Uint8List), nativePort, dispose) — no protocol/msgpack/Flet specifics. DynamicLibrary discovery is platform- aware: process() on iOS (static link), .dylib/.dll/.so elsewhere. - pubspec.yaml: declares ffiPlugin on all five platforms, path deps on serious_python + serious_python_darwin (patch_pubspec.py rewrites at release). - README/CHANGELOG/LICENSE/analysis_options matching sibling plugin pattern. - python/pyproject.toml: drop readme reference outside project root that setuptools rejected. --- src/serious_python_bridge/CHANGELOG.md | 5 + src/serious_python_bridge/LICENSE | 201 ++++++++++++++++++ src/serious_python_bridge/README.md | 53 +++++ .../analysis_options.yaml | 4 + .../lib/serious_python_bridge.dart | 124 +++++++++++ src/serious_python_bridge/pubspec.yaml | 41 ++++ .../python/pyproject.toml | 1 - 7 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 src/serious_python_bridge/CHANGELOG.md create mode 100644 src/serious_python_bridge/LICENSE create mode 100644 src/serious_python_bridge/README.md create mode 100644 src/serious_python_bridge/analysis_options.yaml create mode 100644 src/serious_python_bridge/lib/serious_python_bridge.dart create mode 100644 src/serious_python_bridge/pubspec.yaml diff --git a/src/serious_python_bridge/CHANGELOG.md b/src/serious_python_bridge/CHANGELOG.md new file mode 100644 index 00000000..ddf41ee3 --- /dev/null +++ b/src/serious_python_bridge/CHANGELOG.md @@ -0,0 +1,5 @@ +## 2.0.0 + +* Initial release. Generic in-process Dart ↔ Python byte transport built on + Dart's native API DL (`Dart_PostCObject_DL`) and the embedded Python runtime + provided by `serious_python`. diff --git a/src/serious_python_bridge/LICENSE b/src/serious_python_bridge/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/src/serious_python_bridge/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/serious_python_bridge/README.md b/src/serious_python_bridge/README.md new file mode 100644 index 00000000..953cefa4 --- /dev/null +++ b/src/serious_python_bridge/README.md @@ -0,0 +1,53 @@ +# serious_python_bridge + +A generic in-process Dart ↔ Python byte transport for the embedded Python +runtime provided by [`serious_python`](../serious_python). Eliminates the +socket/TCP/WebSocket overhead of out-of-process IPC by exchanging bytes +directly across the Dart FFI / CPython C API boundary. + +This package is **independent of any specific protocol** — it exchanges +opaque byte buffers. Higher-level frameworks (e.g. Flet) layer their own +serialization (msgpack, JSON, etc.) on top. + +## Usage + +Dart side: + +```dart +import 'package:serious_python_bridge/serious_python_bridge.dart'; + +final bridge = PythonBridge.init(); + +bridge.messages.listen((bytes) { + // bytes posted by Python via dart_bridge.send_bytes(port, payload) +}); + +// Hand off the native port id to Python (typically as the first frame). +bridge.send(_encodeNativePort(bridge.nativePort)); + +// Send arbitrary bytes to Python. +bridge.send(Uint8List.fromList([0x01, 0x02, 0x03])); +``` + +Python side (executed inside the embedded interpreter started by +`serious_python`): + +```python +import dart_bridge + +def on_message(data: bytes) -> None: + ... + +dart_bridge.set_enqueue_handler_func(on_message) +dart_bridge.send_bytes(native_port, b"reply") +``` + +## Threading + +`PythonBridge.send()` is synchronous and acquires the Python GIL for the +duration of the dispatch. Call it from a dedicated isolate rather than the +root isolate to avoid stalling Flutter UI frames. + +## License + +See [LICENSE](LICENSE). diff --git a/src/serious_python_bridge/analysis_options.yaml b/src/serious_python_bridge/analysis_options.yaml new file mode 100644 index 00000000..a5744c1c --- /dev/null +++ b/src/serious_python_bridge/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/src/serious_python_bridge/lib/serious_python_bridge.dart b/src/serious_python_bridge/lib/serious_python_bridge.dart new file mode 100644 index 00000000..99908214 --- /dev/null +++ b/src/serious_python_bridge/lib/serious_python_bridge.dart @@ -0,0 +1,124 @@ +import 'dart:async'; +import 'dart:ffi'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:typed_data'; + +import 'package:ffi/ffi.dart'; + +typedef _DartBridgeInitNative = IntPtr Function(Pointer); +typedef _DartBridgeInit = int Function(Pointer); + +typedef _DartBridgeEnqueueNative = Void Function(Pointer, IntPtr); +typedef _DartBridgeEnqueue = void Function(Pointer, int); + +/// Generic in-process Dart ↔ Python byte transport. +/// +/// Wraps the native `dart_bridge` C symbols (`DartBridge_InitDartApiDL`, +/// `DartBridge_EnqueueMessage`, and the corresponding Python-side +/// `dart_bridge.send_bytes`) into an idiomatic Dart API: +/// +/// * `messages` — broadcast stream of byte buffers posted from Python. +/// * `send(bytes)` — push bytes to Python (synchronous; acquires the GIL). +/// * `nativePort` — the Dart native port id Python uses to post back; the +/// caller is responsible for handing this id to Python in whatever way its +/// protocol requires (typically as the first frame). +/// +/// The bridge is process-global state (Python's `global_enqueue_handler_func` +/// and Dart's API-DL initialization are both singletons), so this class is +/// implemented as a singleton. `PythonBridge.init()` is idempotent. +/// +/// Threading: `send()` blocks the calling thread for the duration of the +/// Python handler dispatch (which runs synchronously under `PyGILState_Ensure`). +/// To avoid stalling Flutter UI frames, call `send()` from a dedicated isolate +/// rather than the root isolate. +class PythonBridge { + PythonBridge._(); + + static PythonBridge? _instance; + + late final DynamicLibrary _lib; + late final _DartBridgeInit _initDartApiDL; + late final _DartBridgeEnqueue _enqueueMessage; + + late final ReceivePort _receivePort; + final StreamController _messages = + StreamController.broadcast(); + + /// Returns the singleton bridge instance, initializing it on first call. + factory PythonBridge.init() { + final existing = _instance; + if (existing != null) return existing; + final bridge = PythonBridge._().._initialize(); + _instance = bridge; + return bridge; + } + + /// The currently initialized bridge, or `null` if `init()` hasn't been called. + static PythonBridge? get instance => _instance; + + void _initialize() { + _lib = _openNativeLibrary(); + + _initDartApiDL = _lib + .lookup>('DartBridge_InitDartApiDL') + .asFunction(); + _enqueueMessage = _lib + .lookup>('DartBridge_EnqueueMessage') + .asFunction(); + + if (_initDartApiDL(NativeApi.initializeApiDLData) != 0) { + throw StateError( + 'DartBridge_InitDartApiDL failed: Dart VM API version mismatch'); + } + + _receivePort = ReceivePort(); + _receivePort.listen((message) { + if (message is Uint8List) { + _messages.add(message); + } else if (message is TransferableTypedData) { + _messages.add(message.materialize().asUint8List()); + } + }); + } + + static DynamicLibrary _openNativeLibrary() { + // iOS: the bridge is statically linked into the serious_python framework. + if (Platform.isIOS) return DynamicLibrary.process(); + if (Platform.isMacOS) return DynamicLibrary.open('libflet_bridge.dylib'); + if (Platform.isWindows) return DynamicLibrary.open('flet_bridge.dll'); + if (Platform.isLinux || Platform.isAndroid) { + return DynamicLibrary.open('libflet_bridge.so'); + } + throw UnsupportedError( + 'serious_python_bridge does not support ${Platform.operatingSystem}'); + } + + /// Bytes posted from Python via `dart_bridge.send_bytes(port, payload)`. + Stream get messages => _messages.stream; + + /// Native port id to hand to Python so it can post back to this bridge. + int get nativePort => _receivePort.sendPort.nativePort; + + /// Send a buffer to the Python handler registered via + /// `dart_bridge.set_enqueue_handler_func`. + /// + /// The call is synchronous and acquires the Python GIL for the duration of + /// the dispatch. Callers should run this off the root isolate to avoid + /// stalling Flutter UI frames. + void send(Uint8List bytes) { + using((arena) { + final ptr = arena(bytes.length); + ptr.asTypedList(bytes.length).setAll(0, bytes); + _enqueueMessage(ptr, bytes.length); + }); + } + + /// Release resources and tear down the singleton. After dispose, callers + /// must invoke `PythonBridge.init()` again before further use. + void dispose() { + _receivePort.close(); + _messages.close(); + _instance = null; + } +} diff --git a/src/serious_python_bridge/pubspec.yaml b/src/serious_python_bridge/pubspec.yaml new file mode 100644 index 00000000..a32faff1 --- /dev/null +++ b/src/serious_python_bridge/pubspec.yaml @@ -0,0 +1,41 @@ +name: serious_python_bridge +description: Generic in-process Dart ↔ Python byte transport for the embedded Python runtime provided by serious_python. +homepage: https://flet.dev +repository: https://github.com/flet-dev/serious-python +version: 2.0.0 + +environment: + sdk: ">=3.0.0 <4.0.0" + flutter: ">=3.7.0" + +dependencies: + flutter: + sdk: flutter + ffi: ^2.1.0 + serious_python: + path: ../serious_python + serious_python_darwin: + path: ../serious_python_darwin + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +flutter: + plugin: + platforms: + android: + ffiPlugin: true + ios: + pluginClass: SeriousPythonBridgePlugin + ffiPlugin: true + sharedDarwinSource: true + macos: + pluginClass: SeriousPythonBridgePlugin + ffiPlugin: true + sharedDarwinSource: true + linux: + ffiPlugin: true + windows: + ffiPlugin: true diff --git a/src/serious_python_bridge/python/pyproject.toml b/src/serious_python_bridge/python/pyproject.toml index c5bc4b5e..9ddaaf49 100644 --- a/src/serious_python_bridge/python/pyproject.toml +++ b/src/serious_python_bridge/python/pyproject.toml @@ -6,7 +6,6 @@ build-backend = "setuptools.build_meta" name = "dart_bridge" version = "0.0.0" description = "Python C extension exposing the dart_bridge module — bidirectional Dart ↔ Python byte transport for serious_python_bridge." -readme = "../README.md" authors = [ { name = "Flet Team", email = "hello@flet.dev" }, ] From 7044e7f705ba138b4dcba56152fcefe3f0be166a Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:45:40 -0700 Subject: [PATCH 004/114] Add Linux + Windows CMakeLists for libflet_bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Standard Flutter FFI plugin layout: per-platform CMakeLists wrappers under linux/ and windows/ each call add_subdirectory("../native"), and set serious_python_bridge_bundled_libraries to $ so Flutter bundles the produced shared library alongside the app binary. The cross-platform native/CMakeLists.txt uses find_package(Python3 ... Development.Module) + Python3::Module — this gives header-only Python deps and the correct per-platform link behavior (Linux: dynamic resolution; Windows: pythonXY.lib import library; macOS: -undefined dynamic_lookup, though macOS desktop uses the podspec, not this CMakeLists). Verified locally on macOS host: configure + build produces libflet_bridge.dylib (53K) with exported DartBridge_InitDartApiDL + DartBridge_EnqueueMessage and unresolved Py* references (PyGILState_*, PyBytes_*, PyObject_CallFunctionObjArgs, etc.) — resolved at runtime against libpython loaded by serious_python. Known limitation: uses the host system's Python.h. Cross-build correctness (Android NDK, manylinux CI) will need an override pointing at the matching python-build-standalone tarball; deferred until step that needs it. --- .../linux/CMakeLists.txt | 13 +++++++ .../native/CMakeLists.txt | 35 +++++++++++++++++++ .../windows/CMakeLists.txt | 15 ++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/serious_python_bridge/linux/CMakeLists.txt create mode 100644 src/serious_python_bridge/native/CMakeLists.txt create mode 100644 src/serious_python_bridge/windows/CMakeLists.txt diff --git a/src/serious_python_bridge/linux/CMakeLists.txt b/src/serious_python_bridge/linux/CMakeLists.txt new file mode 100644 index 00000000..be9816ce --- /dev/null +++ b/src/serious_python_bridge/linux/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.10) + +set(PROJECT_NAME "serious_python_bridge") +project(${PROJECT_NAME} LANGUAGES C) + +add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# Flutter picks up bundled libraries via this variable and copies the file +# alongside the app binary; Dart resolves it via DynamicLibrary.open. +set(serious_python_bridge_bundled_libraries + $ + PARENT_SCOPE +) diff --git a/src/serious_python_bridge/native/CMakeLists.txt b/src/serious_python_bridge/native/CMakeLists.txt new file mode 100644 index 00000000..80966c4e --- /dev/null +++ b/src/serious_python_bridge/native/CMakeLists.txt @@ -0,0 +1,35 @@ +# Cross-platform CMake target for libflet_bridge. +# +# Built from the same dart_bridge.c source used by the Python shim (which CI +# builds via cibuildwheel). Per-platform wrappers under linux/, windows/, etc. +# include this file via add_subdirectory. + +cmake_minimum_required(VERSION 3.15) + +project(flet_bridge VERSION 0.0.1 LANGUAGES C) + +# Python3::Module brings in headers + the platform-correct link behavior: +# - Windows: links pythonXY.lib (import library) +# - macOS: adds -undefined dynamic_lookup +# - Linux: nothing (default dynamic resolution) +# Py* symbols are resolved at runtime against the libpython that serious_python +# has already loaded into the process. +find_package(Python3 REQUIRED COMPONENTS Development.Module) + +add_library(flet_bridge SHARED + "dart_bridge.c" + "dart_api/dart_api_dl.c" +) + +target_include_directories(flet_bridge PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(flet_bridge PRIVATE Python3::Module) + +set_target_properties(flet_bridge PROPERTIES + C_VISIBILITY_PRESET hidden + OUTPUT_NAME "flet_bridge" +) + +target_compile_definitions(flet_bridge PRIVATE DART_SHARED_LIB) diff --git a/src/serious_python_bridge/windows/CMakeLists.txt b/src/serious_python_bridge/windows/CMakeLists.txt new file mode 100644 index 00000000..80697a9a --- /dev/null +++ b/src/serious_python_bridge/windows/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.15) + +set(PROJECT_NAME "serious_python_bridge") +project(${PROJECT_NAME} LANGUAGES C) + +cmake_policy(VERSION 3.15...3.25) + +add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# Flutter picks up bundled libraries via this variable and copies the file +# alongside the app binary; Dart resolves it via DynamicLibrary.open. +set(serious_python_bridge_bundled_libraries + $ + PARENT_SCOPE +) From 84f5a2c702de1a1bbfb0744dc7d0fcfb15f539df Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:45:40 -0700 Subject: [PATCH 005/114] Add darwin podspec + Swift plugin class registering dart_bridge inittab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unified Apple-platform path: both iOS and macOS desktop statically link dart_bridge.c into the app process and register PyInit_dart_bridge via serious_python_darwin's registerPythonExtension hook. This diverges from the original plan (which had macOS in the same "two artifacts via RTLD_GLOBAL" bucket as Linux/Windows/Android), and is cleaner: the macOS wheel matrix vanishes, Dart's view and Python's view of global_enqueue_handler_func are guaranteed to share storage, and the iOS and macOS code paths are now symmetrical. - darwin/serious_python_bridge.podspec: source_files pulls Classes/**/* + ../native/dart_bridge.c + the Dart SDK headers; OTHER_LDFLAGS includes -undefined dynamic_lookup so Py* references defer to the final app link against serious_python_darwin's vendored Python xcframework; depends on serious_python_darwin pod. - darwin/Classes/SeriousPythonBridgePlugin.h: forward-declares PyInit_dart_bridge for Swift module-map visibility. - darwin/Classes/SeriousPythonBridgePlugin.swift: imports Python + serious_python_darwin, calls registerPythonExtension at Flutter plugin init time on both iOS and macOS. - lib/serious_python_bridge.dart: _openNativeLibrary now uses DynamicLibrary.process() on macOS too (no separate dylib lookup). pod spec lint --quick produces the same 2 warnings as the sibling serious_python_darwin.podspec (license type + source primary key) — both publication-metadata, irrelevant for in-monorepo plugins. --- .../Classes/SeriousPythonBridgePlugin.h | 11 +++++ .../Classes/SeriousPythonBridgePlugin.swift | 26 ++++++++++ .../darwin/serious_python_bridge.podspec | 49 +++++++++++++++++++ .../lib/serious_python_bridge.dart | 8 +-- 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h create mode 100644 src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift create mode 100644 src/serious_python_bridge/darwin/serious_python_bridge.podspec diff --git a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h new file mode 100644 index 00000000..04ceab30 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h @@ -0,0 +1,11 @@ +#ifndef SeriousPythonBridgePlugin_h +#define SeriousPythonBridgePlugin_h + +#include + +// Defined in ../native/dart_bridge.c. Declared here so the Swift plugin code +// can pass it to SeriousPython.registerPythonExtension(name:initFn:) via the +// auto-generated Clang module map for this pod. +PyObject* PyInit_dart_bridge(void); + +#endif diff --git a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift new file mode 100644 index 00000000..b572537c --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift @@ -0,0 +1,26 @@ +#if os(iOS) +import Flutter +import UIKit +#elseif os(macOS) +import FlutterMacOS +#endif + +import Python +import serious_python_darwin + +public class SeriousPythonBridgePlugin: NSObject, FlutterPlugin { + + public static func register(with registrar: FlutterPluginRegistrar) { + // Register dart_bridge as a built-in CPython module so `import + // dart_bridge` resolves against the statically linked symbols in + // ../native/dart_bridge.c instead of looking for a filesystem .so. + // Required on iOS (no late-loaded dylibs allowed). Used on macOS too + // for symbol-visibility consistency: Dart's DynamicLibrary.process() + // and Python's `import dart_bridge` then share the same + // global_enqueue_handler_func state. + SeriousPythonPlugin.registerPythonExtension( + name: "dart_bridge", + initFn: PyInit_dart_bridge + ) + } +} diff --git a/src/serious_python_bridge/darwin/serious_python_bridge.podspec b/src/serious_python_bridge/darwin/serious_python_bridge.podspec new file mode 100644 index 00000000..b900ea43 --- /dev/null +++ b/src/serious_python_bridge/darwin/serious_python_bridge.podspec @@ -0,0 +1,49 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint serious_python_bridge.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'serious_python_bridge' + s.version = '2.0.0' + s.summary = 'Generic in-process Dart ↔ Python byte transport for serious_python.' + s.description = <<-DESC + Pure-FFI Flutter plugin that exposes the dart_bridge C primitives + (DartBridge_InitDartApiDL, DartBridge_EnqueueMessage) and the matching + Python module (send_bytes, set_enqueue_handler_func). On Apple platforms + the bridge is statically linked into the app process and registered with + CPython via serious_python_darwin's registerPythonExtension hook. + DESC + s.homepage = 'https://flet.dev' + s.license = { :file => '../LICENSE' } + s.author = { 'Appveyor Systems Inc.' => 'hello@flet.dev' } + s.source = { :path => '.' } + + # Swift plugin class + C sources from ../native. + s.source_files = [ + 'Classes/**/*.{h,m,swift}', + '../native/dart_bridge.c', + '../native/dart_api/dart_api_dl.c', + '../native/dart_api/*.h', + '../native/dart_api/internal/*.h', + ] + s.public_header_files = 'Classes/**/*.h' + s.preserve_paths = '../native/dart_api/**/*.h' + + s.ios.dependency 'Flutter' + s.osx.dependency 'FlutterMacOS' + s.dependency 'serious_python_darwin' + + s.ios.deployment_target = '13.0' + s.osx.deployment_target = '10.15' + + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + # dart_bridge.c does `#include "dart_api/dart_api_dl.h"`; surface the + # vendored Dart SDK headers. + 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}/../native"', + # Py* symbols are resolved at the final app link against the Python + # framework provided by serious_python_darwin's vendored xcframework. + 'OTHER_LDFLAGS' => '$(inherited) -undefined dynamic_lookup', + } + s.swift_version = '5.0' +end diff --git a/src/serious_python_bridge/lib/serious_python_bridge.dart b/src/serious_python_bridge/lib/serious_python_bridge.dart index 99908214..06ca98b8 100644 --- a/src/serious_python_bridge/lib/serious_python_bridge.dart +++ b/src/serious_python_bridge/lib/serious_python_bridge.dart @@ -83,9 +83,11 @@ class PythonBridge { } static DynamicLibrary _openNativeLibrary() { - // iOS: the bridge is statically linked into the serious_python framework. - if (Platform.isIOS) return DynamicLibrary.process(); - if (Platform.isMacOS) return DynamicLibrary.open('libflet_bridge.dylib'); + // Apple platforms (iOS + macOS desktop): the bridge is linked into the + // app process by the serious_python_bridge pod and registered with CPython + // via inittab. DynamicLibrary.process() resolves DartBridge_* via dlsym + // on the host process; no separate dylib open is needed. + if (Platform.isIOS || Platform.isMacOS) return DynamicLibrary.process(); if (Platform.isWindows) return DynamicLibrary.open('flet_bridge.dll'); if (Platform.isLinux || Platform.isAndroid) { return DynamicLibrary.open('libflet_bridge.so'); From 6bdb5070f4874fc3ad38e724274e3b50ea67cfa0 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:51:14 -0700 Subject: [PATCH 006/114] Add Android NDK build for libflet_bridge Bridge plugin's Android gradle downloads the same python-android-dart tarball serious_python_android uses, but extracts only include/ + lib/libpython*.so into a build-time scratch dir (build/python-dist//). libflet_bridge.so links against libpython3.so at build time so Android's strict dynamic linker accepts the .so on load; at runtime libpython is resolved against the copy serious_python_android ships in the same jniLibs// directory of the APK. We do NOT ship libpython from this plugin. - android/build.gradle: AGP 7.3.0 + de.undercouch.download (matching the sibling), per-ABI downloadPythonDist_ + extractPythonDist_ tasks wired into preBuild. ABI matrix matches the sibling's PEP-738 logic (32-bit only on 3.12). Caches under the shared FLET_CACHE_DIR. - android/CMakeLists.txt: sets FLET_BRIDGE_PYTHON_INCLUDE_DIRS and FLET_BRIDGE_PYTHON_LIBRARIES to point at the staged dir, then includes ../native via add_subdirectory. Adds the Android 15 16KB-page-size link flag matching the sibling. - android/src/main/AndroidManifest.xml: minimal, matches the sibling. - native/CMakeLists.txt: refactored to accept FLET_BRIDGE_PYTHON_* from a parent scope (Android uses this) and fall back to find_package(Python3 ... Development.Module) + Python3::Module on desktop platforms. Backward-compatible: macOS host configure+build still produces libflet_bridge.dylib with the same exports + unresolved Py* references. --- .../android/CMakeLists.txt | 26 +++++ .../android/build.gradle | 108 ++++++++++++++++++ .../android/src/main/AndroidManifest.xml | 3 + .../native/CMakeLists.txt | 28 +++-- 4 files changed, 154 insertions(+), 11 deletions(-) create mode 100644 src/serious_python_bridge/android/CMakeLists.txt create mode 100644 src/serious_python_bridge/android/build.gradle create mode 100644 src/serious_python_bridge/android/src/main/AndroidManifest.xml diff --git a/src/serious_python_bridge/android/CMakeLists.txt b/src/serious_python_bridge/android/CMakeLists.txt new file mode 100644 index 00000000..11991281 --- /dev/null +++ b/src/serious_python_bridge/android/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.10) + +set(PROJECT_NAME "serious_python_bridge") +project(${PROJECT_NAME} LANGUAGES C) + +# Python headers + libpython3.so come from the python-android-dart tarball +# that build.gradle's preparePythonDist task extracted into +# build/python-dist/${ANDROID_ABI}/. We link against libpython at build time +# so Android's strict dynamic linker accepts the .so on load; at runtime the +# linker resolves libpython3.so against the copy serious_python_android +# already shipped in the same jniLibs/${ANDROID_ABI}/ directory. +set(PYTHON_DIST_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build/python-dist/${ANDROID_ABI}") +set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS "${PYTHON_DIST_DIR}/include/python${PYTHON_VERSION}") +set(FLET_BRIDGE_PYTHON_LIBRARIES "${PYTHON_DIST_DIR}/lib/libpython3.so") + +add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# Android 15: 16 KB page size support. +set_target_properties(flet_bridge PROPERTIES + LINK_FLAGS "-Wl,-z,max-page-size=16384" +) + +set(serious_python_bridge_bundled_libraries + $ + PARENT_SCOPE +) diff --git a/src/serious_python_bridge/android/build.gradle b/src/serious_python_bridge/android/build.gradle new file mode 100644 index 00000000..55d2f356 --- /dev/null +++ b/src/serious_python_bridge/android/build.gradle @@ -0,0 +1,108 @@ +group 'com.flet.serious_python_bridge' +version '2.0.0' + +def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: '3.14' + +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'de.undercouch:gradle-download-task:4.1.2' + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'de.undercouch.download' + +android { + namespace "com.flet.serious_python_bridge" + + compileSdkVersion 31 + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + // CMake 3.10.2 is the AGP default; do not raise (Flutter docs). + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 21 + + ndk { + // Match the ABI set serious_python_android supports for the same + // python_version (32-bit dropped for 3.13+ per PEP 738). + if (python_version == '3.12') { + abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64' + } else { + abiFilters 'arm64-v8a', 'x86_64' + } + } + + externalNativeBuild { + cmake { + arguments "-DPYTHON_VERSION=${python_version}" + } + } + } +} + +import de.undercouch.gradle.tasks.download.Download + +def fletCacheRoot = System.getenv('FLET_CACHE_DIR') +def pythonCacheDir = new File( + fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), + "python-build/v${python_version}" +) + +// Headers and libpython3.so are extracted from the same python-android-dart +// tarball that serious_python_android uses. We extract into a build-time +// scratch dir (not jniLibs/) because we do NOT want to ship libpython +// ourselves — serious_python_android ships it; we just link against it at +// build time. +def pythonStagingRoot = new File(buildDir, 'python-dist') + +def prepareTasks = [] +android.defaultConfig.ndk.abiFilters.each { abi -> + def archiveName = "python-android-dart-${python_version}-${abi}.tar.gz" + def stagingDir = new File(pythonStagingRoot, abi) + + tasks.register("downloadPythonDist_${abi}", Download) { + src "https://github.com/flet-dev/python-build/releases/download/v${python_version}/${archiveName}" + dest new File(pythonCacheDir, archiveName) + onlyIfModified true + useETag "all" + tempAndMove true + doFirst { dest.parentFile.mkdirs() } + } + + tasks.register("extractPythonDist_${abi}", Copy) { + dependsOn "downloadPythonDist_${abi}" + from tarTree(tasks.named("downloadPythonDist_${abi}").get().dest) + into stagingDir + // Headers + libpython only; everything else is dead weight for our + // build-time link (serious_python_android ships the runtime copy). + include "include/**", "lib/libpython*.so" + } + + prepareTasks.add("extractPythonDist_${abi}") +} + +task preparePythonDist { dependsOn prepareTasks } +preBuild.dependsOn preparePythonDist diff --git a/src/serious_python_bridge/android/src/main/AndroidManifest.xml b/src/serious_python_bridge/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..080338e5 --- /dev/null +++ b/src/serious_python_bridge/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/src/serious_python_bridge/native/CMakeLists.txt b/src/serious_python_bridge/native/CMakeLists.txt index 80966c4e..7d13225d 100644 --- a/src/serious_python_bridge/native/CMakeLists.txt +++ b/src/serious_python_bridge/native/CMakeLists.txt @@ -1,20 +1,25 @@ # Cross-platform CMake target for libflet_bridge. # -# Built from the same dart_bridge.c source used by the Python shim (which CI -# builds via cibuildwheel). Per-platform wrappers under linux/, windows/, etc. -# include this file via add_subdirectory. +# Built from the same dart_bridge.c source used by the Python shim. Per-platform +# wrappers under linux/, windows/, android/ include this file via add_subdirectory. +# +# Python integration: +# - If FLET_BRIDGE_PYTHON_INCLUDE_DIRS + FLET_BRIDGE_PYTHON_LIBRARIES are set +# before add_subdirectory, those are used (Android uses this path to point +# at the python-android-dart tarball it downloads). +# - Otherwise we use find_package(Python3 ... Development.Module) + the +# Python3::Module imported target, which handles Linux/macOS/Windows link +# conventions automatically. cmake_minimum_required(VERSION 3.15) project(flet_bridge VERSION 0.0.1 LANGUAGES C) -# Python3::Module brings in headers + the platform-correct link behavior: -# - Windows: links pythonXY.lib (import library) -# - macOS: adds -undefined dynamic_lookup -# - Linux: nothing (default dynamic resolution) -# Py* symbols are resolved at runtime against the libpython that serious_python -# has already loaded into the process. -find_package(Python3 REQUIRED COMPONENTS Development.Module) +if(NOT DEFINED FLET_BRIDGE_PYTHON_INCLUDE_DIRS) + find_package(Python3 REQUIRED COMPONENTS Development.Module) + set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS ${Python3_INCLUDE_DIRS}) + set(FLET_BRIDGE_PYTHON_LIBRARIES Python3::Module) +endif() add_library(flet_bridge SHARED "dart_bridge.c" @@ -23,9 +28,10 @@ add_library(flet_bridge SHARED target_include_directories(flet_bridge PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" + ${FLET_BRIDGE_PYTHON_INCLUDE_DIRS} ) -target_link_libraries(flet_bridge PRIVATE Python3::Module) +target_link_libraries(flet_bridge PRIVATE ${FLET_BRIDGE_PYTHON_LIBRARIES}) set_target_properties(flet_bridge PROPERTIES C_VISIBILITY_PRESET hidden From 77c80109553820932496fce14a1c7b46c7cbb688 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 11:59:55 -0700 Subject: [PATCH 007/114] Add bridge example app (Flutter UI + Python echo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minimal Flutter app exercising serious_python_bridge end-to-end without Flet. Sends bytes from Dart via PythonBridge.send(), Python echoes them back via dart_bridge.send_bytes(). Scaffolded with `flutter create --platforms=android,ios,linux,macos,windows --org=com.flet`; bulk of the 126 files is standard Flutter platform boilerplate. Hand-authored pieces: - lib/main.dart: PythonBridge.init() + ReceivePort listener, fire-and- forget SeriousPython.run("app/app.zip"), 8-byte little-endian handshake frame containing bridge.nativePort, button-driven `ping #N` sends. - app/src/main.py: dart_bridge echo loop; first frame interpreted as native_port, subsequent frames echoed back via dart_bridge.send_bytes() prefixed with b"echo: ". threading.Event().wait() keeps the interpreter alive indefinitely. - app/src/requirements.txt: empty (dart_bridge is static-linked on iOS+ macOS via inittab, downloaded via --bridge on Linux/Windows/Android). - pubspec.yaml: slimmed from default scaffold; deps are just serious_python (path) + serious_python_bridge (path) + integration_test dev dep. Aligned SDK constraint to monorepo standard. - integration_test/.gitkeep: placeholder; step 5 of the plan populates this with the round-trip echo test. - README.md: build + run instructions. - .gitignore: appended /app/app.zip and /app/app.zip.hash (build artifacts from `dart run serious_python:main package`). - Removed auto-generated test/widget_test.dart (referenced default scaffold class names). flutter analyze: 1 warning (asset_does_not_exist for app/app.zip — the build artifact built by package_command at integration test time); zero errors. --- src/serious_python_bridge/example/.gitignore | 49 ++ src/serious_python_bridge/example/.metadata | 42 ++ src/serious_python_bridge/example/README.md | 35 + .../example/analysis_options.yaml | 28 + .../example/android/.gitignore | 14 + .../example/android/app/build.gradle.kts | 44 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 45 ++ .../MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + .../example/android/build.gradle.kts | 24 + .../example/android/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../example/android/settings.gradle.kts | 26 + .../example/app/src/main.py | 51 ++ .../example/app/src/requirements.txt | 4 + .../example/integration_test/.gitkeep | 3 + .../example/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 24 + .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + src/serious_python_bridge/example/ios/Podfile | 43 ++ .../ios/Runner.xcodeproj/project.pbxproj | 620 +++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 101 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 16 + .../AppIcon.appiconset/Contents.json | 122 +++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../example/ios/Runner/Info.plist | 70 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/ios/Runner/SceneDelegate.swift | 6 + .../example/ios/RunnerTests/RunnerTests.swift | 12 + .../example/lib/main.dart | 110 +++ .../example/linux/.gitignore | 1 + .../example/linux/CMakeLists.txt | 128 ++++ .../example/linux/flutter/CMakeLists.txt | 88 +++ .../flutter/generated_plugin_registrant.cc | 15 + .../flutter/generated_plugin_registrant.h | 15 + .../linux/flutter/generated_plugins.cmake | 26 + .../example/linux/runner/CMakeLists.txt | 26 + .../example/linux/runner/main.cc | 6 + .../example/linux/runner/my_application.cc | 148 ++++ .../example/linux/runner/my_application.h | 21 + .../example/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 2 + .../macos/Flutter/Flutter-Release.xcconfig | 2 + .../Flutter/GeneratedPluginRegistrant.swift | 14 + .../example/macos/Podfile | 42 ++ .../macos/Runner.xcodeproj/project.pbxproj | 705 ++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 99 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../example/macos/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 68 ++ .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 +++++++++ .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 12 + .../example/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + .../example/macos/Runner/Release.entitlements | 8 + .../macos/RunnerTests/RunnerTests.swift | 12 + .../example/pubspec.yaml | 33 + .../example/windows/.gitignore | 17 + .../example/windows/CMakeLists.txt | 108 +++ .../example/windows/flutter/CMakeLists.txt | 109 +++ .../flutter/generated_plugin_registrant.cc | 14 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 26 + .../example/windows/runner/CMakeLists.txt | 40 + .../example/windows/runner/Runner.rc | 121 +++ .../example/windows/runner/flutter_window.cpp | 71 ++ .../example/windows/runner/flutter_window.h | 33 + .../example/windows/runner/main.cpp | 43 ++ .../example/windows/runner/resource.h | 16 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes .../windows/runner/runner.exe.manifest | 14 + .../example/windows/runner/utils.cpp | 65 ++ .../example/windows/runner/utils.h | 19 + .../example/windows/runner/win32_window.cpp | 288 +++++++ .../example/windows/runner/win32_window.h | 102 +++ 126 files changed, 4787 insertions(+) create mode 100644 src/serious_python_bridge/example/.gitignore create mode 100644 src/serious_python_bridge/example/.metadata create mode 100644 src/serious_python_bridge/example/README.md create mode 100644 src/serious_python_bridge/example/analysis_options.yaml create mode 100644 src/serious_python_bridge/example/android/.gitignore create mode 100644 src/serious_python_bridge/example/android/app/build.gradle.kts create mode 100644 src/serious_python_bridge/example/android/app/src/debug/AndroidManifest.xml create mode 100644 src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml create mode 100644 src/serious_python_bridge/example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/values-night/styles.xml create mode 100644 src/serious_python_bridge/example/android/app/src/main/res/values/styles.xml create mode 100644 src/serious_python_bridge/example/android/app/src/profile/AndroidManifest.xml create mode 100644 src/serious_python_bridge/example/android/build.gradle.kts create mode 100644 src/serious_python_bridge/example/android/gradle.properties create mode 100644 src/serious_python_bridge/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 src/serious_python_bridge/example/android/settings.gradle.kts create mode 100644 src/serious_python_bridge/example/app/src/main.py create mode 100644 src/serious_python_bridge/example/app/src/requirements.txt create mode 100644 src/serious_python_bridge/example/integration_test/.gitkeep create mode 100644 src/serious_python_bridge/example/ios/.gitignore create mode 100644 src/serious_python_bridge/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 src/serious_python_bridge/example/ios/Flutter/Debug.xcconfig create mode 100644 src/serious_python_bridge/example/ios/Flutter/Release.xcconfig create mode 100644 src/serious_python_bridge/example/ios/Podfile create mode 100644 src/serious_python_bridge/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 src/serious_python_bridge/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 src/serious_python_bridge/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 src/serious_python_bridge/example/ios/Runner/AppDelegate.swift create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 src/serious_python_bridge/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 src/serious_python_bridge/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 src/serious_python_bridge/example/ios/Runner/Info.plist create mode 100644 src/serious_python_bridge/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 src/serious_python_bridge/example/ios/Runner/SceneDelegate.swift create mode 100644 src/serious_python_bridge/example/ios/RunnerTests/RunnerTests.swift create mode 100644 src/serious_python_bridge/example/lib/main.dart create mode 100644 src/serious_python_bridge/example/linux/.gitignore create mode 100644 src/serious_python_bridge/example/linux/CMakeLists.txt create mode 100644 src/serious_python_bridge/example/linux/flutter/CMakeLists.txt create mode 100644 src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.cc create mode 100644 src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.h create mode 100644 src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake create mode 100644 src/serious_python_bridge/example/linux/runner/CMakeLists.txt create mode 100644 src/serious_python_bridge/example/linux/runner/main.cc create mode 100644 src/serious_python_bridge/example/linux/runner/my_application.cc create mode 100644 src/serious_python_bridge/example/linux/runner/my_application.h create mode 100644 src/serious_python_bridge/example/macos/.gitignore create mode 100644 src/serious_python_bridge/example/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 src/serious_python_bridge/example/macos/Flutter/Flutter-Release.xcconfig create mode 100644 src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 src/serious_python_bridge/example/macos/Podfile create mode 100644 src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj create mode 100644 src/serious_python_bridge/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python_bridge/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 src/serious_python_bridge/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python_bridge/example/macos/Runner/AppDelegate.swift create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 src/serious_python_bridge/example/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 src/serious_python_bridge/example/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 src/serious_python_bridge/example/macos/Runner/Configs/Debug.xcconfig create mode 100644 src/serious_python_bridge/example/macos/Runner/Configs/Release.xcconfig create mode 100644 src/serious_python_bridge/example/macos/Runner/Configs/Warnings.xcconfig create mode 100644 src/serious_python_bridge/example/macos/Runner/DebugProfile.entitlements create mode 100644 src/serious_python_bridge/example/macos/Runner/Info.plist create mode 100644 src/serious_python_bridge/example/macos/Runner/MainFlutterWindow.swift create mode 100644 src/serious_python_bridge/example/macos/Runner/Release.entitlements create mode 100644 src/serious_python_bridge/example/macos/RunnerTests/RunnerTests.swift create mode 100644 src/serious_python_bridge/example/pubspec.yaml create mode 100644 src/serious_python_bridge/example/windows/.gitignore create mode 100644 src/serious_python_bridge/example/windows/CMakeLists.txt create mode 100644 src/serious_python_bridge/example/windows/flutter/CMakeLists.txt create mode 100644 src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.cc create mode 100644 src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.h create mode 100644 src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake create mode 100644 src/serious_python_bridge/example/windows/runner/CMakeLists.txt create mode 100644 src/serious_python_bridge/example/windows/runner/Runner.rc create mode 100644 src/serious_python_bridge/example/windows/runner/flutter_window.cpp create mode 100644 src/serious_python_bridge/example/windows/runner/flutter_window.h create mode 100644 src/serious_python_bridge/example/windows/runner/main.cpp create mode 100644 src/serious_python_bridge/example/windows/runner/resource.h create mode 100644 src/serious_python_bridge/example/windows/runner/resources/app_icon.ico create mode 100644 src/serious_python_bridge/example/windows/runner/runner.exe.manifest create mode 100644 src/serious_python_bridge/example/windows/runner/utils.cpp create mode 100644 src/serious_python_bridge/example/windows/runner/utils.h create mode 100644 src/serious_python_bridge/example/windows/runner/win32_window.cpp create mode 100644 src/serious_python_bridge/example/windows/runner/win32_window.h diff --git a/src/serious_python_bridge/example/.gitignore b/src/serious_python_bridge/example/.gitignore new file mode 100644 index 00000000..32f8d81d --- /dev/null +++ b/src/serious_python_bridge/example/.gitignore @@ -0,0 +1,49 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +# serious_python packaging artifacts (built by `dart run serious_python:main package`) +/app/app.zip +/app/app.zip.hash diff --git a/src/serious_python_bridge/example/.metadata b/src/serious_python_bridge/example/.metadata new file mode 100644 index 00000000..814a9dca --- /dev/null +++ b/src/serious_python_bridge/example/.metadata @@ -0,0 +1,42 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "cc0734ac716fbb8b90f3f9db8020958b1553afa7" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + - platform: android + create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + - platform: ios + create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + - platform: linux + create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + - platform: macos + create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + - platform: windows + create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/src/serious_python_bridge/example/README.md b/src/serious_python_bridge/example/README.md new file mode 100644 index 00000000..8e4705ff --- /dev/null +++ b/src/serious_python_bridge/example/README.md @@ -0,0 +1,35 @@ +# serious_python_bridge_example + +Minimal Flutter app exercising [`serious_python_bridge`](../). Sends bytes +from Dart to Python via `PythonBridge.send()`, and Python echoes them back +through `dart_bridge.send_bytes()`. No Flet, no msgpack, no protocol layer — +the smallest possible end-to-end demonstration of the byte transport. + +## Build the Python app bundle + +Before running, package the Python source into `app/app.zip`: + +```sh +# From this directory: +dart run serious_python:main package app/src --platform Darwin \ + --python-version 3.14 +``` + +Substitute `Darwin` with `Linux`, `Windows`, or `Android` for those targets. +On Linux/Windows/Android also pass `--bridge` so the prebuilt `dart_bridge` +Python shim is downloaded from the `serious-python` GitHub Release and +dropped into the bundled site-packages. (Not required on macOS/iOS — the +shim is statically linked into the app process and registered with CPython +via `serious_python_darwin`'s `registerPythonExtension` hook.) + +## Run + +```sh +flutter run -d macos # or -d linux / windows / +``` + +The app starts the embedded Python interpreter (which runs `app/src/main.py` +in a background thread), sends an 8-byte handshake frame containing the Dart +`ReceivePort` native port id, and then sends `ping #N` payloads when the +button is pressed. Python echoes them back; received messages appear in the +list view. diff --git a/src/serious_python_bridge/example/analysis_options.yaml b/src/serious_python_bridge/example/analysis_options.yaml new file mode 100644 index 00000000..0d290213 --- /dev/null +++ b/src/serious_python_bridge/example/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/src/serious_python_bridge/example/android/.gitignore b/src/serious_python_bridge/example/android/.gitignore new file mode 100644 index 00000000..be3943c9 --- /dev/null +++ b/src/serious_python_bridge/example/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/src/serious_python_bridge/example/android/app/build.gradle.kts b/src/serious_python_bridge/example/android/app/build.gradle.kts new file mode 100644 index 00000000..509ae797 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.flet.serious_python_bridge_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.flet.serious_python_bridge_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/src/serious_python_bridge/example/android/app/src/debug/AndroidManifest.xml b/src/serious_python_bridge/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml b/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..59c44ce5 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python_bridge/example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt b/src/serious_python_bridge/example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt new file mode 100644 index 00000000..19d8bb67 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.flet.serious_python_bridge_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/src/serious_python_bridge/example/android/app/src/main/res/drawable-v21/launch_background.xml b/src/serious_python_bridge/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/src/serious_python_bridge/example/android/app/src/main/res/drawable/launch_background.xml b/src/serious_python_bridge/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/serious_python_bridge/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/serious_python_bridge/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/android/app/src/main/res/values-night/styles.xml b/src/serious_python_bridge/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/serious_python_bridge/example/android/app/src/main/res/values/styles.xml b/src/serious_python_bridge/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/serious_python_bridge/example/android/app/src/profile/AndroidManifest.xml b/src/serious_python_bridge/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/src/serious_python_bridge/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/src/serious_python_bridge/example/android/build.gradle.kts b/src/serious_python_bridge/example/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/src/serious_python_bridge/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/src/serious_python_bridge/example/android/gradle.properties b/src/serious_python_bridge/example/android/gradle.properties new file mode 100644 index 00000000..fbee1d8c --- /dev/null +++ b/src/serious_python_bridge/example/android/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true diff --git a/src/serious_python_bridge/example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python_bridge/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..e4ef43fb --- /dev/null +++ b/src/serious_python_bridge/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/src/serious_python_bridge/example/android/settings.gradle.kts b/src/serious_python_bridge/example/android/settings.gradle.kts new file mode 100644 index 00000000..ca7fe065 --- /dev/null +++ b/src/serious_python_bridge/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/src/serious_python_bridge/example/app/src/main.py b/src/serious_python_bridge/example/app/src/main.py new file mode 100644 index 00000000..b1923844 --- /dev/null +++ b/src/serious_python_bridge/example/app/src/main.py @@ -0,0 +1,51 @@ +"""Echo loop exercising serious_python_bridge. + +Protocol used by this example (NOT the Flet protocol — this is just the +simplest possible thing that proves the byte transport works): + +* First frame from Dart: 8-byte little-endian int64 = the Dart native port id + that Python should reply to. Captured into ``native_port`` and not echoed. +* Subsequent frames: arbitrary bytes; echoed back unchanged, prefixed with + ``b"echo: "``. + +Python keeps the interpreter alive indefinitely so messages can keep arriving; +Dart drives the lifetime (when the app exits, the embedded Python is torn down). +""" + +from __future__ import annotations + +import struct +import sys +import threading + +import dart_bridge + +native_port: int | None = None +_ready = threading.Event() + + +def on_dart_message(data: bytes) -> None: + global native_port + + if native_port is None: + if len(data) != 8: + print( + f"[bridge_example] expected 8-byte handshake, got {len(data)} bytes", + file=sys.stderr, + flush=True, + ) + return + native_port = struct.unpack(" + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/src/serious_python_bridge/example/ios/Flutter/Debug.xcconfig b/src/serious_python_bridge/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/src/serious_python_bridge/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/src/serious_python_bridge/example/ios/Flutter/Release.xcconfig b/src/serious_python_bridge/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/src/serious_python_bridge/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/src/serious_python_bridge/example/ios/Podfile b/src/serious_python_bridge/example/ios/Podfile new file mode 100644 index 00000000..620e46eb --- /dev/null +++ b/src/serious_python_bridge/example/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..13de7c7d --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,620 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python_bridge/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..e3773d42 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python_bridge/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python_bridge/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/src/serious_python_bridge/example/ios/Runner/AppDelegate.swift b/src/serious_python_bridge/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..c30b367e --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,16 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } +} diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/src/serious_python_bridge/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/src/serious_python_bridge/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python_bridge/example/ios/Runner/Base.lproj/Main.storyboard b/src/serious_python_bridge/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python_bridge/example/ios/Runner/Info.plist b/src/serious_python_bridge/example/ios/Runner/Info.plist new file mode 100644 index 00000000..532e679b --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Info.plist @@ -0,0 +1,70 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Serious Python Bridge Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + serious_python_bridge_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/src/serious_python_bridge/example/ios/Runner/Runner-Bridging-Header.h b/src/serious_python_bridge/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/src/serious_python_bridge/example/ios/Runner/SceneDelegate.swift b/src/serious_python_bridge/example/ios/Runner/SceneDelegate.swift new file mode 100644 index 00000000..b9ce8ea2 --- /dev/null +++ b/src/serious_python_bridge/example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/src/serious_python_bridge/example/ios/RunnerTests/RunnerTests.swift b/src/serious_python_bridge/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/src/serious_python_bridge/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/src/serious_python_bridge/example/lib/main.dart b/src/serious_python_bridge/example/lib/main.dart new file mode 100644 index 00000000..88803714 --- /dev/null +++ b/src/serious_python_bridge/example/lib/main.dart @@ -0,0 +1,110 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:serious_python/serious_python.dart'; +import 'package:serious_python_bridge/serious_python_bridge.dart'; + +void main() { + runApp(const BridgeExampleApp()); +} + +class BridgeExampleApp extends StatefulWidget { + const BridgeExampleApp({super.key}); + + @override + State createState() => _BridgeExampleAppState(); +} + +class _BridgeExampleAppState extends State { + PythonBridge? _bridge; + StreamSubscription? _subscription; + final List _log = []; + int _sendCounter = 0; + + @override + void initState() { + super.initState(); + _start(); + } + + Future _start() async { + final bridge = PythonBridge.init(); + _subscription = bridge.messages.listen((bytes) { + setState(() { + _log.add('Python -> Dart: ${utf8.decode(bytes, allowMalformed: true)}'); + }); + }); + + // Fire-and-forget; Python runs on a background thread and never returns + // (its main.py blocks waiting for messages). + unawaited(SeriousPython.run("app/app.zip")); + + // Crude: wait for Python to register its receive handler. A production + // protocol would have Python send a "ready" sentinel and Dart wait for + // that on bridge.messages before sending the handshake. + await Future.delayed(const Duration(seconds: 2)); + + // Handshake: send the Dart ReceivePort native port id as the first frame. + final portBytes = Uint8List(8); + portBytes.buffer.asByteData().setInt64(0, bridge.nativePort, Endian.little); + bridge.send(portBytes); + + setState(() { + _bridge = bridge; + _log.add('handshake sent (native_port=${bridge.nativePort})'); + }); + } + + void _sendTestMessage() { + final bridge = _bridge; + if (bridge == null) return; + _sendCounter++; + final payload = utf8.encode('ping #$_sendCounter'); + bridge.send(Uint8List.fromList(payload)); + setState(() => _log.add('Dart -> Python: ping #$_sendCounter')); + } + + @override + void dispose() { + _subscription?.cancel(); + _bridge?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'serious_python_bridge example', + home: Scaffold( + appBar: AppBar(title: const Text('serious_python_bridge example')), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16), + child: ElevatedButton( + key: const Key('send'), + onPressed: _bridge != null ? _sendTestMessage : null, + child: const Text('Send ping to Python'), + ), + ), + const Divider(), + Expanded( + child: ListView.builder( + itemCount: _log.length, + itemBuilder: (context, index) => ListTile( + dense: true, + title: Text( + _log[index], + style: const TextStyle(fontSize: 12), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/src/serious_python_bridge/example/linux/.gitignore b/src/serious_python_bridge/example/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/src/serious_python_bridge/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/src/serious_python_bridge/example/linux/CMakeLists.txt b/src/serious_python_bridge/example/linux/CMakeLists.txt new file mode 100644 index 00000000..6e2c3aa1 --- /dev/null +++ b/src/serious_python_bridge/example/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "serious_python_bridge_example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.flet.serious_python_bridge_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/src/serious_python_bridge/example/linux/flutter/CMakeLists.txt b/src/serious_python_bridge/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/src/serious_python_bridge/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.cc b/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..4dbcd894 --- /dev/null +++ b/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) serious_python_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "SeriousPythonLinuxPlugin"); + serious_python_linux_plugin_register_with_registrar(serious_python_linux_registrar); +} diff --git a/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.h b/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake b/src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..a130b7aa --- /dev/null +++ b/src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + serious_python_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni + serious_python_bridge +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/src/serious_python_bridge/example/linux/runner/CMakeLists.txt b/src/serious_python_bridge/example/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/src/serious_python_bridge/example/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/src/serious_python_bridge/example/linux/runner/main.cc b/src/serious_python_bridge/example/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/src/serious_python_bridge/example/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/src/serious_python_bridge/example/linux/runner/my_application.cc b/src/serious_python_bridge/example/linux/runner/my_application.cc new file mode 100644 index 00000000..11eb205b --- /dev/null +++ b/src/serious_python_bridge/example/linux/runner/my_application.cc @@ -0,0 +1,148 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView* view) { + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "serious_python_bridge_example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "serious_python_bridge_example"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 + // for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), + self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); +} diff --git a/src/serious_python_bridge/example/linux/runner/my_application.h b/src/serious_python_bridge/example/linux/runner/my_application.h new file mode 100644 index 00000000..db16367a --- /dev/null +++ b/src/serious_python_bridge/example/linux/runner/my_application.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, + my_application, + MY, + APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/src/serious_python_bridge/example/macos/.gitignore b/src/serious_python_bridge/example/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/src/serious_python_bridge/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/src/serious_python_bridge/example/macos/Flutter/Flutter-Debug.xcconfig b/src/serious_python_bridge/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/src/serious_python_bridge/example/macos/Flutter/Flutter-Release.xcconfig b/src/serious_python_bridge/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..9f3d8753 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import serious_python_bridge +import serious_python_darwin + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + SeriousPythonBridgePlugin.register(with: registry.registrar(forPlugin: "SeriousPythonBridgePlugin")) + SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) +} diff --git a/src/serious_python_bridge/example/macos/Podfile b/src/serious_python_bridge/example/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/src/serious_python_bridge/example/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..6a7d27cf --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* serious_python_bridge_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "serious_python_bridge_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* serious_python_bridge_example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* serious_python_bridge_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/serious_python_bridge_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/serious_python_bridge_example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/serious_python_bridge_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/serious_python_bridge_example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/serious_python_bridge_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/serious_python_bridge_example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python_bridge/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..1fb7fdd6 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/serious_python_bridge/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python_bridge/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python_bridge/example/macos/Runner/AppDelegate.swift b/src/serious_python_bridge/example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 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 literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python_bridge/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..6558c5b4 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = serious_python_bridge_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.flet.seriousPythonBridgeExample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2026 com.flet. All rights reserved. diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/Debug.xcconfig b/src/serious_python_bridge/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/Release.xcconfig b/src/serious_python_bridge/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/Warnings.xcconfig b/src/serious_python_bridge/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/src/serious_python_bridge/example/macos/Runner/DebugProfile.entitlements b/src/serious_python_bridge/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/src/serious_python_bridge/example/macos/Runner/Info.plist b/src/serious_python_bridge/example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/src/serious_python_bridge/example/macos/Runner/MainFlutterWindow.swift b/src/serious_python_bridge/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/src/serious_python_bridge/example/macos/Runner/Release.entitlements b/src/serious_python_bridge/example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/src/serious_python_bridge/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/src/serious_python_bridge/example/macos/RunnerTests/RunnerTests.swift b/src/serious_python_bridge/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/src/serious_python_bridge/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/src/serious_python_bridge/example/pubspec.yaml b/src/serious_python_bridge/example/pubspec.yaml new file mode 100644 index 00000000..f0600924 --- /dev/null +++ b/src/serious_python_bridge/example/pubspec.yaml @@ -0,0 +1,33 @@ +name: serious_python_bridge_example +description: "Minimal Flutter app exercising the serious_python_bridge byte transport." +publish_to: 'none' + +version: 1.0.0+1 + +environment: + sdk: ">=3.0.0 <4.0.0" + flutter: ">=3.7.0" + +dependencies: + flutter: + sdk: flutter + + serious_python: + path: ../../serious_python + serious_python_bridge: + path: ../ + + cupertino_icons: ^1.0.8 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + flutter_lints: ^2.0.0 + +flutter: + uses-material-design: true + + assets: + - app/app.zip diff --git a/src/serious_python_bridge/example/windows/.gitignore b/src/serious_python_bridge/example/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/src/serious_python_bridge/example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/src/serious_python_bridge/example/windows/CMakeLists.txt b/src/serious_python_bridge/example/windows/CMakeLists.txt new file mode 100644 index 00000000..1d3f761b --- /dev/null +++ b/src/serious_python_bridge/example/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(serious_python_bridge_example LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "serious_python_bridge_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/src/serious_python_bridge/example/windows/flutter/CMakeLists.txt b/src/serious_python_bridge/example/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/src/serious_python_bridge/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.cc b/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e985e51a --- /dev/null +++ b/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + SeriousPythonWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SeriousPythonWindowsPluginCApi")); +} diff --git a/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.h b/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake b/src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..af6720d3 --- /dev/null +++ b/src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + serious_python_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni + serious_python_bridge +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/src/serious_python_bridge/example/windows/runner/CMakeLists.txt b/src/serious_python_bridge/example/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/src/serious_python_bridge/example/windows/runner/Runner.rc b/src/serious_python_bridge/example/windows/runner/Runner.rc new file mode 100644 index 00000000..330bcad5 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.flet" "\0" + VALUE "FileDescription", "serious_python_bridge_example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "serious_python_bridge_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2026 com.flet. All rights reserved." "\0" + VALUE "OriginalFilename", "serious_python_bridge_example.exe" "\0" + VALUE "ProductName", "serious_python_bridge_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/serious_python_bridge/example/windows/runner/flutter_window.cpp b/src/serious_python_bridge/example/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/src/serious_python_bridge/example/windows/runner/flutter_window.h b/src/serious_python_bridge/example/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/src/serious_python_bridge/example/windows/runner/main.cpp b/src/serious_python_bridge/example/windows/runner/main.cpp new file mode 100644 index 00000000..d6f35140 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"serious_python_bridge_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/src/serious_python_bridge/example/windows/runner/resource.h b/src/serious_python_bridge/example/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/serious_python_bridge/example/windows/runner/resources/app_icon.ico b/src/serious_python_bridge/example/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 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 literal 0 HcmV?d00001 diff --git a/src/serious_python_bridge/example/windows/runner/runner.exe.manifest b/src/serious_python_bridge/example/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/src/serious_python_bridge/example/windows/runner/utils.cpp b/src/serious_python_bridge/example/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/src/serious_python_bridge/example/windows/runner/utils.h b/src/serious_python_bridge/example/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/src/serious_python_bridge/example/windows/runner/win32_window.cpp b/src/serious_python_bridge/example/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/src/serious_python_bridge/example/windows/runner/win32_window.h b/src/serious_python_bridge/example/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/src/serious_python_bridge/example/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ From 473aa7c4b5c955cba3b221a854f1e5171203cdc3 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 12:11:13 -0700 Subject: [PATCH 008/114] Add release CI: cibuildwheel wheels + GitHub Release attachment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On tag pushes (refs/tags/v*) the workflow now: 1. release_build (matrix): cibuildwheel v2.21.3 against src/serious_python_bridge/python on ubuntu-24.04, ubuntu-24.04-arm, windows-latest, producing wheels for cp312/cp313/cp314. Wheels uploaded as bridge-wheels- artifacts. Apple platforms (iOS + macOS desktop) excluded — they use static-link + inittab via the bridge plugin's darwin podspec; no wheel needed. 2. collect_release: downloads all wheel artifacts, creates (or updates) the GitHub Release for the tag, attaches every .whl as a release asset via softprops/action-gh-release@v2. 3. publish: now gated on collect_release (binaries must be on the GitHub Release before pub.dev pushes are irreversible). Bridge package added to the patch_pubspec.py loop and to the dart pub publish sequence; published last (after a sleep 600) so its path-deps on serious_python + serious_python_darwin have time to propagate on pub.dev. Android wheels deferred — cibuildwheel's Android support is experimental and serious_python_android already downloads platform- specific tarballs via a custom NDK-aware gradle path. Will be added in a follow-up CI change. Pre-flight: python -m build --wheel against the package locally produced dart_bridge-0.0.0-cp312-cp312-macosx_14_0_arm64.whl containing just dart_bridge.cpython-312-darwin.so + metadata, confirming the ../native relative path in setup.py survives PEP 517. --- .github/workflows/ci.yml | 65 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1f7b112..436d9cb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,6 +236,57 @@ jobs: dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + release_build: + name: Build dart_bridge wheel (${{ matrix.os }}) + if: startsWith(github.ref, 'refs/tags/v') + strategy: + fail-fast: false + matrix: + # Apple platforms use static-link + inittab (see serious_python_bridge/ + # darwin/), so no macOS/iOS wheel. Android needs an NDK cross-build + # that's deferred to a follow-up CI change. + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.21.3 + with: + package-dir: src/serious_python_bridge/python + + - name: Upload wheel artifacts + uses: actions/upload-artifact@v4 + with: + name: bridge-wheels-${{ matrix.os }} + path: wheelhouse/*.whl + if-no-files-found: error + + collect_release: + name: Attach bridge wheels to GitHub Release + needs: release_build + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + permissions: + contents: write + steps: + - name: Download all wheel artifacts + uses: actions/download-artifact@v4 + with: + pattern: bridge-wheels-* + merge-multiple: true + path: wheels + + - name: List collected wheels + run: ls -la wheels/ + + - name: Create or update GitHub Release with wheel assets + uses: softprops/action-gh-release@v2 + with: + files: wheels/*.whl + fail_on_unmatched_files: true + publish: name: Publish to pub.dev needs: @@ -244,6 +295,7 @@ jobs: - android - windows - linux + - collect_release runs-on: ubuntu-22.04 if: startsWith(github.ref, 'refs/tags/v') steps: @@ -301,14 +353,15 @@ jobs: "serious_python_android" \ "serious_python_darwin" \ "serious_python_windows" \ - "serious_python_linux"; do - + "serious_python_linux" \ + "serious_python_bridge"; do + uv run "$SCRIPTS/patch_pubspec.py" "$pkg/pubspec.yaml" "$PKG_VER" done - name: Publish packages run: | - publish_pkg () { + publish_pkg () { pushd "$1" >/dev/null dart pub publish --force popd >/dev/null @@ -321,4 +374,8 @@ jobs: publish_pkg src/serious_python_windows publish_pkg src/serious_python_linux sleep 600 - publish_pkg src/serious_python \ No newline at end of file + publish_pkg src/serious_python + sleep 600 + # Bridge depends on serious_python + serious_python_darwin; publish + # last so all its path-deps already resolve on pub.dev. + publish_pkg src/serious_python_bridge \ No newline at end of file From e17bc8fda9025e4f324d5ba0aa9e16c383a08432 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 12:36:16 -0700 Subject: [PATCH 009/114] Switch dart_bridge to abi3 + add Android NDK cross-build matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit abi3 / Limited API ------------------ One binary per platform now serves all Python 3.12+ minor versions (forward-compatible with 3.15, 3.16, etc. with no rebuild). Every Py* symbol used in dart_bridge.c is in the Limited API since 3.2 (oldest: PyGILState_Ensure/Release in 3.4). - native/dart_bridge.c: #define Py_LIMITED_API 0x030c0000 before Python.h. Comment lists symbol provenance. - python/setup.py: Extension(..., py_limited_api=True, define_macros=[("Py_LIMITED_API", "0x030c0000")]). py_limited_api on Extension controls the module suffix (.abi3.so) but NOT the wheel filename tag. - python/setup.cfg (new): [bdist_wheel] py_limited_api = cp312 so the produced wheel filename gets the cp312-abi3- tag (consumed by any Python 3.12+). - python/pyproject.toml: narrowed [tool.cibuildwheel] build from "cp312-* cp313-* cp314-*" to just "cp312-*". One wheel build per host suffices. Verified locally on macOS: setup.py build_ext --inplace produces dart_bridge.abi3.so (smoke test passes — set_enqueue_handler_func, send_bytes(0) and send_bytes(non_zero) all behave correctly). python -m build --wheel produces dart_bridge-0.0.0-cp312-abi3-macosx_14_0_arm64.whl. Android NDK cross-build ----------------------- New release_build_android job in ci.yml runs on ubuntu-24.04, matrix of just ABIs (arm64-v8a, armeabi-v7a, x86_64). Single Python version (3.12) pinned for headers + libpython to link against; abi3 makes the resulting .so usable across all Python 3.12+. - Downloads python-android-dart-3.12-.tar.gz from flet-dev/python-build (same source serious_python_android uses). - Discovers Python.h + libpython3.12.so defensively via `find`. - Cross-compiles with NDK clang to dart_bridge.abi3-android-.so (ABI in filename so all three ABIs coexist as Release assets without collision; package_command.dart will rename to canonical dart_bridge.abi3.so when placing into the bundled site-packages). - 16K page size link flag for Android 15. - collect_release extended: downloads bridge-android-* artifacts alongside bridge-wheels-*, attaches both to the GitHub Release. Total Release-asset reduction: 16 → 6 binaries (3 wheels + 3 Android .so files). --- .github/workflows/ci.yml | 112 ++++++++++++++++-- .../native/dart_bridge.c | 4 + .../python/pyproject.toml | 4 +- src/serious_python_bridge/python/setup.cfg | 5 + src/serious_python_bridge/python/setup.py | 4 + 5 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 src/serious_python_bridge/python/setup.cfg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 436d9cb7..de8e29bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -263,28 +263,124 @@ jobs: path: wheelhouse/*.whl if-no-files-found: error + release_build_android: + name: Build dart_bridge.abi3.so (Android ${{ matrix.abi }}) + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + # Single abi3 binary per ABI works across all Python 3.12+ versions; + # we only need to pin a Python version for the headers + libpython to + # link against, not for the matrix dimension. 3.12 chosen for header + # parity with the abi3 floor in pyproject.toml. armeabi-v7a is still + # included because PEP 738 dropped it in 3.13, so 3.12 headers are + # the only ones with that ABI tarball. + abi: [arm64-v8a, armeabi-v7a, x86_64] + env: + PYTHON_VERSION: "3.12" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download python-android-dart tarball + run: | + set -euo pipefail + VER="$PYTHON_VERSION" + ABI="${{ matrix.abi }}" + ARCHIVE="python-android-dart-${VER}-${ABI}.tar.gz" + curl -fL -o "$ARCHIVE" \ + "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" + mkdir -p pydist + tar -xzf "$ARCHIVE" -C pydist + echo "tarball contents:" + find pydist -maxdepth 3 -type d + echo "libpython candidates:" + find pydist -name "libpython*.so" -maxdepth 3 + + - name: Cross-compile dart_bridge.abi3.so + run: | + set -euxo pipefail + VER="$PYTHON_VERSION" + ABI="${{ matrix.abi }}" + + case "$ABI" in + arm64-v8a) TARGET=aarch64-linux-android ;; + armeabi-v7a) TARGET=armv7a-linux-androideabi ;; + x86_64) TARGET=x86_64-linux-android ;; + *) echo "unsupported ABI: $ABI" >&2 ; exit 1 ;; + esac + + # Android API 21 matches serious_python_android's minSdkVersion. + API=21 + NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK_LATEST_HOME}}" + TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64" + CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" + test -x "$CC" + + INCLUDE_DIR=$(find pydist -name "Python.h" -exec dirname {} \; | head -n1) + LIBPYTHON=$(find pydist -name "libpython${VER}.so" | head -n1) + test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" + + # ABI in the filename so all three coexist as Release assets without + # collision. package_command.dart renames back to dart_bridge.abi3.so + # when placing into the bundled site-packages (CPython's import + # mechanism requires the canonical name). + OUT="dart_bridge.abi3-android-${ABI}.so" + + $CC -shared -fPIC -fvisibility=hidden \ + -DPy_LIMITED_API=0x030c0000 \ + -I"$INCLUDE_DIR" \ + -I"src/serious_python_bridge/native" \ + src/serious_python_bridge/native/dart_bridge.c \ + src/serious_python_bridge/native/dart_api/dart_api_dl.c \ + "$LIBPYTHON" \ + -Wl,-z,max-page-size=16384 \ + -o "$OUT" + + file "$OUT" + ls -lh "$OUT" + + - name: Upload .so artifact + uses: actions/upload-artifact@v4 + with: + name: bridge-android-${{ matrix.abi }} + path: dart_bridge.abi3-android-*.so + if-no-files-found: error + collect_release: - name: Attach bridge wheels to GitHub Release - needs: release_build + name: Attach bridge binaries to GitHub Release + needs: + - release_build + - release_build_android runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write steps: - - name: Download all wheel artifacts + - name: Download wheel artifacts (Linux / Windows) uses: actions/download-artifact@v4 with: pattern: bridge-wheels-* merge-multiple: true - path: wheels + path: release-assets + + - name: Download Android .so artifacts + uses: actions/download-artifact@v4 + with: + pattern: bridge-android-* + merge-multiple: true + path: release-assets - - name: List collected wheels - run: ls -la wheels/ + - name: List collected assets + run: ls -la release-assets/ - - name: Create or update GitHub Release with wheel assets + - name: Create or update GitHub Release with bridge binaries uses: softprops/action-gh-release@v2 with: - files: wheels/*.whl + files: | + release-assets/*.whl + release-assets/dart_bridge.abi3-android-*.so fail_on_unmatched_files: true publish: diff --git a/src/serious_python_bridge/native/dart_bridge.c b/src/serious_python_bridge/native/dart_bridge.c index 062e3aec..f17cb99c 100644 --- a/src/serious_python_bridge/native/dart_bridge.c +++ b/src/serious_python_bridge/native/dart_bridge.c @@ -1,4 +1,8 @@ #define PY_SSIZE_T_CLEAN +// Build against the CPython Limited API so a single compiled .so works across +// all Python 3.12+ minor versions (abi3 stable ABI). Every Py* symbol used +// below is in the Limited API since 3.2 (3.4 for PyGILState_*). +#define Py_LIMITED_API 0x030c0000 #include #include #include diff --git a/src/serious_python_bridge/python/pyproject.toml b/src/serious_python_bridge/python/pyproject.toml index 9ddaaf49..6398ab25 100644 --- a/src/serious_python_bridge/python/pyproject.toml +++ b/src/serious_python_bridge/python/pyproject.toml @@ -28,5 +28,7 @@ Homepage = "https://github.com/flet-dev/serious-python" Issues = "https://github.com/flet-dev/serious-python/issues" [tool.cibuildwheel] -build = "cp312-* cp313-* cp314-*" +# Limited API / abi3: a single wheel built against Python 3.12's stable ABI +# loads on any Python 3.12+ minor version, so we only need cp312-* here. +build = "cp312-*" skip = ["pp*", "*-musllinux_*"] diff --git a/src/serious_python_bridge/python/setup.cfg b/src/serious_python_bridge/python/setup.cfg new file mode 100644 index 00000000..12a1329c --- /dev/null +++ b/src/serious_python_bridge/python/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +# Tag the produced wheel as abi3 so pip / package_command.dart install it on +# any Python 3.12+ minor version. Keep in lockstep with Py_LIMITED_API in +# dart_bridge.c and the py_limited_api flag in setup.py. +py_limited_api = cp312 diff --git a/src/serious_python_bridge/python/setup.py b/src/serious_python_bridge/python/setup.py index 7d5826fa..1d061862 100644 --- a/src/serious_python_bridge/python/setup.py +++ b/src/serious_python_bridge/python/setup.py @@ -11,6 +11,10 @@ f"{NATIVE_ROOT}/dart_api/dart_api_dl.c", ], include_dirs=[NATIVE_ROOT], + # Limited API / abi3: one .so per platform works for any Python + # 3.12+. Keep this in lockstep with Py_LIMITED_API in dart_bridge.c. + define_macros=[("Py_LIMITED_API", "0x030c0000")], + py_limited_api=True, ) ], ) From 69277f3ccb63ac99716085093f5b96a5d3f24d0f Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 12:37:39 -0700 Subject: [PATCH 010/114] Add throwaway test-bridge-build workflow Mirrors release_build + release_build_android from ci.yml without the refs/tags/v gate and without GH Release / pub.dev publish steps. Triggered on push to dart-bridge branch or via workflow_dispatch, so we can verify the cibuildwheel matrix + Android NDK cross-build actually produce the expected abi3 binaries before we ever cut a real release tag. Adds "list built wheels" + "inspect output" steps so failures are diagnosable from CI logs. Delete this workflow file before merging to main. --- .github/workflows/test-bridge-build.yml | 111 ++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .github/workflows/test-bridge-build.yml diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml new file mode 100644 index 00000000..d197e0ac --- /dev/null +++ b/.github/workflows/test-bridge-build.yml @@ -0,0 +1,111 @@ +name: Test bridge build (no publish) + +# Throwaway workflow that exercises the cibuildwheel matrix and Android NDK +# cross-build added for serious_python_bridge without triggering the publish +# or GitHub Release steps in ci.yml. Delete before merging to main. + +on: + push: + branches: [dart-bridge] + workflow_dispatch: + +jobs: + test_wheel_build: + name: cibuildwheel (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.21.3 + with: + package-dir: src/serious_python_bridge/python + + - name: List built wheels + shell: bash + run: | + ls -la wheelhouse/ + echo + echo "Wheel filenames (expect cp312-abi3-):" + ls wheelhouse/*.whl + echo + echo "Wheel contents (expect dart_bridge.abi3.so):" + for whl in wheelhouse/*.whl; do + echo "--- $whl ---" + python -m zipfile -l "$whl" + done + + test_android_build: + name: Android cross-build (${{ matrix.abi }}) + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + abi: [arm64-v8a, armeabi-v7a, x86_64] + env: + PYTHON_VERSION: "3.12" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download python-android-dart tarball + run: | + set -euo pipefail + VER="$PYTHON_VERSION" + ABI="${{ matrix.abi }}" + ARCHIVE="python-android-dart-${VER}-${ABI}.tar.gz" + curl -fL -o "$ARCHIVE" \ + "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" + mkdir -p pydist + tar -xzf "$ARCHIVE" -C pydist + echo "tarball top-level layout:" + find pydist -maxdepth 3 -type d + echo "Python.h candidates:" + find pydist -name "Python.h" + echo "libpython candidates:" + find pydist -name "libpython*.so" + + - name: Cross-compile dart_bridge.abi3.so + run: | + set -euxo pipefail + VER="$PYTHON_VERSION" + ABI="${{ matrix.abi }}" + + case "$ABI" in + arm64-v8a) TARGET=aarch64-linux-android ;; + armeabi-v7a) TARGET=armv7a-linux-androideabi ;; + x86_64) TARGET=x86_64-linux-android ;; + *) echo "unsupported ABI: $ABI" >&2 ; exit 1 ;; + esac + + API=21 + NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK_LATEST_HOME}}" + TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64" + CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" + test -x "$CC" + + INCLUDE_DIR=$(find pydist -name "Python.h" -exec dirname {} \; | head -n1) + LIBPYTHON=$(find pydist -name "libpython${VER}.so" | head -n1) + test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" + + OUT="dart_bridge.abi3-android-${ABI}.so" + + $CC -shared -fPIC -fvisibility=hidden \ + -DPy_LIMITED_API=0x030c0000 \ + -I"$INCLUDE_DIR" \ + -I"src/serious_python_bridge/native" \ + src/serious_python_bridge/native/dart_bridge.c \ + src/serious_python_bridge/native/dart_api/dart_api_dl.c \ + "$LIBPYTHON" \ + -Wl,-z,max-page-size=16384 \ + -o "$OUT" + + - name: Inspect output + run: | + ls -lh dart_bridge.abi3-android-*.so + file dart_bridge.abi3-android-*.so From 07cc7ab9484f783cb12de3f11a42ce1ef4728b17 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 12:44:00 -0700 Subject: [PATCH 011/114] Fix Android cross-build: switch to mobile-forge tarball for headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The python-android-dart-.tar.gz variant only ships libpython3.X.so and libpythonbundle.so — no Python.h. That was fine for serious_python_android (which uses pre-generated ffigen bindings) but broke our bridge cross-compile, which #include . Switching to python-android-mobile-forge-3.12.tar.gz: - Single 314MB tarball contains all 4 Android ABIs' python-3.12.13/ installs with both include/ and lib/ subtrees - Selective tar extraction (only install/android//python-3.12.13/ include/ + lib/) keeps disk usage per cell modest - find paths now match install/android//python-3.12.13/include/ python3.12/Python.h and lib/libpython3.12.so Verified locally: tarball contents match the expected layout (install/android//python-3.12.13/include/python3.12/Python.h exists for arm64-v8a, armeabi-v7a, x86, x86_64). Same fix applied to both ci.yml's release_build_android and the throwaway test-bridge-build.yml. --- .github/workflows/ci.yml | 21 ++++++++++++--------- .github/workflows/test-bridge-build.yml | 14 +++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de8e29bd..216ba60f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -283,20 +283,23 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Download python-android-dart tarball + - name: Download python-android-mobile-forge tarball (one tarball, all ABIs) run: | set -euo pipefail VER="$PYTHON_VERSION" ABI="${{ matrix.abi }}" - ARCHIVE="python-android-dart-${VER}-${ABI}.tar.gz" + ARCHIVE="python-android-mobile-forge-${VER}.tar.gz" curl -fL -o "$ARCHIVE" \ "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" + # Extract only the python-*/include and python-*/lib subtrees for our + # target ABI — the full archive is ~314MB and includes openssl/sqlite + # builds we don't need. mkdir -p pydist - tar -xzf "$ARCHIVE" -C pydist - echo "tarball contents:" - find pydist -maxdepth 3 -type d - echo "libpython candidates:" - find pydist -name "libpython*.so" -maxdepth 3 + tar -xzf "$ARCHIVE" -C pydist \ + "install/android/${ABI}/python-${VER}.13/include/" \ + "install/android/${ABI}/python-${VER}.13/lib/" + find pydist -name "Python.h" + find pydist -name "libpython*.so" | head -5 - name: Cross-compile dart_bridge.abi3.so run: | @@ -318,8 +321,8 @@ jobs: CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" test -x "$CC" - INCLUDE_DIR=$(find pydist -name "Python.h" -exec dirname {} \; | head -n1) - LIBPYTHON=$(find pydist -name "libpython${VER}.so" | head -n1) + INCLUDE_DIR=$(find pydist -path "*/python-${VER}.13/include/python${VER}" | head -n1) + LIBPYTHON=$(find pydist -path "*/python-${VER}.13/lib/libpython${VER}.so" | head -n1) test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" # ABI in the filename so all three coexist as Release assets without diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index d197e0ac..439b2076 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -53,18 +53,18 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Download python-android-dart tarball + - name: Download python-android-mobile-forge tarball run: | set -euo pipefail VER="$PYTHON_VERSION" ABI="${{ matrix.abi }}" - ARCHIVE="python-android-dart-${VER}-${ABI}.tar.gz" + ARCHIVE="python-android-mobile-forge-${VER}.tar.gz" curl -fL -o "$ARCHIVE" \ "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" mkdir -p pydist - tar -xzf "$ARCHIVE" -C pydist - echo "tarball top-level layout:" - find pydist -maxdepth 3 -type d + tar -xzf "$ARCHIVE" -C pydist \ + "install/android/${ABI}/python-${VER}.13/include/" \ + "install/android/${ABI}/python-${VER}.13/lib/" echo "Python.h candidates:" find pydist -name "Python.h" echo "libpython candidates:" @@ -89,8 +89,8 @@ jobs: CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" test -x "$CC" - INCLUDE_DIR=$(find pydist -name "Python.h" -exec dirname {} \; | head -n1) - LIBPYTHON=$(find pydist -name "libpython${VER}.so" | head -n1) + INCLUDE_DIR=$(find pydist -path "*/python-${VER}.13/include/python${VER}" | head -n1) + LIBPYTHON=$(find pydist -path "*/python-${VER}.13/lib/libpython${VER}.so" | head -n1) test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" OUT="dart_bridge.abi3-android-${ABI}.so" From 22114e8116fd17411351fca9bf4482a338e7135e Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 14:45:42 -0700 Subject: [PATCH 012/114] Bridge round-trip end-to-end working on macOS (1KB integration test passes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round-trip echo test in integration_test/bridge_echo_test.dart sends a 1KB random Uint8List from Dart, Python's app/src/main.py echoes it back with a b"echo: " prefix, Dart asserts byte-identical equality. Passes on macOS host in ~1s. Several issues discovered + fixed getting the bridge to actually run: native/dart_bridge.c Add Py_IsInitialized() guard at the top of DartBridge_EnqueueMessage. Dart's first handshake send arrives BEFORE Python's Py_Initialize completes; without the guard PyGILState_Ensure aborts with "PyMUTEX_LOCK(gil->mutex) failed" against the uninitialized gil mutex. The guard makes early sends a silent no-op so Dart's retry loop can resend until Python is up. darwin/Classes/dart_bridge.c, darwin/Classes/dart_api/** (symlinks) CocoaPods silently drops s.source_files entries that traverse outside the pod root via '../', so committed per-file symlinks into native/ are the only reliable way to compile dart_bridge.c + dart_api_dl.c on Apple platforms. Directory symlinks don't work either — Ruby's Dir.glob doesn't descend through them. Per-file symlinks inside a real dart_api/ directory + a real dart_api/internal/ directory work. darwin/serious_python_bridge.podspec - Add Python.framework's Headers/ subdirectory to HEADER_SEARCH_PATHS so dart_bridge.c's `#include ` (no framework prefix) resolves once CocoaPods has extracted the xcframework slice into PODS_XCFRAMEWORKS_BUILD_DIR. - Drop public_header_files (no SeriousPythonBridgePlugin.h anymore). darwin/Classes/SeriousPythonBridgePlugin.{swift,h} Drop the C header that declared PyInit_dart_bridge — having in the pod's umbrella modulemap required Python framework search paths during modulemap scanning that CocoaPods doesn't propagate reliably from transitive deps. Swift now uses dlsym(RTLD_DEFAULT, "PyInit_dart_bridge") to find the symbol via the global process table. example/app/src/main.py After capturing native_port from the 8-byte handshake, echo the same 8 bytes back. Dart uses that echo as the readiness signal. example/lib/main.dart Replace the racy `Future.delayed(2s)` with a retry-until-Python- echoes-the-handshake loop. Subscribe to bridge.messages BEFORE sending (broadcast streams don't replay; subscribing after send loses fast echoes). Debug prints retained for diagnosability. example/integration_test/bridge_echo_test.dart (new) Drives the bridge directly without going through BridgeExampleApp's UI: pump a minimal SizedBox to trigger plugin registration, then init the bridge, run the handshake retry, send a fixed-seed 1KB random payload, await the echo, assert byte-identical. example/macos/{Runner.xcodeproj,Runner.xcworkspace,Podfile.lock} Updated by `pod install` to register the bridge pod. flet_example tracks the same files; keeping parity. --- .../Classes/SeriousPythonBridgePlugin.h | 11 --- .../Classes/SeriousPythonBridgePlugin.swift | 20 ++-- .../darwin/Classes/dart_api/dart_api.h | 1 + .../darwin/Classes/dart_api/dart_api_dl.c | 1 + .../darwin/Classes/dart_api/dart_api_dl.h | 1 + .../darwin/Classes/dart_api/dart_native_api.h | 1 + .../darwin/Classes/dart_api/dart_tools_api.h | 1 + .../darwin/Classes/dart_api/dart_version.h | 1 + .../dart_api/internal/dart_api_dl_impl.h | 1 + .../darwin/Classes/dart_bridge.c | 1 + .../darwin/serious_python_bridge.podspec | 30 +++--- .../example/app/src/main.py | 18 ++-- .../example/integration_test/.gitkeep | 3 - .../integration_test/bridge_echo_test.dart | 85 ++++++++++++++++ .../example/lib/main.dart | 56 +++++++++-- .../example/macos/Podfile.lock | 31 ++++++ .../macos/Runner.xcodeproj/project.pbxproj | 98 ++++++++++++++++++- .../contents.xcworkspacedata | 3 + .../native/dart_bridge.c | 8 ++ 19 files changed, 319 insertions(+), 52 deletions(-) delete mode 100644 src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h create mode 120000 src/serious_python_bridge/darwin/Classes/dart_bridge.c delete mode 100644 src/serious_python_bridge/example/integration_test/.gitkeep create mode 100644 src/serious_python_bridge/example/integration_test/bridge_echo_test.dart create mode 100644 src/serious_python_bridge/example/macos/Podfile.lock diff --git a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h deleted file mode 100644 index 04ceab30..00000000 --- a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SeriousPythonBridgePlugin_h -#define SeriousPythonBridgePlugin_h - -#include - -// Defined in ../native/dart_bridge.c. Declared here so the Swift plugin code -// can pass it to SeriousPython.registerPythonExtension(name:initFn:) via the -// auto-generated Clang module map for this pod. -PyObject* PyInit_dart_bridge(void); - -#endif diff --git a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift index b572537c..01d4dd7d 100644 --- a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift +++ b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift @@ -5,7 +5,7 @@ import UIKit import FlutterMacOS #endif -import Python +import Darwin import serious_python_darwin public class SeriousPythonBridgePlugin: NSObject, FlutterPlugin { @@ -16,11 +16,19 @@ public class SeriousPythonBridgePlugin: NSObject, FlutterPlugin { // ../native/dart_bridge.c instead of looking for a filesystem .so. // Required on iOS (no late-loaded dylibs allowed). Used on macOS too // for symbol-visibility consistency: Dart's DynamicLibrary.process() - // and Python's `import dart_bridge` then share the same + // and Python's `import dart_bridge` share the same // global_enqueue_handler_func state. - SeriousPythonPlugin.registerPythonExtension( - name: "dart_bridge", - initFn: PyInit_dart_bridge - ) + // + // dlsym(RTLD_DEFAULT) finds PyInit_dart_bridge in the process's global + // symbol table — populated by linking dart_bridge.c into this pod. We + // avoid declaring the symbol in a header because doing so pulls + // into the umbrella module map, which CocoaPods scans + // without the Python.framework search path. + guard let symbol = dlsym(UnsafeMutableRawPointer(bitPattern: -2), "PyInit_dart_bridge") else { + NSLog("[SeriousPythonBridgePlugin] PyInit_dart_bridge symbol not found in process") + return + } + let initFn = unsafeBitCast(symbol, to: SeriousPythonPlugin.PyInitFunction.self) + SeriousPythonPlugin.registerPythonExtension(name: "dart_bridge", initFn: initFn) } } diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h new file mode 120000 index 00000000..8779aae9 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h @@ -0,0 +1 @@ +../../../native/dart_api/dart_api.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c new file mode 120000 index 00000000..436f0e2d --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c @@ -0,0 +1 @@ +../../../native/dart_api/dart_api_dl.c \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h new file mode 120000 index 00000000..5e1f970b --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h @@ -0,0 +1 @@ +../../../native/dart_api/dart_api_dl.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h new file mode 120000 index 00000000..e9be7b9e --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h @@ -0,0 +1 @@ +../../../native/dart_api/dart_native_api.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h new file mode 120000 index 00000000..f8b2a698 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h @@ -0,0 +1 @@ +../../../native/dart_api/dart_tools_api.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h new file mode 120000 index 00000000..58d7bc46 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h @@ -0,0 +1 @@ +../../../native/dart_api/dart_version.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h b/src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h new file mode 120000 index 00000000..5e5068b9 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h @@ -0,0 +1 @@ +../../../../native/dart_api/internal/dart_api_dl_impl.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_bridge.c b/src/serious_python_bridge/darwin/Classes/dart_bridge.c new file mode 120000 index 00000000..b3c323a8 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_bridge.c @@ -0,0 +1 @@ +../../native/dart_bridge.c \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/serious_python_bridge.podspec b/src/serious_python_bridge/darwin/serious_python_bridge.podspec index b900ea43..41ee8cc0 100644 --- a/src/serious_python_bridge/darwin/serious_python_bridge.podspec +++ b/src/serious_python_bridge/darwin/serious_python_bridge.podspec @@ -18,16 +18,16 @@ Pod::Spec.new do |s| s.author = { 'Appveyor Systems Inc.' => 'hello@flet.dev' } s.source = { :path => '.' } - # Swift plugin class + C sources from ../native. - s.source_files = [ - 'Classes/**/*.{h,m,swift}', - '../native/dart_bridge.c', - '../native/dart_api/dart_api_dl.c', - '../native/dart_api/*.h', - '../native/dart_api/internal/*.h', - ] - s.public_header_files = 'Classes/**/*.h' - s.preserve_paths = '../native/dart_api/**/*.h' + # CocoaPods silently drops `s.source_files` entries that traverse outside + # the podspec's directory (`../native/*.c`), so Classes/ contains committed + # symlinks to the canonical native/ sources. Symlinks (rather than copies) + # keep native/ as the single source of truth shared with linux/, windows/, + # android/ CMakeLists builds. The darwin/ pod is only built on Apple + # platforms where symlinks-in-git work fine. + # + # No public headers exposed — Swift accesses PyInit_dart_bridge via + # dlsym(RTLD_DEFAULT, ...), keeping out of the umbrella modulemap. + s.source_files = 'Classes/**/*.{swift,c,h}' s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' @@ -38,9 +38,13 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', - # dart_bridge.c does `#include "dart_api/dart_api_dl.h"`; surface the - # vendored Dart SDK headers. - 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}/../native"', + # First entry: dart_bridge.c does `#include "dart_api/dart_api_dl.h"`. + # Second entry: dart_bridge.c does `#include ` (standard, + # non-framework form). The Python xcframework's slice is extracted by + # CocoaPods into PODS_XCFRAMEWORKS_BUILD_DIR/serious_python_darwin/ + # Python.framework, so pointing at its Headers/ subdirectory lets the + # unprefixed include resolve without changing the .c source. + 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}/../native" "${PODS_XCFRAMEWORKS_BUILD_DIR}/serious_python_darwin/Python.framework/Headers"', # Py* symbols are resolved at the final app link against the Python # framework provided by serious_python_darwin's vendored xcframework. 'OTHER_LDFLAGS' => '$(inherited) -undefined dynamic_lookup', diff --git a/src/serious_python_bridge/example/app/src/main.py b/src/serious_python_bridge/example/app/src/main.py index b1923844..a0e0bc9b 100644 --- a/src/serious_python_bridge/example/app/src/main.py +++ b/src/serious_python_bridge/example/app/src/main.py @@ -1,12 +1,14 @@ """Echo loop exercising serious_python_bridge. -Protocol used by this example (NOT the Flet protocol — this is just the -simplest possible thing that proves the byte transport works): +Protocol used by this example (NOT the Flet protocol — just the simplest +thing that proves the byte transport works): * First frame from Dart: 8-byte little-endian int64 = the Dart native port id - that Python should reply to. Captured into ``native_port`` and not echoed. -* Subsequent frames: arbitrary bytes; echoed back unchanged, prefixed with - ``b"echo: "``. + that Python should reply to. On receipt, Python echoes the same 8 bytes + back via the captured port — Dart uses that echo to detect readiness + (because the `set_enqueue_handler_func` registration may not have run by + the time Dart's first send arrives). +* Subsequent frames: arbitrary bytes; echoed back prefixed with ``b"echo: "``. Python keeps the interpreter alive indefinitely so messages can keep arriving; Dart drives the lifetime (when the app exits, the embedded Python is torn down). @@ -21,7 +23,6 @@ import dart_bridge native_port: int | None = None -_ready = threading.Event() def on_dart_message(data: bytes) -> None: @@ -36,8 +37,9 @@ def on_dart_message(data: bytes) -> None: ) return native_port = struct.unpack(".generate(1024, (_) => rng.nextInt(256)), + ); + final expectedPrefix = Uint8List.fromList('echo: '.codeUnits); + final expectedReply = Uint8List(expectedPrefix.length + payload.length) + ..setRange(0, expectedPrefix.length, expectedPrefix) + ..setRange(expectedPrefix.length, expectedPrefix.length + payload.length, + payload); + + // Pre-subscribe to the echo before sending. + final replyFuture = bridge.messages + .firstWhere((b) => b.length == expectedReply.length) + .timeout(const Duration(seconds: 10)); + + bridge.send(payload); + + final reply = await replyFuture; + expect(reply, equals(expectedReply)); + }); +} + +Future _waitForHandshakeEcho( + PythonBridge bridge, Uint8List portBytes) async { + const retryInterval = Duration(milliseconds: 500); + const overallTimeout = Duration(seconds: 30); + final deadline = DateTime.now().add(overallTimeout); + + while (DateTime.now().isBefore(deadline)) { + final echoFuture = bridge.messages + .firstWhere((b) => _bytesEqual(b, portBytes)) + .timeout(retryInterval); + bridge.send(portBytes); + try { + await echoFuture; + return; + } on TimeoutException { + // Python not ready yet — retry. + } + } + throw TimeoutException( + 'Python did not echo handshake within ${overallTimeout.inSeconds}s'); +} + +bool _bytesEqual(Uint8List a, Uint8List b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) { + if (a[i] != b[i]) return false; + } + return true; +} diff --git a/src/serious_python_bridge/example/lib/main.dart b/src/serious_python_bridge/example/lib/main.dart index 88803714..4b333c8a 100644 --- a/src/serious_python_bridge/example/lib/main.dart +++ b/src/serious_python_bridge/example/lib/main.dart @@ -30,8 +30,11 @@ class _BridgeExampleAppState extends State { } Future _start() async { + debugPrint('[bridge_example] _start: initializing bridge'); final bridge = PythonBridge.init(); + debugPrint('[bridge_example] bridge.nativePort=${bridge.nativePort}'); _subscription = bridge.messages.listen((bytes) { + debugPrint('[bridge_example] received ${bytes.length} bytes from Python'); setState(() { _log.add('Python -> Dart: ${utf8.decode(bytes, allowMalformed: true)}'); }); @@ -39,24 +42,57 @@ class _BridgeExampleAppState extends State { // Fire-and-forget; Python runs on a background thread and never returns // (its main.py blocks waiting for messages). + debugPrint('[bridge_example] starting Python via SeriousPython.run'); unawaited(SeriousPython.run("app/app.zip")); - // Crude: wait for Python to register its receive handler. A production - // protocol would have Python send a "ready" sentinel and Dart wait for - // that on bridge.messages before sending the handshake. - await Future.delayed(const Duration(seconds: 2)); - - // Handshake: send the Dart ReceivePort native port id as the first frame. - final portBytes = Uint8List(8); - portBytes.buffer.asByteData().setInt64(0, bridge.nativePort, Endian.little); - bridge.send(portBytes); + // Retry the handshake until Python echoes it back — Dart's first send may + // arrive before main.py has called set_enqueue_handler_func, and the + // bridge silently drops messages when no handler is registered. + final portBytes = Uint8List(8) + ..buffer.asByteData().setInt64(0, bridge.nativePort, Endian.little); + debugPrint('[bridge_example] starting handshake retry'); + await _handshakeUntilReady(bridge, portBytes); + debugPrint('[bridge_example] handshake complete'); setState(() { _bridge = bridge; - _log.add('handshake sent (native_port=${bridge.nativePort})'); + _log.add('handshake complete (native_port=${bridge.nativePort})'); }); } + Future _handshakeUntilReady( + PythonBridge bridge, Uint8List portBytes) async { + const retryInterval = Duration(milliseconds: 500); + const overallTimeout = Duration(seconds: 30); + final deadline = DateTime.now().add(overallTimeout); + + while (DateTime.now().isBefore(deadline)) { + // Subscribe FIRST so a fast Python echo isn't missed — bridge.messages + // is a broadcast stream and doesn't replay past emissions. + final echoFuture = bridge.messages + .firstWhere((b) => + b.length == portBytes.length && _bytesEqual(b, portBytes)) + .timeout(retryInterval); + bridge.send(portBytes); + try { + await echoFuture; + return; + } on TimeoutException { + // Python not ready yet — retry. + } + } + throw TimeoutException( + 'Python did not echo the handshake within ${overallTimeout.inSeconds}s'); + } + + static bool _bytesEqual(Uint8List a, Uint8List b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) { + if (a[i] != b[i]) return false; + } + return true; + } + void _sendTestMessage() { final bridge = _bridge; if (bridge == null) return; diff --git a/src/serious_python_bridge/example/macos/Podfile.lock b/src/serious_python_bridge/example/macos/Podfile.lock new file mode 100644 index 00000000..70ae0b4d --- /dev/null +++ b/src/serious_python_bridge/example/macos/Podfile.lock @@ -0,0 +1,31 @@ +PODS: + - FlutterMacOS (1.0.0) + - serious_python_bridge (2.0.0): + - Flutter + - FlutterMacOS + - serious_python_darwin + - serious_python_darwin (2.0.0): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - serious_python_bridge (from `Flutter/ephemeral/.symlinks/plugins/serious_python_bridge/darwin`) + - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + serious_python_bridge: + :path: Flutter/ephemeral/.symlinks/plugins/serious_python_bridge/darwin + serious_python_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + serious_python_bridge: 3c906c29f7b53d86374dc1f2d6ad7c325776932f + serious_python_darwin: 51cea45f3f6e3322e607b2d0716db26de8b6c512 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.14.3 diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj index 6a7d27cf..0a23e339 100644 --- a/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + B72E96C288A175DA4181F1E9 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9E3AB6184BEAE07C5108EE3 /* Pods_Runner.framework */; }; + E3DFE7ECAF91BB85499213B0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E0FC039480642B362225F49B /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 2775C3F1F7682B199C8C7E03 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* serious_python_bridge_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "serious_python_bridge_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* serious_python_bridge_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = serious_python_bridge_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +79,15 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 39E5122CF63AF062558CE40F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 4DDC5FA0C150DCFDA5784BFA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 7556ABD1A47FA4D65C4B0DFC /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8B28C1B131F74EC8875EDFCF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + B9E3AB6184BEAE07C5108EE3 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E0E386E07F09A8340444FB67 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + E0FC039480642B362225F49B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E3DFE7ECAF91BB85499213B0 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,6 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B72E96C288A175DA4181F1E9 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + DFB3DE593331416D447154E0 /* Pods */, ); sourceTree = ""; }; @@ -175,10 +188,26 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + B9E3AB6184BEAE07C5108EE3 /* Pods_Runner.framework */, + E0FC039480642B362225F49B /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; + DFB3DE593331416D447154E0 /* Pods */ = { + isa = PBXGroup; + children = ( + 4DDC5FA0C150DCFDA5784BFA /* Pods-Runner.debug.xcconfig */, + 39E5122CF63AF062558CE40F /* Pods-Runner.release.xcconfig */, + 2775C3F1F7682B199C8C7E03 /* Pods-Runner.profile.xcconfig */, + E0E386E07F09A8340444FB67 /* Pods-RunnerTests.debug.xcconfig */, + 7556ABD1A47FA4D65C4B0DFC /* Pods-RunnerTests.release.xcconfig */, + 8B28C1B131F74EC8875EDFCF /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + BBA99A121B65ED7E52DABCEE /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + DEC72C495FFE1070D6EED4DF /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 5019070AFE2F41F3F49E930B /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -329,6 +361,67 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 5019070AFE2F41F3F49E930B /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + BBA99A121B65ED7E52DABCEE /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + DEC72C495FFE1070D6EED4DF /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -380,6 +473,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E0E386E07F09A8340444FB67 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -394,6 +488,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7556ABD1A47FA4D65C4B0DFC /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -408,6 +503,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 8B28C1B131F74EC8875EDFCF /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/src/serious_python_bridge/native/dart_bridge.c b/src/serious_python_bridge/native/dart_bridge.c index f17cb99c..e167a005 100644 --- a/src/serious_python_bridge/native/dart_bridge.c +++ b/src/serious_python_bridge/native/dart_bridge.c @@ -27,6 +27,14 @@ EXPORT intptr_t DartBridge_InitDartApiDL(void* data) { } EXPORT void DartBridge_EnqueueMessage(const char* data, size_t len) { + // Drop messages sent before Python has finished Py_Initialize. Acquiring + // the GIL against an uninitialized interpreter triggers a fatal + // PyMUTEX_LOCK failure (the gil->mutex is uninitialized). Dart's retry + // loop will resend until Python is up. + if (!Py_IsInitialized()) { + return; + } + PyGILState_STATE gstate = PyGILState_Ensure(); if (!global_enqueue_handler_func) { From 60e296688a88d8d23b693775e8ba2bd626d8560a Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 14:47:21 -0700 Subject: [PATCH 013/114] Wire bridge example into CI as a macOS matrix job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New bridge_example_macos job mirrors the existing macos job but operates on src/serious_python_bridge/example/. Runs the same Python version matrix (3.12 / 3.13 / 3.14) — verifies the abi3 + static-link + inittab path works against each embedded CPython. Steps: 1. dart run serious_python:main package app/src --platform Darwin --python-version (builds app.zip; --bridge not needed on macOS since the bridge is static-linked via the darwin podspec) 2. flutter test integration_test -d macos (runs the 1KB byte- identical echo test from bridge_echo_test.dart) Added bridge_example_macos to publish.needs so a failing round-trip blocks pub.dev publication. Linux/Windows/Android/iOS bridge_example jobs are deferred to the next step (5c). --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 216ba60f..2255440b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,6 +236,31 @@ jobs: dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + bridge_example_macos: + name: Test bridge example on macOS (Python ${{ matrix.python_version }}) + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Run integration test + working-directory: "src/serious_python_bridge/example" + run: | + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} + flutter test integration_test -d macos + release_build: name: Build dart_bridge wheel (${{ matrix.os }}) if: startsWith(github.ref, 'refs/tags/v') @@ -394,6 +419,7 @@ jobs: - android - windows - linux + - bridge_example_macos - collect_release runs-on: ubuntu-22.04 if: startsWith(github.ref, 'refs/tags/v') From 63c4fb998fa434f85f11b37e263ab709e492b3a1 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 14:51:20 -0700 Subject: [PATCH 014/114] Speed up dart-bridge iteration: scope ci.yml to main + add macOS bridge example to throwaway workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ci.yml `on.push.branches` temporarily narrowed from '**' to ['main', 'master'] so iteration pushes to dart-bridge skip the ~20-30 min flet_example platform matrix. Tag pushes still fire the full workflow (release builds + publish). REVERT before merging. - test-bridge-build.yml: add test_bridge_example_macos matrix job (Python 3.12/3.13/3.14) that mirrors the new bridge_example_macos job from ci.yml without the dependency on the rest of the matrix. Renamed workflow's display name to reflect broader scope. Net effect on dart-bridge pushes: only the fast throwaway workflow runs (~3 build cells + 3 Android cross-build cells + 3 macOS bridge example cells ≈ ~3-5 min for the slowest cell vs ~30 min before). --- .github/workflows/ci.yml | 7 ++++- .github/workflows/test-bridge-build.yml | 35 ++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2255440b..b04aeed5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,14 @@ name: CI +# TEMPORARY (dart-bridge branch only): scoped to main + tags + dispatch so +# iteration pushes to dart-bridge don't fire the slow flet_example platform +# matrix (~20-30 min per run). The throwaway test-bridge-build.yml covers +# the new bridge work fast. REVERT to `branches: '**'` before merging. on: push: branches: - - '**' + - main + - master tags: - '*' pull_request: diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 439b2076..c420a3f7 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -1,8 +1,10 @@ -name: Test bridge build (no publish) +name: Test bridge (no publish, no slow platform tests) -# Throwaway workflow that exercises the cibuildwheel matrix and Android NDK -# cross-build added for serious_python_bridge without triggering the publish -# or GitHub Release steps in ci.yml. Delete before merging to main. +# Throwaway workflow that exercises just the new serious_python_bridge work — +# the cibuildwheel matrix, the Android NDK cross-build, and the macOS bridge +# example integration test — without triggering the slow flet_example +# platform matrix or the publish/release steps in ci.yml. Delete before +# merging to main. on: push: @@ -109,3 +111,28 @@ jobs: run: | ls -lh dart_bridge.abi3-android-*.so file dart_bridge.abi3-android-*.so + + test_bridge_example_macos: + name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Package + run integration test + working-directory: "src/serious_python_bridge/example" + run: | + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} + flutter test integration_test -d macos From 08bbadc67b23e107e094d80d5af82f4dc1baf56b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 14:58:55 -0700 Subject: [PATCH 015/114] Add iOS/Linux/Windows bridge example tests + bump Flutter to 3.41.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flutter version --------------- .fvmrc: 3.29.3 → 3.41.7 to match flet repo. Bridge example matrix expanded (step 5c) ---------------------------------------- ci.yml + test-bridge-build.yml now run the bridge integration test on: - macOS (Apple path: static-link + inittab via darwin podspec) - iOS (same Apple path; simulator launched via futureware-tech/ simulator-action — same as flet_example) - Linux amd64 + arm64 (abi3 wheel from release_build/test_wheel_build passed to `dart run serious_python:main package --requirements `) - Windows (same wheel-from-artifact pattern) All run the 3.12/3.13/3.14 Python matrix (abi3 means the same .so loads on each). 13 cells per workflow: 3 macos + 3 ios + 6 linux (2 arches × 3 versions) + 3 windows Linux/Windows jobs depend on release_build (ci.yml) or test_wheel_build (throwaway) so the locally-built wheel is available. Linux/Windows are also gated to tag pushes in ci.yml — release_build only runs on tags. publish.needs extended with all four new bridge_example_ jobs so a failing round-trip blocks pub.dev publication. Android deferred — its site-packages live inside libpythonsitepackages .so (a zip-as-.so archive built by serious_python_android's gradle), so injecting dart_bridge.abi3.so needs a different path than the desktop wheel-as-requirement approach. Will need either: - package_command.dart `--bridge` flag (step 7 work) that knows how to inject .so into Android's pythonsitepackages zip, or - A custom script step in the test workflow that patches the bundle before the integration test runs. --- .fvmrc | 2 +- .github/workflows/ci.yml | 167 ++++++++++++++++++++++++ .github/workflows/test-bridge-build.yml | 157 ++++++++++++++++++++++ 3 files changed, 325 insertions(+), 1 deletion(-) diff --git a/.fvmrc b/.fvmrc index 07470f9c..94d87f34 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.29.3" + "flutter": "3.41.7" } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b04aeed5..234f5e88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -266,6 +266,170 @@ jobs: dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} flutter test integration_test -d macos + bridge_example_ios: + name: Test bridge example on iOS (Python ${{ matrix.python_version }}) + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Setup iOS Simulator + id: simulator + uses: futureware-tech/simulator-action@v4 + with: + model: 'iPhone 16 Pro Max' + os: "iOS" + os_version: "^18.6" + shutdown_after_job: true + wait_for_boot: true + + - name: Run integration test + working-directory: "src/serious_python_bridge/example" + run: | + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} + flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} + + bridge_example_linux: + name: Test bridge example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) + runs-on: ${{ matrix.runner }} + # Linux desktop needs the dart_bridge abi3 wheel installed into the bundled + # Python (no static-link path like on Apple); pull it from the wheel build. + needs: release_build + if: startsWith(github.ref, 'refs/tags/v') + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + arch: [arm64, amd64] + include: + - arch: arm64 + runner: ubuntu-24.04-arm + title: ARM64 + wheel_artifact: bridge-wheels-ubuntu-24.04-arm + - arch: amd64 + runner: ubuntu-24.04 + title: AMD64 + wheel_artifact: bridge-wheels-ubuntu-24.04 + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Get Flutter version from .fvmrc + uses: kuhnroyal/flutter-fvm-config-action/config@v3 + id: fvm-config-action + with: + path: '.fvmrc' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} + cache: true + + - name: Install Linux desktop build deps + run: | + sudo apt-get update --allow-releaseinfo-change + sudo apt-get install -y xvfb libgtk-3-dev + if [ "${{ matrix.arch }}" = "amd64" ]; then + sudo apt-get install -y \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + else + sudo apt-get install -y \ + clang ninja-build gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + fi + + - name: Download dart_bridge wheel artifact + uses: actions/download-artifact@v4 + with: + name: ${{ matrix.wheel_artifact }} + path: ${{ runner.temp }}/dart_bridge_wheels + + - name: Pick matching wheel for this arch + id: wheel + run: | + set -euo pipefail + # cibuildwheel produces one wheel per arch in this artifact; the + # repaired manylinux wheel is the one we want. + WHL=$(ls "${{ runner.temp }}/dart_bridge_wheels"/dart_bridge-*manylinux*.whl | head -n1) + test -n "$WHL" + echo "path=$WHL" >> "$GITHUB_OUTPUT" + echo "Picked: $WHL" + + - name: Run integration test + working-directory: src/serious_python_bridge/example + run: | + flutter pub get + dart run serious_python:main package app/src \ + --platform Linux \ + --python-version ${{ matrix.python_version }} \ + --requirements ${{ steps.wheel.outputs.path }} + xvfb-run flutter test integration_test -d linux + + bridge_example_windows: + name: Test bridge example on Windows (Python ${{ matrix.python_version }}) + runs-on: windows-latest + needs: release_build + if: startsWith(github.ref, 'refs/tags/v') + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Download dart_bridge wheel artifact + uses: actions/download-artifact@v4 + with: + name: bridge-wheels-windows-latest + path: ${{ runner.temp }}\dart_bridge_wheels + + - name: Pick matching wheel + id: wheel + shell: bash + run: | + set -euo pipefail + WHL=$(ls "$RUNNER_TEMP/dart_bridge_wheels"/dart_bridge-*-win_amd64.whl | head -n1) + test -n "$WHL" + echo "path=$WHL" >> "$GITHUB_OUTPUT" + echo "Picked: $WHL" + + - name: Run integration test + working-directory: "src/serious_python_bridge/example" + run: | + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} + flutter test integration_test -d windows + release_build: name: Build dart_bridge wheel (${{ matrix.os }}) if: startsWith(github.ref, 'refs/tags/v') @@ -425,6 +589,9 @@ jobs: - windows - linux - bridge_example_macos + - bridge_example_ios + - bridge_example_linux + - bridge_example_windows - collect_release runs-on: ubuntu-22.04 if: startsWith(github.ref, 'refs/tags/v') diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index c420a3f7..9e57421f 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -136,3 +136,160 @@ jobs: run: | dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} flutter test integration_test -d macos + + test_bridge_example_ios: + name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Setup iOS Simulator + id: simulator + uses: futureware-tech/simulator-action@v4 + with: + model: 'iPhone 16 Pro Max' + os: "iOS" + os_version: "^18.6" + shutdown_after_job: true + wait_for_boot: true + + - name: Package + run integration test + working-directory: "src/serious_python_bridge/example" + run: | + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} + flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} + + test_bridge_example_linux: + name: Bridge example Linux ${{ matrix.title }} round-trip (Python ${{ matrix.python_version }}) + runs-on: ${{ matrix.runner }} + needs: test_wheel_build + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + include: + - arch: arm64 + runner: ubuntu-24.04-arm + title: ARM64 + wheel_artifact: bridge-wheels-ubuntu-24.04-arm + - arch: amd64 + runner: ubuntu-24.04 + title: AMD64 + wheel_artifact: bridge-wheels-ubuntu-24.04 + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Get Flutter version from .fvmrc + uses: kuhnroyal/flutter-fvm-config-action/config@v3 + id: fvm-config-action + with: + path: '.fvmrc' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} + cache: true + + - name: Install Linux desktop build deps + run: | + sudo apt-get update --allow-releaseinfo-change + sudo apt-get install -y xvfb libgtk-3-dev + if [ "${{ matrix.arch }}" = "amd64" ]; then + sudo apt-get install -y \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + else + sudo apt-get install -y \ + clang ninja-build gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + fi + + - name: Download dart_bridge wheel artifact + uses: actions/download-artifact@v4 + with: + name: ${{ matrix.wheel_artifact }} + path: ${{ runner.temp }}/dart_bridge_wheels + + - name: Pick matching wheel for this arch + id: wheel + run: | + set -euo pipefail + WHL=$(ls "${{ runner.temp }}/dart_bridge_wheels"/dart_bridge-*manylinux*.whl | head -n1) + test -n "$WHL" + echo "path=$WHL" >> "$GITHUB_OUTPUT" + echo "Picked: $WHL" + + - name: Package + run integration test + working-directory: src/serious_python_bridge/example + run: | + flutter pub get + dart run serious_python:main package app/src \ + --platform Linux \ + --python-version ${{ matrix.python_version }} \ + --requirements ${{ steps.wheel.outputs.path }} + xvfb-run flutter test integration_test -d linux + + test_bridge_example_windows: + name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) + runs-on: windows-latest + needs: test_wheel_build + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Download dart_bridge wheel artifact + uses: actions/download-artifact@v4 + with: + name: bridge-wheels-windows-latest + path: ${{ runner.temp }}\dart_bridge_wheels + + - name: Pick matching wheel + id: wheel + shell: bash + run: | + set -euo pipefail + WHL=$(ls "$RUNNER_TEMP/dart_bridge_wheels"/dart_bridge-*-win_amd64.whl | head -n1) + test -n "$WHL" + echo "path=$WHL" >> "$GITHUB_OUTPUT" + echo "Picked: $WHL" + + - name: Package + run integration test + working-directory: "src/serious_python_bridge/example" + run: | + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} + flutter test integration_test -d windows From 446434e8c673a942048cea4a7dfb8c4a482c334f Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 15:16:11 -0700 Subject: [PATCH 016/114] Fix iOS + Linux/Windows bridge_example CI failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three issues from the previous CI run: 1. test_wheel_build (throwaway) didn't upload wheel artifacts — only built them and listed filenames. Bridge example Linux/Windows then failed downloading the missing artifacts. Added actions/upload- artifact step that mirrors ci.yml's release_build. 2. iOS bridge_example failed: serious_python_darwin's sync_site_packages.sh only populates dist_ios/site-xcframeworks when iOS-specific site-packages subdirs (iphoneos.arm64, iphonesimulator.arm64, iphonesimulator.x86_64) exist. Empty --requirements falls to the macOS branch which doesn't create that directory, and bundle-python-frameworks-ios.sh later fails `find dist_ios/site-xcframeworks` with `No such file or directory`. Workaround: pass `--requirements certifi` (a tiny pure-Python placeholder, the same shape as flet_example's flet==0.28.3) to trigger the iOS site-xcframeworks population. 3. test-bridge-build.yml had no workflow-level SERIOUS_PYTHON_SITE_PACKAGES env var. ci.yml sets this at the top (line 15) so all jobs inherit. The throwaway needs the same so sync_site_packages.sh knows where package_command.dart staged the bundled site-packages. The certifi workaround is fragile; a cleaner long-term fix is to patch sync_site_packages.sh to always create site-xcframeworks (with just the base python xcframeworks, no user deps required). Adding to bridge-followups. --- .github/workflows/ci.yml | 8 +++++++- .github/workflows/test-bridge-build.yml | 26 ++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 234f5e88..13c3227a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -298,7 +298,13 @@ jobs: - name: Run integration test working-directory: "src/serious_python_bridge/example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} + # certifi placeholder: serious_python_darwin's sync_site_packages.sh + # only populates dist_ios/site-xcframeworks when iOS-specific + # site-packages subdirs exist (i.e., requirements installed for + # iphoneos.arm64 + iphonesimulator.arm64 + iphonesimulator.x86_64). + # An empty --requirements skips that branch and bundle-python- + # frameworks-ios.sh later fails finding site-xcframeworks. + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} bridge_example_linux: diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 9e57421f..acb23538 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -11,6 +11,12 @@ on: branches: [dart-bridge] workflow_dispatch: +env: + # Mirrors ci.yml's workflow-level env: serious_python_darwin's + # sync_site_packages.sh and the Linux CMakeLists.txt both read this to know + # where package_command.dart staged the bundled site-packages. + SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" + jobs: test_wheel_build: name: cibuildwheel (${{ matrix.os }}) @@ -35,12 +41,13 @@ jobs: echo echo "Wheel filenames (expect cp312-abi3-):" ls wheelhouse/*.whl - echo - echo "Wheel contents (expect dart_bridge.abi3.so):" - for whl in wheelhouse/*.whl; do - echo "--- $whl ---" - python -m zipfile -l "$whl" - done + + - name: Upload wheel artifacts + uses: actions/upload-artifact@v4 + with: + name: bridge-wheels-${{ matrix.os }} + path: wheelhouse/*.whl + if-no-files-found: error test_android_build: name: Android cross-build (${{ matrix.abi }}) @@ -169,7 +176,12 @@ jobs: - name: Package + run integration test working-directory: "src/serious_python_bridge/example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} + # certifi is a placeholder requirement: serious_python_darwin's + # sync_site_packages.sh only populates dist_ios/site-xcframeworks + # (which bundle-python-frameworks-ios.sh then requires at build + # time) when iOS-specific site-packages subdirs exist. Empty + # --requirements skips that branch and the build fails. + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} test_bridge_example_linux: From e172cb95227e79720685fd31a5164b5ec4dc7afc Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 16:46:27 -0700 Subject: [PATCH 017/114] Fix Linux/Windows bridge_example: skip 32-bit wheels + link Windows abi3 stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three CI failures from the previous run, all in the Linux + Windows bridge_example matrix: Linux: Picked the wrong wheel — cibuildwheel produces both x86_64 AND i686 variants for ubuntu hosts, and `ls | head -n1` lands on dart_bridge-*manylinux*_i686.whl alphabetically. pip then refuses with "is not a supported wheel on this platform". Fix: skip i686 in [tool.cibuildwheel] so only x86_64 ships. (Also pre-emptively skip win32 for symmetry; Flet desktop is 64-bit only.) Windows: `LINK : fatal error LNK1104: cannot open file 'python314_d.lib'` — find_package(Python3 ... Development.Module) picks the version- specific debug-config import lib in Debug builds, but python-build- standalone for Windows doesn't ship a Debug variant. Fix: native/CMakeLists.txt — on WIN32, link against python3.lib (the abi3 stable-ABI stub) directly. It's version-agnostic and has no debug variant requirement, matching our Py_LIMITED_API choice in dart_bridge.c. iOS (separate flake): iOS 3.14 passed in 12m26s but iOS 3.12 and 3.13 hung past 1 hour in the "Package + run integration test" step. Adding timeout-minutes: 25 to both bridge_example_ios in ci.yml and test_bridge_example_ios in the throwaway so future hangs fail loudly within 25 min instead of consuming the 6-hour job default. Root cause TBD — likely a CocoaPods/simulator zombie since one of three Python versions succeeded. --- .github/workflows/ci.yml | 1 + .github/workflows/test-bridge-build.yml | 1 + src/serious_python_bridge/native/CMakeLists.txt | 12 +++++++++++- src/serious_python_bridge/python/pyproject.toml | 4 +++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13c3227a..307b6001 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,6 +269,7 @@ jobs: bridge_example_ios: name: Test bridge example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-latest + timeout-minutes: 25 strategy: fail-fast: false matrix: diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index acb23538..acab8d9d 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -147,6 +147,7 @@ jobs: test_bridge_example_ios: name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) runs-on: macos-latest + timeout-minutes: 25 strategy: fail-fast: false matrix: diff --git a/src/serious_python_bridge/native/CMakeLists.txt b/src/serious_python_bridge/native/CMakeLists.txt index 7d13225d..a018d2a7 100644 --- a/src/serious_python_bridge/native/CMakeLists.txt +++ b/src/serious_python_bridge/native/CMakeLists.txt @@ -18,7 +18,17 @@ project(flet_bridge VERSION 0.0.1 LANGUAGES C) if(NOT DEFINED FLET_BRIDGE_PYTHON_INCLUDE_DIRS) find_package(Python3 REQUIRED COMPONENTS Development.Module) set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS ${Python3_INCLUDE_DIRS}) - set(FLET_BRIDGE_PYTHON_LIBRARIES Python3::Module) + if(WIN32) + # Python3::Module picks pythonXY.lib (or pythonXY_d.lib in Debug builds), + # but python-build-standalone for Windows doesn't ship a Debug variant + # so Flutter's debug builds fail with LNK1104. Link the abi3 stable-ABI + # stub python3.lib instead — it's version-agnostic AND has no debug + # variant requirement (matches our Py_LIMITED_API choice). + get_filename_component(_flet_bridge_python_root "${Python3_INCLUDE_DIRS}" DIRECTORY) + set(FLET_BRIDGE_PYTHON_LIBRARIES "${_flet_bridge_python_root}/libs/python3.lib") + else() + set(FLET_BRIDGE_PYTHON_LIBRARIES Python3::Module) + endif() endif() add_library(flet_bridge SHARED diff --git a/src/serious_python_bridge/python/pyproject.toml b/src/serious_python_bridge/python/pyproject.toml index 6398ab25..06ff40b5 100644 --- a/src/serious_python_bridge/python/pyproject.toml +++ b/src/serious_python_bridge/python/pyproject.toml @@ -31,4 +31,6 @@ Issues = "https://github.com/flet-dev/serious-python/issues" # Limited API / abi3: a single wheel built against Python 3.12's stable ABI # loads on any Python 3.12+ minor version, so we only need cp312-* here. build = "cp312-*" -skip = ["pp*", "*-musllinux_*"] +# Flet targets only 64-bit desktop, so skip 32-bit (i686 / win32). Also skip +# PyPy and musllinux (alternative libc, not what python-build-standalone uses). +skip = ["pp*", "*-musllinux_*", "*-linux_i686", "*-win32"] From 5c3f55906001093a21a768fa8026b9e57dcfa747 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 17:03:10 -0700 Subject: [PATCH 018/114] Fix i686 skip pattern: *_i686 (not *-linux_i686) cibuildwheel's Linux build identifier is `cp312-manylinux_i686`, not `cp312-linux_i686`, so my earlier `*-linux_i686` skip pattern didn't match and i686 wheels kept being built (alphabetically picked first by `ls | head -n1` over x86_64, then rejected by pip with "is not a supported wheel on this platform"). The broader `*_i686` matches every i686 build identifier regardless of the libc prefix (manylinux, musllinux, etc.). --- src/serious_python_bridge/python/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serious_python_bridge/python/pyproject.toml b/src/serious_python_bridge/python/pyproject.toml index 06ff40b5..75109542 100644 --- a/src/serious_python_bridge/python/pyproject.toml +++ b/src/serious_python_bridge/python/pyproject.toml @@ -33,4 +33,4 @@ Issues = "https://github.com/flet-dev/serious-python/issues" build = "cp312-*" # Flet targets only 64-bit desktop, so skip 32-bit (i686 / win32). Also skip # PyPy and musllinux (alternative libc, not what python-build-standalone uses). -skip = ["pp*", "*-musllinux_*", "*-linux_i686", "*-win32"] +skip = ["pp*", "*-musllinux_*", "*_i686", "*-win32"] From e3aa56695e4e5ec89e91a7bb89302d862f7856bc Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 17:22:09 -0700 Subject: [PATCH 019/114] Mark Linux/Windows bridge_example continue-on-error (symbol-split deferred) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause is the symbol visibility split the original plan called out: the wheel-installed dart_bridge.so (cibuildwheel) and the Flutter-built libflet_bridge.so are two separate binaries with two separate copies of global_enqueue_handler_func. Python's set_enqueue_handler_func writes to the wheel's copy; Dart's DartBridge_EnqueueMessage reads libflet_bridge.so's (NULL); messages are silently dropped and the handshake echo never fires — "Python did not echo handshake within 30s". Apple platforms (macOS + iOS) don't hit this because the bridge is static-linked into the framework, so there's only one copy. Proper fix: dart_bridge_core.c + dart_bridge_shim.c, with the shim dlopening libflet_bridge.so RTLD_GLOBAL so its `extern global_enqueue_handler_func` resolves to libflet_bridge.so's copy. Documented in bridge-followups.md. For now, continue-on-error so the iOS/macOS proof-of-life survives and we get diagnostic data on the Linux/Windows symbol-split work without blocking other CI. --- .github/workflows/ci.yml | 10 ++++++++++ .github/workflows/test-bridge-build.yml | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 307b6001..90ea8b3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -315,6 +315,13 @@ jobs: # Python (no static-link path like on Apple); pull it from the wheel build. needs: release_build if: startsWith(github.ref, 'refs/tags/v') + # KNOWN DEFERRED: symbol visibility between the wheel's dart_bridge.so and + # the Flutter-built libflet_bridge.so means Python's enqueue handler is + # never seen by Dart's DartBridge_EnqueueMessage (each has its own copy + # of global_enqueue_handler_func). Proper fix is the shim split from the + # original plan — tracked in bridge-followups.md. continue-on-error so + # the test doesn't block tag releases until the split lands. + continue-on-error: true strategy: fail-fast: false matrix: @@ -399,6 +406,9 @@ jobs: runs-on: windows-latest needs: release_build if: startsWith(github.ref, 'refs/tags/v') + # Same KNOWN DEFERRED as bridge_example_linux above — symbol visibility + # between wheel and libflet_bridge.dll. Tracked in bridge-followups.md. + continue-on-error: true strategy: fail-fast: false matrix: diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index acab8d9d..21047bd0 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -189,6 +189,16 @@ jobs: name: Bridge example Linux ${{ matrix.title }} round-trip (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} needs: test_wheel_build + # KNOWN DEFERRED: the wheel-installed dart_bridge.so and the Flutter-built + # libflet_bridge.so are separate binaries with separate copies of + # global_enqueue_handler_func. Python's set_enqueue_handler_func writes + # to the wheel's copy; Dart's DartBridge_EnqueueMessage reads + # libflet_bridge.so's copy, which is always NULL. Test currently times + # out at handshake echo. Proper fix is the shim split from the original + # plan (dart_bridge_shim.c that dlopens libflet_bridge.so RTLD_GLOBAL) — + # tracked in bridge-followups.md. continue-on-error so this matrix + # leaves data without blocking the rest of CI. + continue-on-error: true strategy: fail-fast: false matrix: @@ -269,6 +279,10 @@ jobs: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) runs-on: windows-latest needs: test_wheel_build + # Same KNOWN DEFERRED as test_bridge_example_linux above — symbol + # visibility between wheel and libflet_bridge.dll. Tracked in + # bridge-followups.md. + continue-on-error: true strategy: fail-fast: false matrix: From 1b86e282d1b000330433ff82c19d754c03221db0 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 17:32:04 -0700 Subject: [PATCH 020/114] Shim split: dart_bridge.c (Dart-callable) + dart_bridge_shim.c (Python module) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the Linux/Windows/Android bridge_example handshake-timeout failure by making Python and Dart share the SAME `global_enqueue_handler_func` cell on every platform. Before: the wheel-installed dart_bridge.so (cibuildwheel) and the Flutter-built libflet_bridge.so each compiled a full copy of dart_bridge.c — two separate binary instances, two separate copies of the static `global_enqueue_handler_func`. Python's set_enqueue_handler_func wrote to the wheel's copy; Dart's DartBridge_EnqueueMessage read libflet_bridge's copy (NULL); messages were silently dropped. After: the core lives in libflet_bridge ONLY. The wheel ships a thin shim that resolves the core's exports at PyInit time via runtime symbol lookup (dlsym(RTLD_DEFAULT) → dlopen RTLD_GLOBAL fallback on Linux/macOS, LoadLibrary+GetProcAddress on Windows). One global cell, visible to both sides. Changes: - native/dart_bridge.c: drop the Python-callable methods. Exports three symbols for the shim to resolve: * dart_bridge_global_enqueue_handler_func (PyObject*, was static) * dart_bridge_post_to_dart (helper that wraps Dart_PostCObject_DL so the shim doesn't need its own copy of dart_api_dl.c) * existing DartBridge_InitDartApiDL + DartBridge_EnqueueMessage - native/dart_bridge_shim.c (NEW): PyInit_dart_bridge resolves the three exports above via shim_sym_lookup(); set_enqueue_handler_func writes through the resolved pointer; send_bytes calls through the resolved function pointer. ImportError if libflet_bridge isn't loaded into the process (catches misconfiguration loudly). - python/setup.py: compile only dart_bridge_shim.c; add -ldl on Linux for the dlopen/dlsym used by the shim. Dropped dart_api_dl.c from the wheel's sources (the shim doesn't call Dart_PostCObject_DL directly). - darwin/Classes/dart_bridge_shim.c (symlink): so the Apple static link picks both .c files into the framework. Apple's dlsym(RTLD_DEFAULT) finds the symbols in-process (smoke-tested: macOS bridge_example_macos still passes). - ci.yml + test-bridge-build.yml: drop continue-on-error from bridge_example_linux and bridge_example_windows — they should pass now. Verified locally on macOS: `flutter test integration_test -d macos` still green. CI verification pending — pushing to dart-bridge will exercise all three desktop platforms. --- .github/workflows/ci.yml | 10 -- .github/workflows/test-bridge-build.yml | 14 -- .../darwin/Classes/dart_bridge_shim.c | 1 + .../native/dart_bridge.c | 84 ++++------- .../native/dart_bridge_shim.c | 131 ++++++++++++++++++ src/serious_python_bridge/python/setup.py | 20 ++- 6 files changed, 171 insertions(+), 89 deletions(-) create mode 120000 src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c create mode 100644 src/serious_python_bridge/native/dart_bridge_shim.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90ea8b3f..307b6001 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -315,13 +315,6 @@ jobs: # Python (no static-link path like on Apple); pull it from the wheel build. needs: release_build if: startsWith(github.ref, 'refs/tags/v') - # KNOWN DEFERRED: symbol visibility between the wheel's dart_bridge.so and - # the Flutter-built libflet_bridge.so means Python's enqueue handler is - # never seen by Dart's DartBridge_EnqueueMessage (each has its own copy - # of global_enqueue_handler_func). Proper fix is the shim split from the - # original plan — tracked in bridge-followups.md. continue-on-error so - # the test doesn't block tag releases until the split lands. - continue-on-error: true strategy: fail-fast: false matrix: @@ -406,9 +399,6 @@ jobs: runs-on: windows-latest needs: release_build if: startsWith(github.ref, 'refs/tags/v') - # Same KNOWN DEFERRED as bridge_example_linux above — symbol visibility - # between wheel and libflet_bridge.dll. Tracked in bridge-followups.md. - continue-on-error: true strategy: fail-fast: false matrix: diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 21047bd0..acab8d9d 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -189,16 +189,6 @@ jobs: name: Bridge example Linux ${{ matrix.title }} round-trip (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} needs: test_wheel_build - # KNOWN DEFERRED: the wheel-installed dart_bridge.so and the Flutter-built - # libflet_bridge.so are separate binaries with separate copies of - # global_enqueue_handler_func. Python's set_enqueue_handler_func writes - # to the wheel's copy; Dart's DartBridge_EnqueueMessage reads - # libflet_bridge.so's copy, which is always NULL. Test currently times - # out at handshake echo. Proper fix is the shim split from the original - # plan (dart_bridge_shim.c that dlopens libflet_bridge.so RTLD_GLOBAL) — - # tracked in bridge-followups.md. continue-on-error so this matrix - # leaves data without blocking the rest of CI. - continue-on-error: true strategy: fail-fast: false matrix: @@ -279,10 +269,6 @@ jobs: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) runs-on: windows-latest needs: test_wheel_build - # Same KNOWN DEFERRED as test_bridge_example_linux above — symbol - # visibility between wheel and libflet_bridge.dll. Tracked in - # bridge-followups.md. - continue-on-error: true strategy: fail-fast: false matrix: diff --git a/src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c b/src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c new file mode 120000 index 00000000..0d896916 --- /dev/null +++ b/src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c @@ -0,0 +1 @@ +../../native/dart_bridge_shim.c \ No newline at end of file diff --git a/src/serious_python_bridge/native/dart_bridge.c b/src/serious_python_bridge/native/dart_bridge.c index e167a005..11f948f3 100644 --- a/src/serious_python_bridge/native/dart_bridge.c +++ b/src/serious_python_bridge/native/dart_bridge.c @@ -15,12 +15,21 @@ #endif // --------------------------------------------------------------------------- -// Core: symbols called from Dart via FFI. On platforms with the shared-lib -// split these live in libflet_bridge; on iOS they're linked statically into -// the serious_python framework. +// Core: symbols called from Dart via FFI plus exported helpers the Python-side +// shim (dart_bridge_shim.c) resolves at runtime via dlsym. Compiled into +// libflet_bridge.{so,dll,dylib} by the Flutter plugin build. On Apple +// platforms also compiled into the static archive linked into the +// serious_python framework alongside dart_bridge_shim.c. +// +// The shim NEVER defines its own copy of these symbols — it always looks them +// up at runtime. That keeps Dart's view of `global_enqueue_handler_func` and +// the Python shim's view as a single shared cell on every platform. // --------------------------------------------------------------------------- -static PyObject* global_enqueue_handler_func = NULL; +// Exported (non-static) so dart_bridge_shim.c's set_enqueue_handler_func can +// write to it via dlsym. Initialised to NULL; the shim swaps in a PyObject* +// callable when Python registers a handler. +EXPORT PyObject* dart_bridge_global_enqueue_handler_func = NULL; EXPORT intptr_t DartBridge_InitDartApiDL(void* data) { return Dart_InitializeApiDL(data); @@ -37,7 +46,7 @@ EXPORT void DartBridge_EnqueueMessage(const char* data, size_t len) { PyGILState_STATE gstate = PyGILState_Ensure(); - if (!global_enqueue_handler_func) { + if (!dart_bridge_global_enqueue_handler_func) { fprintf(stderr, "[dart_bridge] enqueue handler is not registered\n"); PyGILState_Release(gstate); return; @@ -50,7 +59,8 @@ EXPORT void DartBridge_EnqueueMessage(const char* data, size_t len) { return; } - PyObject* result = PyObject_CallFunctionObjArgs(global_enqueue_handler_func, arg, NULL); + PyObject* result = PyObject_CallFunctionObjArgs( + dart_bridge_global_enqueue_handler_func, arg, NULL); if (!result) { PyErr_Print(); } @@ -60,41 +70,14 @@ EXPORT void DartBridge_EnqueueMessage(const char* data, size_t len) { PyGILState_Release(gstate); } -// --------------------------------------------------------------------------- -// Shim: Python-callable methods exposed by the `dart_bridge` module. -// --------------------------------------------------------------------------- - -static PyObject* set_enqueue_handler_func(PyObject* self, PyObject* args) { - PyObject* func; - - if (!PyArg_ParseTuple(args, "O:set_enqueue_handler_func", &func)) { - return NULL; - } - - if (!PyCallable_Check(func)) { - PyErr_SetString(PyExc_TypeError, "parameter must be callable"); - return NULL; - } - - Py_XINCREF(func); - Py_XDECREF(global_enqueue_handler_func); - global_enqueue_handler_func = func; - - Py_RETURN_NONE; -} - -static PyObject* send_bytes(PyObject* self, PyObject* args) { - int64_t port; - const char* buffer; - Py_ssize_t length; - - if (!PyArg_ParseTuple(args, "Ly#", &port, &buffer, &length)) { - return NULL; - } - +// Exported helper called by the shim's send_bytes(). Keeps the +// Dart_PostCObject_DL invocation in this translation unit so the shim doesn't +// need its own copy of dart_api_dl.c. Returns 0 on success, -1 on failure with +// a Python exception set. +EXPORT int dart_bridge_post_to_dart(int64_t port, const char* buffer, size_t length) { if (port == 0) { PyErr_SetString(PyExc_RuntimeError, "Dart port is 0 (invalid)"); - return NULL; + return -1; } // Dart_PostCObject_DL is a function pointer populated by Dart_InitializeApiDL. @@ -102,7 +85,7 @@ static PyObject* send_bytes(PyObject* self, PyObject* args) { if (Dart_PostCObject_DL == NULL) { PyErr_SetString(PyExc_RuntimeError, "Dart API DL not initialized (call DartBridge_InitDartApiDL from Dart first)"); - return NULL; + return -1; } Dart_CObject obj; @@ -113,24 +96,7 @@ static PyObject* send_bytes(PyObject* self, PyObject* args) { if (!Dart_PostCObject_DL(port, &obj)) { PyErr_SetString(PyExc_RuntimeError, "Dart_PostCObject_DL failed"); - return NULL; + return -1; } - - Py_RETURN_TRUE; -} - -static PyMethodDef methods[] = { - {"send_bytes", send_bytes, METH_VARARGS, "Post a bytes payload to a Dart ReceivePort."}, - {"set_enqueue_handler_func", set_enqueue_handler_func, METH_VARARGS, - "Register the Python callable that receives bytes posted from Dart."}, - {NULL, NULL, 0, NULL} -}; - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "dart_bridge", NULL, -1, methods -}; - -PyMODINIT_FUNC PyInit_dart_bridge(void) { - return PyModule_Create(&moduledef); + return 0; } diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c new file mode 100644 index 00000000..b7bda489 --- /dev/null +++ b/src/serious_python_bridge/native/dart_bridge_shim.c @@ -0,0 +1,131 @@ +// Python-callable shim for the dart_bridge module. +// +// This file is the *only* source compiled into the dart_bridge wheel built by +// cibuildwheel. It contains no Dart-callable symbols and no copy of the +// shared `dart_bridge_global_enqueue_handler_func` cell — instead it resolves +// the core's exports (defined in dart_bridge.c, linked into libflet_bridge) +// at PyInit time via dlsym/GetProcAddress. That keeps Dart's view and +// Python's view of the global as the SAME cell on Linux/Windows/Android. +// +// On Apple platforms this same file is also static-linked into the +// serious_python framework alongside dart_bridge.c — the runtime lookup +// then resolves to the symbols statically linked into the host binary +// (dlopen of libflet_bridge is skipped because there's no such file). + +#define PY_SSIZE_T_CLEAN +#define Py_LIMITED_API 0x030c0000 +#include +#include +#include + +#if defined(_WIN32) +#include +#else +#include +#endif + +// Function-pointer + global types resolved at PyInit time. +typedef int (*PostToDartFn)(int64_t port, const char* buffer, size_t length); + +static PyObject** g_handler_slot = NULL; // points at dart_bridge_global_enqueue_handler_func in libflet_bridge +static PostToDartFn g_post_to_dart = NULL; // dart_bridge_post_to_dart in libflet_bridge + +#if defined(_WIN32) +static void* shim_sym_lookup(const char* name) { + // LoadLibraryA returns the existing handle if flet_bridge.dll is already + // loaded by Flutter (single instance, same memory, just bumps refcount). + // The DLL search path includes the executable's directory, where Flutter + // places plugin DLLs. + HMODULE flet = LoadLibraryA("flet_bridge.dll"); + if (!flet) return NULL; + return (void*)GetProcAddress(flet, name); +} +#else +static void* shim_sym_lookup(const char* name) { + // RTLD_DEFAULT searches every library already loaded into the process + // including ones loaded with RTLD_LOCAL by Dart's DynamicLibrary.open. + void* p = dlsym(RTLD_DEFAULT, name); + if (p) return p; + // Not visible globally (Dart loaded libflet_bridge with RTLD_LOCAL). Try + // an explicit RTLD_GLOBAL dlopen so subsequent lookups see it. dlopen of + // an already-loaded library returns the existing handle — single instance, + // same memory, just promoted into the global namespace. +#if defined(__APPLE__) + void* h = dlopen("libflet_bridge.dylib", RTLD_NOW | RTLD_GLOBAL); +#else + void* h = dlopen("libflet_bridge.so", RTLD_NOW | RTLD_GLOBAL); +#endif + if (!h) return NULL; + return dlsym(h, name); +} +#endif + +static PyObject* set_enqueue_handler_func(PyObject* self, PyObject* args) { + PyObject* func; + + if (!PyArg_ParseTuple(args, "O:set_enqueue_handler_func", &func)) { + return NULL; + } + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return NULL; + } + if (!g_handler_slot) { + PyErr_SetString(PyExc_RuntimeError, + "dart_bridge: libflet_bridge symbol not resolved (was the bridge plugin loaded?)"); + return NULL; + } + + Py_XINCREF(func); + Py_XDECREF(*g_handler_slot); + *g_handler_slot = func; + + Py_RETURN_NONE; +} + +static PyObject* send_bytes(PyObject* self, PyObject* args) { + int64_t port; + const char* buffer; + Py_ssize_t length; + + if (!PyArg_ParseTuple(args, "Ly#", &port, &buffer, &length)) { + return NULL; + } + if (!g_post_to_dart) { + PyErr_SetString(PyExc_RuntimeError, + "dart_bridge: libflet_bridge symbol not resolved (was the bridge plugin loaded?)"); + return NULL; + } + if (g_post_to_dart(port, buffer, (size_t)length) != 0) { + // Helper sets the exception. + return NULL; + } + Py_RETURN_TRUE; +} + +static PyMethodDef methods[] = { + {"send_bytes", send_bytes, METH_VARARGS, "Post a bytes payload to a Dart ReceivePort."}, + {"set_enqueue_handler_func", set_enqueue_handler_func, METH_VARARGS, + "Register the Python callable that receives bytes posted from Dart."}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "dart_bridge", NULL, -1, methods +}; + +PyMODINIT_FUNC PyInit_dart_bridge(void) { + // Resolve the libflet_bridge exports we depend on. Surface a clean + // ImportError if the lookup fails — typically means the bridge plugin's + // native library wasn't loaded into the process before Python ran. + g_handler_slot = (PyObject**)shim_sym_lookup("dart_bridge_global_enqueue_handler_func"); + g_post_to_dart = (PostToDartFn)shim_sym_lookup("dart_bridge_post_to_dart"); + if (!g_handler_slot || !g_post_to_dart) { + PyErr_SetString(PyExc_ImportError, + "dart_bridge: failed to resolve libflet_bridge symbols " + "(is serious_python_bridge's native library loaded into the process?)"); + return NULL; + } + return PyModule_Create(&moduledef); +} diff --git a/src/serious_python_bridge/python/setup.py b/src/serious_python_bridge/python/setup.py index 1d061862..623eddea 100644 --- a/src/serious_python_bridge/python/setup.py +++ b/src/serious_python_bridge/python/setup.py @@ -1,20 +1,28 @@ +import sys from setuptools import Extension, setup NATIVE_ROOT = "../native" +extra_link_args = [] +# dlopen/dlsym on Linux live in libdl. macOS rolls them into libSystem. +# Windows uses LoadLibrary/GetProcAddress from kernel32 (implicit). +if sys.platform.startswith("linux"): + extra_link_args.append("-ldl") + setup( ext_modules=[ Extension( "dart_bridge", - sources=[ - f"{NATIVE_ROOT}/dart_bridge.c", - f"{NATIVE_ROOT}/dart_api/dart_api_dl.c", - ], - include_dirs=[NATIVE_ROOT], + # Shim only — the Dart-callable core and its dart_api_dl.c live in + # libflet_bridge (built by the Flutter plugin) and are resolved at + # PyInit time via dlsym / GetProcAddress. + sources=[f"{NATIVE_ROOT}/dart_bridge_shim.c"], # Limited API / abi3: one .so per platform works for any Python - # 3.12+. Keep this in lockstep with Py_LIMITED_API in dart_bridge.c. + # 3.12+. Keep this in lockstep with Py_LIMITED_API in + # dart_bridge_shim.c. define_macros=[("Py_LIMITED_API", "0x030c0000")], py_limited_api=True, + extra_link_args=extra_link_args, ) ], ) From e93461698198d1565534e4c466d72ce1e3c8a8da Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 20:05:16 -0700 Subject: [PATCH 021/114] Fix Windows + add Android + fix Linux ARM64 matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows: Previous python3.lib fix wasn't enough — Python.h still emits `#pragma comment(lib, "python_d.lib")` in Debug builds via pyconfig.h's auto-link, and python-build-standalone doesn't ship a Debug lib. Add `Py_NO_LINK_LIB` compile-time define to suppress the pragma (Python 3.12+). Our explicit target_link_libraries reference to python3.lib (the abi3 stub) is then the only libpython reference. Linux ARM64 matrix: test-bridge-build.yml's test_bridge_example_linux matrix declared python_version in the base but `arch` only via `include:` entries. GitHub Actions doesn't expand the matrix correctly for that shape — only 3 AMD64 jobs ran, no ARM64. Adding `arch: [arm64, amd64]` to the base so it cross-multiplies with python_version (6 cells). ci.yml already had this right. Android bridge_example (new): Added test_bridge_example_android matrix job to test-bridge-build.yml. Mirrors the existing flet_example Android pattern (reactivecircus/android-emulator-runner, x86_64 emulator, API 33). Targets only x86_64 to match the emulator arch — keeps CI fast. Pre-package step downloads the bridge-android-x86_64 artifact (from test_android_build) and drops the cross-compiled dart_bridge.abi3-android-x86_64.so as `dart_bridge.abi3.so` into $SERIOUS_PYTHON_SITE_PACKAGES/x86_64/. serious_python_android's gradle then zips that directory into libpythonsitepackages.so and bundles it in the APK; at runtime Python's import finds the bridge shim via the canonical filename. The shim then dlopens libflet_ bridge.so (already loaded by Dart) to resolve the core symbols — same single-cell architecture as Linux/macOS/Windows. --- .github/workflows/test-bridge-build.yml | 86 +++++++++++++++++++ .../native/CMakeLists.txt | 9 ++ 2 files changed, 95 insertions(+) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index acab8d9d..aa6a6389 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -193,6 +193,7 @@ jobs: fail-fast: false matrix: python_version: ['3.12', '3.13', '3.14'] + arch: [arm64, amd64] include: - arch: arm64 runner: ubuntu-24.04-arm @@ -265,6 +266,91 @@ jobs: --requirements ${{ steps.wheel.outputs.path }} xvfb-run flutter test integration_test -d linux + test_bridge_example_android: + name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) + runs-on: ubuntu-latest + needs: test_android_build + strategy: + fail-fast: false + matrix: + # x86_64 matches the emulator architecture below; only build/install + # for that ABI to keep CI fast. + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Gradle cache + uses: gradle/actions/setup-gradle@v3 + + - name: AVD cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-bridge + + - name: Download Android bridge .so for x86_64 + uses: actions/download-artifact@v4 + with: + name: bridge-android-x86_64 + path: ${{ runner.temp }}/dart_bridge_android + + - name: Inject dart_bridge.abi3.so into bundled site-packages + run: | + # serious_python_android's gradle takes everything from + # SERIOUS_PYTHON_SITE_PACKAGES// and zips it as + # libpythonsitepackages.so, which ends up in the APK. Drop our + # cross-compiled dart_bridge.abi3.so there so Python finds it at + # runtime. The .so name has to be the canonical 'dart_bridge.abi3.so' + # for CPython's import to match. + set -euxo pipefail + ABI=x86_64 + DEST="$SERIOUS_PYTHON_SITE_PACKAGES/$ABI" + mkdir -p "$DEST" + cp "${{ runner.temp }}/dart_bridge_android/dart_bridge.abi3-android-$ABI.so" \ + "$DEST/dart_bridge.abi3.so" + ls -lh "$DEST" + + - name: Setup Android Emulator + Run tests + uses: reactivecircus/android-emulator-runner@v2 + env: + EMULATOR_PORT: 5554 + with: + avd-name: android_emulator + api-level: 33 + target: google_atd + arch: x86_64 + profile: pixel_5 + sdcard-path-or-size: 128M + ram-size: 2048M + disk-size: 4096M + emulator-port: ${{ env.EMULATOR_PORT }} + disable-animations: true + emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 + pre-emulator-launch-script: | + sdkmanager --list_installed + script: | + cd src/serious_python_bridge/example + dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} + flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} + test_bridge_example_windows: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) runs-on: windows-latest diff --git a/src/serious_python_bridge/native/CMakeLists.txt b/src/serious_python_bridge/native/CMakeLists.txt index a018d2a7..4dc6b920 100644 --- a/src/serious_python_bridge/native/CMakeLists.txt +++ b/src/serious_python_bridge/native/CMakeLists.txt @@ -49,3 +49,12 @@ set_target_properties(flet_bridge PROPERTIES ) target_compile_definitions(flet_bridge PRIVATE DART_SHARED_LIB) + +if(WIN32) + # Python's pyconfig.h emits `#pragma comment(lib, "pythonXY_d.lib")` in + # Debug builds, which makes MSVC auto-link the Debug variant of libpython + # even though we explicitly linked python3.lib above. python-build-standalone + # doesn't ship a Debug lib, so the link fails (LNK1104). Py_NO_LINK_LIB + # suppresses that pragma (Python 3.12+). + target_compile_definitions(flet_bridge PRIVATE Py_NO_LINK_LIB) +endif() From 58059a3e8f03c9e15cd8b79d7139c6e5d3b7e6a5 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 20:19:42 -0700 Subject: [PATCH 022/114] Add missing Android upload-artifact + Windows shim diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - test-bridge-build.yml's test_android_build was missing the actions/upload-artifact step, so test_bridge_example_android's download failed (Artifact not found). Adding the upload mirroring test_wheel_build. - Add stderr diagnostics to dart_bridge_shim's Windows code path: log LoadLibraryA error code if flet_bridge.dll lookup fails, and log GetProcAddress error if a symbol isn't found. The macOS+Linux shim split works, but Windows is still failing with a handshake timeout — instrumented to figure out whether the DLL is on the search path or symbols are exported under different names. --- .github/workflows/test-bridge-build.yml | 7 +++++++ .../native/dart_bridge_shim.c | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index aa6a6389..39776231 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -119,6 +119,13 @@ jobs: ls -lh dart_bridge.abi3-android-*.so file dart_bridge.abi3-android-*.so + - name: Upload .so artifact + uses: actions/upload-artifact@v4 + with: + name: bridge-android-${{ matrix.abi }} + path: dart_bridge.abi3-android-*.so + if-no-files-found: error + test_bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) runs-on: macos-latest diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c index b7bda489..620c604d 100644 --- a/src/serious_python_bridge/native/dart_bridge_shim.c +++ b/src/serious_python_bridge/native/dart_bridge_shim.c @@ -37,8 +37,19 @@ static void* shim_sym_lookup(const char* name) { // The DLL search path includes the executable's directory, where Flutter // places plugin DLLs. HMODULE flet = LoadLibraryA("flet_bridge.dll"); - if (!flet) return NULL; - return (void*)GetProcAddress(flet, name); + if (!flet) { + DWORD err = GetLastError(); + fprintf(stderr, "[dart_bridge_shim] LoadLibraryA(flet_bridge.dll) failed, err=%lu\n", (unsigned long)err); + fflush(stderr); + return NULL; + } + void* p = (void*)GetProcAddress(flet, name); + if (!p) { + DWORD err = GetLastError(); + fprintf(stderr, "[dart_bridge_shim] GetProcAddress(%s) failed, err=%lu\n", name, (unsigned long)err); + fflush(stderr); + } + return p; } #else static void* shim_sym_lookup(const char* name) { From 43aab91ae3cb83579c2f004c99bd5959b78b0533 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 20:35:05 -0700 Subject: [PATCH 023/114] Windows shim: search exe dir for flet_bridge.dll when default path fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When dart_bridge.pyd (the Python shim, loaded into the embedded Python by `import dart_bridge`) does `LoadLibraryA("flet_bridge.dll")`, Windows' default DLL search starts from the calling module's directory — which is `runner/Debug/site-packages/`, NOT `runner/Debug/` where Flutter places plugin DLLs. So LoadLibrary silently returns NULL, the shim raises ImportError at PyInit time, and Dart's handshake retry loop times out at 30s. Fix: shim_find_flet_bridge_module() now tries three strategies in order: 1. GetModuleHandleA("flet_bridge.dll") — picks up a copy already loaded by Dart's DynamicLibrary.open (no I/O). 2. LoadLibraryA("flet_bridge.dll") — default search path. 3. Construct the absolute path next to the running .exe (via GetModuleFileNameA(NULL)) and LoadLibrary that. This is what Flutter's plugin loader uses to locate flet_bridge.dll. Linux/macOS unaffected (dlopen + dlsym pathway unchanged). --- .../native/dart_bridge_shim.c | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c index 620c604d..0438a2ec 100644 --- a/src/serious_python_bridge/native/dart_bridge_shim.c +++ b/src/serious_python_bridge/native/dart_bridge_shim.c @@ -31,15 +31,42 @@ static PyObject** g_handler_slot = NULL; // points at dart_bridge_global_enque static PostToDartFn g_post_to_dart = NULL; // dart_bridge_post_to_dart in libflet_bridge #if defined(_WIN32) +#include + +static HMODULE shim_find_flet_bridge_module(void) { + // 1. GetModuleHandleA looks at modules already loaded into the process + // (e.g. by Dart's DynamicLibrary.open). Returns NULL without loading + // anything if not already mapped. + HMODULE flet = GetModuleHandleA("flet_bridge.dll"); + if (flet) return flet; + + // 2. LoadLibraryA with default DLL search. Reaches the calling module's + // directory (dart_bridge.pyd's dir) + system paths + PATH. + flet = LoadLibraryA("flet_bridge.dll"); + if (flet) return flet; + + // 3. Construct an absolute path next to the running .exe (where Flutter + // places plugin DLLs) and try that. + char exePath[MAX_PATH]; + DWORD len = GetModuleFileNameA(NULL, exePath, MAX_PATH); + if (len == 0 || len >= MAX_PATH) return NULL; + for (DWORD i = len; i > 0; i--) { + if (exePath[i - 1] == '\\' || exePath[i - 1] == '/') { + exePath[i] = '\0'; + break; + } + } + if (strlen(exePath) + strlen("flet_bridge.dll") + 1 >= MAX_PATH) return NULL; + strcat(exePath, "flet_bridge.dll"); + return LoadLibraryA(exePath); +} + static void* shim_sym_lookup(const char* name) { - // LoadLibraryA returns the existing handle if flet_bridge.dll is already - // loaded by Flutter (single instance, same memory, just bumps refcount). - // The DLL search path includes the executable's directory, where Flutter - // places plugin DLLs. - HMODULE flet = LoadLibraryA("flet_bridge.dll"); + HMODULE flet = shim_find_flet_bridge_module(); if (!flet) { DWORD err = GetLastError(); - fprintf(stderr, "[dart_bridge_shim] LoadLibraryA(flet_bridge.dll) failed, err=%lu\n", (unsigned long)err); + fprintf(stderr, "[dart_bridge_shim] could not locate flet_bridge.dll (last error %lu)\n", + (unsigned long)err); fflush(stderr); return NULL; } From 8ed03fa132f7d667efd1a7aa79f7b195eeb31120 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 20:45:16 -0700 Subject: [PATCH 024/114] Windows shim file-log + Android cd-each-line + diagnostics step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows: Python's stderr isn't captured by flutter test on Windows, so fprintf diagnostics in the shim were invisible. Switch to file logging — shim now appends to dart_bridge_shim.log in CWD with every lookup attempt + result. New diagnostics step at end of the windows job (if: failure()) lists the runner/Debug build dir, site-packages contents, and cats the shim log so we can see exactly which lookup strategy failed. Android: Earlier `cd src/serious_python_bridge/example` ran on its own line in the emulator-runner script — each line is a fresh shell, so subsequent `dart run` saw the workspace root (no pubspec.yaml) and failed with "Found no pubspec.yaml file". Switched to flet_example's pattern: cd && command on each line. --- .github/workflows/test-bridge-build.yml | 22 +++++++- .../native/dart_bridge_shim.c | 56 +++++++++++++++---- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 39776231..2a687294 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -354,9 +354,8 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python_bridge/example - dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} - flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} + cd src/serious_python_bridge/example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} + cd src/serious_python_bridge/example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} test_bridge_example_windows: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) @@ -399,3 +398,20 @@ jobs: run: | dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} flutter test integration_test -d windows + + - name: Diagnostics on failure + if: failure() + shell: bash + working-directory: "src/serious_python_bridge/example" + run: | + echo "=== runner/Debug dir ===" + ls -la build/windows/x64/runner/Debug/ || true + echo + echo "=== runner/Debug/site-packages ===" + ls -la build/windows/x64/runner/Debug/site-packages/ || true + echo + echo "=== shim log (if any) ===" + find . -name "dart_bridge_shim.log" -exec echo {} \; -exec cat {} \; || true + echo + echo "=== look for stray flet_bridge.dll / dart_bridge.pyd ===" + find build -name "flet_bridge.dll" -o -name "dart_bridge*.pyd" || true diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c index 0438a2ec..d9066b0f 100644 --- a/src/serious_python_bridge/native/dart_bridge_shim.c +++ b/src/serious_python_bridge/native/dart_bridge_shim.c @@ -18,6 +18,8 @@ #include #include +#include + #if defined(_WIN32) #include #else @@ -33,23 +35,49 @@ static PostToDartFn g_post_to_dart = NULL; // dart_bridge_post_to_dart in libfle #if defined(_WIN32) #include +// Diagnostic log file — Python's stderr is not captured by flutter test on +// Windows, so we tee the shim's progress to a known file the workflow can +// dump after the test fails. Path is in CWD so it lands in the .exe's dir. +static void shim_log(const char* fmt, ...) { + FILE* f = fopen("dart_bridge_shim.log", "a"); + if (!f) return; + va_list ap; + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fclose(f); +} + static HMODULE shim_find_flet_bridge_module(void) { // 1. GetModuleHandleA looks at modules already loaded into the process // (e.g. by Dart's DynamicLibrary.open). Returns NULL without loading // anything if not already mapped. HMODULE flet = GetModuleHandleA("flet_bridge.dll"); - if (flet) return flet; + if (flet) { + shim_log("[shim] GetModuleHandleA(flet_bridge.dll) -> %p\n", (void*)flet); + return flet; + } + shim_log("[shim] GetModuleHandleA(flet_bridge.dll) -> NULL (err=%lu)\n", + (unsigned long)GetLastError()); // 2. LoadLibraryA with default DLL search. Reaches the calling module's // directory (dart_bridge.pyd's dir) + system paths + PATH. flet = LoadLibraryA("flet_bridge.dll"); - if (flet) return flet; + if (flet) { + shim_log("[shim] LoadLibraryA(flet_bridge.dll) -> %p\n", (void*)flet); + return flet; + } + shim_log("[shim] LoadLibraryA(flet_bridge.dll) -> NULL (err=%lu)\n", + (unsigned long)GetLastError()); // 3. Construct an absolute path next to the running .exe (where Flutter // places plugin DLLs) and try that. char exePath[MAX_PATH]; DWORD len = GetModuleFileNameA(NULL, exePath, MAX_PATH); - if (len == 0 || len >= MAX_PATH) return NULL; + if (len == 0 || len >= MAX_PATH) { + shim_log("[shim] GetModuleFileNameA failed (len=%lu)\n", (unsigned long)len); + return NULL; + } for (DWORD i = len; i > 0; i--) { if (exePath[i - 1] == '\\' || exePath[i - 1] == '/') { exePath[i] = '\0'; @@ -58,23 +86,29 @@ static HMODULE shim_find_flet_bridge_module(void) { } if (strlen(exePath) + strlen("flet_bridge.dll") + 1 >= MAX_PATH) return NULL; strcat(exePath, "flet_bridge.dll"); - return LoadLibraryA(exePath); + shim_log("[shim] trying absolute path: %s\n", exePath); + flet = LoadLibraryA(exePath); + if (!flet) { + shim_log("[shim] LoadLibraryA(absolute) -> NULL (err=%lu)\n", + (unsigned long)GetLastError()); + } else { + shim_log("[shim] LoadLibraryA(absolute) -> %p\n", (void*)flet); + } + return flet; } static void* shim_sym_lookup(const char* name) { HMODULE flet = shim_find_flet_bridge_module(); if (!flet) { - DWORD err = GetLastError(); - fprintf(stderr, "[dart_bridge_shim] could not locate flet_bridge.dll (last error %lu)\n", - (unsigned long)err); - fflush(stderr); + shim_log("[shim] flet_bridge.dll not found anywhere\n"); return NULL; } void* p = (void*)GetProcAddress(flet, name); if (!p) { - DWORD err = GetLastError(); - fprintf(stderr, "[dart_bridge_shim] GetProcAddress(%s) failed, err=%lu\n", name, (unsigned long)err); - fflush(stderr); + shim_log("[shim] GetProcAddress(%s) -> NULL (err=%lu)\n", name, + (unsigned long)GetLastError()); + } else { + shim_log("[shim] GetProcAddress(%s) -> %p\n", name, p); } return p; } From e862690bd7fe586d6ab18fb9f425c005af159b66 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 20:58:23 -0700 Subject: [PATCH 025/114] Fix Windows bundling (python3.dll) + Android tarball (mobile-forge + flatten) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows — the abi3 wheel dart_bridge.pyd imports python3.dll, but serious_python_windows only bundles python3_d.dll in Debug builds. That made the .pyd silently fail to load (no shim log written, no ImportError surfaced through Python's stderr which flutter test doesn't capture on Windows). Found via the new diagnostics step which dumped runner/Debug/'s contents. Fix: bridge plugin's windows/CMakeLists.txt downloads its own copy of python-windows-for-dart-.zip (the same flet-dev/python-build artifact serious_python_windows uses), extracts just python3.dll, and adds it to serious_python_bridge_bundled_libraries. Flutter copies it next to the .exe; Windows' DLL loader then resolves dart_bridge.pyd's python3.dll dependency. Android — gradle was using python-android-dart-*-.tar.gz which only ships runtime libs (no headers, no libpython3.so), and its include patterns matched files at the tarball's root rather than at the install/android//python-/ nesting. Fix: switched bridge plugin's android/build.gradle to the python-android-mobile-forge-.tar.gz tarball (one download covers all four ABIs with both headers + libpython*.so), expanded include patterns to match the nested layout, and added an eachFile rule to flatten install/android//python-/ out so the staged files land at python-dist//{include,lib}/... where android/CMakeLists.txt expects them. --- .../android/build.gradle | 43 ++++++++++++------- .../windows/CMakeLists.txt | 28 ++++++++++++ 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/serious_python_bridge/android/build.gradle b/src/serious_python_bridge/android/build.gradle index 55d2f356..76ea4ea4 100644 --- a/src/serious_python_bridge/android/build.gradle +++ b/src/serious_python_bridge/android/build.gradle @@ -78,27 +78,40 @@ def pythonCacheDir = new File( // build time. def pythonStagingRoot = new File(buildDir, 'python-dist') +// Single tarball contains all 4 Android ABIs' Python installs WITH headers +// and the libpython3.so abi3 stub. The python-android-dart variant is just +// runtime libs (no headers), which can't satisfy dart_bridge.c's +// `#include ` at build time. +def archiveName = "python-android-mobile-forge-${python_version}.tar.gz" +def archiveCachePath = new File(pythonCacheDir, archiveName) + +tasks.register("downloadPythonDist", Download) { + src "https://github.com/flet-dev/python-build/releases/download/v${python_version}/${archiveName}" + dest archiveCachePath + onlyIfModified true + useETag "all" + tempAndMove true + doFirst { dest.parentFile.mkdirs() } +} + def prepareTasks = [] android.defaultConfig.ndk.abiFilters.each { abi -> - def archiveName = "python-android-dart-${python_version}-${abi}.tar.gz" def stagingDir = new File(pythonStagingRoot, abi) - tasks.register("downloadPythonDist_${abi}", Download) { - src "https://github.com/flet-dev/python-build/releases/download/v${python_version}/${archiveName}" - dest new File(pythonCacheDir, archiveName) - onlyIfModified true - useETag "all" - tempAndMove true - doFirst { dest.parentFile.mkdirs() } - } - tasks.register("extractPythonDist_${abi}", Copy) { - dependsOn "downloadPythonDist_${abi}" - from tarTree(tasks.named("downloadPythonDist_${abi}").get().dest) + dependsOn "downloadPythonDist" + from tarTree(archiveCachePath) into stagingDir - // Headers + libpython only; everything else is dead weight for our - // build-time link (serious_python_android ships the runtime copy). - include "include/**", "lib/libpython*.so" + // mobile-forge layout: install/android//python-/... + include "install/android/${abi}/python-${python_version}.*/include/**" + include "install/android/${abi}/python-${python_version}.*/lib/libpython*.so" + // Flatten the install/android//python-/ prefix so the + // result is python-dist//{include,lib}/... — matches what + // android/CMakeLists.txt expects. + eachFile { fcd -> + fcd.path = fcd.path.replaceAll("^install/android/[^/]+/python-[^/]+/", "") + } + includeEmptyDirs = false } prepareTasks.add("extractPythonDist_${abi}") diff --git a/src/serious_python_bridge/windows/CMakeLists.txt b/src/serious_python_bridge/windows/CMakeLists.txt index 80697a9a..c66658dc 100644 --- a/src/serious_python_bridge/windows/CMakeLists.txt +++ b/src/serious_python_bridge/windows/CMakeLists.txt @@ -7,9 +7,37 @@ cmake_policy(VERSION 3.15...3.25) add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") +# python3.dll (the abi3 stable-ABI loader) is what cibuildwheel-built abi3 +# wheels — including the dart_bridge.pyd dropped into bundled site-packages — +# import. serious_python_windows only bundles python3_d.dll in Debug builds, +# so Python's import of dart_bridge.pyd fails before PyInit can run with +# "ImportError: DLL load failed". Pull our own python3.dll from the same +# python-windows-for-dart tarball serious_python_windows uses and add it to +# the plugin's bundled_libraries list. +if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) + set(PYTHON_VERSION "$ENV{SERIOUS_PYTHON_VERSION}") +else() + set(PYTHON_VERSION "3.14") +endif() +set(PYTHON_DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/python_dist) +set(PYTHON_DLL_PATH "${PYTHON_DOWNLOAD_DIR}/python3.dll") +if(NOT EXISTS "${PYTHON_DLL_PATH}") + set(PYTHON_ZIP "${CMAKE_BINARY_DIR}/python-windows-for-dart-${PYTHON_VERSION}.zip") + if(NOT EXISTS "${PYTHON_ZIP}") + file(DOWNLOAD + "https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-windows-for-dart-${PYTHON_VERSION}.zip" + "${PYTHON_ZIP}") + endif() + file(MAKE_DIRECTORY "${PYTHON_DOWNLOAD_DIR}") + file(ARCHIVE_EXTRACT INPUT "${PYTHON_ZIP}" + DESTINATION "${PYTHON_DOWNLOAD_DIR}" + PATTERNS "python3.dll") +endif() + # Flutter picks up bundled libraries via this variable and copies the file # alongside the app binary; Dart resolves it via DynamicLibrary.open. set(serious_python_bridge_bundled_libraries $ + "${PYTHON_DLL_PATH}" PARENT_SCOPE ) From 9abcf40ed96ff24c9c1247d6321a90c11385e130 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 21:11:05 -0700 Subject: [PATCH 026/114] Windows shim: log to %TEMP%, add PyInit-entry marker, diagnostics step extras MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous shim_log used a relative path that landed wherever Python's cwd was at PyInit time — Python on Windows runs from app/ extraction dir, not from src/serious_python_bridge/example/ where the diagnostics step was searching. Switched to GetTempPathA-based absolute path. Added a shim_log_init() call at the very top of PyInit_dart_bridge. If the log is missing entirely from %TEMP%, PyInit never ran (the .pyd failed to load before module init). If the log has "PyInit entered" but no further lookups, the issue is elsewhere. Diagnostics step now cats $TEMP/$RUNNER_TEMP for the shim log and also runs dumpbin /dependents against the .pyd to confirm its import requirements vs what's in runner/Debug/. --- .github/workflows/test-bridge-build.yml | 11 ++++++-- .../native/dart_bridge_shim.c | 27 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 2a687294..03e88540 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -410,8 +410,15 @@ jobs: echo "=== runner/Debug/site-packages ===" ls -la build/windows/x64/runner/Debug/site-packages/ || true echo - echo "=== shim log (if any) ===" - find . -name "dart_bridge_shim.log" -exec echo {} \; -exec cat {} \; || true + echo "=== shim log at %TEMP%\\dart_bridge_shim.log ===" + cat "$TEMP/dart_bridge_shim.log" 2>/dev/null || cat "$RUNNER_TEMP/dart_bridge_shim.log" 2>/dev/null || echo "(log not found)" echo echo "=== look for stray flet_bridge.dll / dart_bridge.pyd ===" find build -name "flet_bridge.dll" -o -name "dart_bridge*.pyd" || true + echo + echo "=== run dart_bridge.pyd dependency check via dumpbin ===" + # Verify what python.exe sees when trying to load the .pyd. + DUMPBIN=$(find "/c/Program Files" -name "dumpbin.exe" 2>/dev/null | head -n1) + if [ -n "$DUMPBIN" ]; then + "$DUMPBIN" //dependents build/windows/x64/runner/Debug/site-packages/dart_bridge.pyd | head -30 || true + fi diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c index d9066b0f..49c59ca5 100644 --- a/src/serious_python_bridge/native/dart_bridge_shim.c +++ b/src/serious_python_bridge/native/dart_bridge_shim.c @@ -36,10 +36,14 @@ static PostToDartFn g_post_to_dart = NULL; // dart_bridge_post_to_dart in libfle #include // Diagnostic log file — Python's stderr is not captured by flutter test on -// Windows, so we tee the shim's progress to a known file the workflow can -// dump after the test fails. Path is in CWD so it lands in the .exe's dir. +// Windows, so we tee the shim's progress to a known absolute path the +// workflow can dump after the test fails. static void shim_log(const char* fmt, ...) { - FILE* f = fopen("dart_bridge_shim.log", "a"); + char path[MAX_PATH]; + DWORD n = GetTempPathA(MAX_PATH, path); + if (n == 0 || n + 25 > MAX_PATH) return; + strcat(path, "dart_bridge_shim.log"); + FILE* f = fopen(path, "a"); if (!f) return; va_list ap; va_start(ap, fmt); @@ -48,6 +52,20 @@ static void shim_log(const char* fmt, ...) { fclose(f); } +// Marker call so we can detect whether PyInit ran at all (helps distinguish +// "PyInit ran but flet_bridge.dll lookup failed" from "PyInit never ran +// because the .pyd failed to load"). +static void shim_log_init(const char* phase) { + char path[MAX_PATH]; + DWORD n = GetTempPathA(MAX_PATH, path); + if (n == 0 || n + 25 > MAX_PATH) return; + strcat(path, "dart_bridge_shim.log"); + FILE* f = fopen(path, "a"); + if (!f) return; + fprintf(f, "[shim] === %s ===\n", phase); + fclose(f); +} + static HMODULE shim_find_flet_bridge_module(void) { // 1. GetModuleHandleA looks at modules already loaded into the process // (e.g. by Dart's DynamicLibrary.open). Returns NULL without loading @@ -188,6 +206,9 @@ static struct PyModuleDef moduledef = { }; PyMODINIT_FUNC PyInit_dart_bridge(void) { +#if defined(_WIN32) + shim_log_init("PyInit_dart_bridge entered"); +#endif // Resolve the libflet_bridge exports we depend on. Surface a clean // ImportError if the lookup fails — typically means the bridge plugin's // native library wasn't loaded into the process before Python ran. From 4d0705159d555a8e4dd0a3c08aa4dc81d95f3851 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 8 Jun 2026 21:24:26 -0700 Subject: [PATCH 027/114] Windows shim log goes next to .exe + direct import test in diagnostics Two changes to find why PyInit_dart_bridge isn't running on Windows: 1. shim_log writes to a path constructed from GetModuleFileNameA(NULL) (alongside the running .exe in runner/Debug/) instead of GetTempPathA. The latter can resolve differently between Python's embedded environment and the diagnostics shell's $TEMP, so even if the shim was logging we'd miss it. 2. Diagnostics step now runs a direct `python -c "import dart_bridge"` against the bundled Python in runner/Debug/ to surface the actual ImportError that Python sees when loading dart_bridge.pyd. If that succeeds, the .pyd loads and the issue is elsewhere; if it fails, the error message tells us exactly which dependency is missing or which symbol clash trips the loader. --- .github/workflows/test-bridge-build.yml | 26 +++++++++------- .../native/dart_bridge_shim.c | 30 ++++++++++++++----- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 03e88540..81576e8e 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -404,21 +404,25 @@ jobs: shell: bash working-directory: "src/serious_python_bridge/example" run: | + DBG_DIR=build/windows/x64/runner/Debug echo "=== runner/Debug dir ===" - ls -la build/windows/x64/runner/Debug/ || true + ls -la $DBG_DIR/ || true echo echo "=== runner/Debug/site-packages ===" - ls -la build/windows/x64/runner/Debug/site-packages/ || true + ls -la $DBG_DIR/site-packages/ || true echo - echo "=== shim log at %TEMP%\\dart_bridge_shim.log ===" - cat "$TEMP/dart_bridge_shim.log" 2>/dev/null || cat "$RUNNER_TEMP/dart_bridge_shim.log" 2>/dev/null || echo "(log not found)" + echo "=== shim log next to .exe ===" + cat $DBG_DIR/dart_bridge_shim.log 2>/dev/null || echo "(log not found)" + echo + echo "=== direct import test (catches the actual ImportError) ===" + # Try to import dart_bridge using the bundled Python so we can see + # the actual error. Python search paths the bundle uses. + PY_BUNDLED=$(find $DBG_DIR -maxdepth 1 -name "python.exe" -o -name "python3*.exe" 2>/dev/null | head -n1) + if [ -z "$PY_BUNDLED" ]; then + echo "(no python.exe in $DBG_DIR — trying system python)" + PY_BUNDLED=python + fi + (cd $DBG_DIR && PYTHONPATH="site-packages;." "$PY_BUNDLED" -c "import sys; print('sys.path:', sys.path); import dart_bridge; print('imported OK:', dart_bridge)") 2>&1 || true echo echo "=== look for stray flet_bridge.dll / dart_bridge.pyd ===" find build -name "flet_bridge.dll" -o -name "dart_bridge*.pyd" || true - echo - echo "=== run dart_bridge.pyd dependency check via dumpbin ===" - # Verify what python.exe sees when trying to load the .pyd. - DUMPBIN=$(find "/c/Program Files" -name "dumpbin.exe" 2>/dev/null | head -n1) - if [ -n "$DUMPBIN" ]; then - "$DUMPBIN" //dependents build/windows/x64/runner/Debug/site-packages/dart_bridge.pyd | head -30 || true - fi diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c index 49c59ca5..8ac720cc 100644 --- a/src/serious_python_bridge/native/dart_bridge_shim.c +++ b/src/serious_python_bridge/native/dart_bridge_shim.c @@ -37,12 +37,29 @@ static PostToDartFn g_post_to_dart = NULL; // dart_bridge_post_to_dart in libfle // Diagnostic log file — Python's stderr is not captured by flutter test on // Windows, so we tee the shim's progress to a known absolute path the -// workflow can dump after the test fails. +// workflow can dump after the test fails. We write next to the running +// .exe (runner/Debug/) since GetTempPathA's return value varies depending +// on how the embedded Python's environment is set up. +static void shim_log_path(char* out) { + DWORD n = GetModuleFileNameA(NULL, out, MAX_PATH); + if (n == 0 || n >= MAX_PATH) { out[0] = '\0'; return; } + for (DWORD i = n; i > 0; i--) { + if (out[i - 1] == '\\' || out[i - 1] == '/') { + out[i] = '\0'; + break; + } + } + if (strlen(out) + strlen("dart_bridge_shim.log") + 1 >= MAX_PATH) { + out[0] = '\0'; + return; + } + strcat(out, "dart_bridge_shim.log"); +} + static void shim_log(const char* fmt, ...) { char path[MAX_PATH]; - DWORD n = GetTempPathA(MAX_PATH, path); - if (n == 0 || n + 25 > MAX_PATH) return; - strcat(path, "dart_bridge_shim.log"); + shim_log_path(path); + if (!path[0]) return; FILE* f = fopen(path, "a"); if (!f) return; va_list ap; @@ -57,9 +74,8 @@ static void shim_log(const char* fmt, ...) { // because the .pyd failed to load"). static void shim_log_init(const char* phase) { char path[MAX_PATH]; - DWORD n = GetTempPathA(MAX_PATH, path); - if (n == 0 || n + 25 > MAX_PATH) return; - strcat(path, "dart_bridge_shim.log"); + shim_log_path(path); + if (!path[0]) return; FILE* f = fopen(path, "a"); if (!f) return; fprintf(f, "[shim] === %s ===\n", phase); From c0901ee717bcf42055367a66b447e3ebfdddd7e2 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 06:05:44 -0700 Subject: [PATCH 028/114] Windows: use --profile to match abi3 wheel; Android: log extractPythonDist Windows: Flutter's --debug config makes serious_python_windows bundle the Debug python3XY_d.dll while the cibuildwheel-built abi3 dart_bridge wheel imports python3.dll, which forwards to the Release python3XY.dll. Use --profile (Release Python) on the integration test so the embedded interpreter matches the wheel's link target. Android: extractPythonDist_ still ends without libpython3.so on disk. Print the tar path, staging dir, and final tree contents so we can see whether the task is even running and what include patterns actually match. --- .github/workflows/test-bridge-build.yml | 9 ++++++++- src/serious_python_bridge/android/build.gradle | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 81576e8e..490b322a 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -395,9 +395,16 @@ jobs: - name: Package + run integration test working-directory: "src/serious_python_bridge/example" + # --profile (vs default --debug) is essential on Windows: serious_python_ + # windows links/bundles the Debug python3XY_d.dll suffix only on Debug + # configs, and the cibuildwheel-built abi3 wheel's python3.dll stub + # forwards to the Release python3XY.dll. With --debug we'd need both + # python3XY.dll AND python3XY_d.dll bundled, plus python3.dll AND + # python3_d.dll — fragile. Profile uses Release Python on the embed + # side which matches the abi3 wheel. run: | dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} - flutter test integration_test -d windows + flutter test integration_test -d windows --profile - name: Diagnostics on failure if: failure() diff --git a/src/serious_python_bridge/android/build.gradle b/src/serious_python_bridge/android/build.gradle index 76ea4ea4..2ab6e83e 100644 --- a/src/serious_python_bridge/android/build.gradle +++ b/src/serious_python_bridge/android/build.gradle @@ -112,6 +112,22 @@ android.defaultConfig.ndk.abiFilters.each { abi -> fcd.path = fcd.path.replaceAll("^install/android/[^/]+/python-[^/]+/", "") } includeEmptyDirs = false + + doFirst { + println "[serious_python_bridge] extractPythonDist_${abi}: staging to ${stagingDir}" + println "[serious_python_bridge] tar: ${archiveCachePath} (exists=${archiveCachePath.exists()})" + } + doLast { + def libpython = new File(stagingDir, "lib/libpython3.so") + def header = new File(stagingDir, "include/python${python_version}/Python.h") + println "[serious_python_bridge] extractPythonDist_${abi} done" + println "[serious_python_bridge] ${libpython}: exists=${libpython.exists()}" + println "[serious_python_bridge] ${header}: exists=${header.exists()}" + if (!libpython.exists() || !header.exists()) { + println "[serious_python_bridge] STAGED CONTENTS:" + stagingDir.eachFileRecurse { f -> println " ${f}" } + } + } } prepareTasks.add("extractPythonDist_${abi}") From dd7b7295e5fd932ba0467d78d768f1fb41ae1bca Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 06:27:15 -0700 Subject: [PATCH 029/114] Windows: always ship Release Python; Android: thread PYTHON_DIST_DIR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows: drop the $:_d> generator expressions in serious_python_windows so the plugin always links and bundles Release pythonXY.dll / python3.dll, regardless of Flutter's build config. Add Py_NO_LINK_LIB to the plugin target so pyconfig.h's auto-link pragma doesn't pull in pythonXY_d.lib in Debug Flutter builds. The cibuildwheel- built abi3 dart_bridge wheel (and any future C-extension wheel piped through `package_command.dart --bridge`) is Release-ABI; mixed Debug serious_python_windows + Release wheel was the only configuration that ever failed the bridge example. Release CRT is already shipped unconditionally next to the .exe, so the wheel's CRT dependency is satisfied in Debug Flutter builds too. Side effect: removes the `flutter test --profile` workaround from the bridge example Windows job — default Debug `flutter test` now matches the abi3 wheel. Android: the gradle preparePythonDist task stages headers + libpython3.so into ${buildDir}/python-dist/, where buildDir is the *consumer module's* build dir (e.g. example/build/serious_python_bridge/), not the bridge plugin's source tree. android/CMakeLists.txt was hardcoded to ${CMAKE_CURRENT_SOURCE_DIR}/build/python-dist/ (plugin-source- relative) — never the same path. Thread the actual staging root from gradle to CMake via -DPYTHON_DIST_DIR. --- .github/workflows/test-bridge-build.yml | 9 +------- .../android/CMakeLists.txt | 23 +++++++++++-------- .../android/build.gradle | 7 +++++- .../windows/CMakeLists.txt | 20 ++++++++++++---- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 490b322a..81576e8e 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -395,16 +395,9 @@ jobs: - name: Package + run integration test working-directory: "src/serious_python_bridge/example" - # --profile (vs default --debug) is essential on Windows: serious_python_ - # windows links/bundles the Debug python3XY_d.dll suffix only on Debug - # configs, and the cibuildwheel-built abi3 wheel's python3.dll stub - # forwards to the Release python3XY.dll. With --debug we'd need both - # python3XY.dll AND python3XY_d.dll bundled, plus python3.dll AND - # python3_d.dll — fragile. Profile uses Release Python on the embed - # side which matches the abi3 wheel. run: | dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} - flutter test integration_test -d windows --profile + flutter test integration_test -d windows - name: Diagnostics on failure if: failure() diff --git a/src/serious_python_bridge/android/CMakeLists.txt b/src/serious_python_bridge/android/CMakeLists.txt index 11991281..682fdc83 100644 --- a/src/serious_python_bridge/android/CMakeLists.txt +++ b/src/serious_python_bridge/android/CMakeLists.txt @@ -3,15 +3,20 @@ cmake_minimum_required(VERSION 3.10) set(PROJECT_NAME "serious_python_bridge") project(${PROJECT_NAME} LANGUAGES C) -# Python headers + libpython3.so come from the python-android-dart tarball -# that build.gradle's preparePythonDist task extracted into -# build/python-dist/${ANDROID_ABI}/. We link against libpython at build time -# so Android's strict dynamic linker accepts the .so on load; at runtime the -# linker resolves libpython3.so against the copy serious_python_android -# already shipped in the same jniLibs/${ANDROID_ABI}/ directory. -set(PYTHON_DIST_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build/python-dist/${ANDROID_ABI}") -set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS "${PYTHON_DIST_DIR}/include/python${PYTHON_VERSION}") -set(FLET_BRIDGE_PYTHON_LIBRARIES "${PYTHON_DIST_DIR}/lib/libpython3.so") +# Python headers + libpython3.so come from the python-android-mobile-forge +# tarball that build.gradle's preparePythonDist task extracts. The gradle +# script passes the staging root via -DPYTHON_DIST_DIR (set to the gradle +# module's buildDir/python-dist — which lives under the *consumer's* build +# tree, NOT the bridge plugin's source dir). We link against libpython at +# build time so Android's strict dynamic linker accepts the .so on load; at +# runtime the linker resolves libpython3.so against the copy +# serious_python_android already shipped in the same jniLibs/${ANDROID_ABI}/. +if(NOT DEFINED PYTHON_DIST_DIR) + message(FATAL_ERROR "PYTHON_DIST_DIR not set — build.gradle must pass it via -DPYTHON_DIST_DIR=") +endif() +set(PYTHON_ABI_DIR "${PYTHON_DIST_DIR}/${ANDROID_ABI}") +set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS "${PYTHON_ABI_DIR}/include/python${PYTHON_VERSION}") +set(FLET_BRIDGE_PYTHON_LIBRARIES "${PYTHON_ABI_DIR}/lib/libpython3.so") add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") diff --git a/src/serious_python_bridge/android/build.gradle b/src/serious_python_bridge/android/build.gradle index 2ab6e83e..addb07a1 100644 --- a/src/serious_python_bridge/android/build.gradle +++ b/src/serious_python_bridge/android/build.gradle @@ -57,7 +57,12 @@ android { externalNativeBuild { cmake { - arguments "-DPYTHON_VERSION=${python_version}" + // PYTHON_DIST_DIR is read by android/CMakeLists.txt — must + // match the pythonStagingRoot the extract task writes to + // (which is `buildDir/python-dist`, where buildDir is the + // consumer module's gradle build dir — NOT plugin source). + arguments "-DPYTHON_VERSION=${python_version}", + "-DPYTHON_DIST_DIR=${pythonStagingRoot}" } } } diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index 53910244..4df18ae3 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -68,17 +68,29 @@ include_directories( target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) +# Always link/bundle the Release Python regardless of Flutter's build config. +# Reason: Python C extension wheels (including the cibuildwheel-built abi3 +# dart_bridge shim downloaded by `package_command.dart --bridge`) are compiled +# against Release CPython and reference Release python3.dll / pythonXY.dll. A +# Debug Flutter build that bundled pythonXY_d.dll couldn't load those wheels. +# python-build-standalone also doesn't ship a Debug variant in the same shape, +# so a single Release Python is the consistent ABI target. +# +# Py_NO_LINK_LIB (set on the plugin target) suppresses pyconfig.h's +# `#pragma comment(lib, "pythonXY_d.lib")` that fires in Debug builds, so the +# explicit link to pythonXY.lib below is honored. target_link_libraries(${PLUGIN_NAME} PRIVATE - "${PYTHON_PACKAGE}/libs/python${PYTHON_VERSION_NODOT}$<$:_d>.lib" + "${PYTHON_PACKAGE}/libs/python${PYTHON_VERSION_NODOT}.lib" ) +target_compile_definitions(${PLUGIN_NAME} PRIVATE Py_NO_LINK_LIB) # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. string(REPLACE "\\" "/" SERIOUS_PYTHON_WINDIR "$ENV{WINDIR}") set(serious_python_windows_bundled_libraries - "${PYTHON_PACKAGE}/python${PYTHON_VERSION_NODOT}$<$:_d>.dll" - "${PYTHON_PACKAGE}/python3$<$:_d>.dll" + "${PYTHON_PACKAGE}/python${PYTHON_VERSION_NODOT}.dll" + "${PYTHON_PACKAGE}/python3.dll" "${SERIOUS_PYTHON_WINDIR}/System32/msvcp140.dll" "${SERIOUS_PYTHON_WINDIR}/System32/vcruntime140.dll" "${SERIOUS_PYTHON_WINDIR}/System32/vcruntime140_1.dll" @@ -96,7 +108,7 @@ add_custom_command(TARGET CopyPythonDLLs POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYTHON_PACKAGE}/DLLs" "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs" - COMMAND IF \"$<$:release>\" == \"release\" DEL \"${CMAKE_BINARY_DIR}/runner/Release/DLLs\\*_d.*\" /S /Q + COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*_d.*\" /S /Q COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*.ico\" /S /Q COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*.cat\" /S /Q COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\tcl86t.dll\" /Q From af1a620d81de1d0b4885164fba5cc4a48bdbc7c3 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 06:38:05 -0700 Subject: [PATCH 030/114] Windows: /NODEFAULTLIB:pythonXY_d.lib; Android: hoist pythonStagingRoot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows: Py_NO_LINK_LIB is only honored by Python 3.14+'s pyconfig.h — 3.12 and 3.13 don't guard the `pragma comment(lib, "pythonXY_d.lib")` auto-link directive with that macro, so the Debug pragma fired regardless and the link failed with LNK1104. Add `/NODEFAULTLIB:pythonXY_d.lib` at link time to both serious_python_windows_plugin and flet_bridge — works across every supported Python version. Keep the Py_NO_LINK_LIB define too, for 3.14+ cleanliness. Android: gradle errored with "unknown property 'pythonStagingRoot'" because the variable was defined after the `android {}` block but referenced inside it (in the cmake.arguments expression). Hoist the definition above `android {}`. --- src/serious_python_bridge/android/build.gradle | 8 ++++++-- src/serious_python_bridge/native/CMakeLists.txt | 9 ++++++++- src/serious_python_windows/windows/CMakeLists.txt | 12 +++++++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/serious_python_bridge/android/build.gradle b/src/serious_python_bridge/android/build.gradle index addb07a1..3dcebc51 100644 --- a/src/serious_python_bridge/android/build.gradle +++ b/src/serious_python_bridge/android/build.gradle @@ -25,6 +25,10 @@ rootProject.allprojects { apply plugin: 'com.android.library' apply plugin: 'de.undercouch.download' +// Hoisted before `android { ... }` so the cmake.arguments block below can +// reference it. Mirrors the same expression used later for the extract task. +def pythonStagingRoot = new File(buildDir, 'python-dist') + android { namespace "com.flet.serious_python_bridge" @@ -80,8 +84,8 @@ def pythonCacheDir = new File( // tarball that serious_python_android uses. We extract into a build-time // scratch dir (not jniLibs/) because we do NOT want to ship libpython // ourselves — serious_python_android ships it; we just link against it at -// build time. -def pythonStagingRoot = new File(buildDir, 'python-dist') +// build time. (`pythonStagingRoot` is defined above the android{} block so +// it can be passed into the cmake arguments.) // Single tarball contains all 4 Android ABIs' Python installs WITH headers // and the libpython3.so abi3 stub. The python-android-dart variant is just diff --git a/src/serious_python_bridge/native/CMakeLists.txt b/src/serious_python_bridge/native/CMakeLists.txt index 4dc6b920..5c3dea02 100644 --- a/src/serious_python_bridge/native/CMakeLists.txt +++ b/src/serious_python_bridge/native/CMakeLists.txt @@ -55,6 +55,13 @@ if(WIN32) # Debug builds, which makes MSVC auto-link the Debug variant of libpython # even though we explicitly linked python3.lib above. python-build-standalone # doesn't ship a Debug lib, so the link fails (LNK1104). Py_NO_LINK_LIB - # suppresses that pragma (Python 3.12+). + # suppresses the pragma in Python 3.14+, but 3.12 and 3.13 pyconfig.h don't + # honor it — use /NODEFAULTLIB:pythonXY_d.lib to explicitly exclude the + # Debug lib at link time. Works on every supported version. target_compile_definitions(flet_bridge PRIVATE Py_NO_LINK_LIB) + if(Python3_VERSION_MAJOR AND Python3_VERSION_MINOR) + target_link_options(flet_bridge PRIVATE + "/NODEFAULTLIB:python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}_d.lib" + ) + endif() endif() diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index 4df18ae3..803a5ace 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -76,13 +76,19 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) # python-build-standalone also doesn't ship a Debug variant in the same shape, # so a single Release Python is the consistent ABI target. # -# Py_NO_LINK_LIB (set on the plugin target) suppresses pyconfig.h's -# `#pragma comment(lib, "pythonXY_d.lib")` that fires in Debug builds, so the -# explicit link to pythonXY.lib below is honored. +# In Debug Flutter builds, pyconfig.h emits `#pragma comment(lib, +# "pythonXY_d.lib")` to ask MSVC to auto-link the Debug Python lib. That lib +# isn't shipped by python-build-standalone, so the link fails with LNK1104. +# Py_NO_LINK_LIB (Python 3.14+) would suppress that pragma but 3.12 and 3.13 +# pyconfig.h doesn't honor it — so use /NODEFAULTLIB to explicitly exclude +# the Debug lib request at link time. Works across all supported versions. target_link_libraries(${PLUGIN_NAME} PRIVATE "${PYTHON_PACKAGE}/libs/python${PYTHON_VERSION_NODOT}.lib" ) target_compile_definitions(${PLUGIN_NAME} PRIVATE Py_NO_LINK_LIB) +target_link_options(${PLUGIN_NAME} PRIVATE + "/NODEFAULTLIB:python${PYTHON_VERSION_NODOT}_d.lib" +) # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an From 9a2344bdb9fbc6b61e2dbd27a417f92885b2f56f Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 07:13:34 -0700 Subject: [PATCH 031/114] Windows: ship both Release+Debug dart_bridge.pyd in the wheel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert serious_python_windows back to its original Debug/Release Python split: Debug Flutter builds bundle pythonXY_d.dll + python3_d.dll, Release builds bundle the unsuffixed pair. This restores the ability to run `fvm flutter run` (default Debug config) without an ABI mismatch. For the abi3 dart_bridge.pyd to work in *both* configs, ship two variants in the wheel: - dart_bridge.cp312-win_amd64.pyd — Release-CRT, imports python3.dll - dart_bridge_d.cp312-win_amd64.pyd — Debug-CRT, imports python3_d.dll CPython appends `_d` to EXT_SUFFIX when built in Debug mode, so the interpreter picks the right .pyd at import time automatically — no runtime switching logic, no extra package_command flag. Wheel-build CI now runs a post-cibuildwheel step on windows-latest that: 1. Downloads python-windows-for-dart-3.12.zip (Debug headers + python3_d.lib). 2. Drives cl.exe via vcvars64 to compile dart_bridge_shim.c with `/MDd /D_DEBUG /DPy_LIMITED_API=0x030c0000`, linking python3_d.lib. 3. Unpacks each Windows wheel, drops the Debug .pyd alongside the Release one, repacks. Bridge plugin's windows/CMakeLists.txt now downloads python-windows-for-dart itself (same tarball serious_python_windows uses) and feeds the right abi3 stub lib (python3.lib in Release, python3_d.lib in Debug) into flet_bridge's link — find_package(Python3)'s system Python lacks pythonXY_d.lib so the previous setup couldn't link in Debug. Also adds the tarball's libs/ to flet_bridge's LIBPATH so pyconfig.h's auto-link pragma resolves cleanly in both configs. The bridge plugin no longer bundles its own python3.dll — that's serious_python_windows's job, and it picks the correct Debug/Release variant. --- .github/workflows/test-bridge-build.yml | 76 +++++++++++++++++++ .../windows/CMakeLists.txt | 52 +++++++++---- .../windows/CMakeLists.txt | 26 +------ 3 files changed, 116 insertions(+), 38 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 81576e8e..12695439 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -34,6 +34,74 @@ jobs: with: package-dir: src/serious_python_bridge/python + # Windows ships two CPython variants (Release pythonXY.dll and Debug + # pythonXY_d.dll). The cibuildwheel-built abi3 .pyd is Release-CRT; a + # Debug Flutter app loads Debug Python and tries to import + # dart_bridge_d.cp-win_amd64.pyd (CPython appends _d to EXT_SUFFIX + # when built in Debug mode). Compile a Debug-CRT variant of the same + # dart_bridge_shim.c and pack it alongside the Release .pyd in each + # wheel. Released wheels then work in both `flutter build` (Release) + # and `fvm flutter run` (Debug) without a serious_python_windows split. + - name: Build Debug-variant dart_bridge.pyd and inject into Windows wheels + if: matrix.os == 'windows-latest' + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + # Use 3.12 headers — abi3 (Py_LIMITED_API=0x030c0000) means one .pyd + # built against the minimum supported version works for every + # 3.12+ runtime. + $pyver = '3.12' + $pyverNodot = '312' + $pywinZip = "python-windows-for-dart-$pyver.zip" + $pywinUrl = "https://github.com/flet-dev/python-build/releases/download/v$pyver/$pywinZip" + Write-Host "Downloading $pywinUrl" + Invoke-WebRequest -Uri $pywinUrl -OutFile $pywinZip + Expand-Archive -Path $pywinZip -DestinationPath "pywin-$pyver" -Force + + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vsPath = & $vswhere -latest -property installationPath + $vcvars = "$vsPath\VC\Auxiliary\Build\vcvars64.bat" + Write-Host "vcvars: $vcvars" + + $shimSrc = (Resolve-Path 'src/serious_python_bridge/native/dart_bridge_shim.c').Path + $includeDir = (Resolve-Path "pywin-$pyver/include").Path + $libDir = (Resolve-Path "pywin-$pyver/libs").Path + $outDir = "$PWD\debug_build" + New-Item -ItemType Directory -Force -Path $outDir | Out-Null + $outPyd = "$outDir\dart_bridge_d.cp$pyverNodot-win_amd64.pyd" + + # /LD = build DLL. /MDd = link Debug CRT (vcruntime140d/msvcp140d). + # /D_DEBUG = trigger pyconfig.h's Debug branch + match Debug CRT. + # /DPy_LIMITED_API = mirror the Release wheel's abi3 contract. + # Link the Debug abi3 stub python3_d.lib (forwards to python3_d.dll + # which serious_python_windows ships in Debug Flutter builds). + $clCmd = "cl /nologo /LD /MDd /D_DEBUG /DPy_LIMITED_API=0x030c0000 /I `"$includeDir`" `"$shimSrc`" /link /OUT:`"$outPyd`" `"$libDir\python3_d.lib`"" + Write-Host "Running: $clCmd" + cmd /c "`"$vcvars`" >NUL && $clCmd" + if (-not (Test-Path $outPyd)) { + throw "Debug .pyd not produced: $outPyd" + } + Write-Host "Built: $outPyd" + Get-Item $outPyd | Format-List FullName, Length + + # Inject the Debug .pyd into each Windows wheel. + python -m pip install --quiet wheel + foreach ($whl in Get-ChildItem "wheelhouse\dart_bridge-*-cp312-abi3-win_amd64.whl") { + $unpackDir = Join-Path $env:RUNNER_TEMP ("unpack_" + [IO.Path]::GetFileNameWithoutExtension($whl.Name)) + if (Test-Path $unpackDir) { Remove-Item -Recurse -Force $unpackDir } + python -m wheel unpack -d $unpackDir $whl.FullName + $unpackedRoot = Get-ChildItem $unpackDir -Directory | Select-Object -First 1 + # Find where the existing dart_bridge.cp312-win_amd64.pyd lives — + # wheel/setuptools puts top-level extensions at the wheel root. + $existing = Get-ChildItem -Recurse -Path $unpackedRoot.FullName -Filter 'dart_bridge.cp*-win_amd64.pyd' | Select-Object -First 1 + if (-not $existing) { throw "Release .pyd not found inside $($whl.FullName)" } + $debugDest = Join-Path $existing.DirectoryName "dart_bridge_d.cp$pyverNodot-win_amd64.pyd" + Copy-Item $outPyd $debugDest + Write-Host "Injected: $debugDest" + Remove-Item $whl.FullName + python -m wheel pack -d wheelhouse $unpackedRoot.FullName + } + - name: List built wheels shell: bash run: | @@ -41,6 +109,14 @@ jobs: echo echo "Wheel filenames (expect cp312-abi3-):" ls wheelhouse/*.whl + if [ "${{ matrix.os }}" = "windows-latest" ]; then + echo + echo "Wheel contents (verify Debug + Release .pyd both present):" + for w in wheelhouse/*.whl; do + echo "--- $w ---" + python -m zipfile -l "$w" | grep -E "dart_bridge.*\.pyd" || true + done + fi - name: Upload wheel artifacts uses: actions/upload-artifact@v4 diff --git a/src/serious_python_bridge/windows/CMakeLists.txt b/src/serious_python_bridge/windows/CMakeLists.txt index c66658dc..68badac2 100644 --- a/src/serious_python_bridge/windows/CMakeLists.txt +++ b/src/serious_python_bridge/windows/CMakeLists.txt @@ -5,24 +5,22 @@ project(${PROJECT_NAME} LANGUAGES C) cmake_policy(VERSION 3.15...3.25) -add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") - -# python3.dll (the abi3 stable-ABI loader) is what cibuildwheel-built abi3 -# wheels — including the dart_bridge.pyd dropped into bundled site-packages — -# import. serious_python_windows only bundles python3_d.dll in Debug builds, -# so Python's import of dart_bridge.pyd fails before PyInit can run with -# "ImportError: DLL load failed". Pull our own python3.dll from the same -# python-windows-for-dart tarball serious_python_windows uses and add it to -# the plugin's bundled_libraries list. +# flet_bridge.dll's import table must reference python3.dll in Release Flutter +# builds and python3_d.dll in Debug builds — to match the python(_d).dll +# bundled by serious_python_windows. find_package(Python3) only points at the +# system Python's libs/ folder, which typically lacks python_d.lib, so +# Debug builds would fail to link (the auto-link pragma in pyconfig.h asks for +# python_d.lib). Download the same python-windows-for-dart tarball that +# serious_python_windows uses — it ships both Release and Debug abi3 stubs +# (libs/python3.lib + libs/python3_d.lib) plus Debug-variant pythonXY_d.lib. if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) set(PYTHON_VERSION "$ENV{SERIOUS_PYTHON_VERSION}") else() set(PYTHON_VERSION "3.14") endif() -set(PYTHON_DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/python_dist) -set(PYTHON_DLL_PATH "${PYTHON_DOWNLOAD_DIR}/python3.dll") -if(NOT EXISTS "${PYTHON_DLL_PATH}") - set(PYTHON_ZIP "${CMAKE_BINARY_DIR}/python-windows-for-dart-${PYTHON_VERSION}.zip") +set(PYTHON_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/python_dist") +set(PYTHON_ZIP "${CMAKE_BINARY_DIR}/python-windows-for-dart-${PYTHON_VERSION}.zip") +if(NOT EXISTS "${PYTHON_DOWNLOAD_DIR}/include/Python.h") if(NOT EXISTS "${PYTHON_ZIP}") file(DOWNLOAD "https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-windows-for-dart-${PYTHON_VERSION}.zip" @@ -30,14 +28,36 @@ if(NOT EXISTS "${PYTHON_DLL_PATH}") endif() file(MAKE_DIRECTORY "${PYTHON_DOWNLOAD_DIR}") file(ARCHIVE_EXTRACT INPUT "${PYTHON_ZIP}" - DESTINATION "${PYTHON_DOWNLOAD_DIR}" - PATTERNS "python3.dll") + DESTINATION "${PYTHON_DOWNLOAD_DIR}") endif() +set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS "${PYTHON_DOWNLOAD_DIR}/include") +# Pick Debug abi3 stub (python3_d.lib) when Flutter is building Debug, Release +# stub (python3.lib) otherwise. The corresponding python3(_d).dll is bundled +# by serious_python_windows. +set(FLET_BRIDGE_PYTHON_LIBRARIES + "${PYTHON_DOWNLOAD_DIR}/libs/python3$<$:_d>.lib" +) + +add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") + +# Make python-windows-for-dart's libs/ visible to MSVC's auto-link. pyconfig.h +# emits `#pragma comment(lib, "pythonXY(_d).lib")` and MSVC's default LIB path +# wouldn't find the file otherwise. The tarball ships pythonXY.lib AND +# pythonXY_d.lib for every version, so both Debug and Release auto-link +# resolve. (We pass /NODEFAULTLIB in native/CMakeLists for the cibuildwheel +# setup.py build path, but here the request can be satisfied properly so we +# let it through.) +target_link_directories(flet_bridge PRIVATE "${PYTHON_DOWNLOAD_DIR}/libs") + # Flutter picks up bundled libraries via this variable and copies the file # alongside the app binary; Dart resolves it via DynamicLibrary.open. +# +# The bridge plugin only ships flet_bridge.dll. python3.dll / python3_d.dll +# (the abi3 stable-ABI loader that dart_bridge.pyd imports) is bundled by +# serious_python_windows, which already chooses the correct Debug/Release +# variant matching Flutter's build config. set(serious_python_bridge_bundled_libraries $ - "${PYTHON_DLL_PATH}" PARENT_SCOPE ) diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index 803a5ace..53910244 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -68,26 +68,8 @@ include_directories( target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -# Always link/bundle the Release Python regardless of Flutter's build config. -# Reason: Python C extension wheels (including the cibuildwheel-built abi3 -# dart_bridge shim downloaded by `package_command.dart --bridge`) are compiled -# against Release CPython and reference Release python3.dll / pythonXY.dll. A -# Debug Flutter build that bundled pythonXY_d.dll couldn't load those wheels. -# python-build-standalone also doesn't ship a Debug variant in the same shape, -# so a single Release Python is the consistent ABI target. -# -# In Debug Flutter builds, pyconfig.h emits `#pragma comment(lib, -# "pythonXY_d.lib")` to ask MSVC to auto-link the Debug Python lib. That lib -# isn't shipped by python-build-standalone, so the link fails with LNK1104. -# Py_NO_LINK_LIB (Python 3.14+) would suppress that pragma but 3.12 and 3.13 -# pyconfig.h doesn't honor it — so use /NODEFAULTLIB to explicitly exclude -# the Debug lib request at link time. Works across all supported versions. target_link_libraries(${PLUGIN_NAME} PRIVATE - "${PYTHON_PACKAGE}/libs/python${PYTHON_VERSION_NODOT}.lib" -) -target_compile_definitions(${PLUGIN_NAME} PRIVATE Py_NO_LINK_LIB) -target_link_options(${PLUGIN_NAME} PRIVATE - "/NODEFAULTLIB:python${PYTHON_VERSION_NODOT}_d.lib" + "${PYTHON_PACKAGE}/libs/python${PYTHON_VERSION_NODOT}$<$:_d>.lib" ) # List of absolute paths to libraries that should be bundled with the plugin. @@ -95,8 +77,8 @@ target_link_options(${PLUGIN_NAME} PRIVATE # external build triggered from this build file. string(REPLACE "\\" "/" SERIOUS_PYTHON_WINDIR "$ENV{WINDIR}") set(serious_python_windows_bundled_libraries - "${PYTHON_PACKAGE}/python${PYTHON_VERSION_NODOT}.dll" - "${PYTHON_PACKAGE}/python3.dll" + "${PYTHON_PACKAGE}/python${PYTHON_VERSION_NODOT}$<$:_d>.dll" + "${PYTHON_PACKAGE}/python3$<$:_d>.dll" "${SERIOUS_PYTHON_WINDIR}/System32/msvcp140.dll" "${SERIOUS_PYTHON_WINDIR}/System32/vcruntime140.dll" "${SERIOUS_PYTHON_WINDIR}/System32/vcruntime140_1.dll" @@ -114,7 +96,7 @@ add_custom_command(TARGET CopyPythonDLLs POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYTHON_PACKAGE}/DLLs" "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs" - COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*_d.*\" /S /Q + COMMAND IF \"$<$:release>\" == \"release\" DEL \"${CMAKE_BINARY_DIR}/runner/Release/DLLs\\*_d.*\" /S /Q COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*.ico\" /S /Q COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*.cat\" /S /Q COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\tcl86t.dll\" /Q From 20f39f44ca1df9418c932024a3362ea01c2486b7 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 07:19:31 -0700 Subject: [PATCH 032/114] Debug wheel build: add /LIBPATH so pyconfig.h auto-link finds python312_d.lib --- .github/workflows/test-bridge-build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 12695439..50a1f1ef 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -75,7 +75,11 @@ jobs: # /DPy_LIMITED_API = mirror the Release wheel's abi3 contract. # Link the Debug abi3 stub python3_d.lib (forwards to python3_d.dll # which serious_python_windows ships in Debug Flutter builds). - $clCmd = "cl /nologo /LD /MDd /D_DEBUG /DPy_LIMITED_API=0x030c0000 /I `"$includeDir`" `"$shimSrc`" /link /OUT:`"$outPyd`" `"$libDir\python3_d.lib`"" + # /LIBPATH puts python-windows-for-dart's libs/ folder on the + # linker search path so pyconfig.h's auto-link `#pragma comment( + # lib, "pythonXY_d.lib")` resolves (it asks for python312_d.lib by + # name; that file ships in the same libs/ folder). + $clCmd = "cl /nologo /LD /MDd /D_DEBUG /DPy_LIMITED_API=0x030c0000 /I `"$includeDir`" `"$shimSrc`" /link /LIBPATH:`"$libDir`" /OUT:`"$outPyd`" `"$libDir\python3_d.lib`"" Write-Host "Running: $clCmd" cmd /c "`"$vcvars`" >NUL && $clCmd" if (-not (Test-Path $outPyd)) { From 193d099b708d55cc5dc3007bbd6fd0858b65bd8d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 07:24:40 -0700 Subject: [PATCH 033/114] Widen dart_bridge.pyd search inside wheel + log unpacked tree for diagnostics --- .github/workflows/test-bridge-build.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 50a1f1ef..a2af1eaf 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -95,10 +95,16 @@ jobs: if (Test-Path $unpackDir) { Remove-Item -Recurse -Force $unpackDir } python -m wheel unpack -d $unpackDir $whl.FullName $unpackedRoot = Get-ChildItem $unpackDir -Directory | Select-Object -First 1 - # Find where the existing dart_bridge.cp312-win_amd64.pyd lives — - # wheel/setuptools puts top-level extensions at the wheel root. - $existing = Get-ChildItem -Recurse -Path $unpackedRoot.FullName -Filter 'dart_bridge.cp*-win_amd64.pyd' | Select-Object -First 1 - if (-not $existing) { throw "Release .pyd not found inside $($whl.FullName)" } + Write-Host "Unpacked tree:" + Get-ChildItem -Recurse -Path $unpackedRoot.FullName | ForEach-Object { + Write-Host " $($_.FullName.Substring($unpackedRoot.FullName.Length))" + } + # Find any existing dart_bridge*.pyd to know where to place the Debug + # sibling. setuptools may name it dart_bridge.pyd, dart_bridge.abi3.pyd, + # dart_bridge.cp312-win_amd64.pyd, etc., depending on the build setup. + $existing = Get-ChildItem -Recurse -Path $unpackedRoot.FullName -Filter 'dart_bridge*.pyd' | Select-Object -First 1 + if (-not $existing) { throw "No dart_bridge*.pyd found inside $($whl.FullName)" } + Write-Host "Found Release pyd: $($existing.Name)" $debugDest = Join-Path $existing.DirectoryName "dart_bridge_d.cp$pyverNodot-win_amd64.pyd" Copy-Item $outPyd $debugDest Write-Host "Injected: $debugDest" From c36ce415b307052d8f9932e7080a9901265ba5c0 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 07:36:49 -0700 Subject: [PATCH 034/114] Name Debug variant dart_bridge_d.pyd (no version tag) so Python 3.13/3.14 Debug picks it up too --- .github/workflows/test-bridge-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index a2af1eaf..271eaaf9 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -68,7 +68,7 @@ jobs: $libDir = (Resolve-Path "pywin-$pyver/libs").Path $outDir = "$PWD\debug_build" New-Item -ItemType Directory -Force -Path $outDir | Out-Null - $outPyd = "$outDir\dart_bridge_d.cp$pyverNodot-win_amd64.pyd" + $outPyd = "$outDir\dart_bridge_d.pyd" # /LD = build DLL. /MDd = link Debug CRT (vcruntime140d/msvcp140d). # /D_DEBUG = trigger pyconfig.h's Debug branch + match Debug CRT. @@ -105,7 +105,7 @@ jobs: $existing = Get-ChildItem -Recurse -Path $unpackedRoot.FullName -Filter 'dart_bridge*.pyd' | Select-Object -First 1 if (-not $existing) { throw "No dart_bridge*.pyd found inside $($whl.FullName)" } Write-Host "Found Release pyd: $($existing.Name)" - $debugDest = Join-Path $existing.DirectoryName "dart_bridge_d.cp$pyverNodot-win_amd64.pyd" + $debugDest = Join-Path $existing.DirectoryName "dart_bridge_d.pyd" Copy-Item $outPyd $debugDest Write-Host "Injected: $debugDest" Remove-Item $whl.FullName From d0b0b119aeda41fa23df09b3b6f12a6712af46f4 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 07:53:10 -0700 Subject: [PATCH 035/114] Android: add post-failure diagnostics inspecting jniLibs, intermediate merge output, and APK contents --- .github/workflows/test-bridge-build.yml | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 271eaaf9..5bb71fa5 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -443,6 +443,34 @@ jobs: cd src/serious_python_bridge/example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} cd src/serious_python_bridge/example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} + - name: Diagnostics on failure + if: failure() + shell: bash + run: | + set +e + REPO="$GITHUB_WORKSPACE" + ABI=x86_64 + echo "=== serious_python_android/android/src/main/jniLibs/$ABI/ (post-extract source) ===" + ls -la "$REPO/src/serious_python_android/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" + echo + echo "=== serious_python_bridge/android/src/main/jniLibs/$ABI/ ===" + ls -la "$REPO/src/serious_python_bridge/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" + echo + echo "=== example/build/app/intermediates/merged_native_libs/.../$ABI/ ===" + find "$REPO/src/serious_python_bridge/example/build/app/intermediates/merged_native_libs" -type f 2>/dev/null + echo + echo "=== example/build/app/outputs/apk/debug/*.apk ===" + APK=$(find "$REPO/src/serious_python_bridge/example/build" -name "*-debug.apk" 2>/dev/null | head -n1) + echo "APK: $APK" + if [ -n "$APK" ]; then + echo "Native libs inside APK:" + unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" + fi + echo + echo "=== installed app native lib dir (adb) ===" + adb shell run-as com.flet.serious_python_bridge_example ls -la /data/data/com.flet.serious_python_bridge_example/lib/ 2>/dev/null || true + adb shell pm path com.flet.serious_python_bridge_example 2>/dev/null || true + test_bridge_example_windows: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) runs-on: windows-latest From fa6c44dee42f8a9066e2cd2b772a395d2d5e15c5 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 08:15:08 -0700 Subject: [PATCH 036/114] Android example: set extractNativeLibs=true so libpython3.X.so lands in nativeLibraryDir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modern AGP+minSdk23+ defaults extractNativeLibs to false: .so files stay mmapped inside the APK and never appear in /data/app/.../lib//. serious_python_android's run() scans nativeLibraryDir with Directory(...).listSync() to discover the version-specific libpython filename — that fails silently because the directory is empty, throwing "No libpython3.*.so found". Production flet build apps get the right manifest by default; this is example-specific. --- .../example/android/app/src/main/AndroidManifest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml b/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml index 59c44ce5..6789e302 100644 --- a/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml +++ b/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:icon="@mipmap/ic_launcher" + android:extractNativeLibs="true"> Date: Tue, 9 Jun 2026 12:02:48 -0700 Subject: [PATCH 037/114] Android cross-build: compile dart_bridge_shim.c (not dart_bridge.c) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Android cross-build was compiling the core dart_bridge.c, which has no PyInit_dart_bridge — so `import dart_bridge` would crash with "dynamic module does not define module export function." That explained the handshake TimeoutException on Android even after extractNativeLibs was fixed: Python failed to import dart_bridge silently, main.py crashed, no echo came back. Switch to dart_bridge_shim.c so the Android wheel mirrors Linux/Windows: a Python module that resolves the bridge's globals at PyInit time via dlsym/dlopen against libflet_bridge.so (the Flutter plugin's separately- shipped .so). Adding the core directly into this .so would also create a duplicate global_enqueue_handler_func cell that Dart never sees. --- .github/workflows/test-bridge-build.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 5bb71fa5..ab36f124 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -190,13 +190,22 @@ jobs: OUT="dart_bridge.abi3-android-${ABI}.so" + # Compile dart_bridge_shim.c (the Python-callable module) — same + # source used by the Linux/Windows wheels. Symbols from the core + # (dart_bridge_global_enqueue_handler_func, dart_bridge_post_to_dart) + # are resolved at PyInit time via dlsym/dlopen against + # libflet_bridge.so, which the Flutter plugin builds + bundles + # separately. Linking dart_bridge.c directly into this .so would + # produce a second, isolated copy of the global handler cell — + # Dart's side and Python's side would never see the same value. + # -ldl gives dart_bridge_shim.c its dlsym/dlopen. $CC -shared -fPIC -fvisibility=hidden \ -DPy_LIMITED_API=0x030c0000 \ -I"$INCLUDE_DIR" \ -I"src/serious_python_bridge/native" \ - src/serious_python_bridge/native/dart_bridge.c \ - src/serious_python_bridge/native/dart_api/dart_api_dl.c \ + src/serious_python_bridge/native/dart_bridge_shim.c \ "$LIBPYTHON" \ + -ldl \ -Wl,-z,max-page-size=16384 \ -o "$OUT" From 441933204bb8b93408c93895a1b747596f71fc2b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 12:15:33 -0700 Subject: [PATCH 038/114] Android: don't link libpython into dart_bridge.abi3.so Hardcoded link against the 3.12 libpython.so emitted DT_NEEDED for libpython3.12.so; Android's linker then failed loading the .so under 3.13 / 3.14 Python (which ship only libpython3..so). Drop the explicit link, let Python's C API symbols stay undefined in the .so, and rely on dlopen-time resolution against whatever libpython the host process has already loaded. Same model the Linux/macOS abi3 wheels use. --- .github/workflows/test-bridge-build.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index ab36f124..5f64079b 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -199,13 +199,24 @@ jobs: # produce a second, isolated copy of the global handler cell — # Dart's side and Python's side would never see the same value. # -ldl gives dart_bridge_shim.c its dlsym/dlopen. + # + # Intentionally NOT linking $LIBPYTHON: hardcoding it would emit + # DT_NEEDED for the version-specific libpython3.X.so used at build + # time (we build once with 3.12), and Android's linker would then + # fail to load this .so under 3.13/3.14 Python (which ship + # libpython3.13.so / libpython3.14.so but not libpython3.12.so). + # `-shared` allows undefined Python symbols; they resolve at import + # time because dlopen flags propagate from the already-loaded + # libpython into the new module's symbol lookup. + # `-Wl,--allow-shlib-undefined` makes the linker tolerate the + # unresolved Python C API references during the link itself. $CC -shared -fPIC -fvisibility=hidden \ -DPy_LIMITED_API=0x030c0000 \ -I"$INCLUDE_DIR" \ -I"src/serious_python_bridge/native" \ src/serious_python_bridge/native/dart_bridge_shim.c \ - "$LIBPYTHON" \ -ldl \ + -Wl,--allow-shlib-undefined \ -Wl,-z,max-page-size=16384 \ -o "$OUT" From f3c7fd1280635146a25a42f343c9029a58ca6b57 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 12:46:18 -0700 Subject: [PATCH 039/114] =?UTF-8?q?Android:=20cross-build=20matrix=20expan?= =?UTF-8?q?ds=20to=20abi=20=C3=97=20python=5Fversion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-link dart_bridge.abi3.so against the version-specific libpythonX.Y.so (via the python-android-mobile-forge tarball for that version), and produce one artifact per (abi × python_version). The test job downloads the matching python_version artifact. abi3 makes the symbol set portable across Python versions, but Android's dynamic linker still validates DT_NEEDED entries against files present in the APK at load time. Removing the libpython link entirely left the Python C API symbols unresolved at dlopen(RTLD_NOW) time — the test process timed out even on 3.12. Per-version builds restore correct loading. Excludes armeabi-v7a × {3.13, 3.14} because PEP 738 dropped 32-bit Android in 3.13+ and the mobile-forge tarball has no install layout for those combos. --- .github/workflows/test-bridge-build.yml | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 5f64079b..5476b6b4 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -136,14 +136,23 @@ jobs: if-no-files-found: error test_android_build: - name: Android cross-build (${{ matrix.abi }}) + name: Android cross-build (${{ matrix.abi }}, Py ${{ matrix.python_version }}) runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: abi: [arm64-v8a, armeabi-v7a, x86_64] + python_version: ['3.12', '3.13', '3.14'] + exclude: + # 32-bit Android was dropped in CPython 3.13+ (PEP 738) — the + # python-android-mobile-forge tarball doesn't ship an armeabi-v7a + # install for those versions. + - abi: armeabi-v7a + python_version: '3.13' + - abi: armeabi-v7a + python_version: '3.14' env: - PYTHON_VERSION: "3.12" + PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -200,23 +209,19 @@ jobs: # Dart's side and Python's side would never see the same value. # -ldl gives dart_bridge_shim.c its dlsym/dlopen. # - # Intentionally NOT linking $LIBPYTHON: hardcoding it would emit - # DT_NEEDED for the version-specific libpython3.X.so used at build - # time (we build once with 3.12), and Android's linker would then - # fail to load this .so under 3.13/3.14 Python (which ship - # libpython3.13.so / libpython3.14.so but not libpython3.12.so). - # `-shared` allows undefined Python symbols; they resolve at import - # time because dlopen flags propagate from the already-loaded - # libpython into the new module's symbol lookup. - # `-Wl,--allow-shlib-undefined` makes the linker tolerate the - # unresolved Python C API references during the link itself. + # Link $LIBPYTHON for this specific Python version so DT_NEEDED + # references libpythonX.Y.so and matches the libpython + # serious_python_android bundles at runtime for the same version. + # abi3 makes the *symbol set* portable, but Android's linker still + # needs the DT_NEEDED entry to resolve to a file that exists in the + # APK at load time — which is why we build per-version (matrix). $CC -shared -fPIC -fvisibility=hidden \ -DPy_LIMITED_API=0x030c0000 \ -I"$INCLUDE_DIR" \ -I"src/serious_python_bridge/native" \ src/serious_python_bridge/native/dart_bridge_shim.c \ + "$LIBPYTHON" \ -ldl \ - -Wl,--allow-shlib-undefined \ -Wl,-z,max-page-size=16384 \ -o "$OUT" @@ -228,7 +233,7 @@ jobs: - name: Upload .so artifact uses: actions/upload-artifact@v4 with: - name: bridge-android-${{ matrix.abi }} + name: bridge-android-${{ matrix.abi }}-py${{ matrix.python_version }} path: dart_bridge.abi3-android-*.so if-no-files-found: error @@ -422,7 +427,7 @@ jobs: - name: Download Android bridge .so for x86_64 uses: actions/download-artifact@v4 with: - name: bridge-android-x86_64 + name: bridge-android-x86_64-py${{ matrix.python_version }} path: ${{ runner.temp }}/dart_bridge_android - name: Inject dart_bridge.abi3.so into bundled site-packages From 74ae640c6d391e56538b83e81f1eccb48a0f21bc Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 12:54:54 -0700 Subject: [PATCH 040/114] Android cross-build: drop hardcoded .13 patch version; use wildcards --- .github/workflows/test-bridge-build.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 5476b6b4..565af10a 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -166,9 +166,13 @@ jobs: curl -fL -o "$ARCHIVE" \ "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" mkdir -p pydist + # The patch version inside the tarball path (python-X.Y.Z/) shifts + # over time, so extract by ABI/include + ABI/lib prefix and let + # tar pick whatever python-X.Y.* directory is there. tar -xzf "$ARCHIVE" -C pydist \ - "install/android/${ABI}/python-${VER}.13/include/" \ - "install/android/${ABI}/python-${VER}.13/lib/" + --wildcards \ + "install/android/${ABI}/python-${VER}.*/include/" \ + "install/android/${ABI}/python-${VER}.*/lib/" echo "Python.h candidates:" find pydist -name "Python.h" echo "libpython candidates:" @@ -193,8 +197,8 @@ jobs: CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" test -x "$CC" - INCLUDE_DIR=$(find pydist -path "*/python-${VER}.13/include/python${VER}" | head -n1) - LIBPYTHON=$(find pydist -path "*/python-${VER}.13/lib/libpython${VER}.so" | head -n1) + INCLUDE_DIR=$(find pydist -path "*/python-${VER}.*/include/python${VER}" | head -n1) + LIBPYTHON=$(find pydist -path "*/python-${VER}.*/lib/libpython${VER}.so" | head -n1) test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" OUT="dart_bridge.abi3-android-${ABI}.so" From b5c2c268f030dff350899e9c3eeabd6fd5e67164 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 9 Jun 2026 13:21:50 -0700 Subject: [PATCH 041/114] iOS: cache python-ios-dart framework + log step timestamps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prepare_ios.sh in serious_python_darwin downloads python-ios-dart-.tar.gz (~100MB) on every run and skips only if the extracted dist_ios/ directory already exists. Wrap the directory in actions/cache keyed by python_version so the download happens once per version and is reused across subsequent jobs in the same workflow run and across reruns. Also wrap the package + flutter test calls with `date` timestamps so slow runs make it obvious which sub-step (packaging vs simulator boot vs flutter test) is responsible — useful for follow-up tuning. The cache key is suffixed `-v1` so we can invalidate by bumping when prepare_ios.sh's behavior changes. --- .github/workflows/test-bridge-build.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 565af10a..8c361fd7 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -286,6 +286,16 @@ jobs: path: '.fvmrc' cache: true + # serious_python_darwin's prepare_ios.sh downloads python-ios-dart-.tar.gz + # (~100MB) into src/serious_python_darwin/darwin/dist_ios/ and skips the + # download if the directory already exists. Cache it so reruns and + # subsequent matrix jobs don't re-fetch from GitHub Releases. + - name: Cache iOS Python framework + uses: actions/cache@v4 + with: + path: src/serious_python_darwin/darwin/dist_ios + key: ios-python-dist-${{ matrix.python_version }}-v1 + - name: Setup iOS Simulator id: simulator uses: futureware-tech/simulator-action@v4 @@ -299,13 +309,17 @@ jobs: - name: Package + run integration test working-directory: "src/serious_python_bridge/example" run: | + ts() { date '+%H:%M:%S'; } + echo "[$(ts)] >>> dart run serious_python:main package" # certifi is a placeholder requirement: serious_python_darwin's # sync_site_packages.sh only populates dist_ios/site-xcframeworks # (which bundle-python-frameworks-ios.sh then requires at build # time) when iOS-specific site-packages subdirs exist. Empty # --requirements skips that branch and the build fails. dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi + echo "[$(ts)] >>> flutter test integration_test" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} + echo "[$(ts)] >>> done" test_bridge_example_linux: name: Bridge example Linux ${{ matrix.title }} round-trip (Python ${{ matrix.python_version }}) From 109276932ab3361076dab1fa5ad16a05dd7514af Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 10:24:30 -0700 Subject: [PATCH 042/114] Darwin: absorb Python lifecycle into dart_bridge.xcframework + add PythonBridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Darwin (iOS + macOS) is the first platform to consume dart-bridge as a pre-built binary instead of building Python lifecycle code locally. What moved: - prepare_{ios,macos}.sh download dart_bridge-apple.xcframework.zip (pinned to DART_BRIDGE_VERSION=1.2.0) into dist_{ios,macos}/xcframeworks/. The podspec's existing `vendored_frameworks = "dist_*/xcframeworks/*"` glob picks it up automatically. - SeriousPythonPlugin.swift shrinks to a thin method-channel handler for `getPlatformVersion` + `getResourcePath` (python.bundle lookup). Python lifecycle code (Py_Initialize, PyRun_*, threading, env setup) is gone — it now lives in libdart_bridge's serious_python_run. - @_silgen_name keep-alive references make sure the host app's -dead_strip pass doesn't drop the symbols Dart looks up via DynamicLibrary.process(). - serious_python_darwin.dart's run() is now one FFI call to serious_python_run. Shared FFI bindings: - New serious_python_platform_interface/lib/src/dart_bridge_ffi.dart with `DartBridge`, `SpRunConfig`, `runPython()`, plus auto per-platform loader (process() on Apple, libdart_bridge.so on Android/Linux, dart_bridge[_d].dll on Windows). Other platform plugins will reuse it. PythonBridge: - New `package:serious_python/bridge.dart` exporting `PythonBridge`. Each instance owns a ReceivePort whose nativePort is the channel key in both directions (matches the v1.2.0 dart-bridge keyed-handlers model). Multiple bridges can coexist for distinct channels (UI / logs / etc.); the user controls which env-var name carries which port to Python. --- src/serious_python/lib/bridge.dart | 6 + src/serious_python/lib/src/python_bridge.dart | 109 +++++++++ src/serious_python/pubspec.yaml | 1 + .../darwin/Classes/SeriousPythonPlugin.swift | 174 +++----------- .../darwin/prepare_ios.sh | 15 ++ .../darwin/prepare_macos.sh | 13 ++ .../lib/serious_python_darwin.dart | 66 ++++-- .../serious_python_platform_interface.dart | 1 + .../lib/src/dart_bridge_ffi.dart | 218 ++++++++++++++++++ .../pubspec.yaml | 1 + 10 files changed, 452 insertions(+), 152 deletions(-) create mode 100644 src/serious_python/lib/bridge.dart create mode 100644 src/serious_python/lib/src/python_bridge.dart create mode 100644 src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart diff --git a/src/serious_python/lib/bridge.dart b/src/serious_python/lib/bridge.dart new file mode 100644 index 00000000..53676175 --- /dev/null +++ b/src/serious_python/lib/bridge.dart @@ -0,0 +1,6 @@ +/// In-process Dart ↔ Python byte channel. +/// +/// See [PythonBridge] for usage. +library; + +export 'src/python_bridge.dart' show PythonBridge; diff --git a/src/serious_python/lib/src/python_bridge.dart b/src/serious_python/lib/src/python_bridge.dart new file mode 100644 index 00000000..ca847de4 --- /dev/null +++ b/src/serious_python/lib/src/python_bridge.dart @@ -0,0 +1,109 @@ +import 'dart:async'; +import 'dart:ffi'; +import 'dart:isolate'; +import 'dart:typed_data'; + +import 'package:ffi/ffi.dart'; +import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; + +/// An in-process Dart ↔ Python byte channel, backed by the `dart_bridge` +/// native library. +/// +/// Each [PythonBridge] owns a [ReceivePort] whose native port doubles as the +/// channel key in both directions: +/// +/// - Python → Dart: when Python calls `dart_bridge.send_bytes(port, payload)`, +/// the payload arrives on this bridge's [messages] stream. +/// - Dart → Python: [send] hands bytes to the Python handler registered for +/// this port via `dart_bridge.set_enqueue_handler_func(port, handler)`. +/// +/// Multiple bridges (UI channel, logging channel, future camera-stream +/// channel, ...) can coexist in a single app — each bridge has its own port +/// and its own Python-side handler. +/// +/// Typical use: +/// +/// ```dart +/// final ui = PythonBridge(); +/// final logs = PythonBridge(); +/// +/// ui.messages.listen((Uint8List bytes) { /* UI events */ }); +/// logs.messages.listen((Uint8List bytes) { /* log lines */ }); +/// +/// await SeriousPython.run('app/main.py', environmentVariables: { +/// 'MY_APP_UI_PORT': '${ui.port}', +/// 'MY_APP_LOGS_PORT': '${logs.port}', +/// }); +/// +/// ui.send(Uint8List.fromList([1, 2, 3])); +/// ``` +/// +/// The Python side reads the chosen env-var names to discover its port +/// numbers — no convention is baked in here. +class PythonBridge { + PythonBridge() { + _bridge = DartBridge.instance; + _bridge.initDartApiDL(); + _rx.listen(_onMessage); + } + + final ReceivePort _rx = ReceivePort(); + final StreamController _messages = + StreamController.broadcast(); + late final DartBridge _bridge; + bool _closed = false; + + /// Dart native port acting as this channel's key. Pass it to the Python + /// program (typically via an environment variable) so Python knows where + /// to send messages and which port to register its handler under. + int get port => _rx.sendPort.nativePort; + + /// Bytes pushed by Python via `dart_bridge.send_bytes(port, payload)`. + Stream get messages => _messages.stream; + + /// Send [bytes] to the Python handler registered for this bridge's [port]. + /// + /// Returns `true` on successful delivery, `false` if no Python handler is + /// currently registered for this port (typical reason: Python hasn't yet + /// called `dart_bridge.set_enqueue_handler_func`). The caller may retry. + /// + /// Throws [StateError] if the Python interpreter is not running. + bool send(Uint8List bytes) { + if (_closed) { + throw StateError('PythonBridge is closed'); + } + final len = bytes.length; + final buf = malloc(len == 0 ? 1 : len); + try { + if (len > 0) { + buf.asTypedList(len).setAll(0, bytes); + } + final rc = _bridge.enqueueMessage(port, buf, len); + if (rc == -2) { + throw StateError('Python interpreter is not initialized'); + } + return rc == 0; + } finally { + malloc.free(buf); + } + } + + /// Release this bridge's ReceivePort. After closing, [send] throws and the + /// [messages] stream emits done. + void close() { + if (_closed) return; + _closed = true; + _rx.close(); + _messages.close(); + } + + void _onMessage(dynamic message) { + if (message is Uint8List) { + _messages.add(message); + } else if (message is List) { + _messages.add(Uint8List.fromList(message)); + } + // Drop unexpected message shapes silently — the Python side only ever + // posts typed-data via Dart_PostCObject_DL. + } +} diff --git a/src/serious_python/pubspec.yaml b/src/serious_python/pubspec.yaml index 84671715..d40242dd 100644 --- a/src/serious_python/pubspec.yaml +++ b/src/serious_python/pubspec.yaml @@ -52,6 +52,7 @@ dependencies: shelf: ^1.4.1 crypto: ^3.0.5 glob: ^2.1.3 + ffi: ^2.1.2 dev_dependencies: flutter_test: diff --git a/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift b/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift index 201be1c1..8305c55e 100644 --- a/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift +++ b/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift @@ -5,51 +5,22 @@ import UIKit import FlutterMacOS #endif -import Python - +// 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) + +/// Thin Flutter plugin: surfaces the python.bundle resource path to Dart and +/// exposes the standard `getPlatformVersion`. All Python lifecycle now lives +/// in `serious_python_run` (dart_bridge.xcframework), invoked from Dart. public class SeriousPythonPlugin: NSObject, FlutterPlugin { - public typealias PyInitFunction = @convention(c) () -> UnsafeMutablePointer? - - private struct PythonExtensionEntry { - // PyImport_AppendInittab does not copy the name string; the storage must - // outlive the interpreter. We strdup on register and intentionally leak. - let name: UnsafeMutablePointer - let initFn: PyInitFunction - } - - private static var registeredExtensions: [PythonExtensionEntry] = [] - private static let registrationLock = NSLock() - - /// Register a statically linked Python C extension to be made available as a - /// built-in module on every Py_Initialize. Intended for iOS, where dlopen of - /// late-loaded .so extensions is forbidden, but available on macOS too so - /// callers don't need platform conditionals. - /// - /// Must be called before serious_python's first runPython invocation. Calling - /// twice with the same name is the caller's responsibility to avoid. - public static func registerPythonExtension(name: String, initFn: PyInitFunction) { - registrationLock.lock() - defer { registrationLock.unlock() } - guard let copied = strdup(name) else { - NSLog("[SeriousPython] strdup failed for extension name \(name)") - return - } - registeredExtensions.append(PythonExtensionEntry(name: copied, initFn: initFn)) - } - - private func applyRegisteredExtensions() { - SeriousPythonPlugin.registrationLock.lock() - let entries = SeriousPythonPlugin.registeredExtensions - SeriousPythonPlugin.registrationLock.unlock() - - for entry in entries { - if PyImport_AppendInittab(entry.name, entry.initFn) != 0 { - NSLog("[SeriousPython] PyImport_AppendInittab failed for \(String(cString: entry.name))") - } - } - } - public static func register(with registrar: FlutterPluginRegistrar) { // Workaround for https://github.com/flutter/flutter/issues/118103. #if os(iOS) @@ -60,8 +31,17 @@ 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) + } } - + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "getPlatformVersion": @@ -70,110 +50,30 @@ public class SeriousPythonPlugin: NSObject, FlutterPlugin { #else result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) #endif - case "runPython": - let args: [String: Any] = call.arguments as? [String: Any] ?? [:] - let appPath = args["appPath"] as! String - let script = args["script"] as? String - let modulePaths = args["modulePaths"] as? [String] ?? [] - let envVars = args["environmentVariables"] as? [String:String] ?? [:] - let sync = args["sync"] as? Bool ?? false - - NSLog("Swift runPython(appPath: \(appPath), modulePaths: \(modulePaths))") - - let appDir = URL(fileURLWithPath: appPath).deletingLastPathComponent().path - - // bundle root path + + case "getResourcePath": + // The python.bundle that prepare_{ios,macos}.sh assembles ends up + // inside this plugin's framework bundle as a Resources subbundle. + // Dart calls this to discover the stdlib / site-packages layout + // before invoking `serious_python_run`. guard let frameworkBundle = Bundle(for: type(of: self)).resourceURL else { - result(FlutterError(code: "FRAMEWORK_BUNDLE_ERROR", - message: "Failed to get framework resource URL", + result(FlutterError(code: "FRAMEWORK_BUNDLE_ERROR", + message: "Failed to get framework resource URL", details: nil)) return } - let pythonBundleURL = frameworkBundle.appendingPathComponent("python.bundle") - - guard let pythonBundle = Bundle(url: pythonBundleURL) else { - result(FlutterError(code: "PYTHON_BUNDLE_ERROR", - message: "Failed to load Python bundle", + guard let pythonBundle = Bundle(url: pythonBundleURL), + let resourcePath = pythonBundle.resourcePath else { + result(FlutterError(code: "PYTHON_BUNDLE_ERROR", + message: "Failed to load python.bundle", details: pythonBundleURL.path)) return } + result(resourcePath) - guard let resourcePath = pythonBundle.resourcePath else { - result(FlutterError(code: "RESOURCE_PATH_ERROR", - message: "Failed to locate Python bundle resources", - details: nil)) - return - } - - let pythonPaths: [String] = modulePaths + [ - appDir, - "\(appDir)/__pypackages__", - "\(resourcePath)/site-packages", - "\(resourcePath)/stdlib", - "\(resourcePath)/stdlib/lib-dynload" - ] - - setenv("PYTHONINSPECT", "1", 1) - setenv("PYTHONDONTWRITEBYTECODE", "1", 1) - setenv("PYTHONNOUSERSITE", "1", 1) - setenv("PYTHONUNBUFFERED", "1", 1) - setenv("LC_CTYPE", "UTF-8", 1) - setenv("PYTHONHOME", resourcePath, 1) - setenv("PYTHONPATH", pythonPaths.joined(separator: ":"), 1) - - // custom env vars - envVars.forEach {v in - setenv(v.key, v.value, 1) - } - - // run program either sync or in a thread - if (sync) { - if (script == nil) { - runPythonFile(appPath: appPath) - } else { - runPythonScript(script: script!) - } - } else { - if (script == nil) { - let t = Thread(target: self, selector: #selector(runPythonFile), object: appPath) - t.start() - } else { - let t = Thread(target: self, selector: #selector(runPythonScript), object: script!) - t.start() - } - } - - result(nil) default: result(FlutterMethodNotImplemented) } } - - @objc func runPythonFile(appPath: String) { - applyRegisteredExtensions() - Py_Initialize() - - // run app - let file = fopen(appPath, "r") - let result = PyRun_SimpleFileEx(file, appPath, 1) - if (result != 0) { - print("Python program completed with error.") - } - - Py_Finalize() - } - - @objc func runPythonScript(script: String) { - applyRegisteredExtensions() - Py_Initialize() - - // run app - let result = PyRun_SimpleString(script) - if (result != 0) { - print("Python script completed with error.") - } - - Py_Finalize() - } } diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index 9242b021..e10f8545 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -3,6 +3,10 @@ python_version=${1:?} script_dir=$(cd "$(dirname "$0")" && pwd -P) dist=$script_dir/dist_ios +# Pinned dart-bridge release (flet-dev/dart-bridge). The xcframework is abi3 and +# version-independent of CPython, so one binary covers all 3.12+ Python versions. +dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.0} + if [ ! -d "$dist" ]; then mkdir -p $dist @@ -14,4 +18,15 @@ if [ ! -d "$dist" ]; then tar -xzf $python_ios_dist_file -C $dist mv $dist/python-stdlib $dist/stdlib rm $python_ios_dist_file +fi + +# dart_bridge.xcframework — separate cache guard so a stale dist_ios from before +# this change still picks up the new artifact on first re-prepare. +if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ]; then + mkdir -p "$dist/xcframeworks" + dart_bridge_file="dart_bridge-apple.xcframework.zip" + dart_bridge_url="https://github.com/flet-dev/dart-bridge/releases/download/v$dart_bridge_version/$dart_bridge_file" + curl -fL -o "$dart_bridge_file" "$dart_bridge_url" + unzip -q "$dart_bridge_file" -d "$dist/xcframeworks/" + rm "$dart_bridge_file" fi \ No newline at end of file diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index ecba57d2..ccd7825c 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -3,6 +3,10 @@ python_version=${1:?} script_dir=$(cd "$(dirname "$0")" && pwd -P) dist=$script_dir/dist_macos +# Pinned dart-bridge release (flet-dev/dart-bridge). Same xcframework is reused +# across iOS and macOS — it carries slices for both. +dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.0} + if [ ! -d "$dist" ]; then mkdir -p $dist @@ -14,4 +18,13 @@ if [ ! -d "$dist" ]; then tar -xzf $python_macos_dist_file -C $dist mv $dist/python-stdlib $dist/stdlib rm $python_macos_dist_file +fi + +if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ]; then + mkdir -p "$dist/xcframeworks" + dart_bridge_file="dart_bridge-apple.xcframework.zip" + dart_bridge_url="https://github.com/flet-dev/dart-bridge/releases/download/v$dart_bridge_version/$dart_bridge_file" + curl -fL -o "$dart_bridge_file" "$dart_bridge_url" + unzip -q "$dart_bridge_file" -d "$dist/xcframeworks/" + rm "$dart_bridge_file" fi \ No newline at end of file diff --git a/src/serious_python_darwin/lib/serious_python_darwin.dart b/src/serious_python_darwin/lib/serious_python_darwin.dart index 3392ba34..3a509b5c 100644 --- a/src/serious_python_darwin/lib/serious_python_darwin.dart +++ b/src/serious_python_darwin/lib/serious_python_darwin.dart @@ -1,24 +1,25 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:path/path.dart' as p; import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; -/// An implementation of [SeriousPythonPlatform] that uses method channels. +/// iOS / macOS implementation of [SeriousPythonPlatform]. +/// +/// Python lifecycle (env, sys.path, Py_Initialize, run, finalize, sync/async) +/// lives in `serious_python_run`, statically linked into the host app via +/// dart_bridge.xcframework. This class just resolves the python.bundle +/// resource path from the Swift plugin and dispatches a single FFI call. class SeriousPythonDarwin extends SeriousPythonPlatform { - /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('serious_python'); - /// Registers this class as the default instance of [SeriousPythonPlatform] static void registerWith() { SeriousPythonPlatform.instance = SeriousPythonDarwin(); } @override - Future getPlatformVersion() async { - final version = - await methodChannel.invokeMethod('getPlatformVersion'); - return version; - } + Future getPlatformVersion() => + methodChannel.invokeMethod('getPlatformVersion'); @override Future run(String appPath, @@ -26,13 +27,48 @@ class SeriousPythonDarwin extends SeriousPythonPlatform { List? modulePaths, Map? environmentVariables, bool? sync}) async { - final Map arguments = { - 'appPath': appPath, - 'script': script, - 'modulePaths': modulePaths, - 'environmentVariables': environmentVariables, - 'sync': sync + final resourcePath = + await methodChannel.invokeMethod('getResourcePath'); + if (resourcePath == null) { + throw StateError( + 'serious_python: failed to resolve plugin resource path'); + } + + final appDir = p.dirname(appPath); + final pythonPaths = [ + ...?modulePaths, + appDir, + p.join(appDir, '__pypackages__'), + p.join(resourcePath, 'site-packages'), + p.join(resourcePath, 'stdlib'), + p.join(resourcePath, 'stdlib', 'lib-dynload'), + ]; + + final env = { + 'PYTHONINSPECT': '1', + 'PYTHONDONTWRITEBYTECODE': '1', + 'PYTHONNOUSERSITE': '1', + 'PYTHONUNBUFFERED': '1', + 'LC_CTYPE': 'UTF-8', + 'PYTHONHOME': resourcePath, + 'PYTHONPATH': pythonPaths.join(':'), + ...?environmentVariables, }; - return await methodChannel.invokeMethod('runPython', arguments); + + final rc = runPython( + bridge: DartBridge.instance, + appPath: script == null ? appPath : null, + script: script, + modulePaths: pythonPaths, + environmentVariables: env, + sync: sync ?? false, + ); + + // sync=true: rc is the Python exit code. sync=false: rc is the spawn + // result (0 = worker thread started successfully). + if (rc != 0) { + return 'Python exited with code $rc'; + } + return null; } } diff --git a/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart b/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart index 17c63116..a1ac3e77 100644 --- a/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart +++ b/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart @@ -2,6 +2,7 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'src/method_channel_serious_python.dart'; +export 'src/dart_bridge_ffi.dart'; export 'src/utils.dart'; abstract class SeriousPythonPlatform extends PlatformInterface { diff --git a/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart b/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart new file mode 100644 index 00000000..380119cf --- /dev/null +++ b/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart @@ -0,0 +1,218 @@ +import 'dart:ffi'; +import 'dart:io' show Platform; + +import 'package:ffi/ffi.dart'; +import 'package:flutter/foundation.dart' show kDebugMode; + +/// FFI bindings for the `dart_bridge` C library published by +/// [flet-dev/dart-bridge](https://github.com/flet-dev/dart-bridge). +/// +/// One binding lives in this platform-interface package so every +/// `serious_python_*` plugin can share it. The library handle resolution +/// differs by platform: +/// +/// - Apple (macOS/iOS): statically linked into the host app via +/// `dart_bridge.xcframework` — looked up through [DynamicLibrary.process]. +/// - Android: bundled as `libdart_bridge.so` in jniLibs — opened by name. +/// - Linux: bundled next to the executable — opened by name. +/// - Windows: bundled next to the .exe, with a separate Debug-CRT variant +/// `dart_bridge_d.dll` for `fvm flutter run`. +/// +/// Mirrors the C surface declared in +/// [dart-bridge/src/dart_bridge.c](https://github.com/flet-dev/dart-bridge/blob/main/src/dart_bridge.c) +/// and [dart-bridge/src/serious_python_run.c](https://github.com/flet-dev/dart-bridge/blob/main/src/serious_python_run.c). + +// --------------------------------------------------------------------------- +// C struct layout for serious_python_run +// --------------------------------------------------------------------------- + +final class SpRunConfig extends Struct { + @Int32() + external int mode; // SP_RUN_PATH=0, SP_RUN_SCRIPT=1 + + external Pointer appPath; + external Pointer scriptSource; + external Pointer programName; + external Pointer> modulePaths; // NULL-terminated + external Pointer> envKeys; // NULL-terminated + external Pointer> envValues; // parallel to envKeys + + @Int32() + external int sync; + + @Int64() + external int completionPort; +} + +const int spRunPath = 0; +const int spRunScript = 1; + +// --------------------------------------------------------------------------- +// Native + Dart function signatures +// --------------------------------------------------------------------------- + +typedef _SeriousPythonRunNative = Int32 Function(Pointer); +typedef _SeriousPythonRunDart = int Function(Pointer); + +typedef _DartBridgeInitDartApiDLNative = IntPtr Function(Pointer); +typedef _DartBridgeInitDartApiDLDart = int Function(Pointer); + +typedef _DartBridgeEnqueueMessageNative = Int32 Function( + Int64, Pointer, IntPtr); +typedef _DartBridgeEnqueueMessageDart = int Function( + int, Pointer, int); + +// --------------------------------------------------------------------------- +// Library binding +// --------------------------------------------------------------------------- + +/// Loaded dart_bridge symbols. Use [DartBridge.instance] for the default +/// per-platform handle, or [DartBridge.open] / [DartBridge.process] to load +/// from a specific source (mostly useful for tests). +class DartBridge { + DartBridge._(this._lib) { + _run = _lib + .lookup>('serious_python_run') + .asFunction<_SeriousPythonRunDart>(); + _initApiDL = _lib + .lookup>( + 'DartBridge_InitDartApiDL') + .asFunction<_DartBridgeInitDartApiDLDart>(); + _enqueueMessage = _lib + .lookup>( + 'DartBridge_EnqueueMessage') + .asFunction<_DartBridgeEnqueueMessageDart>(); + } + + final DynamicLibrary _lib; + late final _SeriousPythonRunDart _run; + late final _DartBridgeInitDartApiDLDart _initApiDL; + late final _DartBridgeEnqueueMessageDart _enqueueMessage; + + static DartBridge? _instance; + + /// Default per-platform loader. Cached after the first call. + static DartBridge get instance => _instance ??= DartBridge._(_loadDefault()); + + /// Test/override entry point: open a specific library path. Replaces the + /// cached instance. + static DartBridge open(String path) => + _instance = DartBridge._(DynamicLibrary.open(path)); + + /// Test/override entry point: resolve from the host process (Apple). + /// Replaces the cached instance. + static DartBridge process() => + _instance = DartBridge._(DynamicLibrary.process()); + + static DynamicLibrary _loadDefault() { + if (Platform.isMacOS || Platform.isIOS) { + return DynamicLibrary.process(); + } + if (Platform.isAndroid || Platform.isLinux) { + return DynamicLibrary.open('libdart_bridge.so'); + } + if (Platform.isWindows) { + return DynamicLibrary.open( + kDebugMode ? 'dart_bridge_d.dll' : 'dart_bridge.dll'); + } + throw UnsupportedError( + 'serious_python: dart_bridge has no binary for this platform'); + } + + /// Initialize the Dart Native API DL hooks so the worker thread spawned by + /// `serious_python_run` and `send_bytes` (Python→Dart) can post to ports. + /// Idempotent — calling more than once is a cheap no-op past the first. + bool _apiDLInitialized = false; + void initDartApiDL() { + if (_apiDLInitialized) return; + final rc = _initApiDL(NativeApi.initializeApiDLData); + if (rc != 0) { + throw StateError('DartBridge_InitDartApiDL failed with code $rc'); + } + _apiDLInitialized = true; + } + + /// Run a Python program (`appPath` mode) or source string (`script` mode). + /// See [SpRunConfig] / `serious_python_run`. + int run(Pointer cfg) => _run(cfg); + + /// Deliver bytes to the Python handler registered for [port]. Returns 0 on + /// successful delivery, -1 if no handler is registered (caller may retry), + /// or -2 if the interpreter is not initialized. + int enqueueMessage(int port, Pointer data, int len) => + _enqueueMessage(port, data, len); +} + +// --------------------------------------------------------------------------- +// High-level helper: build SpRunConfig, run, free. +// --------------------------------------------------------------------------- + +/// Allocates a NULL-terminated `char**` for a list of strings using [arena]. +Pointer>? _toCStringArray(Arena arena, List? strings) { + if (strings == null) return null; + final ptr = arena>(strings.length + 1); + for (var i = 0; i < strings.length; i++) { + ptr[i] = strings[i].toNativeUtf8(allocator: arena); + } + ptr[strings.length] = nullptr; + return ptr; +} + +/// Run a Python program via dart_bridge. +/// +/// - `sync: false` (default): spawn a worker thread and return immediately +/// with 0 on successful spawn. The Python run continues in the background; +/// bridge traffic flows over Dart ↔ Python ports independently. +/// - `sync: true`: block the calling thread inside the Python interpreter +/// until the program finishes, then return its exit code. +/// +/// If [completionPort] is provided, the exit code is also posted to that +/// Dart port via `Dart_PostInteger_DL` when Python finishes. Default `0` +/// disables the post. +int runPython({ + required DartBridge bridge, + String? appPath, + String? script, + String? programName, + List? modulePaths, + Map? environmentVariables, + bool sync = false, + int completionPort = 0, +}) { + if ((appPath == null) == (script == null)) { + throw ArgumentError( + 'Provide exactly one of appPath / script (got both or neither)'); + } + + // Worker thread needs the Dart Native API DL hooks so it can post to a + // completion port. Idempotent past the first call; cheap to do every time. + bridge.initDartApiDL(); + + return using((Arena arena) { + final cfg = arena(); + cfg.ref + ..mode = script != null ? spRunScript : spRunPath + ..appPath = + appPath != null ? appPath.toNativeUtf8(allocator: arena) : nullptr + ..scriptSource = + script != null ? script.toNativeUtf8(allocator: arena) : nullptr + ..programName = programName != null + ? programName.toNativeUtf8(allocator: arena) + : nullptr + ..modulePaths = _toCStringArray(arena, modulePaths) ?? nullptr + ..sync = sync ? 1 : 0 + ..completionPort = completionPort; + + if (environmentVariables != null && environmentVariables.isNotEmpty) { + final keys = environmentVariables.keys.toList(); + final values = keys.map((k) => environmentVariables[k]!).toList(); + cfg.ref.envKeys = _toCStringArray(arena, keys)!; + cfg.ref.envValues = _toCStringArray(arena, values)!; + } else { + cfg.ref.envKeys = nullptr; + cfg.ref.envValues = nullptr; + } + + return bridge.run(cfg); + }); +} diff --git a/src/serious_python_platform_interface/pubspec.yaml b/src/serious_python_platform_interface/pubspec.yaml index 22dbe9ee..36688468 100644 --- a/src/serious_python_platform_interface/pubspec.yaml +++ b/src/serious_python_platform_interface/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: path_provider: ^2.1.3 archive: ^4.0.7 path: ^1.9.0 + ffi: ^2.1.2 dev_dependencies: flutter_test: From d0997a7a58595be82e4b5a3bb3aa55cdf80162ae Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 10:32:53 -0700 Subject: [PATCH 043/114] Move + rewrite bridge_example for PythonBridge API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bridge_example used to live alongside the serious_python_bridge plugin (itself slated for deletion in Phase 2). With the v1.2.0 keyed-handlers model and the new PythonBridge class in serious_python/lib/, the example no longer needs serious_python_bridge — it depends only on serious_python. Changes: - git mv src/serious_python_bridge/example → src/serious_python/example/bridge_example - pubspec drops serious_python_bridge; depends only on ../.. - lib/main.dart uses PythonBridge() / bridge.port / bridge.close() - app/src/main.py reads BRIDGE_EXAMPLE_PORT env var and calls the new 2-arg set_enqueue_handler_func(port, handler) - integration_test exercises the same round-trip without the 8-byte handshake dance — Python knows its port from the env var the moment the interpreter starts - README rewritten to reflect new architecture - pubspec.lock gitignored (regenerates on path-deps anyway) test-bridge-build.yml stripped to just the darwin example jobs pointed at the new path. The obsolete cibuildwheel + NDK + linux/windows/android example jobs will return as each platform plugin gets ported to download pre-built libdart_bridge binaries. --- .github/workflows/test-bridge-build.yml | 507 +----------------- .../example/bridge_example}/.gitignore | 1 + .../example/bridge_example}/.metadata | 0 .../example/bridge_example/README.md | 41 ++ .../bridge_example}/analysis_options.yaml | 0 .../bridge_example}/android/.gitignore | 0 .../android/app/build.gradle.kts | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../MainActivity.kt | 0 .../res/drawable-v21/launch_background.xml | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values-night/styles.xml | 0 .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 .../bridge_example}/android/build.gradle.kts | 0 .../bridge_example}/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../android/settings.gradle.kts | 0 .../example/bridge_example/app/src/main.py | 40 ++ .../bridge_example/app/src/requirements.txt | 3 + .../integration_test/bridge_echo_test.dart | 70 +++ .../example/bridge_example}/ios/.gitignore | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../ios/Flutter/Debug.xcconfig | 0 .../ios/Flutter/Release.xcconfig | 0 .../example/bridge_example}/ios/Podfile | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../bridge_example}/ios/Runner/Info.plist | 0 .../ios/Runner/Runner-Bridging-Header.h | 0 .../ios/Runner/SceneDelegate.swift | 0 .../ios/RunnerTests/RunnerTests.swift | 0 .../example/bridge_example/lib/main.dart | 110 ++++ .../example/bridge_example}/linux/.gitignore | 0 .../bridge_example}/linux/CMakeLists.txt | 0 .../linux/flutter/CMakeLists.txt | 0 .../flutter/generated_plugin_registrant.cc | 0 .../flutter/generated_plugin_registrant.h | 0 .../linux/flutter/generated_plugins.cmake | 1 - .../linux/runner/CMakeLists.txt | 0 .../bridge_example}/linux/runner/main.cc | 0 .../linux/runner/my_application.cc | 0 .../linux/runner/my_application.h | 0 .../example/bridge_example}/macos/.gitignore | 0 .../macos/Flutter/Flutter-Debug.xcconfig | 0 .../macos/Flutter/Flutter-Release.xcconfig | 0 .../Flutter/GeneratedPluginRegistrant.swift | 2 - .../example/bridge_example}/macos/Podfile | 0 .../bridge_example}/macos/Podfile.lock | 0 .../macos/Runner.xcodeproj/project.pbxproj | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../macos/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/app_icon_1024.png | Bin .../AppIcon.appiconset/app_icon_128.png | Bin .../AppIcon.appiconset/app_icon_16.png | Bin .../AppIcon.appiconset/app_icon_256.png | Bin .../AppIcon.appiconset/app_icon_32.png | Bin .../AppIcon.appiconset/app_icon_512.png | Bin .../AppIcon.appiconset/app_icon_64.png | Bin .../macos/Runner/Base.lproj/MainMenu.xib | 0 .../macos/Runner/Configs/AppInfo.xcconfig | 0 .../macos/Runner/Configs/Debug.xcconfig | 0 .../macos/Runner/Configs/Release.xcconfig | 0 .../macos/Runner/Configs/Warnings.xcconfig | 0 .../macos/Runner/DebugProfile.entitlements | 0 .../bridge_example}/macos/Runner/Info.plist | 0 .../macos/Runner/MainFlutterWindow.swift | 0 .../macos/Runner/Release.entitlements | 0 .../macos/RunnerTests/RunnerTests.swift | 0 .../example/bridge_example}/pubspec.yaml | 8 +- .../bridge_example}/windows/.gitignore | 0 .../bridge_example}/windows/CMakeLists.txt | 0 .../windows/flutter/CMakeLists.txt | 0 .../flutter/generated_plugin_registrant.cc | 0 .../flutter/generated_plugin_registrant.h | 0 .../windows/flutter/generated_plugins.cmake | 1 - .../windows/runner/CMakeLists.txt | 0 .../bridge_example}/windows/runner/Runner.rc | 0 .../windows/runner/flutter_window.cpp | 0 .../windows/runner/flutter_window.h | 0 .../bridge_example}/windows/runner/main.cpp | 0 .../bridge_example}/windows/runner/resource.h | 0 .../windows/runner/resources/app_icon.ico | Bin .../windows/runner/runner.exe.manifest | 0 .../bridge_example}/windows/runner/utils.cpp | 0 .../bridge_example}/windows/runner/utils.h | 0 .../windows/runner/win32_window.cpp | 0 .../windows/runner/win32_window.h | 0 src/serious_python_bridge/example/README.md | 35 -- .../example/app/src/main.py | 53 -- .../example/app/src/requirements.txt | 4 - .../integration_test/bridge_echo_test.dart | 85 --- .../example/lib/main.dart | 146 ----- 133 files changed, 278 insertions(+), 829 deletions(-) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/.gitignore (98%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/.metadata (100%) create mode 100644 src/serious_python/example/bridge_example/README.md rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/analysis_options.yaml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/.gitignore (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/build.gradle.kts (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/debug/AndroidManifest.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/AndroidManifest.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/drawable-v21/launch_background.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/drawable/launch_background.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/values-night/styles.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/main/res/values/styles.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/app/src/profile/AndroidManifest.xml (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/build.gradle.kts (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/gradle.properties (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/gradle/wrapper/gradle-wrapper.properties (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/android/settings.gradle.kts (100%) create mode 100644 src/serious_python/example/bridge_example/app/src/main.py create mode 100644 src/serious_python/example/bridge_example/app/src/requirements.txt create mode 100644 src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/.gitignore (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Flutter/AppFrameworkInfo.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Flutter/Debug.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Flutter/Release.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Podfile (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcodeproj/project.pbxproj (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/AppDelegate.swift (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Base.lproj/Main.storyboard (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Info.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/Runner-Bridging-Header.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/Runner/SceneDelegate.swift (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/ios/RunnerTests/RunnerTests.swift (100%) create mode 100644 src/serious_python/example/bridge_example/lib/main.dart rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/.gitignore (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/CMakeLists.txt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/flutter/CMakeLists.txt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/flutter/generated_plugin_registrant.cc (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/flutter/generated_plugin_registrant.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/flutter/generated_plugins.cmake (96%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/runner/CMakeLists.txt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/runner/main.cc (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/runner/my_application.cc (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/linux/runner/my_application.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/.gitignore (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Flutter/Flutter-Debug.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Flutter/Flutter-Release.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Flutter/GeneratedPluginRegistrant.swift (66%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Podfile (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Podfile.lock (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner.xcodeproj/project.pbxproj (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner.xcworkspace/contents.xcworkspacedata (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/AppDelegate.swift (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Base.lproj/MainMenu.xib (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Configs/AppInfo.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Configs/Debug.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Configs/Release.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Configs/Warnings.xcconfig (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/DebugProfile.entitlements (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Info.plist (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/MainFlutterWindow.swift (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/Runner/Release.entitlements (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/macos/RunnerTests/RunnerTests.swift (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/pubspec.yaml (65%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/.gitignore (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/CMakeLists.txt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/flutter/CMakeLists.txt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/flutter/generated_plugin_registrant.cc (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/flutter/generated_plugin_registrant.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/flutter/generated_plugins.cmake (96%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/CMakeLists.txt (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/Runner.rc (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/flutter_window.cpp (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/flutter_window.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/main.cpp (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/resource.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/resources/app_icon.ico (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/runner.exe.manifest (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/utils.cpp (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/utils.h (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/win32_window.cpp (100%) rename src/{serious_python_bridge/example => serious_python/example/bridge_example}/windows/runner/win32_window.h (100%) delete mode 100644 src/serious_python_bridge/example/README.md delete mode 100644 src/serious_python_bridge/example/app/src/main.py delete mode 100644 src/serious_python_bridge/example/app/src/requirements.txt delete mode 100644 src/serious_python_bridge/example/integration_test/bridge_echo_test.dart delete mode 100644 src/serious_python_bridge/example/lib/main.dart diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 8c361fd7..3bdf2fb7 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -1,10 +1,12 @@ name: Test bridge (no publish, no slow platform tests) -# Throwaway workflow that exercises just the new serious_python_bridge work — -# the cibuildwheel matrix, the Android NDK cross-build, and the macOS bridge -# example integration test — without triggering the slow flet_example -# platform matrix or the publish/release steps in ci.yml. Delete before -# merging to main. +# Throwaway workflow that exercises just the new bridge_example end-to-end +# on Darwin (macOS + iOS) — the platforms ported so far in the dart-bridge +# branch's consolidation work. Other platforms (Linux/Windows/Android) will +# return as each `serious_python_*` plugin gets wired up to download +# pre-built libdart_bridge binaries from flet-dev/dart-bridge releases. +# +# Delete before merging to main. on: push: @@ -12,235 +14,9 @@ on: workflow_dispatch: env: - # Mirrors ci.yml's workflow-level env: serious_python_darwin's - # sync_site_packages.sh and the Linux CMakeLists.txt both read this to know - # where package_command.dart staged the bundled site-packages. SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" jobs: - test_wheel_build: - name: cibuildwheel (${{ matrix.os }}) - strategy: - fail-fast: false - matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 - with: - package-dir: src/serious_python_bridge/python - - # Windows ships two CPython variants (Release pythonXY.dll and Debug - # pythonXY_d.dll). The cibuildwheel-built abi3 .pyd is Release-CRT; a - # Debug Flutter app loads Debug Python and tries to import - # dart_bridge_d.cp-win_amd64.pyd (CPython appends _d to EXT_SUFFIX - # when built in Debug mode). Compile a Debug-CRT variant of the same - # dart_bridge_shim.c and pack it alongside the Release .pyd in each - # wheel. Released wheels then work in both `flutter build` (Release) - # and `fvm flutter run` (Debug) without a serious_python_windows split. - - name: Build Debug-variant dart_bridge.pyd and inject into Windows wheels - if: matrix.os == 'windows-latest' - shell: pwsh - run: | - $ErrorActionPreference = 'Stop' - # Use 3.12 headers — abi3 (Py_LIMITED_API=0x030c0000) means one .pyd - # built against the minimum supported version works for every - # 3.12+ runtime. - $pyver = '3.12' - $pyverNodot = '312' - $pywinZip = "python-windows-for-dart-$pyver.zip" - $pywinUrl = "https://github.com/flet-dev/python-build/releases/download/v$pyver/$pywinZip" - Write-Host "Downloading $pywinUrl" - Invoke-WebRequest -Uri $pywinUrl -OutFile $pywinZip - Expand-Archive -Path $pywinZip -DestinationPath "pywin-$pyver" -Force - - $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" - $vsPath = & $vswhere -latest -property installationPath - $vcvars = "$vsPath\VC\Auxiliary\Build\vcvars64.bat" - Write-Host "vcvars: $vcvars" - - $shimSrc = (Resolve-Path 'src/serious_python_bridge/native/dart_bridge_shim.c').Path - $includeDir = (Resolve-Path "pywin-$pyver/include").Path - $libDir = (Resolve-Path "pywin-$pyver/libs").Path - $outDir = "$PWD\debug_build" - New-Item -ItemType Directory -Force -Path $outDir | Out-Null - $outPyd = "$outDir\dart_bridge_d.pyd" - - # /LD = build DLL. /MDd = link Debug CRT (vcruntime140d/msvcp140d). - # /D_DEBUG = trigger pyconfig.h's Debug branch + match Debug CRT. - # /DPy_LIMITED_API = mirror the Release wheel's abi3 contract. - # Link the Debug abi3 stub python3_d.lib (forwards to python3_d.dll - # which serious_python_windows ships in Debug Flutter builds). - # /LIBPATH puts python-windows-for-dart's libs/ folder on the - # linker search path so pyconfig.h's auto-link `#pragma comment( - # lib, "pythonXY_d.lib")` resolves (it asks for python312_d.lib by - # name; that file ships in the same libs/ folder). - $clCmd = "cl /nologo /LD /MDd /D_DEBUG /DPy_LIMITED_API=0x030c0000 /I `"$includeDir`" `"$shimSrc`" /link /LIBPATH:`"$libDir`" /OUT:`"$outPyd`" `"$libDir\python3_d.lib`"" - Write-Host "Running: $clCmd" - cmd /c "`"$vcvars`" >NUL && $clCmd" - if (-not (Test-Path $outPyd)) { - throw "Debug .pyd not produced: $outPyd" - } - Write-Host "Built: $outPyd" - Get-Item $outPyd | Format-List FullName, Length - - # Inject the Debug .pyd into each Windows wheel. - python -m pip install --quiet wheel - foreach ($whl in Get-ChildItem "wheelhouse\dart_bridge-*-cp312-abi3-win_amd64.whl") { - $unpackDir = Join-Path $env:RUNNER_TEMP ("unpack_" + [IO.Path]::GetFileNameWithoutExtension($whl.Name)) - if (Test-Path $unpackDir) { Remove-Item -Recurse -Force $unpackDir } - python -m wheel unpack -d $unpackDir $whl.FullName - $unpackedRoot = Get-ChildItem $unpackDir -Directory | Select-Object -First 1 - Write-Host "Unpacked tree:" - Get-ChildItem -Recurse -Path $unpackedRoot.FullName | ForEach-Object { - Write-Host " $($_.FullName.Substring($unpackedRoot.FullName.Length))" - } - # Find any existing dart_bridge*.pyd to know where to place the Debug - # sibling. setuptools may name it dart_bridge.pyd, dart_bridge.abi3.pyd, - # dart_bridge.cp312-win_amd64.pyd, etc., depending on the build setup. - $existing = Get-ChildItem -Recurse -Path $unpackedRoot.FullName -Filter 'dart_bridge*.pyd' | Select-Object -First 1 - if (-not $existing) { throw "No dart_bridge*.pyd found inside $($whl.FullName)" } - Write-Host "Found Release pyd: $($existing.Name)" - $debugDest = Join-Path $existing.DirectoryName "dart_bridge_d.pyd" - Copy-Item $outPyd $debugDest - Write-Host "Injected: $debugDest" - Remove-Item $whl.FullName - python -m wheel pack -d wheelhouse $unpackedRoot.FullName - } - - - name: List built wheels - shell: bash - run: | - ls -la wheelhouse/ - echo - echo "Wheel filenames (expect cp312-abi3-):" - ls wheelhouse/*.whl - if [ "${{ matrix.os }}" = "windows-latest" ]; then - echo - echo "Wheel contents (verify Debug + Release .pyd both present):" - for w in wheelhouse/*.whl; do - echo "--- $w ---" - python -m zipfile -l "$w" | grep -E "dart_bridge.*\.pyd" || true - done - fi - - - name: Upload wheel artifacts - uses: actions/upload-artifact@v4 - with: - name: bridge-wheels-${{ matrix.os }} - path: wheelhouse/*.whl - if-no-files-found: error - - test_android_build: - name: Android cross-build (${{ matrix.abi }}, Py ${{ matrix.python_version }}) - runs-on: ubuntu-24.04 - strategy: - fail-fast: false - matrix: - abi: [arm64-v8a, armeabi-v7a, x86_64] - python_version: ['3.12', '3.13', '3.14'] - exclude: - # 32-bit Android was dropped in CPython 3.13+ (PEP 738) — the - # python-android-mobile-forge tarball doesn't ship an armeabi-v7a - # install for those versions. - - abi: armeabi-v7a - python_version: '3.13' - - abi: armeabi-v7a - python_version: '3.14' - env: - PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Download python-android-mobile-forge tarball - run: | - set -euo pipefail - VER="$PYTHON_VERSION" - ABI="${{ matrix.abi }}" - ARCHIVE="python-android-mobile-forge-${VER}.tar.gz" - curl -fL -o "$ARCHIVE" \ - "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" - mkdir -p pydist - # The patch version inside the tarball path (python-X.Y.Z/) shifts - # over time, so extract by ABI/include + ABI/lib prefix and let - # tar pick whatever python-X.Y.* directory is there. - tar -xzf "$ARCHIVE" -C pydist \ - --wildcards \ - "install/android/${ABI}/python-${VER}.*/include/" \ - "install/android/${ABI}/python-${VER}.*/lib/" - echo "Python.h candidates:" - find pydist -name "Python.h" - echo "libpython candidates:" - find pydist -name "libpython*.so" - - - name: Cross-compile dart_bridge.abi3.so - run: | - set -euxo pipefail - VER="$PYTHON_VERSION" - ABI="${{ matrix.abi }}" - - case "$ABI" in - arm64-v8a) TARGET=aarch64-linux-android ;; - armeabi-v7a) TARGET=armv7a-linux-androideabi ;; - x86_64) TARGET=x86_64-linux-android ;; - *) echo "unsupported ABI: $ABI" >&2 ; exit 1 ;; - esac - - API=21 - NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK_LATEST_HOME}}" - TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64" - CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" - test -x "$CC" - - INCLUDE_DIR=$(find pydist -path "*/python-${VER}.*/include/python${VER}" | head -n1) - LIBPYTHON=$(find pydist -path "*/python-${VER}.*/lib/libpython${VER}.so" | head -n1) - test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" - - OUT="dart_bridge.abi3-android-${ABI}.so" - - # Compile dart_bridge_shim.c (the Python-callable module) — same - # source used by the Linux/Windows wheels. Symbols from the core - # (dart_bridge_global_enqueue_handler_func, dart_bridge_post_to_dart) - # are resolved at PyInit time via dlsym/dlopen against - # libflet_bridge.so, which the Flutter plugin builds + bundles - # separately. Linking dart_bridge.c directly into this .so would - # produce a second, isolated copy of the global handler cell — - # Dart's side and Python's side would never see the same value. - # -ldl gives dart_bridge_shim.c its dlsym/dlopen. - # - # Link $LIBPYTHON for this specific Python version so DT_NEEDED - # references libpythonX.Y.so and matches the libpython - # serious_python_android bundles at runtime for the same version. - # abi3 makes the *symbol set* portable, but Android's linker still - # needs the DT_NEEDED entry to resolve to a file that exists in the - # APK at load time — which is why we build per-version (matrix). - $CC -shared -fPIC -fvisibility=hidden \ - -DPy_LIMITED_API=0x030c0000 \ - -I"$INCLUDE_DIR" \ - -I"src/serious_python_bridge/native" \ - src/serious_python_bridge/native/dart_bridge_shim.c \ - "$LIBPYTHON" \ - -ldl \ - -Wl,-z,max-page-size=16384 \ - -o "$OUT" - - - name: Inspect output - run: | - ls -lh dart_bridge.abi3-android-*.so - file dart_bridge.abi3-android-*.so - - - name: Upload .so artifact - uses: actions/upload-artifact@v4 - with: - name: bridge-android-${{ matrix.abi }}-py${{ matrix.python_version }} - path: dart_bridge.abi3-android-*.so - if-no-files-found: error - test_bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) runs-on: macos-latest @@ -261,7 +37,7 @@ jobs: cache: true - name: Package + run integration test - working-directory: "src/serious_python_bridge/example" + working-directory: "src/serious_python/example/bridge_example" run: | dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} flutter test integration_test -d macos @@ -294,7 +70,7 @@ jobs: uses: actions/cache@v4 with: path: src/serious_python_darwin/darwin/dist_ios - key: ios-python-dist-${{ matrix.python_version }}-v1 + key: ios-python-dist-${{ matrix.python_version }}-v2 - name: Setup iOS Simulator id: simulator @@ -307,7 +83,7 @@ jobs: wait_for_boot: true - name: Package + run integration test - working-directory: "src/serious_python_bridge/example" + working-directory: "src/serious_python/example/bridge_example" run: | ts() { date '+%H:%M:%S'; } echo "[$(ts)] >>> dart run serious_python:main package" @@ -320,266 +96,3 @@ jobs: echo "[$(ts)] >>> flutter test integration_test" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} echo "[$(ts)] >>> done" - - test_bridge_example_linux: - name: Bridge example Linux ${{ matrix.title }} round-trip (Python ${{ matrix.python_version }}) - runs-on: ${{ matrix.runner }} - needs: test_wheel_build - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - arch: [arm64, amd64] - include: - - arch: arm64 - runner: ubuntu-24.04-arm - title: ARM64 - wheel_artifact: bridge-wheels-ubuntu-24.04-arm - - arch: amd64 - runner: ubuntu-24.04 - title: AMD64 - wheel_artifact: bridge-wheels-ubuntu-24.04 - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup uv - uses: astral-sh/setup-uv@v6 - - - name: Get Flutter version from .fvmrc - uses: kuhnroyal/flutter-fvm-config-action/config@v3 - id: fvm-config-action - with: - path: '.fvmrc' - - - name: Setup Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} - channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} - cache: true - - - name: Install Linux desktop build deps - run: | - sudo apt-get update --allow-releaseinfo-change - sudo apt-get install -y xvfb libgtk-3-dev - if [ "${{ matrix.arch }}" = "amd64" ]; then - sudo apt-get install -y \ - libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav - else - sudo apt-get install -y \ - clang ninja-build gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav - fi - - - name: Download dart_bridge wheel artifact - uses: actions/download-artifact@v4 - with: - name: ${{ matrix.wheel_artifact }} - path: ${{ runner.temp }}/dart_bridge_wheels - - - name: Pick matching wheel for this arch - id: wheel - run: | - set -euo pipefail - WHL=$(ls "${{ runner.temp }}/dart_bridge_wheels"/dart_bridge-*manylinux*.whl | head -n1) - test -n "$WHL" - echo "path=$WHL" >> "$GITHUB_OUTPUT" - echo "Picked: $WHL" - - - name: Package + run integration test - working-directory: src/serious_python_bridge/example - run: | - flutter pub get - dart run serious_python:main package app/src \ - --platform Linux \ - --python-version ${{ matrix.python_version }} \ - --requirements ${{ steps.wheel.outputs.path }} - xvfb-run flutter test integration_test -d linux - - test_bridge_example_android: - name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) - runs-on: ubuntu-latest - needs: test_android_build - strategy: - fail-fast: false - matrix: - # x86_64 matches the emulator architecture below; only build/install - # for that ABI to keep CI fast. - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 - - - name: AVD cache - uses: actions/cache@v4 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-bridge - - - name: Download Android bridge .so for x86_64 - uses: actions/download-artifact@v4 - with: - name: bridge-android-x86_64-py${{ matrix.python_version }} - path: ${{ runner.temp }}/dart_bridge_android - - - name: Inject dart_bridge.abi3.so into bundled site-packages - run: | - # serious_python_android's gradle takes everything from - # SERIOUS_PYTHON_SITE_PACKAGES// and zips it as - # libpythonsitepackages.so, which ends up in the APK. Drop our - # cross-compiled dart_bridge.abi3.so there so Python finds it at - # runtime. The .so name has to be the canonical 'dart_bridge.abi3.so' - # for CPython's import to match. - set -euxo pipefail - ABI=x86_64 - DEST="$SERIOUS_PYTHON_SITE_PACKAGES/$ABI" - mkdir -p "$DEST" - cp "${{ runner.temp }}/dart_bridge_android/dart_bridge.abi3-android-$ABI.so" \ - "$DEST/dart_bridge.abi3.so" - ls -lh "$DEST" - - - name: Setup Android Emulator + Run tests - uses: reactivecircus/android-emulator-runner@v2 - env: - EMULATOR_PORT: 5554 - with: - avd-name: android_emulator - api-level: 33 - target: google_atd - arch: x86_64 - profile: pixel_5 - sdcard-path-or-size: 128M - ram-size: 2048M - disk-size: 4096M - emulator-port: ${{ env.EMULATOR_PORT }} - disable-animations: true - emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 - pre-emulator-launch-script: | - sdkmanager --list_installed - script: | - cd src/serious_python_bridge/example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} - cd src/serious_python_bridge/example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} - - - name: Diagnostics on failure - if: failure() - shell: bash - run: | - set +e - REPO="$GITHUB_WORKSPACE" - ABI=x86_64 - echo "=== serious_python_android/android/src/main/jniLibs/$ABI/ (post-extract source) ===" - ls -la "$REPO/src/serious_python_android/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" - echo - echo "=== serious_python_bridge/android/src/main/jniLibs/$ABI/ ===" - ls -la "$REPO/src/serious_python_bridge/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" - echo - echo "=== example/build/app/intermediates/merged_native_libs/.../$ABI/ ===" - find "$REPO/src/serious_python_bridge/example/build/app/intermediates/merged_native_libs" -type f 2>/dev/null - echo - echo "=== example/build/app/outputs/apk/debug/*.apk ===" - APK=$(find "$REPO/src/serious_python_bridge/example/build" -name "*-debug.apk" 2>/dev/null | head -n1) - echo "APK: $APK" - if [ -n "$APK" ]; then - echo "Native libs inside APK:" - unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" - fi - echo - echo "=== installed app native lib dir (adb) ===" - adb shell run-as com.flet.serious_python_bridge_example ls -la /data/data/com.flet.serious_python_bridge_example/lib/ 2>/dev/null || true - adb shell pm path com.flet.serious_python_bridge_example 2>/dev/null || true - - test_bridge_example_windows: - name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) - runs-on: windows-latest - needs: test_wheel_build - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Download dart_bridge wheel artifact - uses: actions/download-artifact@v4 - with: - name: bridge-wheels-windows-latest - path: ${{ runner.temp }}\dart_bridge_wheels - - - name: Pick matching wheel - id: wheel - shell: bash - run: | - set -euo pipefail - WHL=$(ls "$RUNNER_TEMP/dart_bridge_wheels"/dart_bridge-*-win_amd64.whl | head -n1) - test -n "$WHL" - echo "path=$WHL" >> "$GITHUB_OUTPUT" - echo "Picked: $WHL" - - - name: Package + run integration test - working-directory: "src/serious_python_bridge/example" - run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} - flutter test integration_test -d windows - - - name: Diagnostics on failure - if: failure() - shell: bash - working-directory: "src/serious_python_bridge/example" - run: | - DBG_DIR=build/windows/x64/runner/Debug - echo "=== runner/Debug dir ===" - ls -la $DBG_DIR/ || true - echo - echo "=== runner/Debug/site-packages ===" - ls -la $DBG_DIR/site-packages/ || true - echo - echo "=== shim log next to .exe ===" - cat $DBG_DIR/dart_bridge_shim.log 2>/dev/null || echo "(log not found)" - echo - echo "=== direct import test (catches the actual ImportError) ===" - # Try to import dart_bridge using the bundled Python so we can see - # the actual error. Python search paths the bundle uses. - PY_BUNDLED=$(find $DBG_DIR -maxdepth 1 -name "python.exe" -o -name "python3*.exe" 2>/dev/null | head -n1) - if [ -z "$PY_BUNDLED" ]; then - echo "(no python.exe in $DBG_DIR — trying system python)" - PY_BUNDLED=python - fi - (cd $DBG_DIR && PYTHONPATH="site-packages;." "$PY_BUNDLED" -c "import sys; print('sys.path:', sys.path); import dart_bridge; print('imported OK:', dart_bridge)") 2>&1 || true - echo - echo "=== look for stray flet_bridge.dll / dart_bridge.pyd ===" - find build -name "flet_bridge.dll" -o -name "dart_bridge*.pyd" || true diff --git a/src/serious_python_bridge/example/.gitignore b/src/serious_python/example/bridge_example/.gitignore similarity index 98% rename from src/serious_python_bridge/example/.gitignore rename to src/serious_python/example/bridge_example/.gitignore index 32f8d81d..480a7ff6 100644 --- a/src/serious_python_bridge/example/.gitignore +++ b/src/serious_python/example/bridge_example/.gitignore @@ -47,3 +47,4 @@ app.*.map.json # serious_python packaging artifacts (built by `dart run serious_python:main package`) /app/app.zip /app/app.zip.hash +pubspec.lock diff --git a/src/serious_python_bridge/example/.metadata b/src/serious_python/example/bridge_example/.metadata similarity index 100% rename from src/serious_python_bridge/example/.metadata rename to src/serious_python/example/bridge_example/.metadata diff --git a/src/serious_python/example/bridge_example/README.md b/src/serious_python/example/bridge_example/README.md new file mode 100644 index 00000000..a330a0a4 --- /dev/null +++ b/src/serious_python/example/bridge_example/README.md @@ -0,0 +1,41 @@ +# bridge_example + +Minimal Flutter app exercising [`PythonBridge`](../../lib/bridge.dart) — +the in-process byte transport between Dart and the embedded CPython +runtime. Sends bytes from Dart to Python via `bridge.send()`, and Python +echoes them back through `dart_bridge.send_bytes()`. No Flet, no msgpack, +no protocol layer — the smallest possible end-to-end demonstration of the +transport. + +## Build the Python app bundle + +Before running, package the Python source into `app/app.zip`: + +```sh +# From this directory: +dart run serious_python:main package app/src --platform Darwin \ + --python-version 3.14 +``` + +Substitute `Darwin` with `Linux`, `Windows`, or `Android` for those +targets (each platform plugin's CMake/Gradle pipeline downloads the +prebuilt `dart_bridge` native binary from +[flet-dev/dart-bridge](https://github.com/flet-dev/dart-bridge) at build +time — no `--bridge` flag, no PyPI wheel). + +## Run + +```sh +flutter run -d macos # or -d linux / windows / +``` + +How it works: + +1. Dart creates a `PythonBridge`; its `port` (a `ReceivePort.sendPort.nativePort`) + is exported to Python via the `BRIDGE_EXAMPLE_PORT` env var passed to + `SeriousPython.run()`. +2. Python reads the env var, registers a handler keyed on that port via + `dart_bridge.set_enqueue_handler_func(port, handler)`, and echoes any + incoming frame with a `b"echo: "` prefix using `dart_bridge.send_bytes(port, ...)`. +3. Dart's `bridge.send()` returns `false` until the Python-side handler + is registered; the example retries briefly to cover that startup race. diff --git a/src/serious_python_bridge/example/analysis_options.yaml b/src/serious_python/example/bridge_example/analysis_options.yaml similarity index 100% rename from src/serious_python_bridge/example/analysis_options.yaml rename to src/serious_python/example/bridge_example/analysis_options.yaml diff --git a/src/serious_python_bridge/example/android/.gitignore b/src/serious_python/example/bridge_example/android/.gitignore similarity index 100% rename from src/serious_python_bridge/example/android/.gitignore rename to src/serious_python/example/bridge_example/android/.gitignore diff --git a/src/serious_python_bridge/example/android/app/build.gradle.kts b/src/serious_python/example/bridge_example/android/app/build.gradle.kts similarity index 100% rename from src/serious_python_bridge/example/android/app/build.gradle.kts rename to src/serious_python/example/bridge_example/android/app/build.gradle.kts diff --git a/src/serious_python_bridge/example/android/app/src/debug/AndroidManifest.xml b/src/serious_python/example/bridge_example/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/debug/AndroidManifest.xml rename to src/serious_python/example/bridge_example/android/app/src/debug/AndroidManifest.xml diff --git a/src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/bridge_example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/AndroidManifest.xml rename to src/serious_python/example/bridge_example/android/app/src/main/AndroidManifest.xml diff --git a/src/serious_python_bridge/example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt b/src/serious_python/example/bridge_example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt rename to src/serious_python/example/bridge_example/android/app/src/main/kotlin/com/flet/serious_python_bridge_example/MainActivity.kt diff --git a/src/serious_python_bridge/example/android/app/src/main/res/drawable-v21/launch_background.xml b/src/serious_python/example/bridge_example/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/drawable-v21/launch_background.xml rename to src/serious_python/example/bridge_example/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/src/serious_python_bridge/example/android/app/src/main/res/drawable/launch_background.xml b/src/serious_python/example/bridge_example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/drawable/launch_background.xml rename to src/serious_python/example/bridge_example/android/app/src/main/res/drawable/launch_background.xml diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to src/serious_python/example/bridge_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/serious_python_bridge/example/android/app/src/main/res/values-night/styles.xml b/src/serious_python/example/bridge_example/android/app/src/main/res/values-night/styles.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/values-night/styles.xml rename to src/serious_python/example/bridge_example/android/app/src/main/res/values-night/styles.xml diff --git a/src/serious_python_bridge/example/android/app/src/main/res/values/styles.xml b/src/serious_python/example/bridge_example/android/app/src/main/res/values/styles.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/main/res/values/styles.xml rename to src/serious_python/example/bridge_example/android/app/src/main/res/values/styles.xml diff --git a/src/serious_python_bridge/example/android/app/src/profile/AndroidManifest.xml b/src/serious_python/example/bridge_example/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from src/serious_python_bridge/example/android/app/src/profile/AndroidManifest.xml rename to src/serious_python/example/bridge_example/android/app/src/profile/AndroidManifest.xml diff --git a/src/serious_python_bridge/example/android/build.gradle.kts b/src/serious_python/example/bridge_example/android/build.gradle.kts similarity index 100% rename from src/serious_python_bridge/example/android/build.gradle.kts rename to src/serious_python/example/bridge_example/android/build.gradle.kts diff --git a/src/serious_python_bridge/example/android/gradle.properties b/src/serious_python/example/bridge_example/android/gradle.properties similarity index 100% rename from src/serious_python_bridge/example/android/gradle.properties rename to src/serious_python/example/bridge_example/android/gradle.properties diff --git a/src/serious_python_bridge/example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/bridge_example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from src/serious_python_bridge/example/android/gradle/wrapper/gradle-wrapper.properties rename to src/serious_python/example/bridge_example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/src/serious_python_bridge/example/android/settings.gradle.kts b/src/serious_python/example/bridge_example/android/settings.gradle.kts similarity index 100% rename from src/serious_python_bridge/example/android/settings.gradle.kts rename to src/serious_python/example/bridge_example/android/settings.gradle.kts diff --git a/src/serious_python/example/bridge_example/app/src/main.py b/src/serious_python/example/bridge_example/app/src/main.py new file mode 100644 index 00000000..e3eacfb3 --- /dev/null +++ b/src/serious_python/example/bridge_example/app/src/main.py @@ -0,0 +1,40 @@ +"""Echo loop exercising PythonBridge (dart_bridge v1.2.0 keyed-handlers API). + +Protocol: + Dart side creates a PythonBridge; its native port is handed to Python via + the BRIDGE_EXAMPLE_PORT env var. Python registers a handler for that port + and echoes each received frame back prefixed with b"echo: ". + +Python keeps the interpreter alive indefinitely so messages can keep arriving; +Dart drives the process lifetime (when the app exits, the embedded Python is +torn down). +""" + +from __future__ import annotations + +import os +import sys +import threading + +import dart_bridge + +PORT_ENV = "BRIDGE_EXAMPLE_PORT" + +try: + bridge_port = int(os.environ[PORT_ENV]) +except (KeyError, ValueError) as e: + print(f"[bridge_example] missing/invalid {PORT_ENV}: {e}", + file=sys.stderr, flush=True) + raise SystemExit(1) + + +def on_dart_message(data: bytes) -> None: + print(f"[bridge_example] received {len(data)} bytes", flush=True) + dart_bridge.send_bytes(bridge_port, b"echo: " + data) + + +dart_bridge.set_enqueue_handler_func(bridge_port, on_dart_message) +print(f"[bridge_example] handler registered on port {bridge_port}", flush=True) + +# Keep the embedded interpreter alive; Dart drives the process lifetime. +threading.Event().wait() diff --git a/src/serious_python/example/bridge_example/app/src/requirements.txt b/src/serious_python/example/bridge_example/app/src/requirements.txt new file mode 100644 index 00000000..c63040cf --- /dev/null +++ b/src/serious_python/example/bridge_example/app/src/requirements.txt @@ -0,0 +1,3 @@ +# No external dependencies — dart_bridge is bundled with every serious_python +# app as a built-in Python module (registered via PyImport_AppendInittab from +# the dart_bridge native library before Py_Initialize). diff --git a/src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart b/src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart new file mode 100644 index 00000000..4b30bfe0 --- /dev/null +++ b/src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart @@ -0,0 +1,70 @@ +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:serious_python/bridge.dart'; +import 'package:serious_python/serious_python.dart'; + +/// Env-var name carrying the Dart-side native port to Python. Must match the +/// name read by `app/src/main.py`. +const _bridgePortEnv = 'BRIDGE_EXAMPLE_PORT'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('round-trips a 1KB random payload byte-identically', + (tester) async { + // Pump a minimal widget so the Flutter binding + native plugin + // registration runs before we touch FFI. + await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); + + final bridge = PythonBridge(); + addTearDown(bridge.close); + + // Fire-and-forget: Python's main.py blocks waiting for messages and never + // returns. The port reaches Python via the env var — no in-band handshake. + unawaited(SeriousPython.run( + 'app/app.zip', + environmentVariables: {_bridgePortEnv: '${bridge.port}'}, + )); + + // Round-trip a 1KB random buffer. Seed is fixed so repeated runs assert + // against the same bytes — easier to debug regressions. + final rng = Random(0xC0FFEE); + final payload = Uint8List.fromList( + List.generate(1024, (_) => rng.nextInt(256)), + ); + final expectedPrefix = Uint8List.fromList('echo: '.codeUnits); + final expectedReply = Uint8List(expectedPrefix.length + payload.length) + ..setRange(0, expectedPrefix.length, expectedPrefix) + ..setRange(expectedPrefix.length, expectedPrefix.length + payload.length, + payload); + + // Pre-subscribe to the echo before sending. + final replyFuture = bridge.messages + .firstWhere((b) => b.length == expectedReply.length) + .timeout(const Duration(seconds: 30)); + + // Python may not have registered its handler yet; retry until it does. + await _sendUntilDelivered(bridge, payload); + + final reply = await replyFuture; + expect(reply, equals(expectedReply)); + }); +} + +Future _sendUntilDelivered(PythonBridge bridge, Uint8List payload) async { + const retryInterval = Duration(milliseconds: 200); + const overallTimeout = Duration(seconds: 30); + final deadline = DateTime.now().add(overallTimeout); + + while (DateTime.now().isBefore(deadline)) { + if (bridge.send(payload)) return; + await Future.delayed(retryInterval); + } + throw TimeoutException( + 'Python did not register a handler within ${overallTimeout.inSeconds}s'); +} diff --git a/src/serious_python_bridge/example/ios/.gitignore b/src/serious_python/example/bridge_example/ios/.gitignore similarity index 100% rename from src/serious_python_bridge/example/ios/.gitignore rename to src/serious_python/example/bridge_example/ios/.gitignore diff --git a/src/serious_python_bridge/example/ios/Flutter/AppFrameworkInfo.plist b/src/serious_python/example/bridge_example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from src/serious_python_bridge/example/ios/Flutter/AppFrameworkInfo.plist rename to src/serious_python/example/bridge_example/ios/Flutter/AppFrameworkInfo.plist diff --git a/src/serious_python_bridge/example/ios/Flutter/Debug.xcconfig b/src/serious_python/example/bridge_example/ios/Flutter/Debug.xcconfig similarity index 100% rename from src/serious_python_bridge/example/ios/Flutter/Debug.xcconfig rename to src/serious_python/example/bridge_example/ios/Flutter/Debug.xcconfig diff --git a/src/serious_python_bridge/example/ios/Flutter/Release.xcconfig b/src/serious_python/example/bridge_example/ios/Flutter/Release.xcconfig similarity index 100% rename from src/serious_python_bridge/example/ios/Flutter/Release.xcconfig rename to src/serious_python/example/bridge_example/ios/Flutter/Release.xcconfig diff --git a/src/serious_python_bridge/example/ios/Podfile b/src/serious_python/example/bridge_example/ios/Podfile similarity index 100% rename from src/serious_python_bridge/example/ios/Podfile rename to src/serious_python/example/bridge_example/ios/Podfile diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcodeproj/project.pbxproj rename to src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.pbxproj diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/src/serious_python_bridge/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to src/serious_python/example/bridge_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/src/serious_python_bridge/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/bridge_example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to src/serious_python/example/bridge_example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/bridge_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to src/serious_python/example/bridge_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python/example/bridge_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from src/serious_python_bridge/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to src/serious_python/example/bridge_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/src/serious_python_bridge/example/ios/Runner/AppDelegate.swift b/src/serious_python/example/bridge_example/ios/Runner/AppDelegate.swift similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/AppDelegate.swift rename to src/serious_python/example/bridge_example/ios/Runner/AppDelegate.swift diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to src/serious_python/example/bridge_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/src/serious_python_bridge/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/src/serious_python/example/bridge_example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to src/serious_python/example/bridge_example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/src/serious_python_bridge/example/ios/Runner/Base.lproj/Main.storyboard b/src/serious_python/example/bridge_example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Base.lproj/Main.storyboard rename to src/serious_python/example/bridge_example/ios/Runner/Base.lproj/Main.storyboard diff --git a/src/serious_python_bridge/example/ios/Runner/Info.plist b/src/serious_python/example/bridge_example/ios/Runner/Info.plist similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Info.plist rename to src/serious_python/example/bridge_example/ios/Runner/Info.plist diff --git a/src/serious_python_bridge/example/ios/Runner/Runner-Bridging-Header.h b/src/serious_python/example/bridge_example/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/Runner-Bridging-Header.h rename to src/serious_python/example/bridge_example/ios/Runner/Runner-Bridging-Header.h diff --git a/src/serious_python_bridge/example/ios/Runner/SceneDelegate.swift b/src/serious_python/example/bridge_example/ios/Runner/SceneDelegate.swift similarity index 100% rename from src/serious_python_bridge/example/ios/Runner/SceneDelegate.swift rename to src/serious_python/example/bridge_example/ios/Runner/SceneDelegate.swift diff --git a/src/serious_python_bridge/example/ios/RunnerTests/RunnerTests.swift b/src/serious_python/example/bridge_example/ios/RunnerTests/RunnerTests.swift similarity index 100% rename from src/serious_python_bridge/example/ios/RunnerTests/RunnerTests.swift rename to src/serious_python/example/bridge_example/ios/RunnerTests/RunnerTests.swift diff --git a/src/serious_python/example/bridge_example/lib/main.dart b/src/serious_python/example/bridge_example/lib/main.dart new file mode 100644 index 00000000..6c668064 --- /dev/null +++ b/src/serious_python/example/bridge_example/lib/main.dart @@ -0,0 +1,110 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:serious_python/bridge.dart'; +import 'package:serious_python/serious_python.dart'; + +/// Env-var name carrying the Dart-side native port to Python. The bridge +/// library doesn't bake in a convention — the example picks one and Python +/// reads it from os.environ by the same name. +const _bridgePortEnv = 'BRIDGE_EXAMPLE_PORT'; + +void main() { + runApp(const BridgeExampleApp()); +} + +class BridgeExampleApp extends StatefulWidget { + const BridgeExampleApp({super.key}); + + @override + State createState() => _BridgeExampleAppState(); +} + +class _BridgeExampleAppState extends State { + PythonBridge? _bridge; + StreamSubscription? _subscription; + final List _log = []; + int _sendCounter = 0; + + @override + void initState() { + super.initState(); + _start(); + } + + Future _start() async { + final bridge = PythonBridge(); + debugPrint('[bridge_example] bridge.port=${bridge.port}'); + _subscription = bridge.messages.listen((bytes) { + setState(() { + _log.add('Python -> Dart: ${utf8.decode(bytes, allowMalformed: true)}'); + }); + }); + + // Fire-and-forget: Python's main.py blocks waiting for messages and never + // returns. Awaiting SeriousPython.run() would deadlock the UI. + unawaited(SeriousPython.run( + 'app/app.zip', + environmentVariables: {_bridgePortEnv: '${bridge.port}'}, + )); + + setState(() { + _bridge = bridge; + _log.add('bridge ready (port=${bridge.port})'); + }); + } + + void _sendTestMessage() { + final bridge = _bridge; + if (bridge == null) return; + _sendCounter++; + final payload = utf8.encode('ping #$_sendCounter'); + final delivered = bridge.send(Uint8List.fromList(payload)); + setState(() => _log.add( + 'Dart -> Python: ping #$_sendCounter${delivered ? '' : ' (no handler yet)'}')); + } + + @override + void dispose() { + _subscription?.cancel(); + _bridge?.close(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'bridge_example', + home: Scaffold( + appBar: AppBar(title: const Text('PythonBridge example')), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16), + child: ElevatedButton( + key: const Key('send'), + onPressed: _bridge != null ? _sendTestMessage : null, + child: const Text('Send ping to Python'), + ), + ), + const Divider(), + Expanded( + child: ListView.builder( + itemCount: _log.length, + itemBuilder: (context, index) => ListTile( + dense: true, + title: Text( + _log[index], + style: const TextStyle(fontSize: 12), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/src/serious_python_bridge/example/linux/.gitignore b/src/serious_python/example/bridge_example/linux/.gitignore similarity index 100% rename from src/serious_python_bridge/example/linux/.gitignore rename to src/serious_python/example/bridge_example/linux/.gitignore diff --git a/src/serious_python_bridge/example/linux/CMakeLists.txt b/src/serious_python/example/bridge_example/linux/CMakeLists.txt similarity index 100% rename from src/serious_python_bridge/example/linux/CMakeLists.txt rename to src/serious_python/example/bridge_example/linux/CMakeLists.txt diff --git a/src/serious_python_bridge/example/linux/flutter/CMakeLists.txt b/src/serious_python/example/bridge_example/linux/flutter/CMakeLists.txt similarity index 100% rename from src/serious_python_bridge/example/linux/flutter/CMakeLists.txt rename to src/serious_python/example/bridge_example/linux/flutter/CMakeLists.txt diff --git a/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.cc b/src/serious_python/example/bridge_example/linux/flutter/generated_plugin_registrant.cc similarity index 100% rename from src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.cc rename to src/serious_python/example/bridge_example/linux/flutter/generated_plugin_registrant.cc diff --git a/src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.h b/src/serious_python/example/bridge_example/linux/flutter/generated_plugin_registrant.h similarity index 100% rename from src/serious_python_bridge/example/linux/flutter/generated_plugin_registrant.h rename to src/serious_python/example/bridge_example/linux/flutter/generated_plugin_registrant.h diff --git a/src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/bridge_example/linux/flutter/generated_plugins.cmake similarity index 96% rename from src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake rename to src/serious_python/example/bridge_example/linux/flutter/generated_plugins.cmake index a130b7aa..ab50859e 100644 --- a/src/serious_python_bridge/example/linux/flutter/generated_plugins.cmake +++ b/src/serious_python/example/bridge_example/linux/flutter/generated_plugins.cmake @@ -8,7 +8,6 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST jni - serious_python_bridge ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python_bridge/example/linux/runner/CMakeLists.txt b/src/serious_python/example/bridge_example/linux/runner/CMakeLists.txt similarity index 100% rename from src/serious_python_bridge/example/linux/runner/CMakeLists.txt rename to src/serious_python/example/bridge_example/linux/runner/CMakeLists.txt diff --git a/src/serious_python_bridge/example/linux/runner/main.cc b/src/serious_python/example/bridge_example/linux/runner/main.cc similarity index 100% rename from src/serious_python_bridge/example/linux/runner/main.cc rename to src/serious_python/example/bridge_example/linux/runner/main.cc diff --git a/src/serious_python_bridge/example/linux/runner/my_application.cc b/src/serious_python/example/bridge_example/linux/runner/my_application.cc similarity index 100% rename from src/serious_python_bridge/example/linux/runner/my_application.cc rename to src/serious_python/example/bridge_example/linux/runner/my_application.cc diff --git a/src/serious_python_bridge/example/linux/runner/my_application.h b/src/serious_python/example/bridge_example/linux/runner/my_application.h similarity index 100% rename from src/serious_python_bridge/example/linux/runner/my_application.h rename to src/serious_python/example/bridge_example/linux/runner/my_application.h diff --git a/src/serious_python_bridge/example/macos/.gitignore b/src/serious_python/example/bridge_example/macos/.gitignore similarity index 100% rename from src/serious_python_bridge/example/macos/.gitignore rename to src/serious_python/example/bridge_example/macos/.gitignore diff --git a/src/serious_python_bridge/example/macos/Flutter/Flutter-Debug.xcconfig b/src/serious_python/example/bridge_example/macos/Flutter/Flutter-Debug.xcconfig similarity index 100% rename from src/serious_python_bridge/example/macos/Flutter/Flutter-Debug.xcconfig rename to src/serious_python/example/bridge_example/macos/Flutter/Flutter-Debug.xcconfig diff --git a/src/serious_python_bridge/example/macos/Flutter/Flutter-Release.xcconfig b/src/serious_python/example/bridge_example/macos/Flutter/Flutter-Release.xcconfig similarity index 100% rename from src/serious_python_bridge/example/macos/Flutter/Flutter-Release.xcconfig rename to src/serious_python/example/bridge_example/macos/Flutter/Flutter-Release.xcconfig diff --git a/src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/bridge_example/macos/Flutter/GeneratedPluginRegistrant.swift similarity index 66% rename from src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift rename to src/serious_python/example/bridge_example/macos/Flutter/GeneratedPluginRegistrant.swift index 9f3d8753..7ef3a6c2 100644 --- a/src/serious_python_bridge/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/src/serious_python/example/bridge_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import serious_python_bridge import serious_python_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - SeriousPythonBridgePlugin.register(with: registry.registrar(forPlugin: "SeriousPythonBridgePlugin")) SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) } diff --git a/src/serious_python_bridge/example/macos/Podfile b/src/serious_python/example/bridge_example/macos/Podfile similarity index 100% rename from src/serious_python_bridge/example/macos/Podfile rename to src/serious_python/example/bridge_example/macos/Podfile diff --git a/src/serious_python_bridge/example/macos/Podfile.lock b/src/serious_python/example/bridge_example/macos/Podfile.lock similarity index 100% rename from src/serious_python_bridge/example/macos/Podfile.lock rename to src/serious_python/example/bridge_example/macos/Podfile.lock diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.pbxproj similarity index 100% rename from src/serious_python_bridge/example/macos/Runner.xcodeproj/project.pbxproj rename to src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.pbxproj diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from src/serious_python_bridge/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/src/serious_python_bridge/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from src/serious_python_bridge/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to src/serious_python/example/bridge_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/bridge_example/macos/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from src/serious_python_bridge/example/macos/Runner.xcworkspace/contents.xcworkspacedata rename to src/serious_python/example/bridge_example/macos/Runner.xcworkspace/contents.xcworkspacedata diff --git a/src/serious_python_bridge/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/bridge_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from src/serious_python_bridge/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to src/serious_python/example/bridge_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/src/serious_python_bridge/example/macos/Runner/AppDelegate.swift b/src/serious_python/example/bridge_example/macos/Runner/AppDelegate.swift similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/AppDelegate.swift rename to src/serious_python/example/bridge_example/macos/Runner/AppDelegate.swift diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png diff --git a/src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png rename to src/serious_python/example/bridge_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png diff --git a/src/serious_python_bridge/example/macos/Runner/Base.lproj/MainMenu.xib b/src/serious_python/example/bridge_example/macos/Runner/Base.lproj/MainMenu.xib similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Base.lproj/MainMenu.xib rename to src/serious_python/example/bridge_example/macos/Runner/Base.lproj/MainMenu.xib diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python/example/bridge_example/macos/Runner/Configs/AppInfo.xcconfig similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Configs/AppInfo.xcconfig rename to src/serious_python/example/bridge_example/macos/Runner/Configs/AppInfo.xcconfig diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/Debug.xcconfig b/src/serious_python/example/bridge_example/macos/Runner/Configs/Debug.xcconfig similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Configs/Debug.xcconfig rename to src/serious_python/example/bridge_example/macos/Runner/Configs/Debug.xcconfig diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/Release.xcconfig b/src/serious_python/example/bridge_example/macos/Runner/Configs/Release.xcconfig similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Configs/Release.xcconfig rename to src/serious_python/example/bridge_example/macos/Runner/Configs/Release.xcconfig diff --git a/src/serious_python_bridge/example/macos/Runner/Configs/Warnings.xcconfig b/src/serious_python/example/bridge_example/macos/Runner/Configs/Warnings.xcconfig similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Configs/Warnings.xcconfig rename to src/serious_python/example/bridge_example/macos/Runner/Configs/Warnings.xcconfig diff --git a/src/serious_python_bridge/example/macos/Runner/DebugProfile.entitlements b/src/serious_python/example/bridge_example/macos/Runner/DebugProfile.entitlements similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/DebugProfile.entitlements rename to src/serious_python/example/bridge_example/macos/Runner/DebugProfile.entitlements diff --git a/src/serious_python_bridge/example/macos/Runner/Info.plist b/src/serious_python/example/bridge_example/macos/Runner/Info.plist similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Info.plist rename to src/serious_python/example/bridge_example/macos/Runner/Info.plist diff --git a/src/serious_python_bridge/example/macos/Runner/MainFlutterWindow.swift b/src/serious_python/example/bridge_example/macos/Runner/MainFlutterWindow.swift similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/MainFlutterWindow.swift rename to src/serious_python/example/bridge_example/macos/Runner/MainFlutterWindow.swift diff --git a/src/serious_python_bridge/example/macos/Runner/Release.entitlements b/src/serious_python/example/bridge_example/macos/Runner/Release.entitlements similarity index 100% rename from src/serious_python_bridge/example/macos/Runner/Release.entitlements rename to src/serious_python/example/bridge_example/macos/Runner/Release.entitlements diff --git a/src/serious_python_bridge/example/macos/RunnerTests/RunnerTests.swift b/src/serious_python/example/bridge_example/macos/RunnerTests/RunnerTests.swift similarity index 100% rename from src/serious_python_bridge/example/macos/RunnerTests/RunnerTests.swift rename to src/serious_python/example/bridge_example/macos/RunnerTests/RunnerTests.swift diff --git a/src/serious_python_bridge/example/pubspec.yaml b/src/serious_python/example/bridge_example/pubspec.yaml similarity index 65% rename from src/serious_python_bridge/example/pubspec.yaml rename to src/serious_python/example/bridge_example/pubspec.yaml index f0600924..8c33a095 100644 --- a/src/serious_python_bridge/example/pubspec.yaml +++ b/src/serious_python/example/bridge_example/pubspec.yaml @@ -1,5 +1,5 @@ -name: serious_python_bridge_example -description: "Minimal Flutter app exercising the serious_python_bridge byte transport." +name: bridge_example +description: "Minimal Flutter app exercising the in-process Dart ↔ Python byte transport via PythonBridge." publish_to: 'none' version: 1.0.0+1 @@ -13,9 +13,7 @@ dependencies: sdk: flutter serious_python: - path: ../../serious_python - serious_python_bridge: - path: ../ + path: ../../ cupertino_icons: ^1.0.8 diff --git a/src/serious_python_bridge/example/windows/.gitignore b/src/serious_python/example/bridge_example/windows/.gitignore similarity index 100% rename from src/serious_python_bridge/example/windows/.gitignore rename to src/serious_python/example/bridge_example/windows/.gitignore diff --git a/src/serious_python_bridge/example/windows/CMakeLists.txt b/src/serious_python/example/bridge_example/windows/CMakeLists.txt similarity index 100% rename from src/serious_python_bridge/example/windows/CMakeLists.txt rename to src/serious_python/example/bridge_example/windows/CMakeLists.txt diff --git a/src/serious_python_bridge/example/windows/flutter/CMakeLists.txt b/src/serious_python/example/bridge_example/windows/flutter/CMakeLists.txt similarity index 100% rename from src/serious_python_bridge/example/windows/flutter/CMakeLists.txt rename to src/serious_python/example/bridge_example/windows/flutter/CMakeLists.txt diff --git a/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.cc b/src/serious_python/example/bridge_example/windows/flutter/generated_plugin_registrant.cc similarity index 100% rename from src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.cc rename to src/serious_python/example/bridge_example/windows/flutter/generated_plugin_registrant.cc diff --git a/src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.h b/src/serious_python/example/bridge_example/windows/flutter/generated_plugin_registrant.h similarity index 100% rename from src/serious_python_bridge/example/windows/flutter/generated_plugin_registrant.h rename to src/serious_python/example/bridge_example/windows/flutter/generated_plugin_registrant.h diff --git a/src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/bridge_example/windows/flutter/generated_plugins.cmake similarity index 96% rename from src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake rename to src/serious_python/example/bridge_example/windows/flutter/generated_plugins.cmake index af6720d3..f2f58d64 100644 --- a/src/serious_python_bridge/example/windows/flutter/generated_plugins.cmake +++ b/src/serious_python/example/bridge_example/windows/flutter/generated_plugins.cmake @@ -8,7 +8,6 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST jni - serious_python_bridge ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python_bridge/example/windows/runner/CMakeLists.txt b/src/serious_python/example/bridge_example/windows/runner/CMakeLists.txt similarity index 100% rename from src/serious_python_bridge/example/windows/runner/CMakeLists.txt rename to src/serious_python/example/bridge_example/windows/runner/CMakeLists.txt diff --git a/src/serious_python_bridge/example/windows/runner/Runner.rc b/src/serious_python/example/bridge_example/windows/runner/Runner.rc similarity index 100% rename from src/serious_python_bridge/example/windows/runner/Runner.rc rename to src/serious_python/example/bridge_example/windows/runner/Runner.rc diff --git a/src/serious_python_bridge/example/windows/runner/flutter_window.cpp b/src/serious_python/example/bridge_example/windows/runner/flutter_window.cpp similarity index 100% rename from src/serious_python_bridge/example/windows/runner/flutter_window.cpp rename to src/serious_python/example/bridge_example/windows/runner/flutter_window.cpp diff --git a/src/serious_python_bridge/example/windows/runner/flutter_window.h b/src/serious_python/example/bridge_example/windows/runner/flutter_window.h similarity index 100% rename from src/serious_python_bridge/example/windows/runner/flutter_window.h rename to src/serious_python/example/bridge_example/windows/runner/flutter_window.h diff --git a/src/serious_python_bridge/example/windows/runner/main.cpp b/src/serious_python/example/bridge_example/windows/runner/main.cpp similarity index 100% rename from src/serious_python_bridge/example/windows/runner/main.cpp rename to src/serious_python/example/bridge_example/windows/runner/main.cpp diff --git a/src/serious_python_bridge/example/windows/runner/resource.h b/src/serious_python/example/bridge_example/windows/runner/resource.h similarity index 100% rename from src/serious_python_bridge/example/windows/runner/resource.h rename to src/serious_python/example/bridge_example/windows/runner/resource.h diff --git a/src/serious_python_bridge/example/windows/runner/resources/app_icon.ico b/src/serious_python/example/bridge_example/windows/runner/resources/app_icon.ico similarity index 100% rename from src/serious_python_bridge/example/windows/runner/resources/app_icon.ico rename to src/serious_python/example/bridge_example/windows/runner/resources/app_icon.ico diff --git a/src/serious_python_bridge/example/windows/runner/runner.exe.manifest b/src/serious_python/example/bridge_example/windows/runner/runner.exe.manifest similarity index 100% rename from src/serious_python_bridge/example/windows/runner/runner.exe.manifest rename to src/serious_python/example/bridge_example/windows/runner/runner.exe.manifest diff --git a/src/serious_python_bridge/example/windows/runner/utils.cpp b/src/serious_python/example/bridge_example/windows/runner/utils.cpp similarity index 100% rename from src/serious_python_bridge/example/windows/runner/utils.cpp rename to src/serious_python/example/bridge_example/windows/runner/utils.cpp diff --git a/src/serious_python_bridge/example/windows/runner/utils.h b/src/serious_python/example/bridge_example/windows/runner/utils.h similarity index 100% rename from src/serious_python_bridge/example/windows/runner/utils.h rename to src/serious_python/example/bridge_example/windows/runner/utils.h diff --git a/src/serious_python_bridge/example/windows/runner/win32_window.cpp b/src/serious_python/example/bridge_example/windows/runner/win32_window.cpp similarity index 100% rename from src/serious_python_bridge/example/windows/runner/win32_window.cpp rename to src/serious_python/example/bridge_example/windows/runner/win32_window.cpp diff --git a/src/serious_python_bridge/example/windows/runner/win32_window.h b/src/serious_python/example/bridge_example/windows/runner/win32_window.h similarity index 100% rename from src/serious_python_bridge/example/windows/runner/win32_window.h rename to src/serious_python/example/bridge_example/windows/runner/win32_window.h diff --git a/src/serious_python_bridge/example/README.md b/src/serious_python_bridge/example/README.md deleted file mode 100644 index 8e4705ff..00000000 --- a/src/serious_python_bridge/example/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# serious_python_bridge_example - -Minimal Flutter app exercising [`serious_python_bridge`](../). Sends bytes -from Dart to Python via `PythonBridge.send()`, and Python echoes them back -through `dart_bridge.send_bytes()`. No Flet, no msgpack, no protocol layer — -the smallest possible end-to-end demonstration of the byte transport. - -## Build the Python app bundle - -Before running, package the Python source into `app/app.zip`: - -```sh -# From this directory: -dart run serious_python:main package app/src --platform Darwin \ - --python-version 3.14 -``` - -Substitute `Darwin` with `Linux`, `Windows`, or `Android` for those targets. -On Linux/Windows/Android also pass `--bridge` so the prebuilt `dart_bridge` -Python shim is downloaded from the `serious-python` GitHub Release and -dropped into the bundled site-packages. (Not required on macOS/iOS — the -shim is statically linked into the app process and registered with CPython -via `serious_python_darwin`'s `registerPythonExtension` hook.) - -## Run - -```sh -flutter run -d macos # or -d linux / windows / -``` - -The app starts the embedded Python interpreter (which runs `app/src/main.py` -in a background thread), sends an 8-byte handshake frame containing the Dart -`ReceivePort` native port id, and then sends `ping #N` payloads when the -button is pressed. Python echoes them back; received messages appear in the -list view. diff --git a/src/serious_python_bridge/example/app/src/main.py b/src/serious_python_bridge/example/app/src/main.py deleted file mode 100644 index a0e0bc9b..00000000 --- a/src/serious_python_bridge/example/app/src/main.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Echo loop exercising serious_python_bridge. - -Protocol used by this example (NOT the Flet protocol — just the simplest -thing that proves the byte transport works): - -* First frame from Dart: 8-byte little-endian int64 = the Dart native port id - that Python should reply to. On receipt, Python echoes the same 8 bytes - back via the captured port — Dart uses that echo to detect readiness - (because the `set_enqueue_handler_func` registration may not have run by - the time Dart's first send arrives). -* Subsequent frames: arbitrary bytes; echoed back prefixed with ``b"echo: "``. - -Python keeps the interpreter alive indefinitely so messages can keep arriving; -Dart drives the lifetime (when the app exits, the embedded Python is torn down). -""" - -from __future__ import annotations - -import struct -import sys -import threading - -import dart_bridge - -native_port: int | None = None - - -def on_dart_message(data: bytes) -> None: - global native_port - - if native_port is None: - if len(data) != 8: - print( - f"[bridge_example] expected 8-byte handshake, got {len(data)} bytes", - file=sys.stderr, - flush=True, - ) - return - native_port = struct.unpack(".generate(1024, (_) => rng.nextInt(256)), - ); - final expectedPrefix = Uint8List.fromList('echo: '.codeUnits); - final expectedReply = Uint8List(expectedPrefix.length + payload.length) - ..setRange(0, expectedPrefix.length, expectedPrefix) - ..setRange(expectedPrefix.length, expectedPrefix.length + payload.length, - payload); - - // Pre-subscribe to the echo before sending. - final replyFuture = bridge.messages - .firstWhere((b) => b.length == expectedReply.length) - .timeout(const Duration(seconds: 10)); - - bridge.send(payload); - - final reply = await replyFuture; - expect(reply, equals(expectedReply)); - }); -} - -Future _waitForHandshakeEcho( - PythonBridge bridge, Uint8List portBytes) async { - const retryInterval = Duration(milliseconds: 500); - const overallTimeout = Duration(seconds: 30); - final deadline = DateTime.now().add(overallTimeout); - - while (DateTime.now().isBefore(deadline)) { - final echoFuture = bridge.messages - .firstWhere((b) => _bytesEqual(b, portBytes)) - .timeout(retryInterval); - bridge.send(portBytes); - try { - await echoFuture; - return; - } on TimeoutException { - // Python not ready yet — retry. - } - } - throw TimeoutException( - 'Python did not echo handshake within ${overallTimeout.inSeconds}s'); -} - -bool _bytesEqual(Uint8List a, Uint8List b) { - if (a.length != b.length) return false; - for (var i = 0; i < a.length; i++) { - if (a[i] != b[i]) return false; - } - return true; -} diff --git a/src/serious_python_bridge/example/lib/main.dart b/src/serious_python_bridge/example/lib/main.dart deleted file mode 100644 index 4b333c8a..00000000 --- a/src/serious_python_bridge/example/lib/main.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:serious_python/serious_python.dart'; -import 'package:serious_python_bridge/serious_python_bridge.dart'; - -void main() { - runApp(const BridgeExampleApp()); -} - -class BridgeExampleApp extends StatefulWidget { - const BridgeExampleApp({super.key}); - - @override - State createState() => _BridgeExampleAppState(); -} - -class _BridgeExampleAppState extends State { - PythonBridge? _bridge; - StreamSubscription? _subscription; - final List _log = []; - int _sendCounter = 0; - - @override - void initState() { - super.initState(); - _start(); - } - - Future _start() async { - debugPrint('[bridge_example] _start: initializing bridge'); - final bridge = PythonBridge.init(); - debugPrint('[bridge_example] bridge.nativePort=${bridge.nativePort}'); - _subscription = bridge.messages.listen((bytes) { - debugPrint('[bridge_example] received ${bytes.length} bytes from Python'); - setState(() { - _log.add('Python -> Dart: ${utf8.decode(bytes, allowMalformed: true)}'); - }); - }); - - // Fire-and-forget; Python runs on a background thread and never returns - // (its main.py blocks waiting for messages). - debugPrint('[bridge_example] starting Python via SeriousPython.run'); - unawaited(SeriousPython.run("app/app.zip")); - - // Retry the handshake until Python echoes it back — Dart's first send may - // arrive before main.py has called set_enqueue_handler_func, and the - // bridge silently drops messages when no handler is registered. - final portBytes = Uint8List(8) - ..buffer.asByteData().setInt64(0, bridge.nativePort, Endian.little); - debugPrint('[bridge_example] starting handshake retry'); - await _handshakeUntilReady(bridge, portBytes); - debugPrint('[bridge_example] handshake complete'); - - setState(() { - _bridge = bridge; - _log.add('handshake complete (native_port=${bridge.nativePort})'); - }); - } - - Future _handshakeUntilReady( - PythonBridge bridge, Uint8List portBytes) async { - const retryInterval = Duration(milliseconds: 500); - const overallTimeout = Duration(seconds: 30); - final deadline = DateTime.now().add(overallTimeout); - - while (DateTime.now().isBefore(deadline)) { - // Subscribe FIRST so a fast Python echo isn't missed — bridge.messages - // is a broadcast stream and doesn't replay past emissions. - final echoFuture = bridge.messages - .firstWhere((b) => - b.length == portBytes.length && _bytesEqual(b, portBytes)) - .timeout(retryInterval); - bridge.send(portBytes); - try { - await echoFuture; - return; - } on TimeoutException { - // Python not ready yet — retry. - } - } - throw TimeoutException( - 'Python did not echo the handshake within ${overallTimeout.inSeconds}s'); - } - - static bool _bytesEqual(Uint8List a, Uint8List b) { - if (a.length != b.length) return false; - for (var i = 0; i < a.length; i++) { - if (a[i] != b[i]) return false; - } - return true; - } - - void _sendTestMessage() { - final bridge = _bridge; - if (bridge == null) return; - _sendCounter++; - final payload = utf8.encode('ping #$_sendCounter'); - bridge.send(Uint8List.fromList(payload)); - setState(() => _log.add('Dart -> Python: ping #$_sendCounter')); - } - - @override - void dispose() { - _subscription?.cancel(); - _bridge?.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'serious_python_bridge example', - home: Scaffold( - appBar: AppBar(title: const Text('serious_python_bridge example')), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: ElevatedButton( - key: const Key('send'), - onPressed: _bridge != null ? _sendTestMessage : null, - child: const Text('Send ping to Python'), - ), - ), - const Divider(), - Expanded( - child: ListView.builder( - itemCount: _log.length, - itemBuilder: (context, index) => ListTile( - dense: true, - title: Text( - _log[index], - style: const TextStyle(fontSize: 12), - ), - ), - ), - ), - ], - ), - ), - ); - } -} From ae8d2658cae0ee27a610c3823adc822ebc1b5941 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 11:06:18 -0700 Subject: [PATCH 044/114] Declare serious_python_darwin as static_framework for xcframework vendoring CocoaPods 1.16+ refuses to install a vendored xcframework containing static .a archives unless the consuming pod is itself declared static. dart_bridge.xcframework is static (one .a per slice); Python.xcframework also is. Failure: [!] Unable to install vendored xcframework `dart_bridge` for Pod `serious_python_darwin` because it contains static libraries --- .../darwin/serious_python_darwin.podspec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/serious_python_darwin/darwin/serious_python_darwin.podspec b/src/serious_python_darwin/darwin/serious_python_darwin.podspec index 3be1282b..1d313565 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin.podspec +++ b/src/serious_python_darwin/darwin/serious_python_darwin.podspec @@ -13,7 +13,12 @@ Pod::Spec.new do |s| s.license = { :file => '../LICENSE' } s.author = { 'Appveyor Systems Inc.' => 'hello@flet.dev' } s.source = { :path => '.' } - #s.static_framework = true + # 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. + s.static_framework = true s.source_files = ['Classes/**/*'] s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' From f5e71f093ff3da4b691cd7228d76be10ef84ba3c Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 11:18:58 -0700 Subject: [PATCH 045/114] Pin DART_BRIDGE_VERSION to 1.2.1 (uniform .a names across xcframework slices) --- src/serious_python_darwin/darwin/prepare_ios.sh | 2 +- src/serious_python_darwin/darwin/prepare_macos.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index e10f8545..d2496699 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -5,7 +5,7 @@ dist=$script_dir/dist_ios # Pinned dart-bridge release (flet-dev/dart-bridge). The xcframework is abi3 and # version-independent of CPython, so one binary covers all 3.12+ Python versions. -dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.0} +dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} if [ ! -d "$dist" ]; then mkdir -p $dist diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index ccd7825c..82c1d210 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -5,7 +5,7 @@ dist=$script_dir/dist_macos # Pinned dart-bridge release (flet-dev/dart-bridge). Same xcframework is reused # across iOS and macOS — it carries slices for both. -dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.0} +dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} if [ ! -d "$dist" ]; then mkdir -p $dist From 5703baa3f38b3f663170f81b244acc2c6398f9fb Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 11:28:48 -0700 Subject: [PATCH 046/114] PythonBridge.send: don't throw on Py_Initialize-not-yet (rc=-2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The retry-until-delivered pattern needs send() to signal 'try again' for the whole startup window — both 'Python not initialized yet' and 'handler not registered yet'. Throwing on -2 killed the retry loop in the integration test before Python's main.py had a chance to come up. --- src/serious_python/lib/src/python_bridge.dart | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/serious_python/lib/src/python_bridge.dart b/src/serious_python/lib/src/python_bridge.dart index ca847de4..5c69d6e7 100644 --- a/src/serious_python/lib/src/python_bridge.dart +++ b/src/serious_python/lib/src/python_bridge.dart @@ -63,11 +63,11 @@ class PythonBridge { /// Send [bytes] to the Python handler registered for this bridge's [port]. /// - /// Returns `true` on successful delivery, `false` if no Python handler is - /// currently registered for this port (typical reason: Python hasn't yet - /// called `dart_bridge.set_enqueue_handler_func`). The caller may retry. - /// - /// Throws [StateError] if the Python interpreter is not running. + /// Returns `true` on successful delivery, `false` if delivery isn't yet + /// possible: either the Python interpreter hasn't finished `Py_Initialize` + /// yet, or Python hasn't called `dart_bridge.set_enqueue_handler_func` + /// for this port. Both states are transient on app startup — the caller + /// typically retries until `true`. bool send(Uint8List bytes) { if (_closed) { throw StateError('PythonBridge is closed'); @@ -78,10 +78,9 @@ class PythonBridge { if (len > 0) { buf.asTypedList(len).setAll(0, bytes); } + // rc: 0=delivered, -1=no handler yet, -2=Py_Initialize not finished. + // Both negative cases are transient retry signals on app startup. final rc = _bridge.enqueueMessage(port, buf, len); - if (rc == -2) { - throw StateError('Python interpreter is not initialized'); - } return rc == 0; } finally { malloc.free(buf); From a4ece5925c3550b21b2a4816f0491900991455c7 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 11:47:40 -0700 Subject: [PATCH 047/114] Android: absorb Python lifecycle into libdart_bridge.so MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the darwin absorption (commit 1092769) on Android. Python lifecycle code that previously lived on the Dart side (cpython.dart's direct FFI against libpython3.X.so) moves into libdart_bridge.so, a prebuilt artifact downloaded from flet-dev/dart-bridge at gradle build time. What moved: - android/build.gradle gains downloadDartBridge_ + copyDartBridge_ tasks that fetch libdart_bridge-android--py.so for the configured (abi × python_version) and drop it as jniLibs//libdart_bridge.so. Cached under FLET_CACHE_DIR/dart-bridge/v/. - src/CMakeLists.txt + stub serious_python.c/.h deleted — no native code is compiled here anymore. externalNativeBuild block removed. - AndroidPlugin.java loses setEnvironmentVariable + loadLibrary (Dart side now passes env via SpRunConfig and libdart_bridge.so resolves libpython via DT_NEEDED). getNativeLibraryDir, getAppVersion, getPlatformVersion stay; the two Os.setenv calls in onAttachedTo* stay too — Python code may read them. - serious_python_android.dart's run() shrinks to: extract libpythonbundle.so + libpythonsitepackages.so to the app-support dir, build the env/path map, single FFI call into serious_python_run via DartBridge.instance. - lib/src/cpython.dart, lib/src/gen.dart, lib/src/log.dart, and python_ffigen.yaml deleted (Dart-side CPython bindings are obsolete). - pubspec drops ffi + ffigen — ffi comes transitively through serious_python_platform_interface now. CI: test-bridge-build.yml gains a test_bridge_example_android job mirroring the prior wheel/NDK-build approach but now using just the prebuilt dart-bridge .so + the regular `dart run serious_python:main package` flow. --- .github/workflows/test-bridge-build.yml | 79 + .../android/build.gradle | 46 +- .../serious_python_android/AndroidPlugin.java | 32 +- .../lib/serious_python_android.dart | 172 +- .../lib/src/cpython.dart | 244 - src/serious_python_android/lib/src/gen.dart | 27219 ---------------- src/serious_python_android/lib/src/log.dart | 10 - src/serious_python_android/pubspec.yaml | 4 +- src/serious_python_android/python_ffigen.yaml | 27 - src/serious_python_android/src/CMakeLists.txt | 24 - .../src/serious_python.c | 23 - .../src/serious_python.h | 30 - 12 files changed, 185 insertions(+), 27725 deletions(-) delete mode 100644 src/serious_python_android/lib/src/cpython.dart delete mode 100644 src/serious_python_android/lib/src/gen.dart delete mode 100644 src/serious_python_android/lib/src/log.dart delete mode 100644 src/serious_python_android/python_ffigen.yaml delete mode 100644 src/serious_python_android/src/CMakeLists.txt delete mode 100644 src/serious_python_android/src/serious_python.c delete mode 100644 src/serious_python_android/src/serious_python.h diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 3bdf2fb7..6f62b22a 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -96,3 +96,82 @@ jobs: echo "[$(ts)] >>> flutter test integration_test" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} echo "[$(ts)] >>> done" + + test_bridge_example_android: + name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # x86_64 matches the emulator architecture; only build/install for + # that ABI to keep CI fast. + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Gradle cache + uses: gradle/actions/setup-gradle@v3 + + - name: AVD cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-bridge + + - name: Setup Android Emulator + Run tests + uses: reactivecircus/android-emulator-runner@v2 + env: + EMULATOR_PORT: 5554 + with: + avd-name: android_emulator + api-level: 33 + target: google_atd + arch: x86_64 + profile: pixel_5 + sdcard-path-or-size: 128M + ram-size: 2048M + disk-size: 4096M + emulator-port: ${{ env.EMULATOR_PORT }} + disable-animations: true + emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 + pre-emulator-launch-script: | + sdkmanager --list_installed + script: | + cd src/serious_python/example/bridge_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} + cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} + + - name: Diagnostics on failure + if: failure() + shell: bash + run: | + set +e + REPO="$GITHUB_WORKSPACE" + ABI=x86_64 + echo "=== serious_python_android/android/src/main/jniLibs/$ABI/ ===" + ls -la "$REPO/src/serious_python_android/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" + echo + echo "=== example/build/app/outputs/apk/debug/*.apk ===" + APK=$(find "$REPO/src/serious_python/example/bridge_example/build" -name "*-debug.apk" 2>/dev/null | head -n1) + echo "APK: $APK" + if [ -n "$APK" ]; then + echo "Native libs inside APK:" + unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" + fi diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle index edcaef5c..ae3ef1a1 100644 --- a/src/serious_python_android/android/build.gradle +++ b/src/serious_python_android/android/build.gradle @@ -2,6 +2,7 @@ group 'com.flet.serious_python_android' version '2.0.0' def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: '3.14' +def dart_bridge_version = System.getenv('DART_BRIDGE_VERSION') ?: '1.2.1' buildscript { repositories { @@ -28,25 +29,14 @@ apply plugin: 'de.undercouch.download' android { namespace "com.flet.serious_python_android" - + // Bumping the plugin compileSdkVersion requires all clients of this plugin // to bump the version in their app. compileSdkVersion 31 - // Invoke the shared CMake build with the Android Gradle Plugin. - externalNativeBuild { - cmake { - path "../src/CMakeLists.txt" - - // The default CMake version for the Android Gradle Plugin is 3.10.2. - // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake - // - // The Flutter tooling requires that developers have CMake 3.10 or later - // installed. You should not increase this version, as doing so will cause - // the plugin to fail to compile for some customers of the plugin. - // version "3.10.2" - } - } + // No native code is compiled here — libdart_bridge.so is downloaded as a + // pre-built artifact from flet-dev/dart-bridge releases (see the + // downloadDartBridge_$abi tasks below) and dropped into jniLibs. compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -82,6 +72,10 @@ def pythonCacheDir = new File( fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), "python-build/v${python_version}" ) +def dartBridgeCacheDir = new File( + fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), + "dart-bridge/v${dart_bridge_version}" +) task copyBuildDist(type: Copy) { def srcDir = System.getenv('SERIOUS_PYTHON_BUILD_DIST') @@ -137,6 +131,28 @@ android.defaultConfig.ndk.abiFilters.each { abi -> destinationDirectory = file("src/main/jniLibs/$abi") dependsOn "jniCleanUp_$abi", "untarFile_$abi" } + + // dart-bridge ships a per-(abi × Python-minor-version) prebuilt .so. The + // binary's DT_NEEDED is libpython3.X.so (version-specific), so the bridge + // .so MUST match the libpython bundled in the same APK. We download from + // the pinned dart_bridge_version release into a cache shared across + // builds, then drop it as `libdart_bridge.so` (no version suffix) so the + // Dart side can DynamicLibrary.open by a stable short name. + tasks.register("downloadDartBridge_$abi", Download) { + src "https://github.com/flet-dev/dart-bridge/releases/download/v${dart_bridge_version}/libdart_bridge-android-${abi}-py${python_version}.so" + dest new File(dartBridgeCacheDir, "libdart_bridge-android-${abi}-py${python_version}.so") + onlyIfModified true + useETag "all" + tempAndMove true + doFirst { dest.parentFile.mkdirs() } + } + tasks.register("copyDartBridge_$abi", Copy) { + from tasks.named("downloadDartBridge_$abi").get().dest + into "src/main/jniLibs/$abi" + rename '.*', 'libdart_bridge.so' + dependsOn "downloadDartBridge_$abi", "jniCleanUp_$abi" + } + packageTasks.add("copyDartBridge_$abi") } if (System.getenv('SERIOUS_PYTHON_BUILD_DIST')) { diff --git a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java index 1f573921..1705b962 100644 --- a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java +++ b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java @@ -16,19 +16,18 @@ import com.flet.serious_python_android.PythonActivity; -/** AndroidPlugin */ +/** + * Thin Flutter plugin: surfaces nativeLibraryDir and app version to Dart and + * exposes a few process-wide env vars Python code may read. All Python + * lifecycle now lives in libdart_bridge.so (downloaded from + * flet-dev/dart-bridge), invoked from Dart via FFI. + */ public class AndroidPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware { public static final String MAIN_ACTIVITY_HOST_CLASS_NAME = "MAIN_ACTIVITY_HOST_CLASS_NAME"; public static final String MAIN_ACTIVITY_CLASS_NAME = "MAIN_ACTIVITY_CLASS_NAME"; public static final String ANDROID_NATIVE_LIBRARY_DIR = "ANDROID_NATIVE_LIBRARY_DIR"; - /// The MethodChannel that will the communication between Flutter and native - /// Android - /// - /// This local reference serves to register the plugin with the Flutter Engine - /// and unregister it - /// when the Flutter Engine is detached from the Activity private MethodChannel channel; private Context context; @@ -39,7 +38,8 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBindin channel.setMethodCallHandler(this); this.context = flutterPluginBinding.getApplicationContext(); try { - Os.setenv(ANDROID_NATIVE_LIBRARY_DIR, new ContextWrapper(this.context).getApplicationInfo().nativeLibraryDir, true); + Os.setenv(ANDROID_NATIVE_LIBRARY_DIR, + new ContextWrapper(this.context).getApplicationInfo().nativeLibraryDir, true); } catch (Exception e) { // nothing to do } @@ -75,22 +75,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { ContextWrapper contextWrapper = new ContextWrapper(context); String nativeLibraryDir = contextWrapper.getApplicationInfo().nativeLibraryDir; result.success(nativeLibraryDir); - } else if (call.method.equals("loadLibrary")) { - try { - System.loadLibrary(call.argument("libname")); - result.success(null); - } catch (Throwable e) { - result.error("Error", e.getMessage(), null); - } - } else if (call.method.equals("setEnvironmentVariable")) { - String name = call.argument("name"); - String value = call.argument("value"); - try { - Os.setenv(name, value, true); - result.success(null); - } catch (Exception e) { - result.error("Error", e.getMessage(), null); - } } else { result.notImplemented(); } diff --git a/src/serious_python_android/lib/serious_python_android.dart b/src/serious_python_android/lib/serious_python_android.dart index 61b7eaf2..5cde9748 100644 --- a/src/serious_python_android/lib/serious_python_android.dart +++ b/src/serious_python_android/lib/serious_python_android.dart @@ -1,33 +1,34 @@ -import 'dart:async'; import 'dart:io'; -import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:path/path.dart' as p; import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; -import 'src/cpython.dart'; -import 'src/log.dart'; - -/// An implementation of [SeriousPythonPlatform] that uses method channels. +/// Android implementation of [SeriousPythonPlatform]. +/// +/// Python lifecycle (env, sys.path, Py_Initialize, run, finalize, sync/async) +/// lives in `serious_python_run`, packaged as `libdart_bridge.so` and bundled +/// into the APK by the plugin's gradle pipeline (see `android/build.gradle`'s +/// `downloadDartBridge_` tasks). +/// +/// This class: +/// 1. Pulls the python.bundle (zipped stdlib + dynload .so files) out of the +/// APK's nativeLibraryDir into a writable app-support directory, since +/// CPython can't import from inside the .apk. +/// 2. Builds env vars + sys.path entries and hands them to `serious_python_run` +/// in a single FFI call. class SeriousPythonAndroid extends SeriousPythonPlatform { - /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('android_plugin'); - /// Registers this class as the default instance of [SeriousPythonPlatform] static void registerWith() { SeriousPythonPlatform.instance = SeriousPythonAndroid(); } @override - Future getPlatformVersion() async { - final version = - await methodChannel.invokeMethod('getPlatformVersion'); - return version; - } + Future getPlatformVersion() => + methodChannel.invokeMethod('getPlatformVersion'); @override Future run(String appPath, @@ -35,111 +36,70 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { List? modulePaths, Map? environmentVariables, bool? sync}) async { - Future setenv(String key, String value) => - methodChannel.invokeMethod( - 'setEnvironmentVariable', {'name': key, 'value': value}); - - // load libpyjni.so to get JNI reference - try { - await methodChannel - .invokeMethod('loadLibrary', {'libname': 'pyjni'}); - await setenv("FLET_JNI_READY", "1"); - } catch (e) { - spDebug("Unable to load libpyjni.so library: $e"); - } - - // unpack python bundle final nativeLibraryDir = await methodChannel.invokeMethod('getNativeLibraryDir'); - spDebug("getNativeLibraryDir: $nativeLibraryDir"); - - // The bundled libpython filename moves with the Python version - // (e.g. libpython3.12.so vs libpython3.13.so), so resolve it by - // scanning nativeLibraryDir rather than hardcoding a constant — the - // plugin only ever bundles one libpython per build. - final libpythonRe = RegExp(r'^libpython3\.\d+\.so$'); - final pythonSharedLib = Directory(nativeLibraryDir!) - .listSync() - .map((e) => p.basename(e.path)) - .firstWhere( - libpythonRe.hasMatch, - orElse: () => throw Exception( - "No libpython3.*.so found in $nativeLibraryDir"), - ); - spDebug("Resolved Python shared library: $pythonSharedLib"); - - String? getPythonFullVersion() { - try { - final cpython = getCPython(pythonSharedLib); - final versionPtr = cpython.Py_GetVersion(); - return versionPtr.cast().toDartString(); - } catch (e) { - spDebug("Unable to read Python version for invalidation: $e"); - return null; - } + if (nativeLibraryDir == null) { + throw StateError( + 'serious_python: failed to resolve native library dir'); } - Future getAppVersion() async { - try { - return await methodChannel.invokeMethod('getAppVersion'); - } catch (e) { - spDebug("Unable to get app version for invalidation: $e"); - return null; - } + final bundlePath = '$nativeLibraryDir/libpythonbundle.so'; + if (!await File(bundlePath).exists()) { + throw Exception('Python bundle not found: $bundlePath'); } - var bundlePath = "$nativeLibraryDir/libpythonbundle.so"; - var sitePackagesZipPath = "$nativeLibraryDir/libpythonsitepackages.so"; + final appVersion = await _appVersion(); + final invalidateKey = appVersion != null ? 'app:$appVersion' : null; - if (!await File(bundlePath).exists()) { - throw Exception("Python bundle not found: $bundlePath"); - } - final pythonVersion = getPythonFullVersion(); - spDebug("Python version: $pythonVersion"); - final pythonInvalidateKey = pythonVersion != null - ? "python:$pythonVersion" - : "python:$pythonSharedLib"; - var pythonLibPath = await extractFileZip(bundlePath, - targetPath: "python_bundle", invalidateKey: pythonInvalidateKey); - spDebug("pythonLibPath: $pythonLibPath"); + final pythonLibPath = await extractFileZip(bundlePath, + targetPath: 'python_bundle', invalidateKey: invalidateKey); - var programDirPath = p.dirname(appPath); + final sitePackagesZip = '$nativeLibraryDir/libpythonsitepackages.so'; + String? sitePackagesPath; + if (await File(sitePackagesZip).exists()) { + sitePackagesPath = await extractFileZip(sitePackagesZip, + targetPath: 'python_site_packages', invalidateKey: invalidateKey); + } - var moduleSearchPaths = [ - programDirPath, + final programDir = p.dirname(appPath); + final pythonPaths = [ ...?modulePaths, - "$pythonLibPath/modules", - "$pythonLibPath/stdlib" + programDir, + '$pythonLibPath/modules', + '$pythonLibPath/stdlib', + if (sitePackagesPath != null) sitePackagesPath, ]; - if (await File(sitePackagesZipPath).exists()) { - final appVersion = await getAppVersion(); - spDebug("App version: $appVersion"); - final sitePackagesInvalidateKey = - appVersion != null ? "app:$appVersion" : null; - var sitePackagesPath = await extractFileZip(sitePackagesZipPath, - targetPath: "python_site_packages", - invalidateKey: sitePackagesInvalidateKey); - spDebug("sitePackagesPath: $sitePackagesPath"); - moduleSearchPaths.add(sitePackagesPath); - } - - await setenv("PYTHONINSPECT", "1"); - await setenv("PYTHONDONTWRITEBYTECODE", "1"); - await setenv("PYTHONNOUSERSITE", "1"); - await setenv("PYTHONUNBUFFERED", "1"); - await setenv("LC_CTYPE", "UTF-8"); - await setenv("PYTHONHOME", pythonLibPath); - await setenv("PYTHONPATH", moduleSearchPaths.join(":")); + final env = { + 'PYTHONINSPECT': '1', + 'PYTHONDONTWRITEBYTECODE': '1', + 'PYTHONNOUSERSITE': '1', + 'PYTHONUNBUFFERED': '1', + 'LC_CTYPE': 'UTF-8', + 'PYTHONHOME': pythonLibPath, + 'PYTHONPATH': pythonPaths.join(':'), + ...?environmentVariables, + }; + + final rc = runPython( + bridge: DartBridge.instance, + appPath: script == null ? appPath : null, + script: script, + modulePaths: pythonPaths, + environmentVariables: env, + sync: sync ?? false, + ); + + // sync=true: rc is the Python exit code. sync=false: rc is the spawn + // result (0 = worker thread started successfully). + return rc != 0 ? 'Python exited with code $rc' : null; + } - // set environment variables - if (environmentVariables != null) { - for (var v in environmentVariables.entries) { - await setenv(v.key, v.value); - } + Future _appVersion() async { + try { + return await methodChannel.invokeMethod('getAppVersion'); + } catch (_) { + return null; } - - return runPythonProgramFFI( - sync ?? false, pythonSharedLib, appPath, script ?? ""); } } diff --git a/src/serious_python_android/lib/src/cpython.dart b/src/serious_python_android/lib/src/cpython.dart deleted file mode 100644 index 9182eb6a..00000000 --- a/src/serious_python_android/lib/src/cpython.dart +++ /dev/null @@ -1,244 +0,0 @@ -import 'dart:async'; -import 'dart:ffi'; -import 'dart:isolate'; - -import 'package:ffi/ffi.dart'; -import 'package:path/path.dart' as p; - -import 'gen.dart'; -import 'log.dart'; - -export 'gen.dart'; - -CPython? _cpython; -String? _logcatForwardingError; -Future _pythonRunQueue = Future.value(); - -Future _enqueuePythonRun(Future Function() action) { - final completer = Completer(); - _pythonRunQueue = _pythonRunQueue.then((_) async { - try { - completer.complete(await action()); - } catch (e, st) { - completer.completeError(e, st); - } - }); - return completer.future; -} - -const _logcatInitScript = r''' -import logging,sys - -# Make this init idempotent across Dart isolate restarts. -if not getattr(sys, "__serious_python_logcat_configured__", False): - sys.__serious_python_logcat_configured__ = True - - from ctypes import cdll, c_int, c_char_p - liblog = cdll.LoadLibrary("liblog.so") - ANDROID_LOG_INFO = 4 - liblog.__android_log_write.argtypes = [c_int, c_char_p, c_char_p] - liblog.__android_log_write.restype = c_int - - def _log_to_logcat(msg, level=ANDROID_LOG_INFO): - if not msg: - return - if isinstance(msg, bytes): - msg = msg.decode("utf-8", errors="replace") - liblog.__android_log_write(level, b"serious_python", msg.encode("utf-8")) - - class _LogcatWriter: - def write(self, msg): - _log_to_logcat(msg.strip()) - def flush(self): - pass - - sys.stdout = sys.stderr = _LogcatWriter() - handler = logging.StreamHandler(sys.stderr) - handler.setFormatter(logging.Formatter("%(levelname)s %(message)s")) - root = logging.getLogger() - root.handlers[:] = [handler] - root.setLevel(logging.ERROR) -'''; - -CPython getCPython(String dynamicLibPath) { - return _cpython ??= _cpython = CPython(DynamicLibrary.open(dynamicLibPath)); -} - -Future runPythonProgramFFI(bool sync, String dynamicLibPath, - String pythonProgramPath, String script) async { - return _enqueuePythonRun(() async { - spDebug( - "Python run start (sync=$sync, script=${script.isNotEmpty}, program=$pythonProgramPath)"); - if (sync) { - // Sync run: do not involve ports (avoids GC/close races). - final result = - _runPythonProgram(dynamicLibPath, pythonProgramPath, script); - spDebug("Python run done (resultLength=${result.length})"); - return result; - } else { - // Async run: use Isolate.run() to avoid manual port lifecycle issues. - try { - final result = await Isolate.run( - () => _runPythonProgram(dynamicLibPath, pythonProgramPath, script)); - spDebug("Python run done (resultLength=${result.length})"); - return result; - } catch (e, st) { - final message = "Dart error running Python: $e\n$st"; - spDebug(message); - return message; - } - } - }); -} - -String _runPythonProgram( - String dynamicLibPath, String pythonProgramPath, String script) { - var programDirPath = p.dirname(pythonProgramPath); - var programModuleName = p.basenameWithoutExtension(pythonProgramPath); - - spDebug("dynamicLibPath: $dynamicLibPath"); - spDebug("programDirPath: $programDirPath"); - spDebug("programModuleName: $programModuleName"); - - final cpython = getCPython(dynamicLibPath); - spDebug("CPython loaded"); - if (cpython.Py_IsInitialized() != 0) { - spDebug( - "Python already initialized and another program is running, skipping execution."); - return ""; - } - - cpython.Py_Initialize(); - spDebug("after Py_Initialize()"); - - var result = ""; - - final logcatSetupError = _setupLogcatForwarding(cpython); - if (logcatSetupError != null) { - cpython.Py_Finalize(); - return logcatSetupError; - } - - if (script != "") { - // run script - final scriptPtr = script.toNativeUtf8(); - int sr = cpython.PyRun_SimpleString(scriptPtr.cast()); - spDebug("PyRun_SimpleString for script result: $sr"); - malloc.free(scriptPtr); - if (sr != 0) { - result = getPythonError(cpython); - } - } else { - // run program - final moduleNamePtr = programModuleName.toNativeUtf8(); - var modulePtr = cpython.PyImport_ImportModule(moduleNamePtr.cast()); - if (modulePtr == nullptr) { - result = getPythonError(cpython); - } - malloc.free(moduleNamePtr); - } - - cpython.Py_Finalize(); - spDebug("after Py_Finalize()"); - - return result; -} - -String getPythonError(CPython cpython) { - final exPtr = cpython.PyErr_GetRaisedException(); - if (exPtr == nullptr) return "Unknown Python error (no exception set)."; - - try { - final formatted = _formatPythonException(cpython, exPtr); - if (formatted != null && formatted.isNotEmpty) return formatted; - - final fallback = _pyObjectToDartString(cpython, exPtr); - return fallback ?? "Unknown Python error (failed to stringify exception)."; - } finally { - cpython.Py_DecRef(exPtr); - // Defensive: formatting can set a new Python error. - cpython.PyErr_Clear(); - } -} - -String? _formatPythonException( - CPython cpython, Pointer exceptionPtr) { - // Uses `traceback.format_exception(exc)` (Python 3.10+ signature). - final tracebackModuleNamePtr = "traceback".toNativeUtf8(); - final tracebackModulePtr = - cpython.PyImport_ImportModule(tracebackModuleNamePtr.cast()); - malloc.free(tracebackModuleNamePtr); - if (tracebackModulePtr == nullptr) return null; - - try { - final formatFuncNamePtr = "format_exception".toNativeUtf8(); - final formatFuncPtr = cpython.PyObject_GetAttrString( - tracebackModulePtr, formatFuncNamePtr.cast()); - malloc.free(formatFuncNamePtr); - if (formatFuncPtr == nullptr) return null; - - try { - if (cpython.PyCallable_Check(formatFuncPtr) == 0) return null; - - final listPtr = cpython.PyObject_CallOneArg(formatFuncPtr, exceptionPtr); - if (listPtr == nullptr) return null; - - try { - final listSize = cpython.PyList_Size(listPtr); - if (listSize < 0) return null; - - final buffer = StringBuffer(); - for (var i = 0; i < listSize; i++) { - final itemObj = cpython.PyList_GetItem(listPtr, i); // borrowed ref - if (itemObj == nullptr) continue; - - final line = _pyUnicodeToDartString(cpython, itemObj) ?? - _pyObjectToDartString(cpython, itemObj); - if (line == null) continue; - buffer.write(line); - } - return buffer.toString(); - } finally { - cpython.Py_DecRef(listPtr); - } - } finally { - cpython.Py_DecRef(formatFuncPtr); - } - } finally { - cpython.Py_DecRef(tracebackModulePtr); - } -} - -String? _pyUnicodeToDartString( - CPython cpython, Pointer unicodeObjPtr) { - final cStr = cpython.PyUnicode_AsUTF8(unicodeObjPtr); - if (cStr == nullptr) return null; - return cStr.cast().toDartString(); -} - -String? _pyObjectToDartString(CPython cpython, Pointer objPtr) { - final strObj = cpython.PyObject_Str(objPtr); - if (strObj == nullptr) return null; - try { - return _pyUnicodeToDartString(cpython, strObj); - } finally { - cpython.Py_DecRef(strObj); - } -} - -String? _setupLogcatForwarding(CPython cpython) { - if (_logcatForwardingError != null) { - return _logcatForwardingError; - } - - final setupPtr = _logcatInitScript.toNativeUtf8(); - final result = cpython.PyRun_SimpleString(setupPtr.cast()); - malloc.free(setupPtr); - - if (result != 0) { - _logcatForwardingError = getPythonError(cpython); - return _logcatForwardingError; - } - - return null; -} diff --git a/src/serious_python_android/lib/src/gen.dart b/src/serious_python_android/lib/src/gen.dart deleted file mode 100644 index 43c7b1de..00000000 --- a/src/serious_python_android/lib/src/gen.dart +++ /dev/null @@ -1,27219 +0,0 @@ -// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -// ignore_for_file: type=lint -import 'dart:ffi' as ffi; - -/// Bindings to Python C interface -/// ignore_for_file: unused_field, unused_element -/// -class CPython { - /// Holds the symbol lookup function. - final ffi.Pointer Function(String symbolName) - _lookup; - - /// The symbols are looked up in [dynamicLibrary]. - CPython(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup; - - /// The symbols are looked up with [lookup]. - CPython.fromLookup( - ffi.Pointer Function(String symbolName) - lookup) - : _lookup = lookup; - - ffi.Pointer PyMem_Malloc( - int size, - ) { - return _PyMem_Malloc( - size, - ); - } - - late final _PyMem_MallocPtr = - _lookup Function(ffi.Size)>>( - 'PyMem_Malloc'); - late final _PyMem_Malloc = - _PyMem_MallocPtr.asFunction Function(int)>(); - - ffi.Pointer PyMem_Calloc( - int nelem, - int elsize, - ) { - return _PyMem_Calloc( - nelem, - elsize, - ); - } - - late final _PyMem_CallocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Size, ffi.Size)>>('PyMem_Calloc'); - late final _PyMem_Calloc = - _PyMem_CallocPtr.asFunction Function(int, int)>(); - - ffi.Pointer PyMem_Realloc( - ffi.Pointer ptr, - int new_size, - ) { - return _PyMem_Realloc( - ptr, - new_size, - ); - } - - late final _PyMem_ReallocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Size)>>('PyMem_Realloc'); - late final _PyMem_Realloc = _PyMem_ReallocPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - void PyMem_Free( - ffi.Pointer ptr, - ) { - return _PyMem_Free( - ptr, - ); - } - - late final _PyMem_FreePtr = - _lookup)>>( - 'PyMem_Free'); - late final _PyMem_Free = - _PyMem_FreePtr.asFunction)>(); - - ffi.Pointer PyMem_RawMalloc( - int size, - ) { - return _PyMem_RawMalloc( - size, - ); - } - - late final _PyMem_RawMallocPtr = - _lookup Function(ffi.Size)>>( - 'PyMem_RawMalloc'); - late final _PyMem_RawMalloc = - _PyMem_RawMallocPtr.asFunction Function(int)>(); - - ffi.Pointer PyMem_RawCalloc( - int nelem, - int elsize, - ) { - return _PyMem_RawCalloc( - nelem, - elsize, - ); - } - - late final _PyMem_RawCallocPtr = _lookup< - ffi - .NativeFunction Function(ffi.Size, ffi.Size)>>( - 'PyMem_RawCalloc'); - late final _PyMem_RawCalloc = _PyMem_RawCallocPtr.asFunction< - ffi.Pointer Function(int, int)>(); - - ffi.Pointer PyMem_RawRealloc( - ffi.Pointer ptr, - int new_size, - ) { - return _PyMem_RawRealloc( - ptr, - new_size, - ); - } - - late final _PyMem_RawReallocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Size)>>('PyMem_RawRealloc'); - late final _PyMem_RawRealloc = _PyMem_RawReallocPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - void PyMem_RawFree( - ffi.Pointer ptr, - ) { - return _PyMem_RawFree( - ptr, - ); - } - - late final _PyMem_RawFreePtr = - _lookup)>>( - 'PyMem_RawFree'); - late final _PyMem_RawFree = - _PyMem_RawFreePtr.asFunction)>(); - - ffi.Pointer _PyMem_GetCurrentAllocatorName() { - return __PyMem_GetCurrentAllocatorName(); - } - - late final __PyMem_GetCurrentAllocatorNamePtr = - _lookup Function()>>( - '_PyMem_GetCurrentAllocatorName'); - late final __PyMem_GetCurrentAllocatorName = - __PyMem_GetCurrentAllocatorNamePtr - .asFunction Function()>(); - - ffi.Pointer _PyMem_RawStrdup( - ffi.Pointer str, - ) { - return __PyMem_RawStrdup( - str, - ); - } - - late final __PyMem_RawStrdupPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyMem_RawStrdup'); - late final __PyMem_RawStrdup = __PyMem_RawStrdupPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyMem_Strdup( - ffi.Pointer str, - ) { - return __PyMem_Strdup( - str, - ); - } - - late final __PyMem_StrdupPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyMem_Strdup'); - late final __PyMem_Strdup = __PyMem_StrdupPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyMem_RawWcsdup( - ffi.Pointer str, - ) { - return __PyMem_RawWcsdup( - str, - ); - } - - late final __PyMem_RawWcsdupPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyMem_RawWcsdup'); - late final __PyMem_RawWcsdup = __PyMem_RawWcsdupPtr - .asFunction Function(ffi.Pointer)>(); - - void PyMem_GetAllocator( - int domain, - ffi.Pointer allocator, - ) { - return _PyMem_GetAllocator( - domain, - allocator, - ); - } - - late final _PyMem_GetAllocatorPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Int32, ffi.Pointer)>>('PyMem_GetAllocator'); - late final _PyMem_GetAllocator = _PyMem_GetAllocatorPtr.asFunction< - void Function(int, ffi.Pointer)>(); - - void PyMem_SetAllocator( - int domain, - ffi.Pointer allocator, - ) { - return _PyMem_SetAllocator( - domain, - allocator, - ); - } - - late final _PyMem_SetAllocatorPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Int32, ffi.Pointer)>>('PyMem_SetAllocator'); - late final _PyMem_SetAllocator = _PyMem_SetAllocatorPtr.asFunction< - void Function(int, ffi.Pointer)>(); - - void PyMem_SetupDebugHooks() { - return _PyMem_SetupDebugHooks(); - } - - late final _PyMem_SetupDebugHooksPtr = - _lookup>('PyMem_SetupDebugHooks'); - late final _PyMem_SetupDebugHooks = - _PyMem_SetupDebugHooksPtr.asFunction(); - - int PyObject_CheckBuffer( - ffi.Pointer obj, - ) { - return _PyObject_CheckBuffer( - obj, - ); - } - - late final _PyObject_CheckBufferPtr = - _lookup)>>( - 'PyObject_CheckBuffer'); - late final _PyObject_CheckBuffer = _PyObject_CheckBufferPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyObject_GetBuffer( - ffi.Pointer obj, - ffi.Pointer view, - int flags, - ) { - return _PyObject_GetBuffer( - obj, - view, - flags, - ); - } - - late final _PyObject_GetBufferPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyObject_GetBuffer'); - late final _PyObject_GetBuffer = _PyObject_GetBufferPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyBuffer_GetPointer( - ffi.Pointer view, - ffi.Pointer indices, - ) { - return _PyBuffer_GetPointer( - view, - indices, - ); - } - - late final _PyBuffer_GetPointerPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyBuffer_GetPointer'); - late final _PyBuffer_GetPointer = _PyBuffer_GetPointerPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyBuffer_SizeFromFormat( - ffi.Pointer format, - ) { - return _PyBuffer_SizeFromFormat( - format, - ); - } - - late final _PyBuffer_SizeFromFormatPtr = - _lookup)>>( - 'PyBuffer_SizeFromFormat'); - late final _PyBuffer_SizeFromFormat = _PyBuffer_SizeFromFormatPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyBuffer_ToContiguous( - ffi.Pointer buf, - ffi.Pointer view, - int len, - int order, - ) { - return _PyBuffer_ToContiguous( - buf, - view, - len, - order, - ); - } - - late final _PyBuffer_ToContiguousPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t, ffi.Char)>>('PyBuffer_ToContiguous'); - late final _PyBuffer_ToContiguous = _PyBuffer_ToContiguousPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, int)>(); - - int PyBuffer_FromContiguous( - ffi.Pointer view, - ffi.Pointer buf, - int len, - int order, - ) { - return _PyBuffer_FromContiguous( - view, - buf, - len, - order, - ); - } - - late final _PyBuffer_FromContiguousPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t, ffi.Char)>>('PyBuffer_FromContiguous'); - late final _PyBuffer_FromContiguous = _PyBuffer_FromContiguousPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, int)>(); - - int PyObject_CopyData( - ffi.Pointer dest, - ffi.Pointer src, - ) { - return _PyObject_CopyData( - dest, - src, - ); - } - - late final _PyObject_CopyDataPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_CopyData'); - late final _PyObject_CopyData = _PyObject_CopyDataPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyBuffer_IsContiguous( - ffi.Pointer view, - int fort, - ) { - return _PyBuffer_IsContiguous( - view, - fort, - ); - } - - late final _PyBuffer_IsContiguousPtr = _lookup< - ffi - .NativeFunction, ffi.Char)>>( - 'PyBuffer_IsContiguous'); - late final _PyBuffer_IsContiguous = _PyBuffer_IsContiguousPtr.asFunction< - int Function(ffi.Pointer, int)>(); - - void PyBuffer_FillContiguousStrides( - int ndims, - ffi.Pointer shape, - ffi.Pointer strides, - int itemsize, - int fort, - ) { - return _PyBuffer_FillContiguousStrides( - ndims, - shape, - strides, - itemsize, - fort, - ); - } - - late final _PyBuffer_FillContiguousStridesPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Char)>>('PyBuffer_FillContiguousStrides'); - late final _PyBuffer_FillContiguousStrides = - _PyBuffer_FillContiguousStridesPtr.asFunction< - void Function(int, ffi.Pointer, ffi.Pointer, - int, int)>(); - - int PyBuffer_FillInfo( - ffi.Pointer view, - ffi.Pointer o, - ffi.Pointer buf, - int len, - int readonly, - int flags, - ) { - return _PyBuffer_FillInfo( - view, - o, - buf, - len, - readonly, - flags, - ); - } - - late final _PyBuffer_FillInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - Py_ssize_t, - ffi.Int, - ffi.Int)>>('PyBuffer_FillInfo'); - late final _PyBuffer_FillInfo = _PyBuffer_FillInfoPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, int, int, int)>(); - - void PyBuffer_Release( - ffi.Pointer view, - ) { - return _PyBuffer_Release( - view, - ); - } - - late final _PyBuffer_ReleasePtr = - _lookup)>>( - 'PyBuffer_Release'); - late final _PyBuffer_Release = - _PyBuffer_ReleasePtr.asFunction)>(); - - int Py_Is( - ffi.Pointer x, - ffi.Pointer y, - ) { - return _Py_Is( - x, - y, - ); - } - - late final _Py_IsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('Py_Is'); - late final _Py_Is = _Py_IsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyLong_Type = - _lookup('PyLong_Type'); - - PyTypeObject get PyLong_Type => _PyLong_Type.ref; - - late final ffi.Pointer _PyBool_Type = - _lookup('PyBool_Type'); - - PyTypeObject get PyBool_Type => _PyBool_Type.ref; - - ffi.Pointer PyType_FromSpec( - ffi.Pointer arg0, - ) { - return _PyType_FromSpec( - arg0, - ); - } - - late final _PyType_FromSpecPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyType_FromSpec'); - late final _PyType_FromSpec = _PyType_FromSpecPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyType_FromSpecWithBases( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyType_FromSpecWithBases( - arg0, - arg1, - ); - } - - late final _PyType_FromSpecWithBasesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyType_FromSpecWithBases'); - late final _PyType_FromSpecWithBases = - _PyType_FromSpecWithBasesPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyType_GetSlot( - ffi.Pointer arg0, - int arg1, - ) { - return _PyType_GetSlot( - arg0, - arg1, - ); - } - - late final _PyType_GetSlotPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyType_GetSlot'); - late final _PyType_GetSlot = _PyType_GetSlotPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyType_FromModuleAndSpec( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyType_FromModuleAndSpec( - arg0, - arg1, - arg2, - ); - } - - late final _PyType_FromModuleAndSpecPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyType_FromModuleAndSpec'); - late final _PyType_FromModuleAndSpec = - _PyType_FromModuleAndSpecPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyType_GetModule( - ffi.Pointer arg0, - ) { - return _PyType_GetModule( - arg0, - ); - } - - late final _PyType_GetModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyType_GetModule'); - late final _PyType_GetModule = _PyType_GetModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyType_GetModuleState( - ffi.Pointer arg0, - ) { - return _PyType_GetModuleState( - arg0, - ); - } - - late final _PyType_GetModuleStatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyType_GetModuleState'); - late final _PyType_GetModuleState = _PyType_GetModuleStatePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyType_GetName( - ffi.Pointer arg0, - ) { - return _PyType_GetName( - arg0, - ); - } - - late final _PyType_GetNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyType_GetName'); - late final _PyType_GetName = _PyType_GetNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyType_GetQualName( - ffi.Pointer arg0, - ) { - return _PyType_GetQualName( - arg0, - ); - } - - late final _PyType_GetQualNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyType_GetQualName'); - late final _PyType_GetQualName = _PyType_GetQualNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyType_FromMetaclass( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return _PyType_FromMetaclass( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _PyType_FromMetaclassPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyType_FromMetaclass'); - late final _PyType_FromMetaclass = _PyType_FromMetaclassPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyObject_GetTypeData( - ffi.Pointer obj, - ffi.Pointer cls, - ) { - return _PyObject_GetTypeData( - obj, - cls, - ); - } - - late final _PyObject_GetTypeDataPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_GetTypeData'); - late final _PyObject_GetTypeData = _PyObject_GetTypeDataPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyType_GetTypeDataSize( - ffi.Pointer cls, - ) { - return _PyType_GetTypeDataSize( - cls, - ); - } - - late final _PyType_GetTypeDataSizePtr = _lookup< - ffi.NativeFunction)>>( - 'PyType_GetTypeDataSize'); - late final _PyType_GetTypeDataSize = _PyType_GetTypeDataSizePtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyType_IsSubtype( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyType_IsSubtype( - arg0, - arg1, - ); - } - - late final _PyType_IsSubtypePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyType_IsSubtype'); - late final _PyType_IsSubtype = _PyType_IsSubtypePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyType_Type = - _lookup('PyType_Type'); - - PyTypeObject get PyType_Type => _PyType_Type.ref; - - late final ffi.Pointer _PyBaseObject_Type = - _lookup('PyBaseObject_Type'); - - PyTypeObject get PyBaseObject_Type => _PyBaseObject_Type.ref; - - late final ffi.Pointer _PySuper_Type = - _lookup('PySuper_Type'); - - PyTypeObject get PySuper_Type => _PySuper_Type.ref; - - int PyType_GetFlags( - ffi.Pointer arg0, - ) { - return _PyType_GetFlags( - arg0, - ); - } - - late final _PyType_GetFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.UnsignedLong Function( - ffi.Pointer)>>('PyType_GetFlags'); - late final _PyType_GetFlags = - _PyType_GetFlagsPtr.asFunction)>(); - - int PyType_Ready( - ffi.Pointer arg0, - ) { - return _PyType_Ready( - arg0, - ); - } - - late final _PyType_ReadyPtr = - _lookup)>>( - 'PyType_Ready'); - late final _PyType_Ready = - _PyType_ReadyPtr.asFunction)>(); - - ffi.Pointer PyType_GenericAlloc( - ffi.Pointer arg0, - int arg1, - ) { - return _PyType_GenericAlloc( - arg0, - arg1, - ); - } - - late final _PyType_GenericAllocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PyType_GenericAlloc'); - late final _PyType_GenericAlloc = _PyType_GenericAllocPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyType_GenericNew( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyType_GenericNew( - arg0, - arg1, - arg2, - ); - } - - late final _PyType_GenericNewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyType_GenericNew'); - late final _PyType_GenericNew = _PyType_GenericNewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int PyType_ClearCache() { - return _PyType_ClearCache(); - } - - late final _PyType_ClearCachePtr = - _lookup>( - 'PyType_ClearCache'); - late final _PyType_ClearCache = - _PyType_ClearCachePtr.asFunction(); - - void PyType_Modified( - ffi.Pointer arg0, - ) { - return _PyType_Modified( - arg0, - ); - } - - late final _PyType_ModifiedPtr = - _lookup)>>( - 'PyType_Modified'); - late final _PyType_Modified = _PyType_ModifiedPtr.asFunction< - void Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_Repr( - ffi.Pointer arg0, - ) { - return _PyObject_Repr( - arg0, - ); - } - - late final _PyObject_ReprPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_Repr'); - late final _PyObject_Repr = _PyObject_ReprPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_Str( - ffi.Pointer arg0, - ) { - return _PyObject_Str( - arg0, - ); - } - - late final _PyObject_StrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_Str'); - late final _PyObject_Str = _PyObject_StrPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_ASCII( - ffi.Pointer arg0, - ) { - return _PyObject_ASCII( - arg0, - ); - } - - late final _PyObject_ASCIIPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_ASCII'); - late final _PyObject_ASCII = _PyObject_ASCIIPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_Bytes( - ffi.Pointer arg0, - ) { - return _PyObject_Bytes( - arg0, - ); - } - - late final _PyObject_BytesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_Bytes'); - late final _PyObject_Bytes = _PyObject_BytesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_RichCompare( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyObject_RichCompare( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_RichComparePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('PyObject_RichCompare'); - late final _PyObject_RichCompare = _PyObject_RichComparePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - int PyObject_RichCompareBool( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyObject_RichCompareBool( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_RichCompareBoolPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyObject_RichCompareBool'); - late final _PyObject_RichCompareBool = - _PyObject_RichCompareBoolPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyObject_GetAttrString( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_GetAttrString( - arg0, - arg1, - ); - } - - late final _PyObject_GetAttrStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_GetAttrString'); - late final _PyObject_GetAttrString = _PyObject_GetAttrStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyObject_SetAttrString( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyObject_SetAttrString( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_SetAttrStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyObject_SetAttrString'); - late final _PyObject_SetAttrString = _PyObject_SetAttrStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyObject_HasAttrString( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_HasAttrString( - arg0, - arg1, - ); - } - - late final _PyObject_HasAttrStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_HasAttrString'); - late final _PyObject_HasAttrString = _PyObject_HasAttrStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_GetAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_GetAttr( - arg0, - arg1, - ); - } - - late final _PyObject_GetAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_GetAttr'); - late final _PyObject_GetAttr = _PyObject_GetAttrPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyObject_SetAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyObject_SetAttr( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_SetAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyObject_SetAttr'); - late final _PyObject_SetAttr = _PyObject_SetAttrPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyObject_HasAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_HasAttr( - arg0, - arg1, - ); - } - - late final _PyObject_HasAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_HasAttr'); - late final _PyObject_HasAttr = _PyObject_HasAttrPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_SelfIter( - ffi.Pointer arg0, - ) { - return _PyObject_SelfIter( - arg0, - ); - } - - late final _PyObject_SelfIterPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_SelfIter'); - late final _PyObject_SelfIter = _PyObject_SelfIterPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_GenericGetAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_GenericGetAttr( - arg0, - arg1, - ); - } - - late final _PyObject_GenericGetAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_GenericGetAttr'); - late final _PyObject_GenericGetAttr = _PyObject_GenericGetAttrPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyObject_GenericSetAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyObject_GenericSetAttr( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_GenericSetAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyObject_GenericSetAttr'); - late final _PyObject_GenericSetAttr = _PyObject_GenericSetAttrPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyObject_GenericSetDict( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyObject_GenericSetDict( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_GenericSetDictPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyObject_GenericSetDict'); - late final _PyObject_GenericSetDict = _PyObject_GenericSetDictPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyObject_Hash( - ffi.Pointer arg0, - ) { - return _PyObject_Hash( - arg0, - ); - } - - late final _PyObject_HashPtr = - _lookup)>>( - 'PyObject_Hash'); - late final _PyObject_Hash = - _PyObject_HashPtr.asFunction)>(); - - int PyObject_HashNotImplemented( - ffi.Pointer arg0, - ) { - return _PyObject_HashNotImplemented( - arg0, - ); - } - - late final _PyObject_HashNotImplementedPtr = - _lookup)>>( - 'PyObject_HashNotImplemented'); - late final _PyObject_HashNotImplemented = _PyObject_HashNotImplementedPtr - .asFunction)>(); - - int PyObject_IsTrue( - ffi.Pointer arg0, - ) { - return _PyObject_IsTrue( - arg0, - ); - } - - late final _PyObject_IsTruePtr = - _lookup)>>( - 'PyObject_IsTrue'); - late final _PyObject_IsTrue = - _PyObject_IsTruePtr.asFunction)>(); - - int PyObject_Not( - ffi.Pointer arg0, - ) { - return _PyObject_Not( - arg0, - ); - } - - late final _PyObject_NotPtr = - _lookup)>>( - 'PyObject_Not'); - late final _PyObject_Not = - _PyObject_NotPtr.asFunction)>(); - - int PyCallable_Check( - ffi.Pointer arg0, - ) { - return _PyCallable_Check( - arg0, - ); - } - - late final _PyCallable_CheckPtr = - _lookup)>>( - 'PyCallable_Check'); - late final _PyCallable_Check = - _PyCallable_CheckPtr.asFunction)>(); - - void PyObject_ClearWeakRefs( - ffi.Pointer arg0, - ) { - return _PyObject_ClearWeakRefs( - arg0, - ); - } - - late final _PyObject_ClearWeakRefsPtr = - _lookup)>>( - 'PyObject_ClearWeakRefs'); - late final _PyObject_ClearWeakRefs = _PyObject_ClearWeakRefsPtr.asFunction< - void Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_Dir( - ffi.Pointer arg0, - ) { - return _PyObject_Dir( - arg0, - ); - } - - late final _PyObject_DirPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_Dir'); - late final _PyObject_Dir = _PyObject_DirPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer _PyObject_GetState( - ffi.Pointer arg0, - ) { - return __PyObject_GetState( - arg0, - ); - } - - late final __PyObject_GetStatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyObject_GetState'); - late final __PyObject_GetState = __PyObject_GetStatePtr - .asFunction Function(ffi.Pointer)>(); - - int Py_ReprEnter( - ffi.Pointer arg0, - ) { - return _Py_ReprEnter( - arg0, - ); - } - - late final _Py_ReprEnterPtr = - _lookup)>>( - 'Py_ReprEnter'); - late final _Py_ReprEnter = - _Py_ReprEnterPtr.asFunction)>(); - - void Py_ReprLeave( - ffi.Pointer arg0, - ) { - return _Py_ReprLeave( - arg0, - ); - } - - late final _Py_ReprLeavePtr = - _lookup)>>( - 'Py_ReprLeave'); - late final _Py_ReprLeave = - _Py_ReprLeavePtr.asFunction)>(); - - void _Py_Dealloc( - ffi.Pointer arg0, - ) { - return __Py_Dealloc( - arg0, - ); - } - - late final __Py_DeallocPtr = - _lookup)>>( - '_Py_Dealloc'); - late final __Py_Dealloc = - __Py_DeallocPtr.asFunction)>(); - - void Py_IncRef( - ffi.Pointer arg0, - ) { - return _Py_IncRef1( - arg0, - ); - } - - late final _Py_IncRefPtr = - _lookup)>>( - 'Py_IncRef'); - late final _Py_IncRef1 = - _Py_IncRefPtr.asFunction)>(); - - void Py_DecRef( - ffi.Pointer arg0, - ) { - return _Py_DecRef1( - arg0, - ); - } - - late final _Py_DecRefPtr = - _lookup)>>( - 'Py_DecRef'); - late final _Py_DecRef1 = - _Py_DecRefPtr.asFunction)>(); - - void _Py_IncRef( - ffi.Pointer arg0, - ) { - return __Py_IncRef( - arg0, - ); - } - - late final __Py_IncRefPtr = - _lookup)>>( - '_Py_IncRef'); - late final __Py_IncRef = - __Py_IncRefPtr.asFunction)>(); - - void _Py_DecRef( - ffi.Pointer arg0, - ) { - return __Py_DecRef( - arg0, - ); - } - - late final __Py_DecRefPtr = - _lookup)>>( - '_Py_DecRef'); - late final __Py_DecRef = - __Py_DecRefPtr.asFunction)>(); - - ffi.Pointer Py_NewRef( - ffi.Pointer obj, - ) { - return _Py_NewRef( - obj, - ); - } - - late final _Py_NewRefPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('Py_NewRef'); - late final _Py_NewRef = _Py_NewRefPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer Py_XNewRef( - ffi.Pointer obj, - ) { - return _Py_XNewRef( - obj, - ); - } - - late final _Py_XNewRefPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('Py_XNewRef'); - late final _Py_XNewRef = _Py_XNewRefPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer __Py_NoneStruct = - _lookup('_Py_NoneStruct'); - - PyObject get _Py_NoneStruct => __Py_NoneStruct.ref; - - int Py_IsNone( - ffi.Pointer x, - ) { - return _Py_IsNone( - x, - ); - } - - late final _Py_IsNonePtr = - _lookup)>>( - 'Py_IsNone'); - late final _Py_IsNone = - _Py_IsNonePtr.asFunction)>(); - - late final ffi.Pointer __Py_NotImplementedStruct = - _lookup('_Py_NotImplementedStruct'); - - PyObject get _Py_NotImplementedStruct => __Py_NotImplementedStruct.ref; - - void _Py_NewReference( - ffi.Pointer op, - ) { - return __Py_NewReference( - op, - ); - } - - late final __Py_NewReferencePtr = - _lookup)>>( - '_Py_NewReference'); - late final __Py_NewReference = - __Py_NewReferencePtr.asFunction)>(); - - void _Py_NewReferenceNoTotal( - ffi.Pointer op, - ) { - return __Py_NewReferenceNoTotal( - op, - ); - } - - late final __Py_NewReferenceNoTotalPtr = - _lookup)>>( - '_Py_NewReferenceNoTotal'); - late final __Py_NewReferenceNoTotal = __Py_NewReferenceNoTotalPtr - .asFunction)>(); - - ffi.Pointer _PyType_Name( - ffi.Pointer arg0, - ) { - return __PyType_Name( - arg0, - ); - } - - late final __PyType_NamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyType_Name'); - late final __PyType_Name = __PyType_NamePtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyType_Lookup( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyType_Lookup( - arg0, - arg1, - ); - } - - late final __PyType_LookupPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyType_Lookup'); - late final __PyType_Lookup = __PyType_LookupPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyType_LookupId( - ffi.Pointer arg0, - ffi.Pointer<_Py_Identifier> arg1, - ) { - return __PyType_LookupId( - arg0, - arg1, - ); - } - - late final __PyType_LookupIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyType_LookupId'); - late final __PyType_LookupId = __PyType_LookupIdPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - ffi.Pointer _PyObject_LookupSpecialId( - ffi.Pointer arg0, - ffi.Pointer<_Py_Identifier> arg1, - ) { - return __PyObject_LookupSpecialId( - arg0, - arg1, - ); - } - - late final __PyObject_LookupSpecialIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyObject_LookupSpecialId'); - late final __PyObject_LookupSpecialId = - __PyObject_LookupSpecialIdPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - ffi.Pointer _PyType_CalculateMetaclass( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyType_CalculateMetaclass( - arg0, - arg1, - ); - } - - late final __PyType_CalculateMetaclassPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyType_CalculateMetaclass'); - late final __PyType_CalculateMetaclass = - __PyType_CalculateMetaclassPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyType_GetDocFromInternalDoc( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyType_GetDocFromInternalDoc( - arg0, - arg1, - ); - } - - late final __PyType_GetDocFromInternalDocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyType_GetDocFromInternalDoc'); - late final __PyType_GetDocFromInternalDoc = - __PyType_GetDocFromInternalDocPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyType_GetTextSignatureFromInternalDoc( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyType_GetTextSignatureFromInternalDoc( - arg0, - arg1, - ); - } - - late final __PyType_GetTextSignatureFromInternalDocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>( - '_PyType_GetTextSignatureFromInternalDoc'); - late final __PyType_GetTextSignatureFromInternalDoc = - __PyType_GetTextSignatureFromInternalDocPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyType_GetModuleByDef( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyType_GetModuleByDef( - arg0, - arg1, - ); - } - - late final _PyType_GetModuleByDefPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyType_GetModuleByDef'); - late final _PyType_GetModuleByDef = _PyType_GetModuleByDefPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyType_GetDict( - ffi.Pointer arg0, - ) { - return _PyType_GetDict( - arg0, - ); - } - - late final _PyType_GetDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyType_GetDict'); - late final _PyType_GetDict = _PyType_GetDictPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyObject_Print( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyObject_Print( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_PrintPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyObject_Print'); - late final _PyObject_Print = _PyObject_PrintPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - void _Py_BreakPoint() { - return __Py_BreakPoint(); - } - - late final __Py_BreakPointPtr = - _lookup>('_Py_BreakPoint'); - late final __Py_BreakPoint = __Py_BreakPointPtr.asFunction(); - - void _PyObject_Dump( - ffi.Pointer arg0, - ) { - return __PyObject_Dump( - arg0, - ); - } - - late final __PyObject_DumpPtr = - _lookup)>>( - '_PyObject_Dump'); - late final __PyObject_Dump = - __PyObject_DumpPtr.asFunction)>(); - - int _PyObject_IsFreed( - ffi.Pointer arg0, - ) { - return __PyObject_IsFreed( - arg0, - ); - } - - late final __PyObject_IsFreedPtr = - _lookup)>>( - '_PyObject_IsFreed'); - late final __PyObject_IsFreed = - __PyObject_IsFreedPtr.asFunction)>(); - - int _PyObject_IsAbstract( - ffi.Pointer arg0, - ) { - return __PyObject_IsAbstract( - arg0, - ); - } - - late final __PyObject_IsAbstractPtr = - _lookup)>>( - '_PyObject_IsAbstract'); - late final __PyObject_IsAbstract = __PyObject_IsAbstractPtr - .asFunction)>(); - - ffi.Pointer _PyObject_GetAttrId( - ffi.Pointer arg0, - ffi.Pointer<_Py_Identifier> arg1, - ) { - return __PyObject_GetAttrId( - arg0, - arg1, - ); - } - - late final __PyObject_GetAttrIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyObject_GetAttrId'); - late final __PyObject_GetAttrId = __PyObject_GetAttrIdPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - int _PyObject_SetAttrId( - ffi.Pointer arg0, - ffi.Pointer<_Py_Identifier> arg1, - ffi.Pointer arg2, - ) { - return __PyObject_SetAttrId( - arg0, - arg1, - arg2, - ); - } - - late final __PyObject_SetAttrIdPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>, - ffi.Pointer)>>('_PyObject_SetAttrId'); - late final __PyObject_SetAttrId = __PyObject_SetAttrIdPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>, - ffi.Pointer)>(); - - int _PyObject_LookupAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer> arg2, - ) { - return __PyObject_LookupAttr( - arg0, - arg1, - arg2, - ); - } - - late final __PyObject_LookupAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>>('_PyObject_LookupAttr'); - late final __PyObject_LookupAttr = __PyObject_LookupAttrPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>(); - - int _PyObject_LookupAttrId( - ffi.Pointer arg0, - ffi.Pointer<_Py_Identifier> arg1, - ffi.Pointer> arg2, - ) { - return __PyObject_LookupAttrId( - arg0, - arg1, - arg2, - ); - } - - late final __PyObject_LookupAttrIdPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>, - ffi.Pointer>)>>('_PyObject_LookupAttrId'); - late final __PyObject_LookupAttrId = __PyObject_LookupAttrIdPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>, - ffi.Pointer>)>(); - - int _PyObject_GetMethod( - ffi.Pointer obj, - ffi.Pointer name, - ffi.Pointer> method, - ) { - return __PyObject_GetMethod( - obj, - name, - method, - ); - } - - late final __PyObject_GetMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>>('_PyObject_GetMethod'); - late final __PyObject_GetMethod = __PyObject_GetMethodPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>(); - - ffi.Pointer> _PyObject_GetDictPtr( - ffi.Pointer arg0, - ) { - return __PyObject_GetDictPtr( - arg0, - ); - } - - late final __PyObject_GetDictPtrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer)>>('_PyObject_GetDictPtr'); - late final __PyObject_GetDictPtr = __PyObject_GetDictPtrPtr.asFunction< - ffi.Pointer> Function(ffi.Pointer)>(); - - ffi.Pointer _PyObject_NextNotImplemented( - ffi.Pointer arg0, - ) { - return __PyObject_NextNotImplemented( - arg0, - ); - } - - late final __PyObject_NextNotImplementedPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyObject_NextNotImplemented'); - late final __PyObject_NextNotImplemented = __PyObject_NextNotImplementedPtr - .asFunction Function(ffi.Pointer)>(); - - void PyObject_CallFinalizer( - ffi.Pointer arg0, - ) { - return _PyObject_CallFinalizer( - arg0, - ); - } - - late final _PyObject_CallFinalizerPtr = - _lookup)>>( - 'PyObject_CallFinalizer'); - late final _PyObject_CallFinalizer = _PyObject_CallFinalizerPtr.asFunction< - void Function(ffi.Pointer)>(); - - int PyObject_CallFinalizerFromDealloc( - ffi.Pointer arg0, - ) { - return _PyObject_CallFinalizerFromDealloc( - arg0, - ); - } - - late final _PyObject_CallFinalizerFromDeallocPtr = - _lookup)>>( - 'PyObject_CallFinalizerFromDealloc'); - late final _PyObject_CallFinalizerFromDealloc = - _PyObject_CallFinalizerFromDeallocPtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer _PyObject_GenericGetAttrWithDict( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - int arg3, - ) { - return __PyObject_GenericGetAttrWithDict( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyObject_GenericGetAttrWithDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int)>>('_PyObject_GenericGetAttrWithDict'); - late final __PyObject_GenericGetAttrWithDict = - __PyObject_GenericGetAttrWithDictPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer, int)>(); - - int _PyObject_GenericSetAttrWithDict( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return __PyObject_GenericSetAttrWithDict( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyObject_GenericSetAttrWithDictPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyObject_GenericSetAttrWithDict'); - late final __PyObject_GenericSetAttrWithDict = - __PyObject_GenericSetAttrWithDictPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyObject_FunctionStr( - ffi.Pointer arg0, - ) { - return __PyObject_FunctionStr( - arg0, - ); - } - - late final __PyObject_FunctionStrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyObject_FunctionStr'); - late final __PyObject_FunctionStr = __PyObject_FunctionStrPtr - .asFunction Function(ffi.Pointer)>(); - - late final ffi.Pointer __PyNone_Type = - _lookup('_PyNone_Type'); - - PyTypeObject get _PyNone_Type => __PyNone_Type.ref; - - late final ffi.Pointer __PyNotImplemented_Type = - _lookup('_PyNotImplemented_Type'); - - PyTypeObject get _PyNotImplemented_Type => __PyNotImplemented_Type.ref; - - late final ffi.Pointer> __Py_SwappedOp = - _lookup>('_Py_SwappedOp'); - - ffi.Pointer get _Py_SwappedOp => __Py_SwappedOp.value; - - set _Py_SwappedOp(ffi.Pointer value) => __Py_SwappedOp.value = value; - - void _PyDebugAllocatorStats( - ffi.Pointer out, - ffi.Pointer block_name, - int num_blocks, - int sizeof_block, - ) { - return __PyDebugAllocatorStats( - out, - block_name, - num_blocks, - sizeof_block, - ); - } - - late final __PyDebugAllocatorStatsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int, - ffi.Size)>>('_PyDebugAllocatorStats'); - late final __PyDebugAllocatorStats = __PyDebugAllocatorStatsPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, int, int)>(); - - void _PyObject_DebugTypeStats( - ffi.Pointer out, - ) { - return __PyObject_DebugTypeStats( - out, - ); - } - - late final __PyObject_DebugTypeStatsPtr = - _lookup)>>( - '_PyObject_DebugTypeStats'); - late final __PyObject_DebugTypeStats = __PyObject_DebugTypeStatsPtr - .asFunction)>(); - - void _PyObject_AssertFailed( - ffi.Pointer obj, - ffi.Pointer expr, - ffi.Pointer msg, - ffi.Pointer file, - int line, - ffi.Pointer function, - ) { - return __PyObject_AssertFailed( - obj, - expr, - msg, - file, - line, - function, - ); - } - - late final __PyObject_AssertFailedPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer)>>('_PyObject_AssertFailed'); - late final __PyObject_AssertFailed = __PyObject_AssertFailedPtr.asFunction< - void Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer)>(); - - int _PyObject_CheckConsistency( - ffi.Pointer op, - int check_content, - ) { - return __PyObject_CheckConsistency( - op, - check_content, - ); - } - - late final __PyObject_CheckConsistencyPtr = _lookup< - ffi.NativeFunction, ffi.Int)>>( - '_PyObject_CheckConsistency'); - late final __PyObject_CheckConsistency = __PyObject_CheckConsistencyPtr - .asFunction, int)>(); - - int _PyTrash_begin( - ffi.Pointer tstate, - ffi.Pointer op, - ) { - return __PyTrash_begin( - tstate, - op, - ); - } - - late final __PyTrash_beginPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyTrash_begin'); - late final __PyTrash_begin = __PyTrash_beginPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - void _PyTrash_end( - ffi.Pointer tstate, - ) { - return __PyTrash_end( - tstate, - ); - } - - late final __PyTrash_endPtr = _lookup< - ffi.NativeFunction)>>( - '_PyTrash_end'); - late final __PyTrash_end = - __PyTrash_endPtr.asFunction)>(); - - int _PyTrash_cond( - ffi.Pointer op, - destructor dealloc, - ) { - return __PyTrash_cond( - op, - dealloc, - ); - } - - late final __PyTrash_condPtr = _lookup< - ffi - .NativeFunction, destructor)>>( - '_PyTrash_cond'); - late final __PyTrash_cond = __PyTrash_condPtr - .asFunction, destructor)>(); - - ffi.Pointer PyObject_GetItemData( - ffi.Pointer obj, - ) { - return _PyObject_GetItemData( - obj, - ); - } - - late final _PyObject_GetItemDataPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_GetItemData'); - late final _PyObject_GetItemData = _PyObject_GetItemDataPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int _PyObject_VisitManagedDict( - ffi.Pointer obj, - visitproc visit, - ffi.Pointer arg, - ) { - return __PyObject_VisitManagedDict( - obj, - visit, - arg, - ); - } - - late final __PyObject_VisitManagedDictPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, visitproc, - ffi.Pointer)>>('_PyObject_VisitManagedDict'); - late final __PyObject_VisitManagedDict = - __PyObject_VisitManagedDictPtr.asFunction< - int Function( - ffi.Pointer, visitproc, ffi.Pointer)>(); - - void _PyObject_ClearManagedDict( - ffi.Pointer obj, - ) { - return __PyObject_ClearManagedDict( - obj, - ); - } - - late final __PyObject_ClearManagedDictPtr = - _lookup)>>( - '_PyObject_ClearManagedDict'); - late final __PyObject_ClearManagedDict = __PyObject_ClearManagedDictPtr - .asFunction)>(); - - int PyType_AddWatcher( - PyType_WatchCallback callback, - ) { - return _PyType_AddWatcher( - callback, - ); - } - - late final _PyType_AddWatcherPtr = - _lookup>( - 'PyType_AddWatcher'); - late final _PyType_AddWatcher = - _PyType_AddWatcherPtr.asFunction(); - - int PyType_ClearWatcher( - int watcher_id, - ) { - return _PyType_ClearWatcher( - watcher_id, - ); - } - - late final _PyType_ClearWatcherPtr = - _lookup>( - 'PyType_ClearWatcher'); - late final _PyType_ClearWatcher = - _PyType_ClearWatcherPtr.asFunction(); - - int PyType_Watch( - int watcher_id, - ffi.Pointer type, - ) { - return _PyType_Watch( - watcher_id, - type, - ); - } - - late final _PyType_WatchPtr = _lookup< - ffi.NativeFunction)>>( - 'PyType_Watch'); - late final _PyType_Watch = - _PyType_WatchPtr.asFunction)>(); - - int PyType_Unwatch( - int watcher_id, - ffi.Pointer type, - ) { - return _PyType_Unwatch( - watcher_id, - type, - ); - } - - late final _PyType_UnwatchPtr = _lookup< - ffi.NativeFunction)>>( - 'PyType_Unwatch'); - late final _PyType_Unwatch = - _PyType_UnwatchPtr.asFunction)>(); - - int PyUnstable_Type_AssignVersionTag( - ffi.Pointer type, - ) { - return _PyUnstable_Type_AssignVersionTag( - type, - ); - } - - late final _PyUnstable_Type_AssignVersionTagPtr = - _lookup)>>( - 'PyUnstable_Type_AssignVersionTag'); - late final _PyUnstable_Type_AssignVersionTag = - _PyUnstable_Type_AssignVersionTagPtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_Malloc( - int size, - ) { - return _PyObject_Malloc( - size, - ); - } - - late final _PyObject_MallocPtr = - _lookup Function(ffi.Size)>>( - 'PyObject_Malloc'); - late final _PyObject_Malloc = - _PyObject_MallocPtr.asFunction Function(int)>(); - - ffi.Pointer PyObject_Calloc( - int nelem, - int elsize, - ) { - return _PyObject_Calloc( - nelem, - elsize, - ); - } - - late final _PyObject_CallocPtr = _lookup< - ffi - .NativeFunction Function(ffi.Size, ffi.Size)>>( - 'PyObject_Calloc'); - late final _PyObject_Calloc = _PyObject_CallocPtr.asFunction< - ffi.Pointer Function(int, int)>(); - - ffi.Pointer PyObject_Realloc( - ffi.Pointer ptr, - int new_size, - ) { - return _PyObject_Realloc( - ptr, - new_size, - ); - } - - late final _PyObject_ReallocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Size)>>('PyObject_Realloc'); - late final _PyObject_Realloc = _PyObject_ReallocPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - void PyObject_Free( - ffi.Pointer ptr, - ) { - return _PyObject_Free( - ptr, - ); - } - - late final _PyObject_FreePtr = - _lookup)>>( - 'PyObject_Free'); - late final _PyObject_Free = - _PyObject_FreePtr.asFunction)>(); - - ffi.Pointer PyObject_Init( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_Init( - arg0, - arg1, - ); - } - - late final _PyObject_InitPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_Init'); - late final _PyObject_Init = _PyObject_InitPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_InitVar( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyObject_InitVar( - arg0, - arg1, - arg2, - ); - } - - late final _PyObject_InitVarPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, Py_ssize_t)>>('PyObject_InitVar'); - late final _PyObject_InitVar = _PyObject_InitVarPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer _PyObject_New( - ffi.Pointer arg0, - ) { - return __PyObject_New( - arg0, - ); - } - - late final __PyObject_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyObject_New'); - late final __PyObject_New = __PyObject_NewPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyObject_NewVar( - ffi.Pointer arg0, - int arg1, - ) { - return __PyObject_NewVar( - arg0, - arg1, - ); - } - - late final __PyObject_NewVarPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('_PyObject_NewVar'); - late final __PyObject_NewVar = __PyObject_NewVarPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int PyGC_Collect() { - return _PyGC_Collect(); - } - - late final _PyGC_CollectPtr = - _lookup>('PyGC_Collect'); - late final _PyGC_Collect = _PyGC_CollectPtr.asFunction(); - - int PyGC_Enable() { - return _PyGC_Enable(); - } - - late final _PyGC_EnablePtr = - _lookup>('PyGC_Enable'); - late final _PyGC_Enable = _PyGC_EnablePtr.asFunction(); - - int PyGC_Disable() { - return _PyGC_Disable(); - } - - late final _PyGC_DisablePtr = - _lookup>('PyGC_Disable'); - late final _PyGC_Disable = _PyGC_DisablePtr.asFunction(); - - int PyGC_IsEnabled() { - return _PyGC_IsEnabled(); - } - - late final _PyGC_IsEnabledPtr = - _lookup>('PyGC_IsEnabled'); - late final _PyGC_IsEnabled = _PyGC_IsEnabledPtr.asFunction(); - - void PyUnstable_GC_VisitObjects( - gcvisitobjects_t callback, - ffi.Pointer arg, - ) { - return _PyUnstable_GC_VisitObjects( - callback, - arg, - ); - } - - late final _PyUnstable_GC_VisitObjectsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(gcvisitobjects_t, - ffi.Pointer)>>('PyUnstable_GC_VisitObjects'); - late final _PyUnstable_GC_VisitObjects = _PyUnstable_GC_VisitObjectsPtr - .asFunction)>(); - - ffi.Pointer _PyObject_GC_Resize( - ffi.Pointer arg0, - int arg1, - ) { - return __PyObject_GC_Resize( - arg0, - arg1, - ); - } - - late final __PyObject_GC_ResizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('_PyObject_GC_Resize'); - late final __PyObject_GC_Resize = __PyObject_GC_ResizePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer _PyObject_GC_New( - ffi.Pointer arg0, - ) { - return __PyObject_GC_New( - arg0, - ); - } - - late final __PyObject_GC_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyObject_GC_New'); - late final __PyObject_GC_New = __PyObject_GC_NewPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyObject_GC_NewVar( - ffi.Pointer arg0, - int arg1, - ) { - return __PyObject_GC_NewVar( - arg0, - arg1, - ); - } - - late final __PyObject_GC_NewVarPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('_PyObject_GC_NewVar'); - late final __PyObject_GC_NewVar = __PyObject_GC_NewVarPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - void PyObject_GC_Track( - ffi.Pointer arg0, - ) { - return _PyObject_GC_Track( - arg0, - ); - } - - late final _PyObject_GC_TrackPtr = - _lookup)>>( - 'PyObject_GC_Track'); - late final _PyObject_GC_Track = - _PyObject_GC_TrackPtr.asFunction)>(); - - void PyObject_GC_UnTrack( - ffi.Pointer arg0, - ) { - return _PyObject_GC_UnTrack( - arg0, - ); - } - - late final _PyObject_GC_UnTrackPtr = - _lookup)>>( - 'PyObject_GC_UnTrack'); - late final _PyObject_GC_UnTrack = _PyObject_GC_UnTrackPtr.asFunction< - void Function(ffi.Pointer)>(); - - void PyObject_GC_Del( - ffi.Pointer arg0, - ) { - return _PyObject_GC_Del( - arg0, - ); - } - - late final _PyObject_GC_DelPtr = - _lookup)>>( - 'PyObject_GC_Del'); - late final _PyObject_GC_Del = - _PyObject_GC_DelPtr.asFunction)>(); - - int PyObject_GC_IsTracked( - ffi.Pointer arg0, - ) { - return _PyObject_GC_IsTracked( - arg0, - ); - } - - late final _PyObject_GC_IsTrackedPtr = - _lookup)>>( - 'PyObject_GC_IsTracked'); - late final _PyObject_GC_IsTracked = _PyObject_GC_IsTrackedPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyObject_GC_IsFinalized( - ffi.Pointer arg0, - ) { - return _PyObject_GC_IsFinalized( - arg0, - ); - } - - late final _PyObject_GC_IsFinalizedPtr = - _lookup)>>( - 'PyObject_GC_IsFinalized'); - late final _PyObject_GC_IsFinalized = _PyObject_GC_IsFinalizedPtr.asFunction< - int Function(ffi.Pointer)>(); - - void PyObject_GetArenaAllocator( - ffi.Pointer allocator, - ) { - return _PyObject_GetArenaAllocator( - allocator, - ); - } - - late final _PyObject_GetArenaAllocatorPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer)>>( - 'PyObject_GetArenaAllocator'); - late final _PyObject_GetArenaAllocator = _PyObject_GetArenaAllocatorPtr - .asFunction)>(); - - void PyObject_SetArenaAllocator( - ffi.Pointer allocator, - ) { - return _PyObject_SetArenaAllocator( - allocator, - ); - } - - late final _PyObject_SetArenaAllocatorPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer)>>( - 'PyObject_SetArenaAllocator'); - late final _PyObject_SetArenaAllocator = _PyObject_SetArenaAllocatorPtr - .asFunction)>(); - - int PyObject_IS_GC( - ffi.Pointer obj, - ) { - return _PyObject_IS_GC( - obj, - ); - } - - late final _PyObject_IS_GCPtr = - _lookup)>>( - 'PyObject_IS_GC'); - late final _PyObject_IS_GC = - _PyObject_IS_GCPtr.asFunction)>(); - - int PyType_SUPPORTS_WEAKREFS( - ffi.Pointer type, - ) { - return _PyType_SUPPORTS_WEAKREFS( - type, - ); - } - - late final _PyType_SUPPORTS_WEAKREFSPtr = - _lookup)>>( - 'PyType_SUPPORTS_WEAKREFS'); - late final _PyType_SUPPORTS_WEAKREFS = _PyType_SUPPORTS_WEAKREFSPtr - .asFunction)>(); - - ffi.Pointer> PyObject_GET_WEAKREFS_LISTPTR( - ffi.Pointer op, - ) { - return _PyObject_GET_WEAKREFS_LISTPTR( - op, - ); - } - - late final _PyObject_GET_WEAKREFS_LISTPTRPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer)>>('PyObject_GET_WEAKREFS_LISTPTR'); - late final _PyObject_GET_WEAKREFS_LISTPTR = - _PyObject_GET_WEAKREFS_LISTPTRPtr.asFunction< - ffi.Pointer> Function(ffi.Pointer)>(); - - ffi.Pointer PyUnstable_Object_GC_NewWithExtraData( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnstable_Object_GC_NewWithExtraData( - arg0, - arg1, - ); - } - - late final _PyUnstable_Object_GC_NewWithExtraDataPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Size)>>('PyUnstable_Object_GC_NewWithExtraData'); - late final _PyUnstable_Object_GC_NewWithExtraData = - _PyUnstable_Object_GC_NewWithExtraDataPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int _Py_HashDouble( - ffi.Pointer arg0, - double arg1, - ) { - return __Py_HashDouble( - arg0, - arg1, - ); - } - - late final __Py_HashDoublePtr = _lookup< - ffi.NativeFunction< - Py_hash_t Function( - ffi.Pointer, ffi.Double)>>('_Py_HashDouble'); - late final __Py_HashDouble = __Py_HashDoublePtr - .asFunction, double)>(); - - int _Py_HashPointer( - ffi.Pointer arg0, - ) { - return __Py_HashPointer( - arg0, - ); - } - - late final __Py_HashPointerPtr = - _lookup)>>( - '_Py_HashPointer'); - late final __Py_HashPointer = - __Py_HashPointerPtr.asFunction)>(); - - int _Py_HashPointerRaw( - ffi.Pointer arg0, - ) { - return __Py_HashPointerRaw( - arg0, - ); - } - - late final __Py_HashPointerRawPtr = - _lookup)>>( - '_Py_HashPointerRaw'); - late final __Py_HashPointerRaw = - __Py_HashPointerRawPtr.asFunction)>(); - - int _Py_HashBytes( - ffi.Pointer arg0, - int arg1, - ) { - return __Py_HashBytes( - arg0, - arg1, - ); - } - - late final __Py_HashBytesPtr = _lookup< - ffi.NativeFunction< - Py_hash_t Function( - ffi.Pointer, Py_ssize_t)>>('_Py_HashBytes'); - late final __Py_HashBytes = - __Py_HashBytesPtr.asFunction, int)>(); - - late final ffi.Pointer<_Py_HashSecret_t> __Py_HashSecret = - _lookup<_Py_HashSecret_t>('_Py_HashSecret'); - - _Py_HashSecret_t get _Py_HashSecret => __Py_HashSecret.ref; - - ffi.Pointer PyHash_GetFuncDef() { - return _PyHash_GetFuncDef(); - } - - late final _PyHash_GetFuncDefPtr = - _lookup Function()>>( - 'PyHash_GetFuncDef'); - late final _PyHash_GetFuncDef = _PyHash_GetFuncDefPtr.asFunction< - ffi.Pointer Function()>(); - - late final ffi.Pointer _Py_DebugFlag = - _lookup('Py_DebugFlag'); - - int get Py_DebugFlag => _Py_DebugFlag.value; - - set Py_DebugFlag(int value) => _Py_DebugFlag.value = value; - - late final ffi.Pointer _Py_VerboseFlag = - _lookup('Py_VerboseFlag'); - - int get Py_VerboseFlag => _Py_VerboseFlag.value; - - set Py_VerboseFlag(int value) => _Py_VerboseFlag.value = value; - - late final ffi.Pointer _Py_QuietFlag = - _lookup('Py_QuietFlag'); - - int get Py_QuietFlag => _Py_QuietFlag.value; - - set Py_QuietFlag(int value) => _Py_QuietFlag.value = value; - - late final ffi.Pointer _Py_InteractiveFlag = - _lookup('Py_InteractiveFlag'); - - int get Py_InteractiveFlag => _Py_InteractiveFlag.value; - - set Py_InteractiveFlag(int value) => _Py_InteractiveFlag.value = value; - - late final ffi.Pointer _Py_InspectFlag = - _lookup('Py_InspectFlag'); - - int get Py_InspectFlag => _Py_InspectFlag.value; - - set Py_InspectFlag(int value) => _Py_InspectFlag.value = value; - - late final ffi.Pointer _Py_OptimizeFlag = - _lookup('Py_OptimizeFlag'); - - int get Py_OptimizeFlag => _Py_OptimizeFlag.value; - - set Py_OptimizeFlag(int value) => _Py_OptimizeFlag.value = value; - - late final ffi.Pointer _Py_NoSiteFlag = - _lookup('Py_NoSiteFlag'); - - int get Py_NoSiteFlag => _Py_NoSiteFlag.value; - - set Py_NoSiteFlag(int value) => _Py_NoSiteFlag.value = value; - - late final ffi.Pointer _Py_BytesWarningFlag = - _lookup('Py_BytesWarningFlag'); - - int get Py_BytesWarningFlag => _Py_BytesWarningFlag.value; - - set Py_BytesWarningFlag(int value) => _Py_BytesWarningFlag.value = value; - - late final ffi.Pointer _Py_FrozenFlag = - _lookup('Py_FrozenFlag'); - - int get Py_FrozenFlag => _Py_FrozenFlag.value; - - set Py_FrozenFlag(int value) => _Py_FrozenFlag.value = value; - - late final ffi.Pointer _Py_IgnoreEnvironmentFlag = - _lookup('Py_IgnoreEnvironmentFlag'); - - int get Py_IgnoreEnvironmentFlag => _Py_IgnoreEnvironmentFlag.value; - - set Py_IgnoreEnvironmentFlag(int value) => - _Py_IgnoreEnvironmentFlag.value = value; - - late final ffi.Pointer _Py_DontWriteBytecodeFlag = - _lookup('Py_DontWriteBytecodeFlag'); - - int get Py_DontWriteBytecodeFlag => _Py_DontWriteBytecodeFlag.value; - - set Py_DontWriteBytecodeFlag(int value) => - _Py_DontWriteBytecodeFlag.value = value; - - late final ffi.Pointer _Py_NoUserSiteDirectory = - _lookup('Py_NoUserSiteDirectory'); - - int get Py_NoUserSiteDirectory => _Py_NoUserSiteDirectory.value; - - set Py_NoUserSiteDirectory(int value) => - _Py_NoUserSiteDirectory.value = value; - - late final ffi.Pointer _Py_UnbufferedStdioFlag = - _lookup('Py_UnbufferedStdioFlag'); - - int get Py_UnbufferedStdioFlag => _Py_UnbufferedStdioFlag.value; - - set Py_UnbufferedStdioFlag(int value) => - _Py_UnbufferedStdioFlag.value = value; - - late final ffi.Pointer _Py_HashRandomizationFlag = - _lookup('Py_HashRandomizationFlag'); - - int get Py_HashRandomizationFlag => _Py_HashRandomizationFlag.value; - - set Py_HashRandomizationFlag(int value) => - _Py_HashRandomizationFlag.value = value; - - late final ffi.Pointer _Py_IsolatedFlag = - _lookup('Py_IsolatedFlag'); - - int get Py_IsolatedFlag => _Py_IsolatedFlag.value; - - set Py_IsolatedFlag(int value) => _Py_IsolatedFlag.value = value; - - ffi.Pointer Py_GETENV( - ffi.Pointer name, - ) { - return _Py_GETENV( - name, - ); - } - - late final _Py_GETENVPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('Py_GETENV'); - late final _Py_GETENV = _Py_GETENVPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyByteArray_Type = - _lookup('PyByteArray_Type'); - - PyTypeObject get PyByteArray_Type => _PyByteArray_Type.ref; - - late final ffi.Pointer _PyByteArrayIter_Type = - _lookup('PyByteArrayIter_Type'); - - PyTypeObject get PyByteArrayIter_Type => _PyByteArrayIter_Type.ref; - - ffi.Pointer PyByteArray_FromObject( - ffi.Pointer arg0, - ) { - return _PyByteArray_FromObject( - arg0, - ); - } - - late final _PyByteArray_FromObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyByteArray_FromObject'); - late final _PyByteArray_FromObject = _PyByteArray_FromObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyByteArray_Concat( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyByteArray_Concat( - arg0, - arg1, - ); - } - - late final _PyByteArray_ConcatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyByteArray_Concat'); - late final _PyByteArray_Concat = _PyByteArray_ConcatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyByteArray_FromStringAndSize( - ffi.Pointer arg0, - int arg1, - ) { - return _PyByteArray_FromStringAndSize( - arg0, - arg1, - ); - } - - late final _PyByteArray_FromStringAndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - Py_ssize_t)>>('PyByteArray_FromStringAndSize'); - late final _PyByteArray_FromStringAndSize = _PyByteArray_FromStringAndSizePtr - .asFunction Function(ffi.Pointer, int)>(); - - int PyByteArray_Size( - ffi.Pointer arg0, - ) { - return _PyByteArray_Size( - arg0, - ); - } - - late final _PyByteArray_SizePtr = - _lookup)>>( - 'PyByteArray_Size'); - late final _PyByteArray_Size = - _PyByteArray_SizePtr.asFunction)>(); - - ffi.Pointer PyByteArray_AsString( - ffi.Pointer arg0, - ) { - return _PyByteArray_AsString( - arg0, - ); - } - - late final _PyByteArray_AsStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyByteArray_AsString'); - late final _PyByteArray_AsString = _PyByteArray_AsStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyByteArray_Resize( - ffi.Pointer arg0, - int arg1, - ) { - return _PyByteArray_Resize( - arg0, - arg1, - ); - } - - late final _PyByteArray_ResizePtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyByteArray_Resize'); - late final _PyByteArray_Resize = _PyByteArray_ResizePtr.asFunction< - int Function(ffi.Pointer, int)>(); - - late final ffi.Pointer> __PyByteArray_empty_string = - _lookup>('_PyByteArray_empty_string'); - - ffi.Pointer get _PyByteArray_empty_string => - __PyByteArray_empty_string.value; - - set _PyByteArray_empty_string(ffi.Pointer value) => - __PyByteArray_empty_string.value = value; - - late final ffi.Pointer _PyBytes_Type = - _lookup('PyBytes_Type'); - - PyTypeObject get PyBytes_Type => _PyBytes_Type.ref; - - late final ffi.Pointer _PyBytesIter_Type = - _lookup('PyBytesIter_Type'); - - PyTypeObject get PyBytesIter_Type => _PyBytesIter_Type.ref; - - ffi.Pointer PyBytes_FromStringAndSize( - ffi.Pointer arg0, - int arg1, - ) { - return _PyBytes_FromStringAndSize( - arg0, - arg1, - ); - } - - late final _PyBytes_FromStringAndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PyBytes_FromStringAndSize'); - late final _PyBytes_FromStringAndSize = _PyBytes_FromStringAndSizePtr - .asFunction Function(ffi.Pointer, int)>(); - - ffi.Pointer PyBytes_FromString( - ffi.Pointer arg0, - ) { - return _PyBytes_FromString( - arg0, - ); - } - - late final _PyBytes_FromStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyBytes_FromString'); - late final _PyBytes_FromString = _PyBytes_FromStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyBytes_FromObject( - ffi.Pointer arg0, - ) { - return _PyBytes_FromObject( - arg0, - ); - } - - late final _PyBytes_FromObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyBytes_FromObject'); - late final _PyBytes_FromObject = _PyBytes_FromObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyBytes_FromFormatV( - ffi.Pointer arg0, - va_list arg1, - ) { - return _PyBytes_FromFormatV( - arg0, - arg1, - ); - } - - late final _PyBytes_FromFormatVPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, va_list)>>('PyBytes_FromFormatV'); - late final _PyBytes_FromFormatV = _PyBytes_FromFormatVPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, va_list)>(); - - ffi.Pointer PyBytes_FromFormat( - ffi.Pointer arg0, - ) { - return _PyBytes_FromFormat( - arg0, - ); - } - - late final _PyBytes_FromFormatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyBytes_FromFormat'); - late final _PyBytes_FromFormat = _PyBytes_FromFormatPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyBytes_Size( - ffi.Pointer arg0, - ) { - return _PyBytes_Size( - arg0, - ); - } - - late final _PyBytes_SizePtr = - _lookup)>>( - 'PyBytes_Size'); - late final _PyBytes_Size = - _PyBytes_SizePtr.asFunction)>(); - - ffi.Pointer PyBytes_AsString( - ffi.Pointer arg0, - ) { - return _PyBytes_AsString( - arg0, - ); - } - - late final _PyBytes_AsStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyBytes_AsString'); - late final _PyBytes_AsString = _PyBytes_AsStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyBytes_Repr( - ffi.Pointer arg0, - int arg1, - ) { - return _PyBytes_Repr( - arg0, - arg1, - ); - } - - late final _PyBytes_ReprPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyBytes_Repr'); - late final _PyBytes_Repr = _PyBytes_ReprPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - void PyBytes_Concat( - ffi.Pointer> arg0, - ffi.Pointer arg1, - ) { - return _PyBytes_Concat( - arg0, - arg1, - ); - } - - late final _PyBytes_ConcatPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer>, - ffi.Pointer)>>('PyBytes_Concat'); - late final _PyBytes_Concat = _PyBytes_ConcatPtr.asFunction< - void Function( - ffi.Pointer>, ffi.Pointer)>(); - - void PyBytes_ConcatAndDel( - ffi.Pointer> arg0, - ffi.Pointer arg1, - ) { - return _PyBytes_ConcatAndDel( - arg0, - arg1, - ); - } - - late final _PyBytes_ConcatAndDelPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer>, - ffi.Pointer)>>('PyBytes_ConcatAndDel'); - late final _PyBytes_ConcatAndDel = _PyBytes_ConcatAndDelPtr.asFunction< - void Function( - ffi.Pointer>, ffi.Pointer)>(); - - ffi.Pointer PyBytes_DecodeEscape( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - int arg3, - ffi.Pointer arg4, - ) { - return _PyBytes_DecodeEscape1( - arg0, - arg1, - arg2, - arg3, - arg4, - ); - } - - late final _PyBytes_DecodeEscapePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - Py_ssize_t, - ffi.Pointer)>>('PyBytes_DecodeEscape'); - late final _PyBytes_DecodeEscape1 = _PyBytes_DecodeEscapePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, int, ffi.Pointer)>(); - - int PyBytes_AsStringAndSize( - ffi.Pointer obj, - ffi.Pointer> s, - ffi.Pointer len, - ) { - return _PyBytes_AsStringAndSize( - obj, - s, - len, - ); - } - - late final _PyBytes_AsStringAndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyBytes_AsStringAndSize'); - late final _PyBytes_AsStringAndSize = _PyBytes_AsStringAndSizePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer>, - ffi.Pointer)>(); - - int _PyBytes_Resize( - ffi.Pointer> arg0, - int arg1, - ) { - return __PyBytes_Resize( - arg0, - arg1, - ); - } - - late final __PyBytes_ResizePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer>, - Py_ssize_t)>>('_PyBytes_Resize'); - late final __PyBytes_Resize = __PyBytes_ResizePtr - .asFunction>, int)>(); - - ffi.Pointer _PyBytes_FormatEx( - ffi.Pointer format, - int format_len, - ffi.Pointer args, - int use_bytearray, - ) { - return __PyBytes_FormatEx( - format, - format_len, - args, - use_bytearray, - ); - } - - late final __PyBytes_FormatExPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer, ffi.Int)>>('_PyBytes_FormatEx'); - late final __PyBytes_FormatEx = __PyBytes_FormatExPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer, int)>(); - - ffi.Pointer _PyBytes_FromHex( - ffi.Pointer string, - int use_bytearray, - ) { - return __PyBytes_FromHex( - string, - use_bytearray, - ); - } - - late final __PyBytes_FromHexPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('_PyBytes_FromHex'); - late final __PyBytes_FromHex = __PyBytes_FromHexPtr - .asFunction Function(ffi.Pointer, int)>(); - - ffi.Pointer _PyBytes_DecodeEscape( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ffi.Pointer> arg3, - ) { - return __PyBytes_DecodeEscape( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyBytes_DecodeEscapePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer>)>>('_PyBytes_DecodeEscape'); - late final __PyBytes_DecodeEscape = __PyBytes_DecodeEscapePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer>)>(); - - ffi.Pointer _PyBytes_Join( - ffi.Pointer sep, - ffi.Pointer x, - ) { - return __PyBytes_Join( - sep, - x, - ); - } - - late final __PyBytes_JoinPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('_PyBytes_Join'); - late final __PyBytes_Join = __PyBytes_JoinPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - void _PyBytesWriter_Init( - ffi.Pointer<_PyBytesWriter> writer, - ) { - return __PyBytesWriter_Init( - writer, - ); - } - - late final __PyBytesWriter_InitPtr = _lookup< - ffi.NativeFunction)>>( - '_PyBytesWriter_Init'); - late final __PyBytesWriter_Init = __PyBytesWriter_InitPtr - .asFunction)>(); - - ffi.Pointer _PyBytesWriter_Finish( - ffi.Pointer<_PyBytesWriter> writer, - ffi.Pointer str, - ) { - return __PyBytesWriter_Finish( - writer, - str, - ); - } - - late final __PyBytesWriter_FinishPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer<_PyBytesWriter>, - ffi.Pointer)>>('_PyBytesWriter_Finish'); - late final __PyBytesWriter_Finish = __PyBytesWriter_FinishPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer<_PyBytesWriter>, ffi.Pointer)>(); - - void _PyBytesWriter_Dealloc( - ffi.Pointer<_PyBytesWriter> writer, - ) { - return __PyBytesWriter_Dealloc( - writer, - ); - } - - late final __PyBytesWriter_DeallocPtr = _lookup< - ffi.NativeFunction)>>( - '_PyBytesWriter_Dealloc'); - late final __PyBytesWriter_Dealloc = __PyBytesWriter_DeallocPtr - .asFunction)>(); - - ffi.Pointer _PyBytesWriter_Alloc( - ffi.Pointer<_PyBytesWriter> writer, - int size, - ) { - return __PyBytesWriter_Alloc( - writer, - size, - ); - } - - late final __PyBytesWriter_AllocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer<_PyBytesWriter>, - Py_ssize_t)>>('_PyBytesWriter_Alloc'); - late final __PyBytesWriter_Alloc = __PyBytesWriter_AllocPtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_PyBytesWriter>, int)>(); - - ffi.Pointer _PyBytesWriter_Prepare( - ffi.Pointer<_PyBytesWriter> writer, - ffi.Pointer str, - int size, - ) { - return __PyBytesWriter_Prepare( - writer, - str, - size, - ); - } - - late final __PyBytesWriter_PreparePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer<_PyBytesWriter>, - ffi.Pointer, Py_ssize_t)>>('_PyBytesWriter_Prepare'); - late final __PyBytesWriter_Prepare = __PyBytesWriter_PreparePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer<_PyBytesWriter>, ffi.Pointer, int)>(); - - ffi.Pointer _PyBytesWriter_Resize( - ffi.Pointer<_PyBytesWriter> writer, - ffi.Pointer str, - int size, - ) { - return __PyBytesWriter_Resize( - writer, - str, - size, - ); - } - - late final __PyBytesWriter_ResizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer<_PyBytesWriter>, - ffi.Pointer, Py_ssize_t)>>('_PyBytesWriter_Resize'); - late final __PyBytesWriter_Resize = __PyBytesWriter_ResizePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer<_PyBytesWriter>, ffi.Pointer, int)>(); - - ffi.Pointer _PyBytesWriter_WriteBytes( - ffi.Pointer<_PyBytesWriter> writer, - ffi.Pointer str, - ffi.Pointer bytes, - int size, - ) { - return __PyBytesWriter_WriteBytes( - writer, - str, - bytes, - size, - ); - } - - late final __PyBytesWriter_WriteBytesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_PyBytesWriter>, - ffi.Pointer, - ffi.Pointer, - Py_ssize_t)>>('_PyBytesWriter_WriteBytes'); - late final __PyBytesWriter_WriteBytes = - __PyBytesWriter_WriteBytesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_PyBytesWriter>, - ffi.Pointer, ffi.Pointer, int)>(); - - late final ffi.Pointer _PyUnicode_Type = - _lookup('PyUnicode_Type'); - - PyTypeObject get PyUnicode_Type => _PyUnicode_Type.ref; - - late final ffi.Pointer _PyUnicodeIter_Type = - _lookup('PyUnicodeIter_Type'); - - PyTypeObject get PyUnicodeIter_Type => _PyUnicodeIter_Type.ref; - - ffi.Pointer PyUnicode_FromStringAndSize( - ffi.Pointer u, - int size, - ) { - return _PyUnicode_FromStringAndSize( - u, - size, - ); - } - - late final _PyUnicode_FromStringAndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - Py_ssize_t)>>('PyUnicode_FromStringAndSize'); - late final _PyUnicode_FromStringAndSize = _PyUnicode_FromStringAndSizePtr - .asFunction Function(ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_FromString( - ffi.Pointer u, - ) { - return _PyUnicode_FromString( - u, - ); - } - - late final _PyUnicode_FromStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_FromString'); - late final _PyUnicode_FromString = _PyUnicode_FromStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_Substring( - ffi.Pointer str, - int start, - int end, - ) { - return _PyUnicode_Substring( - str, - start, - end, - ); - } - - late final _PyUnicode_SubstringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - Py_ssize_t)>>('PyUnicode_Substring'); - late final _PyUnicode_Substring = _PyUnicode_SubstringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - ffi.Pointer PyUnicode_AsUCS4( - ffi.Pointer unicode, - ffi.Pointer buffer, - int buflen, - int copy_null, - ) { - return _PyUnicode_AsUCS4( - unicode, - buffer, - buflen, - copy_null, - ); - } - - late final _PyUnicode_AsUCS4Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, Py_ssize_t, ffi.Int)>>('PyUnicode_AsUCS4'); - late final _PyUnicode_AsUCS4 = _PyUnicode_AsUCS4Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int, int)>(); - - ffi.Pointer PyUnicode_AsUCS4Copy( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsUCS4Copy( - unicode, - ); - } - - late final _PyUnicode_AsUCS4CopyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsUCS4Copy'); - late final _PyUnicode_AsUCS4Copy = _PyUnicode_AsUCS4CopyPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyUnicode_GetLength( - ffi.Pointer unicode, - ) { - return _PyUnicode_GetLength( - unicode, - ); - } - - late final _PyUnicode_GetLengthPtr = - _lookup)>>( - 'PyUnicode_GetLength'); - late final _PyUnicode_GetLength = - _PyUnicode_GetLengthPtr.asFunction)>(); - - int PyUnicode_ReadChar( - ffi.Pointer unicode, - int index, - ) { - return _PyUnicode_ReadChar( - unicode, - index, - ); - } - - late final _PyUnicode_ReadCharPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicode_ReadChar'); - late final _PyUnicode_ReadChar = _PyUnicode_ReadCharPtr.asFunction< - int Function(ffi.Pointer, int)>(); - - int PyUnicode_WriteChar( - ffi.Pointer unicode, - int index, - int character, - ) { - return _PyUnicode_WriteChar( - unicode, - index, - character, - ); - } - - late final _PyUnicode_WriteCharPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - Py_UCS4)>>('PyUnicode_WriteChar'); - late final _PyUnicode_WriteChar = _PyUnicode_WriteCharPtr.asFunction< - int Function(ffi.Pointer, int, int)>(); - - int PyUnicode_Resize( - ffi.Pointer> unicode, - int length, - ) { - return _PyUnicode_Resize( - unicode, - length, - ); - } - - late final _PyUnicode_ResizePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer>, - Py_ssize_t)>>('PyUnicode_Resize'); - late final _PyUnicode_Resize = _PyUnicode_ResizePtr.asFunction< - int Function(ffi.Pointer>, int)>(); - - ffi.Pointer PyUnicode_FromEncodedObject( - ffi.Pointer obj, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_FromEncodedObject( - obj, - encoding, - errors, - ); - } - - late final _PyUnicode_FromEncodedObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_FromEncodedObject'); - late final _PyUnicode_FromEncodedObject = - _PyUnicode_FromEncodedObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_FromObject( - ffi.Pointer obj, - ) { - return _PyUnicode_FromObject( - obj, - ); - } - - late final _PyUnicode_FromObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_FromObject'); - late final _PyUnicode_FromObject = _PyUnicode_FromObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_FromFormatV( - ffi.Pointer format, - va_list vargs, - ) { - return _PyUnicode_FromFormatV( - format, - vargs, - ); - } - - late final _PyUnicode_FromFormatVPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, va_list)>>('PyUnicode_FromFormatV'); - late final _PyUnicode_FromFormatV = _PyUnicode_FromFormatVPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, va_list)>(); - - ffi.Pointer PyUnicode_FromFormat( - ffi.Pointer format, - ) { - return _PyUnicode_FromFormat( - format, - ); - } - - late final _PyUnicode_FromFormatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_FromFormat'); - late final _PyUnicode_FromFormat = _PyUnicode_FromFormatPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyUnicode_InternInPlace( - ffi.Pointer> arg0, - ) { - return _PyUnicode_InternInPlace( - arg0, - ); - } - - late final _PyUnicode_InternInPlacePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer>)>>('PyUnicode_InternInPlace'); - late final _PyUnicode_InternInPlace = _PyUnicode_InternInPlacePtr.asFunction< - void Function(ffi.Pointer>)>(); - - ffi.Pointer PyUnicode_InternFromString( - ffi.Pointer u, - ) { - return _PyUnicode_InternFromString( - u, - ); - } - - late final _PyUnicode_InternFromStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_InternFromString'); - late final _PyUnicode_InternFromString = _PyUnicode_InternFromStringPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_FromWideChar( - ffi.Pointer w, - int size, - ) { - return _PyUnicode_FromWideChar( - w, - size, - ); - } - - late final _PyUnicode_FromWideCharPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PyUnicode_FromWideChar'); - late final _PyUnicode_FromWideChar = _PyUnicode_FromWideCharPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int PyUnicode_AsWideChar( - ffi.Pointer unicode, - ffi.Pointer w, - int size, - ) { - return _PyUnicode_AsWideChar( - unicode, - w, - size, - ); - } - - late final _PyUnicode_AsWideCharPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t)>>('PyUnicode_AsWideChar'); - late final _PyUnicode_AsWideChar = _PyUnicode_AsWideCharPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_AsWideCharString( - ffi.Pointer unicode, - ffi.Pointer size, - ) { - return _PyUnicode_AsWideCharString( - unicode, - size, - ); - } - - late final _PyUnicode_AsWideCharStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsWideCharString'); - late final _PyUnicode_AsWideCharString = - _PyUnicode_AsWideCharStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_FromOrdinal( - int ordinal, - ) { - return _PyUnicode_FromOrdinal( - ordinal, - ); - } - - late final _PyUnicode_FromOrdinalPtr = - _lookup Function(ffi.Int)>>( - 'PyUnicode_FromOrdinal'); - late final _PyUnicode_FromOrdinal = _PyUnicode_FromOrdinalPtr.asFunction< - ffi.Pointer Function(int)>(); - - ffi.Pointer PyUnicode_GetDefaultEncoding() { - return _PyUnicode_GetDefaultEncoding(); - } - - late final _PyUnicode_GetDefaultEncodingPtr = - _lookup Function()>>( - 'PyUnicode_GetDefaultEncoding'); - late final _PyUnicode_GetDefaultEncoding = _PyUnicode_GetDefaultEncodingPtr - .asFunction Function()>(); - - ffi.Pointer PyUnicode_Decode( - ffi.Pointer s, - int size, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_Decode( - s, - size, - encoding, - errors, - ); - } - - late final _PyUnicode_DecodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Decode'); - late final _PyUnicode_Decode = _PyUnicode_DecodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsDecodedObject( - ffi.Pointer unicode, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_AsDecodedObject( - unicode, - encoding, - errors, - ); - } - - late final _PyUnicode_AsDecodedObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsDecodedObject'); - late final _PyUnicode_AsDecodedObject = - _PyUnicode_AsDecodedObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsDecodedUnicode( - ffi.Pointer unicode, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_AsDecodedUnicode( - unicode, - encoding, - errors, - ); - } - - late final _PyUnicode_AsDecodedUnicodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsDecodedUnicode'); - late final _PyUnicode_AsDecodedUnicode = - _PyUnicode_AsDecodedUnicodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsEncodedObject( - ffi.Pointer unicode, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_AsEncodedObject( - unicode, - encoding, - errors, - ); - } - - late final _PyUnicode_AsEncodedObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsEncodedObject'); - late final _PyUnicode_AsEncodedObject = - _PyUnicode_AsEncodedObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsEncodedString( - ffi.Pointer unicode, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_AsEncodedString( - unicode, - encoding, - errors, - ); - } - - late final _PyUnicode_AsEncodedStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsEncodedString'); - late final _PyUnicode_AsEncodedString = - _PyUnicode_AsEncodedStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsEncodedUnicode( - ffi.Pointer unicode, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyUnicode_AsEncodedUnicode( - unicode, - encoding, - errors, - ); - } - - late final _PyUnicode_AsEncodedUnicodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsEncodedUnicode'); - late final _PyUnicode_AsEncodedUnicode = - _PyUnicode_AsEncodedUnicodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_BuildEncodingMap( - ffi.Pointer string, - ) { - return _PyUnicode_BuildEncodingMap( - string, - ); - } - - late final _PyUnicode_BuildEncodingMapPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_BuildEncodingMap'); - late final _PyUnicode_BuildEncodingMap = _PyUnicode_BuildEncodingMapPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF7( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeUTF7( - string, - length, - errors, - ); - } - - late final _PyUnicode_DecodeUTF7Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeUTF7'); - late final _PyUnicode_DecodeUTF7 = _PyUnicode_DecodeUTF7Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF7Stateful( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer consumed, - ) { - return _PyUnicode_DecodeUTF7Stateful( - string, - length, - errors, - consumed, - ); - } - - late final _PyUnicode_DecodeUTF7StatefulPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeUTF7Stateful'); - late final _PyUnicode_DecodeUTF7Stateful = - _PyUnicode_DecodeUTF7StatefulPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF8( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeUTF8( - string, - length, - errors, - ); - } - - late final _PyUnicode_DecodeUTF8Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeUTF8'); - late final _PyUnicode_DecodeUTF8 = _PyUnicode_DecodeUTF8Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF8Stateful( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer consumed, - ) { - return _PyUnicode_DecodeUTF8Stateful( - string, - length, - errors, - consumed, - ); - } - - late final _PyUnicode_DecodeUTF8StatefulPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeUTF8Stateful'); - late final _PyUnicode_DecodeUTF8Stateful = - _PyUnicode_DecodeUTF8StatefulPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsUTF8String( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsUTF8String1( - unicode, - ); - } - - late final _PyUnicode_AsUTF8StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsUTF8String'); - late final _PyUnicode_AsUTF8String1 = _PyUnicode_AsUTF8StringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsUTF8AndSize( - ffi.Pointer unicode, - ffi.Pointer size, - ) { - return _PyUnicode_AsUTF8AndSize( - unicode, - size, - ); - } - - late final _PyUnicode_AsUTF8AndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsUTF8AndSize'); - late final _PyUnicode_AsUTF8AndSize = _PyUnicode_AsUTF8AndSizePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF32( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer byteorder, - ) { - return _PyUnicode_DecodeUTF32( - string, - length, - errors, - byteorder, - ); - } - - late final _PyUnicode_DecodeUTF32Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeUTF32'); - late final _PyUnicode_DecodeUTF32 = _PyUnicode_DecodeUTF32Ptr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF32Stateful( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer byteorder, - ffi.Pointer consumed, - ) { - return _PyUnicode_DecodeUTF32Stateful( - string, - length, - errors, - byteorder, - consumed, - ); - } - - late final _PyUnicode_DecodeUTF32StatefulPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeUTF32Stateful'); - late final _PyUnicode_DecodeUTF32Stateful = - _PyUnicode_DecodeUTF32StatefulPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsUTF32String( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsUTF32String( - unicode, - ); - } - - late final _PyUnicode_AsUTF32StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsUTF32String'); - late final _PyUnicode_AsUTF32String = _PyUnicode_AsUTF32StringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF16( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer byteorder, - ) { - return _PyUnicode_DecodeUTF16( - string, - length, - errors, - byteorder, - ); - } - - late final _PyUnicode_DecodeUTF16Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeUTF16'); - late final _PyUnicode_DecodeUTF16 = _PyUnicode_DecodeUTF16Ptr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUTF16Stateful( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer byteorder, - ffi.Pointer consumed, - ) { - return _PyUnicode_DecodeUTF16Stateful( - string, - length, - errors, - byteorder, - consumed, - ); - } - - late final _PyUnicode_DecodeUTF16StatefulPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeUTF16Stateful'); - late final _PyUnicode_DecodeUTF16Stateful = - _PyUnicode_DecodeUTF16StatefulPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsUTF16String( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsUTF16String( - unicode, - ); - } - - late final _PyUnicode_AsUTF16StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsUTF16String'); - late final _PyUnicode_AsUTF16String = _PyUnicode_AsUTF16StringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeUnicodeEscape( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeUnicodeEscape( - string, - length, - errors, - ); - } - - late final _PyUnicode_DecodeUnicodeEscapePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeUnicodeEscape'); - late final _PyUnicode_DecodeUnicodeEscape = - _PyUnicode_DecodeUnicodeEscapePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsUnicodeEscapeString( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsUnicodeEscapeString( - unicode, - ); - } - - late final _PyUnicode_AsUnicodeEscapeStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsUnicodeEscapeString'); - late final _PyUnicode_AsUnicodeEscapeString = - _PyUnicode_AsUnicodeEscapeStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeRawUnicodeEscape( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeRawUnicodeEscape( - string, - length, - errors, - ); - } - - late final _PyUnicode_DecodeRawUnicodeEscapePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeRawUnicodeEscape'); - late final _PyUnicode_DecodeRawUnicodeEscape = - _PyUnicode_DecodeRawUnicodeEscapePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsRawUnicodeEscapeString( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsRawUnicodeEscapeString( - unicode, - ); - } - - late final _PyUnicode_AsRawUnicodeEscapeStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsRawUnicodeEscapeString'); - late final _PyUnicode_AsRawUnicodeEscapeString = - _PyUnicode_AsRawUnicodeEscapeStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeLatin1( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeLatin1( - string, - length, - errors, - ); - } - - late final _PyUnicode_DecodeLatin1Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeLatin1'); - late final _PyUnicode_DecodeLatin1 = _PyUnicode_DecodeLatin1Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsLatin1String( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsLatin1String1( - unicode, - ); - } - - late final _PyUnicode_AsLatin1StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsLatin1String'); - late final _PyUnicode_AsLatin1String1 = _PyUnicode_AsLatin1StringPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeASCII( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeASCII( - string, - length, - errors, - ); - } - - late final _PyUnicode_DecodeASCIIPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeASCII'); - late final _PyUnicode_DecodeASCII = _PyUnicode_DecodeASCIIPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsASCIIString( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsASCIIString1( - unicode, - ); - } - - late final _PyUnicode_AsASCIIStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsASCIIString'); - late final _PyUnicode_AsASCIIString1 = _PyUnicode_AsASCIIStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeCharmap( - ffi.Pointer string, - int length, - ffi.Pointer mapping, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeCharmap( - string, - length, - mapping, - errors, - ); - } - - late final _PyUnicode_DecodeCharmapPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeCharmap'); - late final _PyUnicode_DecodeCharmap = _PyUnicode_DecodeCharmapPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_AsCharmapString( - ffi.Pointer unicode, - ffi.Pointer mapping, - ) { - return _PyUnicode_AsCharmapString( - unicode, - mapping, - ); - } - - late final _PyUnicode_AsCharmapStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_AsCharmapString'); - late final _PyUnicode_AsCharmapString = - _PyUnicode_AsCharmapStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeLocaleAndSize( - ffi.Pointer str, - int len, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeLocaleAndSize( - str, - len, - errors, - ); - } - - late final _PyUnicode_DecodeLocaleAndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnicode_DecodeLocaleAndSize'); - late final _PyUnicode_DecodeLocaleAndSize = - _PyUnicode_DecodeLocaleAndSizePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeLocale( - ffi.Pointer str, - ffi.Pointer errors, - ) { - return _PyUnicode_DecodeLocale( - str, - errors, - ); - } - - late final _PyUnicode_DecodeLocalePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_DecodeLocale'); - late final _PyUnicode_DecodeLocale = _PyUnicode_DecodeLocalePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_EncodeLocale( - ffi.Pointer unicode, - ffi.Pointer errors, - ) { - return _PyUnicode_EncodeLocale( - unicode, - errors, - ); - } - - late final _PyUnicode_EncodeLocalePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_EncodeLocale'); - late final _PyUnicode_EncodeLocale = _PyUnicode_EncodeLocalePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyUnicode_FSConverter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicode_FSConverter( - arg0, - arg1, - ); - } - - late final _PyUnicode_FSConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_FSConverter'); - late final _PyUnicode_FSConverter = _PyUnicode_FSConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicode_FSDecoder( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicode_FSDecoder( - arg0, - arg1, - ); - } - - late final _PyUnicode_FSDecoderPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_FSDecoder'); - late final _PyUnicode_FSDecoder = _PyUnicode_FSDecoderPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeFSDefault( - ffi.Pointer s, - ) { - return _PyUnicode_DecodeFSDefault( - s, - ); - } - - late final _PyUnicode_DecodeFSDefaultPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_DecodeFSDefault'); - late final _PyUnicode_DecodeFSDefault = _PyUnicode_DecodeFSDefaultPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_DecodeFSDefaultAndSize( - ffi.Pointer s, - int size, - ) { - return _PyUnicode_DecodeFSDefaultAndSize( - s, - size, - ); - } - - late final _PyUnicode_DecodeFSDefaultAndSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - Py_ssize_t)>>('PyUnicode_DecodeFSDefaultAndSize'); - late final _PyUnicode_DecodeFSDefaultAndSize = - _PyUnicode_DecodeFSDefaultAndSizePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_EncodeFSDefault( - ffi.Pointer unicode, - ) { - return _PyUnicode_EncodeFSDefault( - unicode, - ); - } - - late final _PyUnicode_EncodeFSDefaultPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_EncodeFSDefault'); - late final _PyUnicode_EncodeFSDefault = _PyUnicode_EncodeFSDefaultPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicode_Concat( - ffi.Pointer left, - ffi.Pointer right, - ) { - return _PyUnicode_Concat( - left, - right, - ); - } - - late final _PyUnicode_ConcatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Concat'); - late final _PyUnicode_Concat = _PyUnicode_ConcatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - void PyUnicode_Append( - ffi.Pointer> pleft, - ffi.Pointer right, - ) { - return _PyUnicode_Append( - pleft, - right, - ); - } - - late final _PyUnicode_AppendPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer>, - ffi.Pointer)>>('PyUnicode_Append'); - late final _PyUnicode_Append = _PyUnicode_AppendPtr.asFunction< - void Function( - ffi.Pointer>, ffi.Pointer)>(); - - void PyUnicode_AppendAndDel( - ffi.Pointer> pleft, - ffi.Pointer right, - ) { - return _PyUnicode_AppendAndDel( - pleft, - right, - ); - } - - late final _PyUnicode_AppendAndDelPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer>, - ffi.Pointer)>>('PyUnicode_AppendAndDel'); - late final _PyUnicode_AppendAndDel = _PyUnicode_AppendAndDelPtr.asFunction< - void Function( - ffi.Pointer>, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_Split( - ffi.Pointer s, - ffi.Pointer sep, - int maxsplit, - ) { - return _PyUnicode_Split( - s, - sep, - maxsplit, - ); - } - - late final _PyUnicode_SplitPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, Py_ssize_t)>>('PyUnicode_Split'); - late final _PyUnicode_Split = _PyUnicode_SplitPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_Splitlines( - ffi.Pointer s, - int keepends, - ) { - return _PyUnicode_Splitlines( - s, - keepends, - ); - } - - late final _PyUnicode_SplitlinesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyUnicode_Splitlines'); - late final _PyUnicode_Splitlines = _PyUnicode_SplitlinesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_Partition( - ffi.Pointer s, - ffi.Pointer sep, - ) { - return _PyUnicode_Partition( - s, - sep, - ); - } - - late final _PyUnicode_PartitionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Partition'); - late final _PyUnicode_Partition = _PyUnicode_PartitionPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_RPartition( - ffi.Pointer s, - ffi.Pointer sep, - ) { - return _PyUnicode_RPartition( - s, - sep, - ); - } - - late final _PyUnicode_RPartitionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_RPartition'); - late final _PyUnicode_RPartition = _PyUnicode_RPartitionPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_RSplit( - ffi.Pointer s, - ffi.Pointer sep, - int maxsplit, - ) { - return _PyUnicode_RSplit( - s, - sep, - maxsplit, - ); - } - - late final _PyUnicode_RSplitPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, Py_ssize_t)>>('PyUnicode_RSplit'); - late final _PyUnicode_RSplit = _PyUnicode_RSplitPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_Translate( - ffi.Pointer str, - ffi.Pointer table, - ffi.Pointer errors, - ) { - return _PyUnicode_Translate( - str, - table, - errors, - ); - } - - late final _PyUnicode_TranslatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Translate'); - late final _PyUnicode_Translate = _PyUnicode_TranslatePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_Join( - ffi.Pointer separator, - ffi.Pointer seq, - ) { - return _PyUnicode_Join( - separator, - seq, - ); - } - - late final _PyUnicode_JoinPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyUnicode_Join'); - late final _PyUnicode_Join = _PyUnicode_JoinPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyUnicode_Tailmatch( - ffi.Pointer str, - ffi.Pointer substr, - int start, - int end, - int direction, - ) { - return _PyUnicode_Tailmatch( - str, - substr, - start, - end, - direction, - ); - } - - late final _PyUnicode_TailmatchPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t, Py_ssize_t, ffi.Int)>>('PyUnicode_Tailmatch'); - late final _PyUnicode_Tailmatch = _PyUnicode_TailmatchPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer, int, int, int)>(); - - int PyUnicode_Find( - ffi.Pointer str, - ffi.Pointer substr, - int start, - int end, - int direction, - ) { - return _PyUnicode_Find( - str, - substr, - start, - end, - direction, - ); - } - - late final _PyUnicode_FindPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t, Py_ssize_t, ffi.Int)>>('PyUnicode_Find'); - late final _PyUnicode_Find = _PyUnicode_FindPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer, int, int, int)>(); - - int PyUnicode_FindChar( - ffi.Pointer str, - int ch, - int start, - int end, - int direction, - ) { - return _PyUnicode_FindChar( - str, - ch, - start, - end, - direction, - ); - } - - late final _PyUnicode_FindCharPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, Py_UCS4, Py_ssize_t, - Py_ssize_t, ffi.Int)>>('PyUnicode_FindChar'); - late final _PyUnicode_FindChar = _PyUnicode_FindCharPtr.asFunction< - int Function(ffi.Pointer, int, int, int, int)>(); - - int PyUnicode_Count( - ffi.Pointer str, - ffi.Pointer substr, - int start, - int end, - ) { - return _PyUnicode_Count( - str, - substr, - start, - end, - ); - } - - late final _PyUnicode_CountPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t, Py_ssize_t)>>('PyUnicode_Count'); - late final _PyUnicode_Count = _PyUnicode_CountPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, int)>(); - - ffi.Pointer PyUnicode_Replace( - ffi.Pointer str, - ffi.Pointer substr, - ffi.Pointer replstr, - int maxcount, - ) { - return _PyUnicode_Replace( - str, - substr, - replstr, - maxcount, - ); - } - - late final _PyUnicode_ReplacePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - Py_ssize_t)>>('PyUnicode_Replace'); - late final _PyUnicode_Replace = _PyUnicode_ReplacePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer, int)>(); - - int PyUnicode_Compare( - ffi.Pointer left, - ffi.Pointer right, - ) { - return _PyUnicode_Compare( - left, - right, - ); - } - - late final _PyUnicode_ComparePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Compare'); - late final _PyUnicode_Compare = _PyUnicode_ComparePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicode_CompareWithASCIIString( - ffi.Pointer left, - ffi.Pointer right, - ) { - return _PyUnicode_CompareWithASCIIString( - left, - right, - ); - } - - late final _PyUnicode_CompareWithASCIIStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_CompareWithASCIIString'); - late final _PyUnicode_CompareWithASCIIString = - _PyUnicode_CompareWithASCIIStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnicode_RichCompare( - ffi.Pointer left, - ffi.Pointer right, - int op, - ) { - return _PyUnicode_RichCompare( - left, - right, - op, - ); - } - - late final _PyUnicode_RichComparePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('PyUnicode_RichCompare'); - late final _PyUnicode_RichCompare = _PyUnicode_RichComparePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyUnicode_Format( - ffi.Pointer format, - ffi.Pointer args, - ) { - return _PyUnicode_Format( - format, - args, - ); - } - - late final _PyUnicode_FormatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Format'); - late final _PyUnicode_Format = _PyUnicode_FormatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyUnicode_Contains( - ffi.Pointer container, - ffi.Pointer element, - ) { - return _PyUnicode_Contains( - container, - element, - ); - } - - late final _PyUnicode_ContainsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicode_Contains'); - late final _PyUnicode_Contains = _PyUnicode_ContainsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicode_IsIdentifier( - ffi.Pointer s, - ) { - return _PyUnicode_IsIdentifier( - s, - ); - } - - late final _PyUnicode_IsIdentifierPtr = - _lookup)>>( - 'PyUnicode_IsIdentifier'); - late final _PyUnicode_IsIdentifier = _PyUnicode_IsIdentifierPtr.asFunction< - int Function(ffi.Pointer)>(); - - int _PyUnicode_CheckConsistency( - ffi.Pointer op, - int check_content, - ) { - return __PyUnicode_CheckConsistency( - op, - check_content, - ); - } - - late final __PyUnicode_CheckConsistencyPtr = _lookup< - ffi.NativeFunction, ffi.Int)>>( - '_PyUnicode_CheckConsistency'); - late final __PyUnicode_CheckConsistency = __PyUnicode_CheckConsistencyPtr - .asFunction, int)>(); - - ffi.Pointer PyUnicode_New( - int size, - int maxchar, - ) { - return _PyUnicode_New( - size, - maxchar, - ); - } - - late final _PyUnicode_NewPtr = _lookup< - ffi - .NativeFunction Function(Py_ssize_t, Py_UCS4)>>( - 'PyUnicode_New'); - late final _PyUnicode_New = - _PyUnicode_NewPtr.asFunction Function(int, int)>(); - - ffi.Pointer _PyUnicode_Copy( - ffi.Pointer unicode, - ) { - return __PyUnicode_Copy( - unicode, - ); - } - - late final __PyUnicode_CopyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyUnicode_Copy'); - late final __PyUnicode_Copy = __PyUnicode_CopyPtr - .asFunction Function(ffi.Pointer)>(); - - int PyUnicode_CopyCharacters( - ffi.Pointer to, - int to_start, - ffi.Pointer from, - int from_start, - int how_many, - ) { - return _PyUnicode_CopyCharacters( - to, - to_start, - from, - from_start, - how_many, - ); - } - - late final _PyUnicode_CopyCharactersPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - Py_ssize_t, - Py_ssize_t)>>('PyUnicode_CopyCharacters'); - late final _PyUnicode_CopyCharacters = - _PyUnicode_CopyCharactersPtr.asFunction< - int Function( - ffi.Pointer, int, ffi.Pointer, int, int)>(); - - void _PyUnicode_FastCopyCharacters( - ffi.Pointer to, - int to_start, - ffi.Pointer from, - int from_start, - int how_many, - ) { - return __PyUnicode_FastCopyCharacters( - to, - to_start, - from, - from_start, - how_many, - ); - } - - late final __PyUnicode_FastCopyCharactersPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - Py_ssize_t, - Py_ssize_t)>>('_PyUnicode_FastCopyCharacters'); - late final __PyUnicode_FastCopyCharacters = - __PyUnicode_FastCopyCharactersPtr.asFunction< - void Function( - ffi.Pointer, int, ffi.Pointer, int, int)>(); - - int PyUnicode_Fill( - ffi.Pointer unicode, - int start, - int length, - int fill_char, - ) { - return _PyUnicode_Fill( - unicode, - start, - length, - fill_char, - ); - } - - late final _PyUnicode_FillPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, Py_ssize_t, Py_ssize_t, - Py_UCS4)>>('PyUnicode_Fill'); - late final _PyUnicode_Fill = _PyUnicode_FillPtr.asFunction< - int Function(ffi.Pointer, int, int, int)>(); - - void _PyUnicode_FastFill( - ffi.Pointer unicode, - int start, - int length, - int fill_char, - ) { - return __PyUnicode_FastFill( - unicode, - start, - length, - fill_char, - ); - } - - late final __PyUnicode_FastFillPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, Py_ssize_t, Py_ssize_t, - Py_UCS4)>>('_PyUnicode_FastFill'); - late final __PyUnicode_FastFill = __PyUnicode_FastFillPtr - .asFunction, int, int, int)>(); - - ffi.Pointer PyUnicode_FromKindAndData( - int kind, - ffi.Pointer buffer, - int size, - ) { - return _PyUnicode_FromKindAndData( - kind, - buffer, - size, - ); - } - - late final _PyUnicode_FromKindAndDataPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Int, ffi.Pointer, - Py_ssize_t)>>('PyUnicode_FromKindAndData'); - late final _PyUnicode_FromKindAndData = - _PyUnicode_FromKindAndDataPtr.asFunction< - ffi.Pointer Function(int, ffi.Pointer, int)>(); - - ffi.Pointer _PyUnicode_FromASCII( - ffi.Pointer buffer, - int size, - ) { - return __PyUnicode_FromASCII( - buffer, - size, - ); - } - - late final __PyUnicode_FromASCIIPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('_PyUnicode_FromASCII'); - late final __PyUnicode_FromASCII = __PyUnicode_FromASCIIPtr - .asFunction Function(ffi.Pointer, int)>(); - - int _PyUnicode_FindMaxChar( - ffi.Pointer unicode, - int start, - int end, - ) { - return __PyUnicode_FindMaxChar( - unicode, - start, - end, - ); - } - - late final __PyUnicode_FindMaxCharPtr = _lookup< - ffi.NativeFunction< - Py_UCS4 Function(ffi.Pointer, Py_ssize_t, - Py_ssize_t)>>('_PyUnicode_FindMaxChar'); - late final __PyUnicode_FindMaxChar = __PyUnicode_FindMaxCharPtr - .asFunction, int, int)>(); - - void _PyUnicodeWriter_Init( - ffi.Pointer<_PyUnicodeWriter> writer, - ) { - return __PyUnicodeWriter_Init( - writer, - ); - } - - late final __PyUnicodeWriter_InitPtr = _lookup< - ffi.NativeFunction)>>( - '_PyUnicodeWriter_Init'); - late final __PyUnicodeWriter_Init = __PyUnicodeWriter_InitPtr - .asFunction)>(); - - int _PyUnicodeWriter_PrepareInternal( - ffi.Pointer<_PyUnicodeWriter> writer, - int length, - int maxchar, - ) { - return __PyUnicodeWriter_PrepareInternal( - writer, - length, - maxchar, - ); - } - - late final __PyUnicodeWriter_PrepareInternalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, Py_ssize_t, - Py_UCS4)>>('_PyUnicodeWriter_PrepareInternal'); - late final __PyUnicodeWriter_PrepareInternal = - __PyUnicodeWriter_PrepareInternalPtr - .asFunction, int, int)>(); - - int _PyUnicodeWriter_PrepareKindInternal( - ffi.Pointer<_PyUnicodeWriter> writer, - int kind, - ) { - return __PyUnicodeWriter_PrepareKindInternal( - writer, - kind, - ); - } - - late final __PyUnicodeWriter_PrepareKindInternalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, - ffi.Int)>>('_PyUnicodeWriter_PrepareKindInternal'); - late final __PyUnicodeWriter_PrepareKindInternal = - __PyUnicodeWriter_PrepareKindInternalPtr - .asFunction, int)>(); - - int _PyUnicodeWriter_WriteChar( - ffi.Pointer<_PyUnicodeWriter> writer, - int ch, - ) { - return __PyUnicodeWriter_WriteChar( - writer, - ch, - ); - } - - late final __PyUnicodeWriter_WriteCharPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, - Py_UCS4)>>('_PyUnicodeWriter_WriteChar'); - late final __PyUnicodeWriter_WriteChar = __PyUnicodeWriter_WriteCharPtr - .asFunction, int)>(); - - int _PyUnicodeWriter_WriteStr( - ffi.Pointer<_PyUnicodeWriter> writer, - ffi.Pointer str, - ) { - return __PyUnicodeWriter_WriteStr( - writer, - str, - ); - } - - late final __PyUnicodeWriter_WriteStrPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, - ffi.Pointer)>>('_PyUnicodeWriter_WriteStr'); - late final __PyUnicodeWriter_WriteStr = - __PyUnicodeWriter_WriteStrPtr.asFunction< - int Function(ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer)>(); - - int _PyUnicodeWriter_WriteSubstring( - ffi.Pointer<_PyUnicodeWriter> writer, - ffi.Pointer str, - int start, - int end, - ) { - return __PyUnicodeWriter_WriteSubstring( - writer, - str, - start, - end, - ); - } - - late final __PyUnicodeWriter_WriteSubstringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, - Py_ssize_t, Py_ssize_t)>>('_PyUnicodeWriter_WriteSubstring'); - late final __PyUnicodeWriter_WriteSubstring = - __PyUnicodeWriter_WriteSubstringPtr.asFunction< - int Function(ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, - int, int)>(); - - int _PyUnicodeWriter_WriteASCIIString( - ffi.Pointer<_PyUnicodeWriter> writer, - ffi.Pointer str, - int len, - ) { - return __PyUnicodeWriter_WriteASCIIString( - writer, - str, - len, - ); - } - - late final __PyUnicodeWriter_WriteASCIIStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, - Py_ssize_t)>>('_PyUnicodeWriter_WriteASCIIString'); - late final __PyUnicodeWriter_WriteASCIIString = - __PyUnicodeWriter_WriteASCIIStringPtr.asFunction< - int Function( - ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, int)>(); - - int _PyUnicodeWriter_WriteLatin1String( - ffi.Pointer<_PyUnicodeWriter> writer, - ffi.Pointer str, - int len, - ) { - return __PyUnicodeWriter_WriteLatin1String( - writer, - str, - len, - ); - } - - late final __PyUnicodeWriter_WriteLatin1StringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, - Py_ssize_t)>>('_PyUnicodeWriter_WriteLatin1String'); - late final __PyUnicodeWriter_WriteLatin1String = - __PyUnicodeWriter_WriteLatin1StringPtr.asFunction< - int Function( - ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, int)>(); - - ffi.Pointer _PyUnicodeWriter_Finish( - ffi.Pointer<_PyUnicodeWriter> writer, - ) { - return __PyUnicodeWriter_Finish( - writer, - ); - } - - late final __PyUnicodeWriter_FinishPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_PyUnicodeWriter>)>>('_PyUnicodeWriter_Finish'); - late final __PyUnicodeWriter_Finish = __PyUnicodeWriter_FinishPtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_PyUnicodeWriter>)>(); - - void _PyUnicodeWriter_Dealloc( - ffi.Pointer<_PyUnicodeWriter> writer, - ) { - return __PyUnicodeWriter_Dealloc( - writer, - ); - } - - late final __PyUnicodeWriter_DeallocPtr = _lookup< - ffi.NativeFunction)>>( - '_PyUnicodeWriter_Dealloc'); - late final __PyUnicodeWriter_Dealloc = __PyUnicodeWriter_DeallocPtr - .asFunction)>(); - - int _PyUnicode_FormatAdvancedWriter( - ffi.Pointer<_PyUnicodeWriter> writer, - ffi.Pointer obj, - ffi.Pointer format_spec, - int start, - int end, - ) { - return __PyUnicode_FormatAdvancedWriter( - writer, - obj, - format_spec, - start, - end, - ); - } - - late final __PyUnicode_FormatAdvancedWriterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer<_PyUnicodeWriter>, - ffi.Pointer, - ffi.Pointer, - Py_ssize_t, - Py_ssize_t)>>('_PyUnicode_FormatAdvancedWriter'); - late final __PyUnicode_FormatAdvancedWriter = - __PyUnicode_FormatAdvancedWriterPtr.asFunction< - int Function(ffi.Pointer<_PyUnicodeWriter>, ffi.Pointer, - ffi.Pointer, int, int)>(); - - ffi.Pointer PyUnicode_AsUTF8( - ffi.Pointer unicode, - ) { - return _PyUnicode_AsUTF8( - unicode, - ); - } - - late final _PyUnicode_AsUTF8Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicode_AsUTF8'); - late final _PyUnicode_AsUTF8 = _PyUnicode_AsUTF8Ptr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_EncodeUTF7( - ffi.Pointer unicode, - int base64SetO, - int base64WhiteSpace, - ffi.Pointer errors, - ) { - return __PyUnicode_EncodeUTF7( - unicode, - base64SetO, - base64WhiteSpace, - errors, - ); - } - - late final __PyUnicode_EncodeUTF7Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Int, - ffi.Int, ffi.Pointer)>>('_PyUnicode_EncodeUTF7'); - late final __PyUnicode_EncodeUTF7 = __PyUnicode_EncodeUTF7Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, int, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_AsUTF8String( - ffi.Pointer unicode, - ffi.Pointer errors, - ) { - return __PyUnicode_AsUTF8String( - unicode, - errors, - ); - } - - late final __PyUnicode_AsUTF8StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_AsUTF8String'); - late final __PyUnicode_AsUTF8String = __PyUnicode_AsUTF8StringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_EncodeUTF32( - ffi.Pointer object, - ffi.Pointer errors, - int byteorder, - ) { - return __PyUnicode_EncodeUTF32( - object, - errors, - byteorder, - ); - } - - late final __PyUnicode_EncodeUTF32Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('_PyUnicode_EncodeUTF32'); - late final __PyUnicode_EncodeUTF32 = __PyUnicode_EncodeUTF32Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer _PyUnicode_EncodeUTF16( - ffi.Pointer unicode, - ffi.Pointer errors, - int byteorder, - ) { - return __PyUnicode_EncodeUTF16( - unicode, - errors, - byteorder, - ); - } - - late final __PyUnicode_EncodeUTF16Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('_PyUnicode_EncodeUTF16'); - late final __PyUnicode_EncodeUTF16 = __PyUnicode_EncodeUTF16Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer _PyUnicode_DecodeUnicodeEscapeStateful( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer consumed, - ) { - return __PyUnicode_DecodeUnicodeEscapeStateful( - string, - length, - errors, - consumed, - ); - } - - late final __PyUnicode_DecodeUnicodeEscapeStatefulPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer, ffi.Pointer)>>( - '_PyUnicode_DecodeUnicodeEscapeStateful'); - late final __PyUnicode_DecodeUnicodeEscapeStateful = - __PyUnicode_DecodeUnicodeEscapeStatefulPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_DecodeUnicodeEscapeInternal( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer consumed, - ffi.Pointer> first_invalid_escape, - ) { - return __PyUnicode_DecodeUnicodeEscapeInternal( - string, - length, - errors, - consumed, - first_invalid_escape, - ); - } - - late final __PyUnicode_DecodeUnicodeEscapeInternalPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>)>>( - '_PyUnicode_DecodeUnicodeEscapeInternal'); - late final __PyUnicode_DecodeUnicodeEscapeInternal = - __PyUnicode_DecodeUnicodeEscapeInternalPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>)>(); - - ffi.Pointer _PyUnicode_DecodeRawUnicodeEscapeStateful( - ffi.Pointer string, - int length, - ffi.Pointer errors, - ffi.Pointer consumed, - ) { - return __PyUnicode_DecodeRawUnicodeEscapeStateful( - string, - length, - errors, - consumed, - ); - } - - late final __PyUnicode_DecodeRawUnicodeEscapeStatefulPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer, ffi.Pointer)>>( - '_PyUnicode_DecodeRawUnicodeEscapeStateful'); - late final __PyUnicode_DecodeRawUnicodeEscapeStateful = - __PyUnicode_DecodeRawUnicodeEscapeStatefulPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_AsLatin1String( - ffi.Pointer unicode, - ffi.Pointer errors, - ) { - return __PyUnicode_AsLatin1String( - unicode, - errors, - ); - } - - late final __PyUnicode_AsLatin1StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_AsLatin1String'); - late final __PyUnicode_AsLatin1String = - __PyUnicode_AsLatin1StringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_AsASCIIString( - ffi.Pointer unicode, - ffi.Pointer errors, - ) { - return __PyUnicode_AsASCIIString( - unicode, - errors, - ); - } - - late final __PyUnicode_AsASCIIStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_AsASCIIString'); - late final __PyUnicode_AsASCIIString = - __PyUnicode_AsASCIIStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_EncodeCharmap( - ffi.Pointer unicode, - ffi.Pointer mapping, - ffi.Pointer errors, - ) { - return __PyUnicode_EncodeCharmap( - unicode, - mapping, - errors, - ); - } - - late final __PyUnicode_EncodeCharmapPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_EncodeCharmap'); - late final __PyUnicode_EncodeCharmap = - __PyUnicode_EncodeCharmapPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_TransformDecimalAndSpaceToASCII( - ffi.Pointer unicode, - ) { - return __PyUnicode_TransformDecimalAndSpaceToASCII( - unicode, - ); - } - - late final __PyUnicode_TransformDecimalAndSpaceToASCIIPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>( - '_PyUnicode_TransformDecimalAndSpaceToASCII'); - late final __PyUnicode_TransformDecimalAndSpaceToASCII = - __PyUnicode_TransformDecimalAndSpaceToASCIIPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_JoinArray( - ffi.Pointer separator, - ffi.Pointer> items, - int seqlen, - ) { - return __PyUnicode_JoinArray( - separator, - items, - seqlen, - ); - } - - late final __PyUnicode_JoinArrayPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - Py_ssize_t)>>('_PyUnicode_JoinArray'); - late final __PyUnicode_JoinArray = __PyUnicode_JoinArrayPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer>, int)>(); - - int _PyUnicode_EqualToASCIIId( - ffi.Pointer left, - ffi.Pointer<_Py_Identifier> right, - ) { - return __PyUnicode_EqualToASCIIId( - left, - right, - ); - } - - late final __PyUnicode_EqualToASCIIIdPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyUnicode_EqualToASCIIId'); - late final __PyUnicode_EqualToASCIIId = - __PyUnicode_EqualToASCIIIdPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - int _PyUnicode_EqualToASCIIString( - ffi.Pointer left, - ffi.Pointer right, - ) { - return __PyUnicode_EqualToASCIIString( - left, - right, - ); - } - - late final __PyUnicode_EqualToASCIIStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_EqualToASCIIString'); - late final __PyUnicode_EqualToASCIIString = __PyUnicode_EqualToASCIIStringPtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer _PyUnicode_XStrip( - ffi.Pointer self, - int striptype, - ffi.Pointer sepobj, - ) { - return __PyUnicode_XStrip( - self, - striptype, - sepobj, - ); - } - - late final __PyUnicode_XStripPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Int, - ffi.Pointer)>>('_PyUnicode_XStrip'); - late final __PyUnicode_XStrip = __PyUnicode_XStripPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - int _PyUnicode_InsertThousandsGrouping( - ffi.Pointer<_PyUnicodeWriter> writer, - int n_buffer, - ffi.Pointer digits, - int d_pos, - int n_digits, - int min_width, - ffi.Pointer grouping, - ffi.Pointer thousands_sep, - ffi.Pointer maxchar, - ) { - return __PyUnicode_InsertThousandsGrouping( - writer, - n_buffer, - digits, - d_pos, - n_digits, - min_width, - grouping, - thousands_sep, - maxchar, - ); - } - - late final __PyUnicode_InsertThousandsGroupingPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function( - ffi.Pointer<_PyUnicodeWriter>, - Py_ssize_t, - ffi.Pointer, - Py_ssize_t, - Py_ssize_t, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_InsertThousandsGrouping'); - late final __PyUnicode_InsertThousandsGrouping = - __PyUnicode_InsertThousandsGroupingPtr.asFunction< - int Function( - ffi.Pointer<_PyUnicodeWriter>, - int, - ffi.Pointer, - int, - int, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - int _PyUnicode_IsLowercase( - int ch, - ) { - return __PyUnicode_IsLowercase( - ch, - ); - } - - late final __PyUnicode_IsLowercasePtr = - _lookup>( - '_PyUnicode_IsLowercase'); - late final __PyUnicode_IsLowercase = - __PyUnicode_IsLowercasePtr.asFunction(); - - int _PyUnicode_IsUppercase( - int ch, - ) { - return __PyUnicode_IsUppercase( - ch, - ); - } - - late final __PyUnicode_IsUppercasePtr = - _lookup>( - '_PyUnicode_IsUppercase'); - late final __PyUnicode_IsUppercase = - __PyUnicode_IsUppercasePtr.asFunction(); - - int _PyUnicode_IsTitlecase( - int ch, - ) { - return __PyUnicode_IsTitlecase( - ch, - ); - } - - late final __PyUnicode_IsTitlecasePtr = - _lookup>( - '_PyUnicode_IsTitlecase'); - late final __PyUnicode_IsTitlecase = - __PyUnicode_IsTitlecasePtr.asFunction(); - - int _PyUnicode_IsXidStart( - int ch, - ) { - return __PyUnicode_IsXidStart( - ch, - ); - } - - late final __PyUnicode_IsXidStartPtr = - _lookup>( - '_PyUnicode_IsXidStart'); - late final __PyUnicode_IsXidStart = - __PyUnicode_IsXidStartPtr.asFunction(); - - int _PyUnicode_IsXidContinue( - int ch, - ) { - return __PyUnicode_IsXidContinue( - ch, - ); - } - - late final __PyUnicode_IsXidContinuePtr = - _lookup>( - '_PyUnicode_IsXidContinue'); - late final __PyUnicode_IsXidContinue = - __PyUnicode_IsXidContinuePtr.asFunction(); - - int _PyUnicode_IsWhitespace( - int ch, - ) { - return __PyUnicode_IsWhitespace( - ch, - ); - } - - late final __PyUnicode_IsWhitespacePtr = - _lookup>( - '_PyUnicode_IsWhitespace'); - late final __PyUnicode_IsWhitespace = - __PyUnicode_IsWhitespacePtr.asFunction(); - - int _PyUnicode_IsLinebreak( - int ch, - ) { - return __PyUnicode_IsLinebreak( - ch, - ); - } - - late final __PyUnicode_IsLinebreakPtr = - _lookup>( - '_PyUnicode_IsLinebreak'); - late final __PyUnicode_IsLinebreak = - __PyUnicode_IsLinebreakPtr.asFunction(); - - int _PyUnicode_ToLowercase( - int ch, - ) { - return __PyUnicode_ToLowercase( - ch, - ); - } - - late final __PyUnicode_ToLowercasePtr = - _lookup>( - '_PyUnicode_ToLowercase'); - late final __PyUnicode_ToLowercase = - __PyUnicode_ToLowercasePtr.asFunction(); - - int _PyUnicode_ToUppercase( - int ch, - ) { - return __PyUnicode_ToUppercase( - ch, - ); - } - - late final __PyUnicode_ToUppercasePtr = - _lookup>( - '_PyUnicode_ToUppercase'); - late final __PyUnicode_ToUppercase = - __PyUnicode_ToUppercasePtr.asFunction(); - - int _PyUnicode_ToTitlecase( - int ch, - ) { - return __PyUnicode_ToTitlecase( - ch, - ); - } - - late final __PyUnicode_ToTitlecasePtr = - _lookup>( - '_PyUnicode_ToTitlecase'); - late final __PyUnicode_ToTitlecase = - __PyUnicode_ToTitlecasePtr.asFunction(); - - int _PyUnicode_ToLowerFull( - int ch, - ffi.Pointer res, - ) { - return __PyUnicode_ToLowerFull( - ch, - res, - ); - } - - late final __PyUnicode_ToLowerFullPtr = _lookup< - ffi.NativeFunction)>>( - '_PyUnicode_ToLowerFull'); - late final __PyUnicode_ToLowerFull = __PyUnicode_ToLowerFullPtr - .asFunction)>(); - - int _PyUnicode_ToTitleFull( - int ch, - ffi.Pointer res, - ) { - return __PyUnicode_ToTitleFull( - ch, - res, - ); - } - - late final __PyUnicode_ToTitleFullPtr = _lookup< - ffi.NativeFunction)>>( - '_PyUnicode_ToTitleFull'); - late final __PyUnicode_ToTitleFull = __PyUnicode_ToTitleFullPtr - .asFunction)>(); - - int _PyUnicode_ToUpperFull( - int ch, - ffi.Pointer res, - ) { - return __PyUnicode_ToUpperFull( - ch, - res, - ); - } - - late final __PyUnicode_ToUpperFullPtr = _lookup< - ffi.NativeFunction)>>( - '_PyUnicode_ToUpperFull'); - late final __PyUnicode_ToUpperFull = __PyUnicode_ToUpperFullPtr - .asFunction)>(); - - int _PyUnicode_ToFoldedFull( - int ch, - ffi.Pointer res, - ) { - return __PyUnicode_ToFoldedFull( - ch, - res, - ); - } - - late final __PyUnicode_ToFoldedFullPtr = _lookup< - ffi.NativeFunction)>>( - '_PyUnicode_ToFoldedFull'); - late final __PyUnicode_ToFoldedFull = __PyUnicode_ToFoldedFullPtr - .asFunction)>(); - - int _PyUnicode_IsCaseIgnorable( - int ch, - ) { - return __PyUnicode_IsCaseIgnorable( - ch, - ); - } - - late final __PyUnicode_IsCaseIgnorablePtr = - _lookup>( - '_PyUnicode_IsCaseIgnorable'); - late final __PyUnicode_IsCaseIgnorable = - __PyUnicode_IsCaseIgnorablePtr.asFunction(); - - int _PyUnicode_IsCased( - int ch, - ) { - return __PyUnicode_IsCased( - ch, - ); - } - - late final __PyUnicode_IsCasedPtr = - _lookup>( - '_PyUnicode_IsCased'); - late final __PyUnicode_IsCased = - __PyUnicode_IsCasedPtr.asFunction(); - - int _PyUnicode_ToDecimalDigit( - int ch, - ) { - return __PyUnicode_ToDecimalDigit( - ch, - ); - } - - late final __PyUnicode_ToDecimalDigitPtr = - _lookup>( - '_PyUnicode_ToDecimalDigit'); - late final __PyUnicode_ToDecimalDigit = - __PyUnicode_ToDecimalDigitPtr.asFunction(); - - int _PyUnicode_ToDigit( - int ch, - ) { - return __PyUnicode_ToDigit( - ch, - ); - } - - late final __PyUnicode_ToDigitPtr = - _lookup>( - '_PyUnicode_ToDigit'); - late final __PyUnicode_ToDigit = - __PyUnicode_ToDigitPtr.asFunction(); - - double _PyUnicode_ToNumeric( - int ch, - ) { - return __PyUnicode_ToNumeric( - ch, - ); - } - - late final __PyUnicode_ToNumericPtr = - _lookup>( - '_PyUnicode_ToNumeric'); - late final __PyUnicode_ToNumeric = - __PyUnicode_ToNumericPtr.asFunction(); - - int _PyUnicode_IsDecimalDigit( - int ch, - ) { - return __PyUnicode_IsDecimalDigit( - ch, - ); - } - - late final __PyUnicode_IsDecimalDigitPtr = - _lookup>( - '_PyUnicode_IsDecimalDigit'); - late final __PyUnicode_IsDecimalDigit = - __PyUnicode_IsDecimalDigitPtr.asFunction(); - - int _PyUnicode_IsDigit( - int ch, - ) { - return __PyUnicode_IsDigit( - ch, - ); - } - - late final __PyUnicode_IsDigitPtr = - _lookup>( - '_PyUnicode_IsDigit'); - late final __PyUnicode_IsDigit = - __PyUnicode_IsDigitPtr.asFunction(); - - int _PyUnicode_IsNumeric( - int ch, - ) { - return __PyUnicode_IsNumeric( - ch, - ); - } - - late final __PyUnicode_IsNumericPtr = - _lookup>( - '_PyUnicode_IsNumeric'); - late final __PyUnicode_IsNumeric = - __PyUnicode_IsNumericPtr.asFunction(); - - int _PyUnicode_IsPrintable( - int ch, - ) { - return __PyUnicode_IsPrintable( - ch, - ); - } - - late final __PyUnicode_IsPrintablePtr = - _lookup>( - '_PyUnicode_IsPrintable'); - late final __PyUnicode_IsPrintable = - __PyUnicode_IsPrintablePtr.asFunction(); - - int _PyUnicode_IsAlpha( - int ch, - ) { - return __PyUnicode_IsAlpha( - ch, - ); - } - - late final __PyUnicode_IsAlphaPtr = - _lookup>( - '_PyUnicode_IsAlpha'); - late final __PyUnicode_IsAlpha = - __PyUnicode_IsAlphaPtr.asFunction(); - - late final ffi.Pointer> __Py_ascii_whitespace = - _lookup>('_Py_ascii_whitespace'); - - ffi.Pointer get _Py_ascii_whitespace => - __Py_ascii_whitespace.value; - - set _Py_ascii_whitespace(ffi.Pointer value) => - __Py_ascii_whitespace.value = value; - - ffi.Pointer _PyUnicode_FormatLong( - ffi.Pointer arg0, - int arg1, - int arg2, - int arg3, - ) { - return __PyUnicode_FormatLong( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyUnicode_FormatLongPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Int, - ffi.Int, ffi.Int)>>('_PyUnicode_FormatLong'); - late final __PyUnicode_FormatLong = __PyUnicode_FormatLongPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int, int)>(); - - ffi.Pointer _PyUnicode_FromId( - ffi.Pointer<_Py_Identifier> arg0, - ) { - return __PyUnicode_FromId( - arg0, - ); - } - - late final __PyUnicode_FromIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_Py_Identifier>)>>('_PyUnicode_FromId'); - late final __PyUnicode_FromId = __PyUnicode_FromIdPtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_Py_Identifier>)>(); - - int _PyUnicode_EQ( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyUnicode_EQ( - arg0, - arg1, - ); - } - - late final __PyUnicode_EQPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('_PyUnicode_EQ'); - late final __PyUnicode_EQ = __PyUnicode_EQPtr - .asFunction, ffi.Pointer)>(); - - int _PyUnicode_Equal( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyUnicode_Equal( - arg0, - arg1, - ); - } - - late final __PyUnicode_EqualPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_Equal'); - late final __PyUnicode_Equal = __PyUnicode_EqualPtr - .asFunction, ffi.Pointer)>(); - - int _PyUnicode_WideCharString_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyUnicode_WideCharString_Converter( - arg0, - arg1, - ); - } - - late final __PyUnicode_WideCharString_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyUnicode_WideCharString_Converter'); - late final __PyUnicode_WideCharString_Converter = - __PyUnicode_WideCharString_ConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyUnicode_WideCharString_Opt_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyUnicode_WideCharString_Opt_Converter( - arg0, - arg1, - ); - } - - late final __PyUnicode_WideCharString_Opt_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer)>>( - '_PyUnicode_WideCharString_Opt_Converter'); - late final __PyUnicode_WideCharString_Opt_Converter = - __PyUnicode_WideCharString_Opt_ConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyUnicode_ScanIdentifier( - ffi.Pointer arg0, - ) { - return __PyUnicode_ScanIdentifier( - arg0, - ); - } - - late final __PyUnicode_ScanIdentifierPtr = - _lookup)>>( - '_PyUnicode_ScanIdentifier'); - late final __PyUnicode_ScanIdentifier = __PyUnicode_ScanIdentifierPtr - .asFunction)>(); - - PyStatus PyStatus_Ok() { - return _PyStatus_Ok(); - } - - late final _PyStatus_OkPtr = - _lookup>('PyStatus_Ok'); - late final _PyStatus_Ok = _PyStatus_OkPtr.asFunction(); - - PyStatus PyStatus_Error( - ffi.Pointer err_msg, - ) { - return _PyStatus_Error( - err_msg, - ); - } - - late final _PyStatus_ErrorPtr = - _lookup)>>( - 'PyStatus_Error'); - late final _PyStatus_Error = - _PyStatus_ErrorPtr.asFunction)>(); - - PyStatus PyStatus_NoMemory() { - return _PyStatus_NoMemory(); - } - - late final _PyStatus_NoMemoryPtr = - _lookup>('PyStatus_NoMemory'); - late final _PyStatus_NoMemory = - _PyStatus_NoMemoryPtr.asFunction(); - - PyStatus PyStatus_Exit( - int exitcode, - ) { - return _PyStatus_Exit( - exitcode, - ); - } - - late final _PyStatus_ExitPtr = - _lookup>('PyStatus_Exit'); - late final _PyStatus_Exit = - _PyStatus_ExitPtr.asFunction(); - - int PyStatus_IsError( - PyStatus err, - ) { - return _PyStatus_IsError( - err, - ); - } - - late final _PyStatus_IsErrorPtr = - _lookup>( - 'PyStatus_IsError'); - late final _PyStatus_IsError = - _PyStatus_IsErrorPtr.asFunction(); - - int PyStatus_IsExit( - PyStatus err, - ) { - return _PyStatus_IsExit( - err, - ); - } - - late final _PyStatus_IsExitPtr = - _lookup>( - 'PyStatus_IsExit'); - late final _PyStatus_IsExit = - _PyStatus_IsExitPtr.asFunction(); - - int PyStatus_Exception( - PyStatus err, - ) { - return _PyStatus_Exception( - err, - ); - } - - late final _PyStatus_ExceptionPtr = - _lookup>( - 'PyStatus_Exception'); - late final _PyStatus_Exception = - _PyStatus_ExceptionPtr.asFunction(); - - ffi.Pointer _PyErr_SetFromPyStatus( - PyStatus status, - ) { - return __PyErr_SetFromPyStatus( - status, - ); - } - - late final __PyErr_SetFromPyStatusPtr = - _lookup Function(PyStatus)>>( - '_PyErr_SetFromPyStatus'); - late final __PyErr_SetFromPyStatus = __PyErr_SetFromPyStatusPtr - .asFunction Function(PyStatus)>(); - - PyStatus PyWideStringList_Append( - ffi.Pointer list, - ffi.Pointer item, - ) { - return _PyWideStringList_Append( - list, - item, - ); - } - - late final _PyWideStringList_AppendPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer, - ffi.Pointer)>>('PyWideStringList_Append'); - late final _PyWideStringList_Append = _PyWideStringList_AppendPtr.asFunction< - PyStatus Function( - ffi.Pointer, ffi.Pointer)>(); - - PyStatus PyWideStringList_Insert( - ffi.Pointer list, - int index, - ffi.Pointer item, - ) { - return _PyWideStringList_Insert( - list, - index, - item, - ); - } - - late final _PyWideStringList_InsertPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyWideStringList_Insert'); - late final _PyWideStringList_Insert = _PyWideStringList_InsertPtr.asFunction< - PyStatus Function( - ffi.Pointer, int, ffi.Pointer)>(); - - void PyPreConfig_InitPythonConfig( - ffi.Pointer config, - ) { - return _PyPreConfig_InitPythonConfig( - config, - ); - } - - late final _PyPreConfig_InitPythonConfigPtr = - _lookup)>>( - 'PyPreConfig_InitPythonConfig'); - late final _PyPreConfig_InitPythonConfig = _PyPreConfig_InitPythonConfigPtr - .asFunction)>(); - - void PyPreConfig_InitIsolatedConfig( - ffi.Pointer config, - ) { - return _PyPreConfig_InitIsolatedConfig( - config, - ); - } - - late final _PyPreConfig_InitIsolatedConfigPtr = - _lookup)>>( - 'PyPreConfig_InitIsolatedConfig'); - late final _PyPreConfig_InitIsolatedConfig = - _PyPreConfig_InitIsolatedConfigPtr.asFunction< - void Function(ffi.Pointer)>(); - - void PyConfig_InitPythonConfig( - ffi.Pointer config, - ) { - return _PyConfig_InitPythonConfig( - config, - ); - } - - late final _PyConfig_InitPythonConfigPtr = - _lookup)>>( - 'PyConfig_InitPythonConfig'); - late final _PyConfig_InitPythonConfig = _PyConfig_InitPythonConfigPtr - .asFunction)>(); - - void PyConfig_InitIsolatedConfig( - ffi.Pointer config, - ) { - return _PyConfig_InitIsolatedConfig( - config, - ); - } - - late final _PyConfig_InitIsolatedConfigPtr = - _lookup)>>( - 'PyConfig_InitIsolatedConfig'); - late final _PyConfig_InitIsolatedConfig = _PyConfig_InitIsolatedConfigPtr - .asFunction)>(); - - void PyConfig_Clear( - ffi.Pointer arg0, - ) { - return _PyConfig_Clear( - arg0, - ); - } - - late final _PyConfig_ClearPtr = - _lookup)>>( - 'PyConfig_Clear'); - late final _PyConfig_Clear = - _PyConfig_ClearPtr.asFunction)>(); - - PyStatus PyConfig_SetString( - ffi.Pointer config, - ffi.Pointer> config_str, - ffi.Pointer str, - ) { - return _PyConfig_SetString( - config, - config_str, - str, - ); - } - - late final _PyConfig_SetStringPtr = _lookup< - ffi.NativeFunction< - PyStatus Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyConfig_SetString'); - late final _PyConfig_SetString = _PyConfig_SetStringPtr.asFunction< - PyStatus Function(ffi.Pointer, - ffi.Pointer>, ffi.Pointer)>(); - - PyStatus PyConfig_SetBytesString( - ffi.Pointer config, - ffi.Pointer> config_str, - ffi.Pointer str, - ) { - return _PyConfig_SetBytesString( - config, - config_str, - str, - ); - } - - late final _PyConfig_SetBytesStringPtr = _lookup< - ffi.NativeFunction< - PyStatus Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyConfig_SetBytesString'); - late final _PyConfig_SetBytesString = _PyConfig_SetBytesStringPtr.asFunction< - PyStatus Function(ffi.Pointer, - ffi.Pointer>, ffi.Pointer)>(); - - PyStatus PyConfig_Read( - ffi.Pointer config, - ) { - return _PyConfig_Read( - config, - ); - } - - late final _PyConfig_ReadPtr = - _lookup)>>( - 'PyConfig_Read'); - late final _PyConfig_Read = - _PyConfig_ReadPtr.asFunction)>(); - - PyStatus PyConfig_SetBytesArgv( - ffi.Pointer config, - int argc, - ffi.Pointer> argv, - ) { - return _PyConfig_SetBytesArgv( - config, - argc, - argv, - ); - } - - late final _PyConfig_SetBytesArgvPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer>)>>('PyConfig_SetBytesArgv'); - late final _PyConfig_SetBytesArgv = _PyConfig_SetBytesArgvPtr.asFunction< - PyStatus Function( - ffi.Pointer, int, ffi.Pointer>)>(); - - PyStatus PyConfig_SetArgv( - ffi.Pointer config, - int argc, - ffi.Pointer> argv, - ) { - return _PyConfig_SetArgv( - config, - argc, - argv, - ); - } - - late final _PyConfig_SetArgvPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer>)>>('PyConfig_SetArgv'); - late final _PyConfig_SetArgv = _PyConfig_SetArgvPtr.asFunction< - PyStatus Function( - ffi.Pointer, int, ffi.Pointer>)>(); - - PyStatus PyConfig_SetWideStringList( - ffi.Pointer config, - ffi.Pointer list, - int length, - ffi.Pointer> items, - ) { - return _PyConfig_SetWideStringList( - config, - list, - length, - items, - ); - } - - late final _PyConfig_SetWideStringListPtr = _lookup< - ffi.NativeFunction< - PyStatus Function( - ffi.Pointer, - ffi.Pointer, - Py_ssize_t, - ffi.Pointer>)>>( - 'PyConfig_SetWideStringList'); - late final _PyConfig_SetWideStringList = - _PyConfig_SetWideStringListPtr.asFunction< - PyStatus Function( - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer>)>(); - - void Py_GetArgcArgv( - ffi.Pointer argc, - ffi.Pointer>> argv, - ) { - return _Py_GetArgcArgv( - argc, - argv, - ); - } - - late final _Py_GetArgcArgvPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer>>)>>( - 'Py_GetArgcArgv'); - late final _Py_GetArgcArgv = _Py_GetArgcArgvPtr.asFunction< - void Function(ffi.Pointer, - ffi.Pointer>>)>(); - - ffi.Pointer PyInterpreterState_New() { - return _PyInterpreterState_New(); - } - - late final _PyInterpreterState_NewPtr = - _lookup Function()>>( - 'PyInterpreterState_New'); - late final _PyInterpreterState_New = _PyInterpreterState_NewPtr.asFunction< - ffi.Pointer Function()>(); - - void PyInterpreterState_Clear( - ffi.Pointer arg0, - ) { - return _PyInterpreterState_Clear( - arg0, - ); - } - - late final _PyInterpreterState_ClearPtr = _lookup< - ffi - .NativeFunction)>>( - 'PyInterpreterState_Clear'); - late final _PyInterpreterState_Clear = _PyInterpreterState_ClearPtr - .asFunction)>(); - - void PyInterpreterState_Delete( - ffi.Pointer arg0, - ) { - return _PyInterpreterState_Delete( - arg0, - ); - } - - late final _PyInterpreterState_DeletePtr = _lookup< - ffi - .NativeFunction)>>( - 'PyInterpreterState_Delete'); - late final _PyInterpreterState_Delete = _PyInterpreterState_DeletePtr - .asFunction)>(); - - ffi.Pointer PyInterpreterState_Get() { - return _PyInterpreterState_Get(); - } - - late final _PyInterpreterState_GetPtr = - _lookup Function()>>( - 'PyInterpreterState_Get'); - late final _PyInterpreterState_Get = _PyInterpreterState_GetPtr.asFunction< - ffi.Pointer Function()>(); - - ffi.Pointer PyInterpreterState_GetDict( - ffi.Pointer arg0, - ) { - return _PyInterpreterState_GetDict( - arg0, - ); - } - - late final _PyInterpreterState_GetDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyInterpreterState_GetDict'); - late final _PyInterpreterState_GetDict = - _PyInterpreterState_GetDictPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyInterpreterState_GetID( - ffi.Pointer arg0, - ) { - return _PyInterpreterState_GetID( - arg0, - ); - } - - late final _PyInterpreterState_GetIDPtr = _lookup< - ffi - .NativeFunction)>>( - 'PyInterpreterState_GetID'); - late final _PyInterpreterState_GetID = _PyInterpreterState_GetIDPtr - .asFunction)>(); - - int PyState_AddModule( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyState_AddModule( - arg0, - arg1, - ); - } - - late final _PyState_AddModulePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyState_AddModule'); - late final _PyState_AddModule = _PyState_AddModulePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyState_RemoveModule( - ffi.Pointer arg0, - ) { - return _PyState_RemoveModule( - arg0, - ); - } - - late final _PyState_RemoveModulePtr = - _lookup)>>( - 'PyState_RemoveModule'); - late final _PyState_RemoveModule = _PyState_RemoveModulePtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer PyState_FindModule( - ffi.Pointer arg0, - ) { - return _PyState_FindModule( - arg0, - ); - } - - late final _PyState_FindModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyState_FindModule'); - late final _PyState_FindModule = _PyState_FindModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyThreadState_New( - ffi.Pointer arg0, - ) { - return _PyThreadState_New( - arg0, - ); - } - - late final _PyThreadState_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyThreadState_New'); - late final _PyThreadState_New = _PyThreadState_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyThreadState_Clear( - ffi.Pointer arg0, - ) { - return _PyThreadState_Clear( - arg0, - ); - } - - late final _PyThreadState_ClearPtr = _lookup< - ffi.NativeFunction)>>( - 'PyThreadState_Clear'); - late final _PyThreadState_Clear = _PyThreadState_ClearPtr.asFunction< - void Function(ffi.Pointer)>(); - - void PyThreadState_Delete( - ffi.Pointer arg0, - ) { - return _PyThreadState_Delete( - arg0, - ); - } - - late final _PyThreadState_DeletePtr = _lookup< - ffi.NativeFunction)>>( - 'PyThreadState_Delete'); - late final _PyThreadState_Delete = _PyThreadState_DeletePtr.asFunction< - void Function(ffi.Pointer)>(); - - ffi.Pointer PyThreadState_Get() { - return _PyThreadState_Get(); - } - - late final _PyThreadState_GetPtr = - _lookup Function()>>( - 'PyThreadState_Get'); - late final _PyThreadState_Get = - _PyThreadState_GetPtr.asFunction Function()>(); - - ffi.Pointer PyThreadState_Swap( - ffi.Pointer arg0, - ) { - return _PyThreadState_Swap( - arg0, - ); - } - - late final _PyThreadState_SwapPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyThreadState_Swap'); - late final _PyThreadState_Swap = _PyThreadState_SwapPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyThreadState_GetDict() { - return _PyThreadState_GetDict1(); - } - - late final _PyThreadState_GetDictPtr = - _lookup Function()>>( - 'PyThreadState_GetDict'); - late final _PyThreadState_GetDict1 = - _PyThreadState_GetDictPtr.asFunction Function()>(); - - int PyThreadState_SetAsyncExc( - int arg0, - ffi.Pointer arg1, - ) { - return _PyThreadState_SetAsyncExc( - arg0, - arg1, - ); - } - - late final _PyThreadState_SetAsyncExcPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.UnsignedLong, - ffi.Pointer)>>('PyThreadState_SetAsyncExc'); - late final _PyThreadState_SetAsyncExc = _PyThreadState_SetAsyncExcPtr - .asFunction)>(); - - ffi.Pointer PyThreadState_GetInterpreter( - ffi.Pointer tstate, - ) { - return _PyThreadState_GetInterpreter( - tstate, - ); - } - - late final _PyThreadState_GetInterpreterPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyThreadState_GetInterpreter'); - late final _PyThreadState_GetInterpreter = - _PyThreadState_GetInterpreterPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer)>(); - - ffi.Pointer PyThreadState_GetFrame( - ffi.Pointer tstate, - ) { - return _PyThreadState_GetFrame( - tstate, - ); - } - - late final _PyThreadState_GetFramePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyThreadState_GetFrame'); - late final _PyThreadState_GetFrame = _PyThreadState_GetFramePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyThreadState_GetID( - ffi.Pointer tstate, - ) { - return _PyThreadState_GetID( - tstate, - ); - } - - late final _PyThreadState_GetIDPtr = _lookup< - ffi.NativeFunction)>>( - 'PyThreadState_GetID'); - late final _PyThreadState_GetID = _PyThreadState_GetIDPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyGILState_Ensure() { - return _PyGILState_Ensure(); - } - - late final _PyGILState_EnsurePtr = - _lookup>('PyGILState_Ensure'); - late final _PyGILState_Ensure = - _PyGILState_EnsurePtr.asFunction(); - - void PyGILState_Release( - int arg0, - ) { - return _PyGILState_Release( - arg0, - ); - } - - late final _PyGILState_ReleasePtr = - _lookup>( - 'PyGILState_Release'); - late final _PyGILState_Release = - _PyGILState_ReleasePtr.asFunction(); - - ffi.Pointer PyGILState_GetThisThreadState() { - return _PyGILState_GetThisThreadState(); - } - - late final _PyGILState_GetThisThreadStatePtr = - _lookup Function()>>( - 'PyGILState_GetThisThreadState'); - late final _PyGILState_GetThisThreadState = _PyGILState_GetThisThreadStatePtr - .asFunction Function()>(); - - int _PyInterpreterState_HasFeature( - ffi.Pointer interp, - int feature, - ) { - return __PyInterpreterState_HasFeature( - interp, - feature, - ); - } - - late final __PyInterpreterState_HasFeaturePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.UnsignedLong)>>('_PyInterpreterState_HasFeature'); - late final __PyInterpreterState_HasFeature = - __PyInterpreterState_HasFeaturePtr - .asFunction, int)>(); - - int _PyInterpreterState_RequiresIDRef( - ffi.Pointer arg0, - ) { - return __PyInterpreterState_RequiresIDRef( - arg0, - ); - } - - late final __PyInterpreterState_RequiresIDRefPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyInterpreterState_RequiresIDRef'); - late final __PyInterpreterState_RequiresIDRef = - __PyInterpreterState_RequiresIDRefPtr - .asFunction)>(); - - void _PyInterpreterState_RequireIDRef( - ffi.Pointer arg0, - int arg1, - ) { - return __PyInterpreterState_RequireIDRef( - arg0, - arg1, - ); - } - - late final __PyInterpreterState_RequireIDRefPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Int)>>('_PyInterpreterState_RequireIDRef'); - late final __PyInterpreterState_RequireIDRef = - __PyInterpreterState_RequireIDRefPtr - .asFunction, int)>(); - - ffi.Pointer _PyInterpreterState_GetMainModule( - ffi.Pointer arg0, - ) { - return __PyInterpreterState_GetMainModule( - arg0, - ); - } - - late final __PyInterpreterState_GetMainModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>( - '_PyInterpreterState_GetMainModule'); - late final __PyInterpreterState_GetMainModule = - __PyInterpreterState_GetMainModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer _PyThreadState_Prealloc( - ffi.Pointer arg0, - ) { - return __PyThreadState_Prealloc( - arg0, - ); - } - - late final __PyThreadState_PreallocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyThreadState_Prealloc'); - late final __PyThreadState_Prealloc = __PyThreadState_PreallocPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer _PyThreadState_UncheckedGet() { - return __PyThreadState_UncheckedGet(); - } - - late final __PyThreadState_UncheckedGetPtr = - _lookup Function()>>( - '_PyThreadState_UncheckedGet'); - late final __PyThreadState_UncheckedGet = __PyThreadState_UncheckedGetPtr - .asFunction Function()>(); - - ffi.Pointer _PyThreadState_GetDict( - ffi.Pointer tstate, - ) { - return __PyThreadState_GetDict( - tstate, - ); - } - - late final __PyThreadState_GetDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyThreadState_GetDict'); - late final __PyThreadState_GetDict = __PyThreadState_GetDictPtr - .asFunction Function(ffi.Pointer)>(); - - void PyThreadState_EnterTracing( - ffi.Pointer tstate, - ) { - return _PyThreadState_EnterTracing( - tstate, - ); - } - - late final _PyThreadState_EnterTracingPtr = _lookup< - ffi.NativeFunction)>>( - 'PyThreadState_EnterTracing'); - late final _PyThreadState_EnterTracing = _PyThreadState_EnterTracingPtr - .asFunction)>(); - - void PyThreadState_LeaveTracing( - ffi.Pointer tstate, - ) { - return _PyThreadState_LeaveTracing( - tstate, - ); - } - - late final _PyThreadState_LeaveTracingPtr = _lookup< - ffi.NativeFunction)>>( - 'PyThreadState_LeaveTracing'); - late final _PyThreadState_LeaveTracing = _PyThreadState_LeaveTracingPtr - .asFunction)>(); - - int PyGILState_Check() { - return _PyGILState_Check(); - } - - late final _PyGILState_CheckPtr = - _lookup>('PyGILState_Check'); - late final _PyGILState_Check = - _PyGILState_CheckPtr.asFunction(); - - ffi.Pointer _PyGILState_GetInterpreterStateUnsafe() { - return __PyGILState_GetInterpreterStateUnsafe(); - } - - late final __PyGILState_GetInterpreterStateUnsafePtr = - _lookup Function()>>( - '_PyGILState_GetInterpreterStateUnsafe'); - late final __PyGILState_GetInterpreterStateUnsafe = - __PyGILState_GetInterpreterStateUnsafePtr - .asFunction Function()>(); - - ffi.Pointer _PyThread_CurrentFrames() { - return __PyThread_CurrentFrames(); - } - - late final __PyThread_CurrentFramesPtr = - _lookup Function()>>( - '_PyThread_CurrentFrames'); - late final __PyThread_CurrentFrames = __PyThread_CurrentFramesPtr - .asFunction Function()>(); - - ffi.Pointer _PyThread_CurrentExceptions() { - return __PyThread_CurrentExceptions(); - } - - late final __PyThread_CurrentExceptionsPtr = - _lookup Function()>>( - '_PyThread_CurrentExceptions'); - late final __PyThread_CurrentExceptions = __PyThread_CurrentExceptionsPtr - .asFunction Function()>(); - - ffi.Pointer PyInterpreterState_Main() { - return _PyInterpreterState_Main(); - } - - late final _PyInterpreterState_MainPtr = - _lookup Function()>>( - 'PyInterpreterState_Main'); - late final _PyInterpreterState_Main = _PyInterpreterState_MainPtr.asFunction< - ffi.Pointer Function()>(); - - ffi.Pointer PyInterpreterState_Head() { - return _PyInterpreterState_Head(); - } - - late final _PyInterpreterState_HeadPtr = - _lookup Function()>>( - 'PyInterpreterState_Head'); - late final _PyInterpreterState_Head = _PyInterpreterState_HeadPtr.asFunction< - ffi.Pointer Function()>(); - - ffi.Pointer PyInterpreterState_Next( - ffi.Pointer arg0, - ) { - return _PyInterpreterState_Next( - arg0, - ); - } - - late final _PyInterpreterState_NextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyInterpreterState_Next'); - late final _PyInterpreterState_Next = _PyInterpreterState_NextPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer)>(); - - ffi.Pointer PyInterpreterState_ThreadHead( - ffi.Pointer arg0, - ) { - return _PyInterpreterState_ThreadHead( - arg0, - ); - } - - late final _PyInterpreterState_ThreadHeadPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>( - 'PyInterpreterState_ThreadHead'); - late final _PyInterpreterState_ThreadHead = - _PyInterpreterState_ThreadHeadPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer)>(); - - ffi.Pointer PyThreadState_Next( - ffi.Pointer arg0, - ) { - return _PyThreadState_Next( - arg0, - ); - } - - late final _PyThreadState_NextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyThreadState_Next'); - late final _PyThreadState_Next = _PyThreadState_NextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyThreadState_DeleteCurrent() { - return _PyThreadState_DeleteCurrent(); - } - - late final _PyThreadState_DeleteCurrentPtr = - _lookup>( - 'PyThreadState_DeleteCurrent'); - late final _PyThreadState_DeleteCurrent = - _PyThreadState_DeleteCurrentPtr.asFunction(); - - _PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc( - ffi.Pointer interp, - ) { - return __PyInterpreterState_GetEvalFrameFunc( - interp, - ); - } - - late final __PyInterpreterState_GetEvalFrameFuncPtr = _lookup< - ffi.NativeFunction< - _PyFrameEvalFunction Function(ffi.Pointer)>>( - '_PyInterpreterState_GetEvalFrameFunc'); - late final __PyInterpreterState_GetEvalFrameFunc = - __PyInterpreterState_GetEvalFrameFuncPtr.asFunction< - _PyFrameEvalFunction Function(ffi.Pointer)>(); - - void _PyInterpreterState_SetEvalFrameFunc( - ffi.Pointer interp, - _PyFrameEvalFunction eval_frame, - ) { - return __PyInterpreterState_SetEvalFrameFunc( - interp, - eval_frame, - ); - } - - late final __PyInterpreterState_SetEvalFrameFuncPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - _PyFrameEvalFunction)>>('_PyInterpreterState_SetEvalFrameFunc'); - late final __PyInterpreterState_SetEvalFrameFunc = - __PyInterpreterState_SetEvalFrameFuncPtr.asFunction< - void Function( - ffi.Pointer, _PyFrameEvalFunction)>(); - - ffi.Pointer _PyInterpreterState_GetConfig( - ffi.Pointer interp, - ) { - return __PyInterpreterState_GetConfig( - interp, - ); - } - - late final __PyInterpreterState_GetConfigPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>( - '_PyInterpreterState_GetConfig'); - late final __PyInterpreterState_GetConfig = - __PyInterpreterState_GetConfigPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int _PyInterpreterState_GetConfigCopy( - ffi.Pointer config, - ) { - return __PyInterpreterState_GetConfigCopy( - config, - ); - } - - late final __PyInterpreterState_GetConfigCopyPtr = - _lookup)>>( - '_PyInterpreterState_GetConfigCopy'); - late final __PyInterpreterState_GetConfigCopy = - __PyInterpreterState_GetConfigCopyPtr - .asFunction)>(); - - int _PyInterpreterState_SetConfig( - ffi.Pointer config, - ) { - return __PyInterpreterState_SetConfig( - config, - ); - } - - late final __PyInterpreterState_SetConfigPtr = - _lookup)>>( - '_PyInterpreterState_SetConfig'); - late final __PyInterpreterState_SetConfig = __PyInterpreterState_SetConfigPtr - .asFunction)>(); - - ffi.Pointer _Py_GetConfig() { - return __Py_GetConfig(); - } - - late final __Py_GetConfigPtr = - _lookup Function()>>( - '_Py_GetConfig'); - late final __Py_GetConfig = - __Py_GetConfigPtr.asFunction Function()>(); - - void _PyCrossInterpreterData_Init( - ffi.Pointer<_PyCrossInterpreterData> data, - ffi.Pointer interp, - ffi.Pointer shared, - ffi.Pointer obj, - xid_newobjectfunc new_object, - ) { - return __PyCrossInterpreterData_Init( - data, - interp, - shared, - obj, - new_object, - ); - } - - late final __PyCrossInterpreterData_InitPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer<_PyCrossInterpreterData>, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - xid_newobjectfunc)>>('_PyCrossInterpreterData_Init'); - late final __PyCrossInterpreterData_Init = - __PyCrossInterpreterData_InitPtr.asFunction< - void Function( - ffi.Pointer<_PyCrossInterpreterData>, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - xid_newobjectfunc)>(); - - int _PyCrossInterpreterData_InitWithSize( - ffi.Pointer<_PyCrossInterpreterData> arg0, - ffi.Pointer interp, - int arg2, - ffi.Pointer arg3, - xid_newobjectfunc arg4, - ) { - return __PyCrossInterpreterData_InitWithSize( - arg0, - interp, - arg2, - arg3, - arg4, - ); - } - - late final __PyCrossInterpreterData_InitWithSizePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer<_PyCrossInterpreterData>, - ffi.Pointer, - ffi.Size, - ffi.Pointer, - xid_newobjectfunc)>>('_PyCrossInterpreterData_InitWithSize'); - late final __PyCrossInterpreterData_InitWithSize = - __PyCrossInterpreterData_InitWithSizePtr.asFunction< - int Function( - ffi.Pointer<_PyCrossInterpreterData>, - ffi.Pointer, - int, - ffi.Pointer, - xid_newobjectfunc)>(); - - void _PyCrossInterpreterData_Clear( - ffi.Pointer arg0, - ffi.Pointer<_PyCrossInterpreterData> arg1, - ) { - return __PyCrossInterpreterData_Clear( - arg0, - arg1, - ); - } - - late final __PyCrossInterpreterData_ClearPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer<_PyCrossInterpreterData>)>>( - '_PyCrossInterpreterData_Clear'); - late final __PyCrossInterpreterData_Clear = - __PyCrossInterpreterData_ClearPtr.asFunction< - void Function(ffi.Pointer, - ffi.Pointer<_PyCrossInterpreterData>)>(); - - int _PyObject_GetCrossInterpreterData( - ffi.Pointer arg0, - ffi.Pointer<_PyCrossInterpreterData> arg1, - ) { - return __PyObject_GetCrossInterpreterData( - arg0, - arg1, - ); - } - - late final __PyObject_GetCrossInterpreterDataPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer<_PyCrossInterpreterData>)>>( - '_PyObject_GetCrossInterpreterData'); - late final __PyObject_GetCrossInterpreterData = - __PyObject_GetCrossInterpreterDataPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer<_PyCrossInterpreterData>)>(); - - ffi.Pointer _PyCrossInterpreterData_NewObject( - ffi.Pointer<_PyCrossInterpreterData> arg0, - ) { - return __PyCrossInterpreterData_NewObject( - arg0, - ); - } - - late final __PyCrossInterpreterData_NewObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_PyCrossInterpreterData>)>>( - '_PyCrossInterpreterData_NewObject'); - late final __PyCrossInterpreterData_NewObject = - __PyCrossInterpreterData_NewObjectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer<_PyCrossInterpreterData>)>(); - - int _PyCrossInterpreterData_Release( - ffi.Pointer<_PyCrossInterpreterData> arg0, - ) { - return __PyCrossInterpreterData_Release( - arg0, - ); - } - - late final __PyCrossInterpreterData_ReleasePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyCrossInterpreterData>)>>( - '_PyCrossInterpreterData_Release'); - late final __PyCrossInterpreterData_Release = - __PyCrossInterpreterData_ReleasePtr - .asFunction)>(); - - int _PyObject_CheckCrossInterpreterData( - ffi.Pointer arg0, - ) { - return __PyObject_CheckCrossInterpreterData( - arg0, - ); - } - - late final __PyObject_CheckCrossInterpreterDataPtr = - _lookup)>>( - '_PyObject_CheckCrossInterpreterData'); - late final __PyObject_CheckCrossInterpreterData = - __PyObject_CheckCrossInterpreterDataPtr - .asFunction)>(); - - int _PyCrossInterpreterData_RegisterClass( - ffi.Pointer arg0, - crossinterpdatafunc arg1, - ) { - return __PyCrossInterpreterData_RegisterClass( - arg0, - arg1, - ); - } - - late final __PyCrossInterpreterData_RegisterClassPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - crossinterpdatafunc)>>('_PyCrossInterpreterData_RegisterClass'); - late final __PyCrossInterpreterData_RegisterClass = - __PyCrossInterpreterData_RegisterClassPtr.asFunction< - int Function(ffi.Pointer, crossinterpdatafunc)>(); - - int _PyCrossInterpreterData_UnregisterClass( - ffi.Pointer arg0, - ) { - return __PyCrossInterpreterData_UnregisterClass( - arg0, - ); - } - - late final __PyCrossInterpreterData_UnregisterClassPtr = - _lookup)>>( - '_PyCrossInterpreterData_UnregisterClass'); - late final __PyCrossInterpreterData_UnregisterClass = - __PyCrossInterpreterData_UnregisterClassPtr - .asFunction)>(); - - crossinterpdatafunc _PyCrossInterpreterData_Lookup( - ffi.Pointer arg0, - ) { - return __PyCrossInterpreterData_Lookup( - arg0, - ); - } - - late final __PyCrossInterpreterData_LookupPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyCrossInterpreterData_Lookup'); - late final __PyCrossInterpreterData_Lookup = - __PyCrossInterpreterData_LookupPtr - .asFunction)>(); - - void PyErr_SetNone( - ffi.Pointer arg0, - ) { - return _PyErr_SetNone( - arg0, - ); - } - - late final _PyErr_SetNonePtr = - _lookup)>>( - 'PyErr_SetNone'); - late final _PyErr_SetNone = - _PyErr_SetNonePtr.asFunction)>(); - - void PyErr_SetObject( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyErr_SetObject( - arg0, - arg1, - ); - } - - late final _PyErr_SetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('PyErr_SetObject'); - late final _PyErr_SetObject = _PyErr_SetObjectPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - void PyErr_SetString( - ffi.Pointer exception, - ffi.Pointer string, - ) { - return _PyErr_SetString( - exception, - string, - ); - } - - late final _PyErr_SetStringPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('PyErr_SetString'); - late final _PyErr_SetString = _PyErr_SetStringPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyErr_Occurred() { - return _PyErr_Occurred(); - } - - late final _PyErr_OccurredPtr = - _lookup Function()>>( - 'PyErr_Occurred'); - late final _PyErr_Occurred = - _PyErr_OccurredPtr.asFunction Function()>(); - - void PyErr_Clear() { - return _PyErr_Clear(); - } - - late final _PyErr_ClearPtr = - _lookup>('PyErr_Clear'); - late final _PyErr_Clear = _PyErr_ClearPtr.asFunction(); - - void PyErr_Fetch( - ffi.Pointer> arg0, - ffi.Pointer> arg1, - ffi.Pointer> arg2, - ) { - return _PyErr_Fetch( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_FetchPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>>('PyErr_Fetch'); - late final _PyErr_Fetch = _PyErr_FetchPtr.asFunction< - void Function( - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>(); - - void PyErr_Restore( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyErr_Restore( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_RestorePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyErr_Restore'); - late final _PyErr_Restore = _PyErr_RestorePtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyErr_GetRaisedException() { - return _PyErr_GetRaisedException(); - } - - late final _PyErr_GetRaisedExceptionPtr = - _lookup Function()>>( - 'PyErr_GetRaisedException'); - late final _PyErr_GetRaisedException = _PyErr_GetRaisedExceptionPtr - .asFunction Function()>(); - - void PyErr_SetRaisedException( - ffi.Pointer arg0, - ) { - return _PyErr_SetRaisedException( - arg0, - ); - } - - late final _PyErr_SetRaisedExceptionPtr = - _lookup)>>( - 'PyErr_SetRaisedException'); - late final _PyErr_SetRaisedException = _PyErr_SetRaisedExceptionPtr - .asFunction)>(); - - ffi.Pointer PyErr_GetHandledException() { - return _PyErr_GetHandledException1(); - } - - late final _PyErr_GetHandledExceptionPtr = - _lookup Function()>>( - 'PyErr_GetHandledException'); - late final _PyErr_GetHandledException1 = _PyErr_GetHandledExceptionPtr - .asFunction Function()>(); - - void PyErr_SetHandledException( - ffi.Pointer arg0, - ) { - return _PyErr_SetHandledException1( - arg0, - ); - } - - late final _PyErr_SetHandledExceptionPtr = - _lookup)>>( - 'PyErr_SetHandledException'); - late final _PyErr_SetHandledException1 = _PyErr_SetHandledExceptionPtr - .asFunction)>(); - - void PyErr_GetExcInfo( - ffi.Pointer> arg0, - ffi.Pointer> arg1, - ffi.Pointer> arg2, - ) { - return _PyErr_GetExcInfo1( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_GetExcInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>>('PyErr_GetExcInfo'); - late final _PyErr_GetExcInfo1 = _PyErr_GetExcInfoPtr.asFunction< - void Function( - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>(); - - void PyErr_SetExcInfo( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyErr_SetExcInfo( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_SetExcInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyErr_SetExcInfo'); - late final _PyErr_SetExcInfo = _PyErr_SetExcInfoPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - void Py_FatalError( - ffi.Pointer message, - ) { - return _Py_FatalError( - message, - ); - } - - late final _Py_FatalErrorPtr = - _lookup)>>( - 'Py_FatalError'); - late final _Py_FatalError = - _Py_FatalErrorPtr.asFunction)>(); - - int PyErr_GivenExceptionMatches( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyErr_GivenExceptionMatches( - arg0, - arg1, - ); - } - - late final _PyErr_GivenExceptionMatchesPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyErr_GivenExceptionMatches'); - late final _PyErr_GivenExceptionMatches = _PyErr_GivenExceptionMatchesPtr - .asFunction, ffi.Pointer)>(); - - int PyErr_ExceptionMatches( - ffi.Pointer arg0, - ) { - return _PyErr_ExceptionMatches( - arg0, - ); - } - - late final _PyErr_ExceptionMatchesPtr = - _lookup)>>( - 'PyErr_ExceptionMatches'); - late final _PyErr_ExceptionMatches = _PyErr_ExceptionMatchesPtr.asFunction< - int Function(ffi.Pointer)>(); - - void PyErr_NormalizeException( - ffi.Pointer> arg0, - ffi.Pointer> arg1, - ffi.Pointer> arg2, - ) { - return _PyErr_NormalizeException( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_NormalizeExceptionPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>>('PyErr_NormalizeException'); - late final _PyErr_NormalizeException = - _PyErr_NormalizeExceptionPtr.asFunction< - void Function( - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>(); - - int PyException_SetTraceback( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyException_SetTraceback( - arg0, - arg1, - ); - } - - late final _PyException_SetTracebackPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyException_SetTraceback'); - late final _PyException_SetTraceback = _PyException_SetTracebackPtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer PyException_GetTraceback( - ffi.Pointer arg0, - ) { - return _PyException_GetTraceback( - arg0, - ); - } - - late final _PyException_GetTracebackPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyException_GetTraceback'); - late final _PyException_GetTraceback = _PyException_GetTracebackPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyException_GetCause( - ffi.Pointer arg0, - ) { - return _PyException_GetCause( - arg0, - ); - } - - late final _PyException_GetCausePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyException_GetCause'); - late final _PyException_GetCause = _PyException_GetCausePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyException_SetCause( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyException_SetCause( - arg0, - arg1, - ); - } - - late final _PyException_SetCausePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('PyException_SetCause'); - late final _PyException_SetCause = _PyException_SetCausePtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyException_GetContext( - ffi.Pointer arg0, - ) { - return _PyException_GetContext( - arg0, - ); - } - - late final _PyException_GetContextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyException_GetContext'); - late final _PyException_GetContext = _PyException_GetContextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyException_SetContext( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyException_SetContext( - arg0, - arg1, - ); - } - - late final _PyException_SetContextPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('PyException_SetContext'); - late final _PyException_SetContext = _PyException_SetContextPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyException_GetArgs( - ffi.Pointer arg0, - ) { - return _PyException_GetArgs( - arg0, - ); - } - - late final _PyException_GetArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyException_GetArgs'); - late final _PyException_GetArgs = _PyException_GetArgsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyException_SetArgs( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyException_SetArgs( - arg0, - arg1, - ); - } - - late final _PyException_SetArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('PyException_SetArgs'); - late final _PyException_SetArgs = _PyException_SetArgsPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyExceptionClass_Name( - ffi.Pointer arg0, - ) { - return _PyExceptionClass_Name( - arg0, - ); - } - - late final _PyExceptionClass_NamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyExceptionClass_Name'); - late final _PyExceptionClass_Name = _PyExceptionClass_NamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer> _PyExc_BaseException = - _lookup>('PyExc_BaseException'); - - ffi.Pointer get PyExc_BaseException => _PyExc_BaseException.value; - - set PyExc_BaseException(ffi.Pointer value) => - _PyExc_BaseException.value = value; - - late final ffi.Pointer> _PyExc_Exception = - _lookup>('PyExc_Exception'); - - ffi.Pointer get PyExc_Exception => _PyExc_Exception.value; - - set PyExc_Exception(ffi.Pointer value) => - _PyExc_Exception.value = value; - - late final ffi.Pointer> _PyExc_BaseExceptionGroup = - _lookup>('PyExc_BaseExceptionGroup'); - - ffi.Pointer get PyExc_BaseExceptionGroup => - _PyExc_BaseExceptionGroup.value; - - set PyExc_BaseExceptionGroup(ffi.Pointer value) => - _PyExc_BaseExceptionGroup.value = value; - - late final ffi.Pointer> _PyExc_StopAsyncIteration = - _lookup>('PyExc_StopAsyncIteration'); - - ffi.Pointer get PyExc_StopAsyncIteration => - _PyExc_StopAsyncIteration.value; - - set PyExc_StopAsyncIteration(ffi.Pointer value) => - _PyExc_StopAsyncIteration.value = value; - - late final ffi.Pointer> _PyExc_StopIteration = - _lookup>('PyExc_StopIteration'); - - ffi.Pointer get PyExc_StopIteration => _PyExc_StopIteration.value; - - set PyExc_StopIteration(ffi.Pointer value) => - _PyExc_StopIteration.value = value; - - late final ffi.Pointer> _PyExc_GeneratorExit = - _lookup>('PyExc_GeneratorExit'); - - ffi.Pointer get PyExc_GeneratorExit => _PyExc_GeneratorExit.value; - - set PyExc_GeneratorExit(ffi.Pointer value) => - _PyExc_GeneratorExit.value = value; - - late final ffi.Pointer> _PyExc_ArithmeticError = - _lookup>('PyExc_ArithmeticError'); - - ffi.Pointer get PyExc_ArithmeticError => - _PyExc_ArithmeticError.value; - - set PyExc_ArithmeticError(ffi.Pointer value) => - _PyExc_ArithmeticError.value = value; - - late final ffi.Pointer> _PyExc_LookupError = - _lookup>('PyExc_LookupError'); - - ffi.Pointer get PyExc_LookupError => _PyExc_LookupError.value; - - set PyExc_LookupError(ffi.Pointer value) => - _PyExc_LookupError.value = value; - - late final ffi.Pointer> _PyExc_AssertionError = - _lookup>('PyExc_AssertionError'); - - ffi.Pointer get PyExc_AssertionError => _PyExc_AssertionError.value; - - set PyExc_AssertionError(ffi.Pointer value) => - _PyExc_AssertionError.value = value; - - late final ffi.Pointer> _PyExc_AttributeError = - _lookup>('PyExc_AttributeError'); - - ffi.Pointer get PyExc_AttributeError => _PyExc_AttributeError.value; - - set PyExc_AttributeError(ffi.Pointer value) => - _PyExc_AttributeError.value = value; - - late final ffi.Pointer> _PyExc_BufferError = - _lookup>('PyExc_BufferError'); - - ffi.Pointer get PyExc_BufferError => _PyExc_BufferError.value; - - set PyExc_BufferError(ffi.Pointer value) => - _PyExc_BufferError.value = value; - - late final ffi.Pointer> _PyExc_EOFError = - _lookup>('PyExc_EOFError'); - - ffi.Pointer get PyExc_EOFError => _PyExc_EOFError.value; - - set PyExc_EOFError(ffi.Pointer value) => - _PyExc_EOFError.value = value; - - late final ffi.Pointer> _PyExc_FloatingPointError = - _lookup>('PyExc_FloatingPointError'); - - ffi.Pointer get PyExc_FloatingPointError => - _PyExc_FloatingPointError.value; - - set PyExc_FloatingPointError(ffi.Pointer value) => - _PyExc_FloatingPointError.value = value; - - late final ffi.Pointer> _PyExc_OSError = - _lookup>('PyExc_OSError'); - - ffi.Pointer get PyExc_OSError => _PyExc_OSError.value; - - set PyExc_OSError(ffi.Pointer value) => - _PyExc_OSError.value = value; - - late final ffi.Pointer> _PyExc_ImportError = - _lookup>('PyExc_ImportError'); - - ffi.Pointer get PyExc_ImportError => _PyExc_ImportError.value; - - set PyExc_ImportError(ffi.Pointer value) => - _PyExc_ImportError.value = value; - - late final ffi.Pointer> _PyExc_ModuleNotFoundError = - _lookup>('PyExc_ModuleNotFoundError'); - - ffi.Pointer get PyExc_ModuleNotFoundError => - _PyExc_ModuleNotFoundError.value; - - set PyExc_ModuleNotFoundError(ffi.Pointer value) => - _PyExc_ModuleNotFoundError.value = value; - - late final ffi.Pointer> _PyExc_IndexError = - _lookup>('PyExc_IndexError'); - - ffi.Pointer get PyExc_IndexError => _PyExc_IndexError.value; - - set PyExc_IndexError(ffi.Pointer value) => - _PyExc_IndexError.value = value; - - late final ffi.Pointer> _PyExc_KeyError = - _lookup>('PyExc_KeyError'); - - ffi.Pointer get PyExc_KeyError => _PyExc_KeyError.value; - - set PyExc_KeyError(ffi.Pointer value) => - _PyExc_KeyError.value = value; - - late final ffi.Pointer> _PyExc_KeyboardInterrupt = - _lookup>('PyExc_KeyboardInterrupt'); - - ffi.Pointer get PyExc_KeyboardInterrupt => - _PyExc_KeyboardInterrupt.value; - - set PyExc_KeyboardInterrupt(ffi.Pointer value) => - _PyExc_KeyboardInterrupt.value = value; - - late final ffi.Pointer> _PyExc_MemoryError = - _lookup>('PyExc_MemoryError'); - - ffi.Pointer get PyExc_MemoryError => _PyExc_MemoryError.value; - - set PyExc_MemoryError(ffi.Pointer value) => - _PyExc_MemoryError.value = value; - - late final ffi.Pointer> _PyExc_NameError = - _lookup>('PyExc_NameError'); - - ffi.Pointer get PyExc_NameError => _PyExc_NameError.value; - - set PyExc_NameError(ffi.Pointer value) => - _PyExc_NameError.value = value; - - late final ffi.Pointer> _PyExc_OverflowError = - _lookup>('PyExc_OverflowError'); - - ffi.Pointer get PyExc_OverflowError => _PyExc_OverflowError.value; - - set PyExc_OverflowError(ffi.Pointer value) => - _PyExc_OverflowError.value = value; - - late final ffi.Pointer> _PyExc_RuntimeError = - _lookup>('PyExc_RuntimeError'); - - ffi.Pointer get PyExc_RuntimeError => _PyExc_RuntimeError.value; - - set PyExc_RuntimeError(ffi.Pointer value) => - _PyExc_RuntimeError.value = value; - - late final ffi.Pointer> _PyExc_RecursionError = - _lookup>('PyExc_RecursionError'); - - ffi.Pointer get PyExc_RecursionError => _PyExc_RecursionError.value; - - set PyExc_RecursionError(ffi.Pointer value) => - _PyExc_RecursionError.value = value; - - late final ffi.Pointer> _PyExc_NotImplementedError = - _lookup>('PyExc_NotImplementedError'); - - ffi.Pointer get PyExc_NotImplementedError => - _PyExc_NotImplementedError.value; - - set PyExc_NotImplementedError(ffi.Pointer value) => - _PyExc_NotImplementedError.value = value; - - late final ffi.Pointer> _PyExc_SyntaxError = - _lookup>('PyExc_SyntaxError'); - - ffi.Pointer get PyExc_SyntaxError => _PyExc_SyntaxError.value; - - set PyExc_SyntaxError(ffi.Pointer value) => - _PyExc_SyntaxError.value = value; - - late final ffi.Pointer> _PyExc_IndentationError = - _lookup>('PyExc_IndentationError'); - - ffi.Pointer get PyExc_IndentationError => - _PyExc_IndentationError.value; - - set PyExc_IndentationError(ffi.Pointer value) => - _PyExc_IndentationError.value = value; - - late final ffi.Pointer> _PyExc_TabError = - _lookup>('PyExc_TabError'); - - ffi.Pointer get PyExc_TabError => _PyExc_TabError.value; - - set PyExc_TabError(ffi.Pointer value) => - _PyExc_TabError.value = value; - - late final ffi.Pointer> _PyExc_ReferenceError = - _lookup>('PyExc_ReferenceError'); - - ffi.Pointer get PyExc_ReferenceError => _PyExc_ReferenceError.value; - - set PyExc_ReferenceError(ffi.Pointer value) => - _PyExc_ReferenceError.value = value; - - late final ffi.Pointer> _PyExc_SystemError = - _lookup>('PyExc_SystemError'); - - ffi.Pointer get PyExc_SystemError => _PyExc_SystemError.value; - - set PyExc_SystemError(ffi.Pointer value) => - _PyExc_SystemError.value = value; - - late final ffi.Pointer> _PyExc_SystemExit = - _lookup>('PyExc_SystemExit'); - - ffi.Pointer get PyExc_SystemExit => _PyExc_SystemExit.value; - - set PyExc_SystemExit(ffi.Pointer value) => - _PyExc_SystemExit.value = value; - - late final ffi.Pointer> _PyExc_TypeError = - _lookup>('PyExc_TypeError'); - - ffi.Pointer get PyExc_TypeError => _PyExc_TypeError.value; - - set PyExc_TypeError(ffi.Pointer value) => - _PyExc_TypeError.value = value; - - late final ffi.Pointer> _PyExc_UnboundLocalError = - _lookup>('PyExc_UnboundLocalError'); - - ffi.Pointer get PyExc_UnboundLocalError => - _PyExc_UnboundLocalError.value; - - set PyExc_UnboundLocalError(ffi.Pointer value) => - _PyExc_UnboundLocalError.value = value; - - late final ffi.Pointer> _PyExc_UnicodeError = - _lookup>('PyExc_UnicodeError'); - - ffi.Pointer get PyExc_UnicodeError => _PyExc_UnicodeError.value; - - set PyExc_UnicodeError(ffi.Pointer value) => - _PyExc_UnicodeError.value = value; - - late final ffi.Pointer> _PyExc_UnicodeEncodeError = - _lookup>('PyExc_UnicodeEncodeError'); - - ffi.Pointer get PyExc_UnicodeEncodeError => - _PyExc_UnicodeEncodeError.value; - - set PyExc_UnicodeEncodeError(ffi.Pointer value) => - _PyExc_UnicodeEncodeError.value = value; - - late final ffi.Pointer> _PyExc_UnicodeDecodeError = - _lookup>('PyExc_UnicodeDecodeError'); - - ffi.Pointer get PyExc_UnicodeDecodeError => - _PyExc_UnicodeDecodeError.value; - - set PyExc_UnicodeDecodeError(ffi.Pointer value) => - _PyExc_UnicodeDecodeError.value = value; - - late final ffi.Pointer> _PyExc_UnicodeTranslateError = - _lookup>('PyExc_UnicodeTranslateError'); - - ffi.Pointer get PyExc_UnicodeTranslateError => - _PyExc_UnicodeTranslateError.value; - - set PyExc_UnicodeTranslateError(ffi.Pointer value) => - _PyExc_UnicodeTranslateError.value = value; - - late final ffi.Pointer> _PyExc_ValueError = - _lookup>('PyExc_ValueError'); - - ffi.Pointer get PyExc_ValueError => _PyExc_ValueError.value; - - set PyExc_ValueError(ffi.Pointer value) => - _PyExc_ValueError.value = value; - - late final ffi.Pointer> _PyExc_ZeroDivisionError = - _lookup>('PyExc_ZeroDivisionError'); - - ffi.Pointer get PyExc_ZeroDivisionError => - _PyExc_ZeroDivisionError.value; - - set PyExc_ZeroDivisionError(ffi.Pointer value) => - _PyExc_ZeroDivisionError.value = value; - - late final ffi.Pointer> _PyExc_BlockingIOError = - _lookup>('PyExc_BlockingIOError'); - - ffi.Pointer get PyExc_BlockingIOError => - _PyExc_BlockingIOError.value; - - set PyExc_BlockingIOError(ffi.Pointer value) => - _PyExc_BlockingIOError.value = value; - - late final ffi.Pointer> _PyExc_BrokenPipeError = - _lookup>('PyExc_BrokenPipeError'); - - ffi.Pointer get PyExc_BrokenPipeError => - _PyExc_BrokenPipeError.value; - - set PyExc_BrokenPipeError(ffi.Pointer value) => - _PyExc_BrokenPipeError.value = value; - - late final ffi.Pointer> _PyExc_ChildProcessError = - _lookup>('PyExc_ChildProcessError'); - - ffi.Pointer get PyExc_ChildProcessError => - _PyExc_ChildProcessError.value; - - set PyExc_ChildProcessError(ffi.Pointer value) => - _PyExc_ChildProcessError.value = value; - - late final ffi.Pointer> _PyExc_ConnectionError = - _lookup>('PyExc_ConnectionError'); - - ffi.Pointer get PyExc_ConnectionError => - _PyExc_ConnectionError.value; - - set PyExc_ConnectionError(ffi.Pointer value) => - _PyExc_ConnectionError.value = value; - - late final ffi.Pointer> _PyExc_ConnectionAbortedError = - _lookup>('PyExc_ConnectionAbortedError'); - - ffi.Pointer get PyExc_ConnectionAbortedError => - _PyExc_ConnectionAbortedError.value; - - set PyExc_ConnectionAbortedError(ffi.Pointer value) => - _PyExc_ConnectionAbortedError.value = value; - - late final ffi.Pointer> _PyExc_ConnectionRefusedError = - _lookup>('PyExc_ConnectionRefusedError'); - - ffi.Pointer get PyExc_ConnectionRefusedError => - _PyExc_ConnectionRefusedError.value; - - set PyExc_ConnectionRefusedError(ffi.Pointer value) => - _PyExc_ConnectionRefusedError.value = value; - - late final ffi.Pointer> _PyExc_ConnectionResetError = - _lookup>('PyExc_ConnectionResetError'); - - ffi.Pointer get PyExc_ConnectionResetError => - _PyExc_ConnectionResetError.value; - - set PyExc_ConnectionResetError(ffi.Pointer value) => - _PyExc_ConnectionResetError.value = value; - - late final ffi.Pointer> _PyExc_FileExistsError = - _lookup>('PyExc_FileExistsError'); - - ffi.Pointer get PyExc_FileExistsError => - _PyExc_FileExistsError.value; - - set PyExc_FileExistsError(ffi.Pointer value) => - _PyExc_FileExistsError.value = value; - - late final ffi.Pointer> _PyExc_FileNotFoundError = - _lookup>('PyExc_FileNotFoundError'); - - ffi.Pointer get PyExc_FileNotFoundError => - _PyExc_FileNotFoundError.value; - - set PyExc_FileNotFoundError(ffi.Pointer value) => - _PyExc_FileNotFoundError.value = value; - - late final ffi.Pointer> _PyExc_InterruptedError = - _lookup>('PyExc_InterruptedError'); - - ffi.Pointer get PyExc_InterruptedError => - _PyExc_InterruptedError.value; - - set PyExc_InterruptedError(ffi.Pointer value) => - _PyExc_InterruptedError.value = value; - - late final ffi.Pointer> _PyExc_IsADirectoryError = - _lookup>('PyExc_IsADirectoryError'); - - ffi.Pointer get PyExc_IsADirectoryError => - _PyExc_IsADirectoryError.value; - - set PyExc_IsADirectoryError(ffi.Pointer value) => - _PyExc_IsADirectoryError.value = value; - - late final ffi.Pointer> _PyExc_NotADirectoryError = - _lookup>('PyExc_NotADirectoryError'); - - ffi.Pointer get PyExc_NotADirectoryError => - _PyExc_NotADirectoryError.value; - - set PyExc_NotADirectoryError(ffi.Pointer value) => - _PyExc_NotADirectoryError.value = value; - - late final ffi.Pointer> _PyExc_PermissionError = - _lookup>('PyExc_PermissionError'); - - ffi.Pointer get PyExc_PermissionError => - _PyExc_PermissionError.value; - - set PyExc_PermissionError(ffi.Pointer value) => - _PyExc_PermissionError.value = value; - - late final ffi.Pointer> _PyExc_ProcessLookupError = - _lookup>('PyExc_ProcessLookupError'); - - ffi.Pointer get PyExc_ProcessLookupError => - _PyExc_ProcessLookupError.value; - - set PyExc_ProcessLookupError(ffi.Pointer value) => - _PyExc_ProcessLookupError.value = value; - - late final ffi.Pointer> _PyExc_TimeoutError = - _lookup>('PyExc_TimeoutError'); - - ffi.Pointer get PyExc_TimeoutError => _PyExc_TimeoutError.value; - - set PyExc_TimeoutError(ffi.Pointer value) => - _PyExc_TimeoutError.value = value; - - late final ffi.Pointer> _PyExc_EnvironmentError = - _lookup>('PyExc_EnvironmentError'); - - ffi.Pointer get PyExc_EnvironmentError => - _PyExc_EnvironmentError.value; - - set PyExc_EnvironmentError(ffi.Pointer value) => - _PyExc_EnvironmentError.value = value; - - late final ffi.Pointer> _PyExc_IOError = - _lookup>('PyExc_IOError'); - - ffi.Pointer get PyExc_IOError => _PyExc_IOError.value; - - set PyExc_IOError(ffi.Pointer value) => - _PyExc_IOError.value = value; - - late final ffi.Pointer> _PyExc_Warning = - _lookup>('PyExc_Warning'); - - ffi.Pointer get PyExc_Warning => _PyExc_Warning.value; - - set PyExc_Warning(ffi.Pointer value) => - _PyExc_Warning.value = value; - - late final ffi.Pointer> _PyExc_UserWarning = - _lookup>('PyExc_UserWarning'); - - ffi.Pointer get PyExc_UserWarning => _PyExc_UserWarning.value; - - set PyExc_UserWarning(ffi.Pointer value) => - _PyExc_UserWarning.value = value; - - late final ffi.Pointer> _PyExc_DeprecationWarning = - _lookup>('PyExc_DeprecationWarning'); - - ffi.Pointer get PyExc_DeprecationWarning => - _PyExc_DeprecationWarning.value; - - set PyExc_DeprecationWarning(ffi.Pointer value) => - _PyExc_DeprecationWarning.value = value; - - late final ffi.Pointer> - _PyExc_PendingDeprecationWarning = - _lookup>('PyExc_PendingDeprecationWarning'); - - ffi.Pointer get PyExc_PendingDeprecationWarning => - _PyExc_PendingDeprecationWarning.value; - - set PyExc_PendingDeprecationWarning(ffi.Pointer value) => - _PyExc_PendingDeprecationWarning.value = value; - - late final ffi.Pointer> _PyExc_SyntaxWarning = - _lookup>('PyExc_SyntaxWarning'); - - ffi.Pointer get PyExc_SyntaxWarning => _PyExc_SyntaxWarning.value; - - set PyExc_SyntaxWarning(ffi.Pointer value) => - _PyExc_SyntaxWarning.value = value; - - late final ffi.Pointer> _PyExc_RuntimeWarning = - _lookup>('PyExc_RuntimeWarning'); - - ffi.Pointer get PyExc_RuntimeWarning => _PyExc_RuntimeWarning.value; - - set PyExc_RuntimeWarning(ffi.Pointer value) => - _PyExc_RuntimeWarning.value = value; - - late final ffi.Pointer> _PyExc_FutureWarning = - _lookup>('PyExc_FutureWarning'); - - ffi.Pointer get PyExc_FutureWarning => _PyExc_FutureWarning.value; - - set PyExc_FutureWarning(ffi.Pointer value) => - _PyExc_FutureWarning.value = value; - - late final ffi.Pointer> _PyExc_ImportWarning = - _lookup>('PyExc_ImportWarning'); - - ffi.Pointer get PyExc_ImportWarning => _PyExc_ImportWarning.value; - - set PyExc_ImportWarning(ffi.Pointer value) => - _PyExc_ImportWarning.value = value; - - late final ffi.Pointer> _PyExc_UnicodeWarning = - _lookup>('PyExc_UnicodeWarning'); - - ffi.Pointer get PyExc_UnicodeWarning => _PyExc_UnicodeWarning.value; - - set PyExc_UnicodeWarning(ffi.Pointer value) => - _PyExc_UnicodeWarning.value = value; - - late final ffi.Pointer> _PyExc_BytesWarning = - _lookup>('PyExc_BytesWarning'); - - ffi.Pointer get PyExc_BytesWarning => _PyExc_BytesWarning.value; - - set PyExc_BytesWarning(ffi.Pointer value) => - _PyExc_BytesWarning.value = value; - - late final ffi.Pointer> _PyExc_EncodingWarning = - _lookup>('PyExc_EncodingWarning'); - - ffi.Pointer get PyExc_EncodingWarning => - _PyExc_EncodingWarning.value; - - set PyExc_EncodingWarning(ffi.Pointer value) => - _PyExc_EncodingWarning.value = value; - - late final ffi.Pointer> _PyExc_ResourceWarning = - _lookup>('PyExc_ResourceWarning'); - - ffi.Pointer get PyExc_ResourceWarning => - _PyExc_ResourceWarning.value; - - set PyExc_ResourceWarning(ffi.Pointer value) => - _PyExc_ResourceWarning.value = value; - - int PyErr_BadArgument() { - return _PyErr_BadArgument(); - } - - late final _PyErr_BadArgumentPtr = - _lookup>('PyErr_BadArgument'); - late final _PyErr_BadArgument = - _PyErr_BadArgumentPtr.asFunction(); - - ffi.Pointer PyErr_NoMemory() { - return _PyErr_NoMemory(); - } - - late final _PyErr_NoMemoryPtr = - _lookup Function()>>( - 'PyErr_NoMemory'); - late final _PyErr_NoMemory = - _PyErr_NoMemoryPtr.asFunction Function()>(); - - ffi.Pointer PyErr_SetFromErrno( - ffi.Pointer arg0, - ) { - return _PyErr_SetFromErrno( - arg0, - ); - } - - late final _PyErr_SetFromErrnoPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyErr_SetFromErrno'); - late final _PyErr_SetFromErrno = _PyErr_SetFromErrnoPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyErr_SetFromErrnoWithFilenameObject( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyErr_SetFromErrnoWithFilenameObject( - arg0, - arg1, - ); - } - - late final _PyErr_SetFromErrnoWithFilenameObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyErr_SetFromErrnoWithFilenameObject'); - late final _PyErr_SetFromErrnoWithFilenameObject = - _PyErr_SetFromErrnoWithFilenameObjectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyErr_SetFromErrnoWithFilenameObjects( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyErr_SetFromErrnoWithFilenameObjects( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_SetFromErrnoWithFilenameObjectsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyErr_SetFromErrnoWithFilenameObjects'); - late final _PyErr_SetFromErrnoWithFilenameObjects = - _PyErr_SetFromErrnoWithFilenameObjectsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyErr_SetFromErrnoWithFilename( - ffi.Pointer exc, - ffi.Pointer filename, - ) { - return _PyErr_SetFromErrnoWithFilename( - exc, - filename, - ); - } - - late final _PyErr_SetFromErrnoWithFilenamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyErr_SetFromErrnoWithFilename'); - late final _PyErr_SetFromErrnoWithFilename = - _PyErr_SetFromErrnoWithFilenamePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyErr_Format( - ffi.Pointer exception, - ffi.Pointer format, - ) { - return _PyErr_Format( - exception, - format, - ); - } - - late final _PyErr_FormatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyErr_Format'); - late final _PyErr_Format = _PyErr_FormatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyErr_FormatV( - ffi.Pointer exception, - ffi.Pointer format, - va_list vargs, - ) { - return _PyErr_FormatV( - exception, - format, - vargs, - ); - } - - late final _PyErr_FormatVPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, va_list)>>('PyErr_FormatV'); - late final _PyErr_FormatV = _PyErr_FormatVPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, va_list)>(); - - ffi.Pointer PyErr_SetImportErrorSubclass( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return _PyErr_SetImportErrorSubclass( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _PyErr_SetImportErrorSubclassPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyErr_SetImportErrorSubclass'); - late final _PyErr_SetImportErrorSubclass = - _PyErr_SetImportErrorSubclassPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyErr_SetImportError( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyErr_SetImportError( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_SetImportErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyErr_SetImportError'); - late final _PyErr_SetImportError = _PyErr_SetImportErrorPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - void PyErr_BadInternalCall() { - return _PyErr_BadInternalCall1(); - } - - late final _PyErr_BadInternalCallPtr = - _lookup>('PyErr_BadInternalCall'); - late final _PyErr_BadInternalCall1 = - _PyErr_BadInternalCallPtr.asFunction(); - - void _PyErr_BadInternalCall( - ffi.Pointer filename, - int lineno, - ) { - return __PyErr_BadInternalCall( - filename, - lineno, - ); - } - - late final __PyErr_BadInternalCallPtr = _lookup< - ffi - .NativeFunction, ffi.Int)>>( - '_PyErr_BadInternalCall'); - late final __PyErr_BadInternalCall = __PyErr_BadInternalCallPtr - .asFunction, int)>(); - - ffi.Pointer PyErr_NewException( - ffi.Pointer name, - ffi.Pointer base, - ffi.Pointer dict, - ) { - return _PyErr_NewException( - name, - base, - dict, - ); - } - - late final _PyErr_NewExceptionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyErr_NewException'); - late final _PyErr_NewException = _PyErr_NewExceptionPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyErr_NewExceptionWithDoc( - ffi.Pointer name, - ffi.Pointer doc, - ffi.Pointer base, - ffi.Pointer dict, - ) { - return _PyErr_NewExceptionWithDoc( - name, - doc, - base, - dict, - ); - } - - late final _PyErr_NewExceptionWithDocPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyErr_NewExceptionWithDoc'); - late final _PyErr_NewExceptionWithDoc = - _PyErr_NewExceptionWithDocPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - void PyErr_WriteUnraisable( - ffi.Pointer arg0, - ) { - return _PyErr_WriteUnraisable( - arg0, - ); - } - - late final _PyErr_WriteUnraisablePtr = - _lookup)>>( - 'PyErr_WriteUnraisable'); - late final _PyErr_WriteUnraisable = _PyErr_WriteUnraisablePtr.asFunction< - void Function(ffi.Pointer)>(); - - int PyErr_CheckSignals() { - return _PyErr_CheckSignals1(); - } - - late final _PyErr_CheckSignalsPtr = - _lookup>('PyErr_CheckSignals'); - late final _PyErr_CheckSignals1 = - _PyErr_CheckSignalsPtr.asFunction(); - - void PyErr_SetInterrupt() { - return _PyErr_SetInterrupt(); - } - - late final _PyErr_SetInterruptPtr = - _lookup>('PyErr_SetInterrupt'); - late final _PyErr_SetInterrupt = - _PyErr_SetInterruptPtr.asFunction(); - - int PyErr_SetInterruptEx( - int signum, - ) { - return _PyErr_SetInterruptEx( - signum, - ); - } - - late final _PyErr_SetInterruptExPtr = - _lookup>( - 'PyErr_SetInterruptEx'); - late final _PyErr_SetInterruptEx = - _PyErr_SetInterruptExPtr.asFunction(); - - void PyErr_SyntaxLocation( - ffi.Pointer filename, - int lineno, - ) { - return _PyErr_SyntaxLocation( - filename, - lineno, - ); - } - - late final _PyErr_SyntaxLocationPtr = _lookup< - ffi - .NativeFunction, ffi.Int)>>( - 'PyErr_SyntaxLocation'); - late final _PyErr_SyntaxLocation = _PyErr_SyntaxLocationPtr.asFunction< - void Function(ffi.Pointer, int)>(); - - void PyErr_SyntaxLocationEx( - ffi.Pointer filename, - int lineno, - int col_offset, - ) { - return _PyErr_SyntaxLocationEx( - filename, - lineno, - col_offset, - ); - } - - late final _PyErr_SyntaxLocationExPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Int, - ffi.Int)>>('PyErr_SyntaxLocationEx'); - late final _PyErr_SyntaxLocationEx = _PyErr_SyntaxLocationExPtr.asFunction< - void Function(ffi.Pointer, int, int)>(); - - ffi.Pointer PyErr_ProgramText( - ffi.Pointer filename, - int lineno, - ) { - return _PyErr_ProgramText( - filename, - lineno, - ); - } - - late final _PyErr_ProgramTextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyErr_ProgramText'); - late final _PyErr_ProgramText = _PyErr_ProgramTextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyUnicodeDecodeError_Create( - ffi.Pointer encoding, - ffi.Pointer object, - int length, - int start, - int end, - ffi.Pointer reason, - ) { - return _PyUnicodeDecodeError_Create( - encoding, - object, - length, - start, - end, - reason, - ); - } - - late final _PyUnicodeDecodeError_CreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - Py_ssize_t, - Py_ssize_t, - Py_ssize_t, - ffi.Pointer)>>('PyUnicodeDecodeError_Create'); - late final _PyUnicodeDecodeError_Create = - _PyUnicodeDecodeError_CreatePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, int, int, int, ffi.Pointer)>(); - - ffi.Pointer PyUnicodeEncodeError_GetEncoding( - ffi.Pointer arg0, - ) { - return _PyUnicodeEncodeError_GetEncoding( - arg0, - ); - } - - late final _PyUnicodeEncodeError_GetEncodingPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeEncodeError_GetEncoding'); - late final _PyUnicodeEncodeError_GetEncoding = - _PyUnicodeEncodeError_GetEncodingPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicodeDecodeError_GetEncoding( - ffi.Pointer arg0, - ) { - return _PyUnicodeDecodeError_GetEncoding( - arg0, - ); - } - - late final _PyUnicodeDecodeError_GetEncodingPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeDecodeError_GetEncoding'); - late final _PyUnicodeDecodeError_GetEncoding = - _PyUnicodeDecodeError_GetEncodingPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicodeEncodeError_GetObject( - ffi.Pointer arg0, - ) { - return _PyUnicodeEncodeError_GetObject( - arg0, - ); - } - - late final _PyUnicodeEncodeError_GetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeEncodeError_GetObject'); - late final _PyUnicodeEncodeError_GetObject = - _PyUnicodeEncodeError_GetObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicodeDecodeError_GetObject( - ffi.Pointer arg0, - ) { - return _PyUnicodeDecodeError_GetObject( - arg0, - ); - } - - late final _PyUnicodeDecodeError_GetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeDecodeError_GetObject'); - late final _PyUnicodeDecodeError_GetObject = - _PyUnicodeDecodeError_GetObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicodeTranslateError_GetObject( - ffi.Pointer arg0, - ) { - return _PyUnicodeTranslateError_GetObject( - arg0, - ); - } - - late final _PyUnicodeTranslateError_GetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeTranslateError_GetObject'); - late final _PyUnicodeTranslateError_GetObject = - _PyUnicodeTranslateError_GetObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyUnicodeEncodeError_GetStart( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicodeEncodeError_GetStart( - arg0, - arg1, - ); - } - - late final _PyUnicodeEncodeError_GetStartPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeEncodeError_GetStart'); - late final _PyUnicodeEncodeError_GetStart = - _PyUnicodeEncodeError_GetStartPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeDecodeError_GetStart( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicodeDecodeError_GetStart( - arg0, - arg1, - ); - } - - late final _PyUnicodeDecodeError_GetStartPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeDecodeError_GetStart'); - late final _PyUnicodeDecodeError_GetStart = - _PyUnicodeDecodeError_GetStartPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeTranslateError_GetStart( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicodeTranslateError_GetStart( - arg0, - arg1, - ); - } - - late final _PyUnicodeTranslateError_GetStartPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeTranslateError_GetStart'); - late final _PyUnicodeTranslateError_GetStart = - _PyUnicodeTranslateError_GetStartPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeEncodeError_SetStart( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnicodeEncodeError_SetStart( - arg0, - arg1, - ); - } - - late final _PyUnicodeEncodeError_SetStartPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicodeEncodeError_SetStart'); - late final _PyUnicodeEncodeError_SetStart = _PyUnicodeEncodeError_SetStartPtr - .asFunction, int)>(); - - int PyUnicodeDecodeError_SetStart( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnicodeDecodeError_SetStart( - arg0, - arg1, - ); - } - - late final _PyUnicodeDecodeError_SetStartPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicodeDecodeError_SetStart'); - late final _PyUnicodeDecodeError_SetStart = _PyUnicodeDecodeError_SetStartPtr - .asFunction, int)>(); - - int PyUnicodeTranslateError_SetStart( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnicodeTranslateError_SetStart( - arg0, - arg1, - ); - } - - late final _PyUnicodeTranslateError_SetStartPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicodeTranslateError_SetStart'); - late final _PyUnicodeTranslateError_SetStart = - _PyUnicodeTranslateError_SetStartPtr.asFunction< - int Function(ffi.Pointer, int)>(); - - int PyUnicodeEncodeError_GetEnd( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicodeEncodeError_GetEnd( - arg0, - arg1, - ); - } - - late final _PyUnicodeEncodeError_GetEndPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeEncodeError_GetEnd'); - late final _PyUnicodeEncodeError_GetEnd = - _PyUnicodeEncodeError_GetEndPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeDecodeError_GetEnd( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicodeDecodeError_GetEnd( - arg0, - arg1, - ); - } - - late final _PyUnicodeDecodeError_GetEndPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeDecodeError_GetEnd'); - late final _PyUnicodeDecodeError_GetEnd = - _PyUnicodeDecodeError_GetEndPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeTranslateError_GetEnd( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyUnicodeTranslateError_GetEnd( - arg0, - arg1, - ); - } - - late final _PyUnicodeTranslateError_GetEndPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeTranslateError_GetEnd'); - late final _PyUnicodeTranslateError_GetEnd = - _PyUnicodeTranslateError_GetEndPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeEncodeError_SetEnd( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnicodeEncodeError_SetEnd( - arg0, - arg1, - ); - } - - late final _PyUnicodeEncodeError_SetEndPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicodeEncodeError_SetEnd'); - late final _PyUnicodeEncodeError_SetEnd = _PyUnicodeEncodeError_SetEndPtr - .asFunction, int)>(); - - int PyUnicodeDecodeError_SetEnd( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnicodeDecodeError_SetEnd( - arg0, - arg1, - ); - } - - late final _PyUnicodeDecodeError_SetEndPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicodeDecodeError_SetEnd'); - late final _PyUnicodeDecodeError_SetEnd = _PyUnicodeDecodeError_SetEndPtr - .asFunction, int)>(); - - int PyUnicodeTranslateError_SetEnd( - ffi.Pointer arg0, - int arg1, - ) { - return _PyUnicodeTranslateError_SetEnd( - arg0, - arg1, - ); - } - - late final _PyUnicodeTranslateError_SetEndPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PyUnicodeTranslateError_SetEnd'); - late final _PyUnicodeTranslateError_SetEnd = - _PyUnicodeTranslateError_SetEndPtr.asFunction< - int Function(ffi.Pointer, int)>(); - - ffi.Pointer PyUnicodeEncodeError_GetReason( - ffi.Pointer arg0, - ) { - return _PyUnicodeEncodeError_GetReason( - arg0, - ); - } - - late final _PyUnicodeEncodeError_GetReasonPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeEncodeError_GetReason'); - late final _PyUnicodeEncodeError_GetReason = - _PyUnicodeEncodeError_GetReasonPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicodeDecodeError_GetReason( - ffi.Pointer arg0, - ) { - return _PyUnicodeDecodeError_GetReason( - arg0, - ); - } - - late final _PyUnicodeDecodeError_GetReasonPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeDecodeError_GetReason'); - late final _PyUnicodeDecodeError_GetReason = - _PyUnicodeDecodeError_GetReasonPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyUnicodeTranslateError_GetReason( - ffi.Pointer arg0, - ) { - return _PyUnicodeTranslateError_GetReason( - arg0, - ); - } - - late final _PyUnicodeTranslateError_GetReasonPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyUnicodeTranslateError_GetReason'); - late final _PyUnicodeTranslateError_GetReason = - _PyUnicodeTranslateError_GetReasonPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyUnicodeEncodeError_SetReason( - ffi.Pointer exc, - ffi.Pointer reason, - ) { - return _PyUnicodeEncodeError_SetReason( - exc, - reason, - ); - } - - late final _PyUnicodeEncodeError_SetReasonPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeEncodeError_SetReason'); - late final _PyUnicodeEncodeError_SetReason = - _PyUnicodeEncodeError_SetReasonPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeDecodeError_SetReason( - ffi.Pointer exc, - ffi.Pointer reason, - ) { - return _PyUnicodeDecodeError_SetReason( - exc, - reason, - ); - } - - late final _PyUnicodeDecodeError_SetReasonPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeDecodeError_SetReason'); - late final _PyUnicodeDecodeError_SetReason = - _PyUnicodeDecodeError_SetReasonPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyUnicodeTranslateError_SetReason( - ffi.Pointer exc, - ffi.Pointer reason, - ) { - return _PyUnicodeTranslateError_SetReason( - exc, - reason, - ); - } - - late final _PyUnicodeTranslateError_SetReasonPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyUnicodeTranslateError_SetReason'); - late final _PyUnicodeTranslateError_SetReason = - _PyUnicodeTranslateError_SetReasonPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyOS_snprintf( - ffi.Pointer str, - int size, - ffi.Pointer format, - ) { - return _PyOS_snprintf( - str, - size, - format, - ); - } - - late final _PyOS_snprintfPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Size, - ffi.Pointer)>>('PyOS_snprintf'); - late final _PyOS_snprintf = _PyOS_snprintfPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - int PyOS_vsnprintf( - ffi.Pointer str, - int size, - ffi.Pointer format, - va_list va, - ) { - return _PyOS_vsnprintf( - str, - size, - format, - va, - ); - } - - late final _PyOS_vsnprintfPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Size, - ffi.Pointer, va_list)>>('PyOS_vsnprintf'); - late final _PyOS_vsnprintf = _PyOS_vsnprintfPtr.asFunction< - int Function( - ffi.Pointer, int, ffi.Pointer, va_list)>(); - - void _PyErr_SetKeyError( - ffi.Pointer arg0, - ) { - return __PyErr_SetKeyError( - arg0, - ); - } - - late final __PyErr_SetKeyErrorPtr = - _lookup)>>( - '_PyErr_SetKeyError'); - late final __PyErr_SetKeyError = - __PyErr_SetKeyErrorPtr.asFunction)>(); - - ffi.Pointer<_PyErr_StackItem> _PyErr_GetTopmostException( - ffi.Pointer tstate, - ) { - return __PyErr_GetTopmostException( - tstate, - ); - } - - late final __PyErr_GetTopmostExceptionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer<_PyErr_StackItem> Function( - ffi.Pointer)>>('_PyErr_GetTopmostException'); - late final __PyErr_GetTopmostException = - __PyErr_GetTopmostExceptionPtr.asFunction< - ffi.Pointer<_PyErr_StackItem> Function(ffi.Pointer)>(); - - ffi.Pointer _PyErr_GetHandledException( - ffi.Pointer arg0, - ) { - return __PyErr_GetHandledException( - arg0, - ); - } - - late final __PyErr_GetHandledExceptionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyErr_GetHandledException'); - late final __PyErr_GetHandledException = __PyErr_GetHandledExceptionPtr - .asFunction Function(ffi.Pointer)>(); - - void _PyErr_SetHandledException( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyErr_SetHandledException( - arg0, - arg1, - ); - } - - late final __PyErr_SetHandledExceptionPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('_PyErr_SetHandledException'); - late final __PyErr_SetHandledException = - __PyErr_SetHandledExceptionPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - void _PyErr_GetExcInfo( - ffi.Pointer arg0, - ffi.Pointer> arg1, - ffi.Pointer> arg2, - ffi.Pointer> arg3, - ) { - return __PyErr_GetExcInfo( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyErr_GetExcInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>>('_PyErr_GetExcInfo'); - late final __PyErr_GetExcInfo = __PyErr_GetExcInfoPtr.asFunction< - void Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>(); - - void _PyErr_ChainExceptions( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return __PyErr_ChainExceptions( - arg0, - arg1, - arg2, - ); - } - - late final __PyErr_ChainExceptionsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('_PyErr_ChainExceptions'); - late final __PyErr_ChainExceptions = __PyErr_ChainExceptionsPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - void _PyErr_ChainExceptions1( - ffi.Pointer arg0, - ) { - return __PyErr_ChainExceptions1( - arg0, - ); - } - - late final __PyErr_ChainExceptions1Ptr = - _lookup)>>( - '_PyErr_ChainExceptions1'); - late final __PyErr_ChainExceptions1 = __PyErr_ChainExceptions1Ptr - .asFunction)>(); - - ffi.Pointer _PyErr_FormatFromCause( - ffi.Pointer exception, - ffi.Pointer format, - ) { - return __PyErr_FormatFromCause( - exception, - format, - ); - } - - late final __PyErr_FormatFromCausePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyErr_FormatFromCause'); - late final __PyErr_FormatFromCause = __PyErr_FormatFromCausePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int _PyException_AddNote( - ffi.Pointer exc, - ffi.Pointer note, - ) { - return __PyException_AddNote( - exc, - note, - ); - } - - late final __PyException_AddNotePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyException_AddNote'); - late final __PyException_AddNote = __PyException_AddNotePtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer PyUnstable_Exc_PrepReraiseStar( - ffi.Pointer orig, - ffi.Pointer excs, - ) { - return _PyUnstable_Exc_PrepReraiseStar( - orig, - excs, - ); - } - - late final _PyUnstable_Exc_PrepReraiseStarPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyUnstable_Exc_PrepReraiseStar'); - late final _PyUnstable_Exc_PrepReraiseStar = - _PyUnstable_Exc_PrepReraiseStarPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PySignal_SetWakeupFd( - int fd, - ) { - return _PySignal_SetWakeupFd( - fd, - ); - } - - late final _PySignal_SetWakeupFdPtr = - _lookup>( - 'PySignal_SetWakeupFd'); - late final _PySignal_SetWakeupFd = - _PySignal_SetWakeupFdPtr.asFunction(); - - int _PyErr_CheckSignals() { - return __PyErr_CheckSignals(); - } - - late final __PyErr_CheckSignalsPtr = - _lookup>('_PyErr_CheckSignals'); - late final __PyErr_CheckSignals = - __PyErr_CheckSignalsPtr.asFunction(); - - void PyErr_SyntaxLocationObject( - ffi.Pointer filename, - int lineno, - int col_offset, - ) { - return _PyErr_SyntaxLocationObject( - filename, - lineno, - col_offset, - ); - } - - late final _PyErr_SyntaxLocationObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Int, - ffi.Int)>>('PyErr_SyntaxLocationObject'); - late final _PyErr_SyntaxLocationObject = _PyErr_SyntaxLocationObjectPtr - .asFunction, int, int)>(); - - void PyErr_RangedSyntaxLocationObject( - ffi.Pointer filename, - int lineno, - int col_offset, - int end_lineno, - int end_col_offset, - ) { - return _PyErr_RangedSyntaxLocationObject( - filename, - lineno, - col_offset, - end_lineno, - end_col_offset, - ); - } - - late final _PyErr_RangedSyntaxLocationObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Int, ffi.Int, ffi.Int, - ffi.Int)>>('PyErr_RangedSyntaxLocationObject'); - late final _PyErr_RangedSyntaxLocationObject = - _PyErr_RangedSyntaxLocationObjectPtr.asFunction< - void Function(ffi.Pointer, int, int, int, int)>(); - - ffi.Pointer PyErr_ProgramTextObject( - ffi.Pointer filename, - int lineno, - ) { - return _PyErr_ProgramTextObject( - filename, - lineno, - ); - } - - late final _PyErr_ProgramTextObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyErr_ProgramTextObject'); - late final _PyErr_ProgramTextObject = _PyErr_ProgramTextObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer _PyErr_ProgramDecodedTextObject( - ffi.Pointer filename, - int lineno, - ffi.Pointer encoding, - ) { - return __PyErr_ProgramDecodedTextObject( - filename, - lineno, - encoding, - ); - } - - late final __PyErr_ProgramDecodedTextObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Int, - ffi.Pointer)>>('_PyErr_ProgramDecodedTextObject'); - late final __PyErr_ProgramDecodedTextObject = - __PyErr_ProgramDecodedTextObjectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer _PyUnicodeTranslateError_Create( - ffi.Pointer object, - int start, - int end, - ffi.Pointer reason, - ) { - return __PyUnicodeTranslateError_Create( - object, - start, - end, - reason, - ); - } - - late final __PyUnicodeTranslateError_CreatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - Py_ssize_t, - ffi.Pointer)>>('_PyUnicodeTranslateError_Create'); - late final __PyUnicodeTranslateError_Create = - __PyUnicodeTranslateError_CreatePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, int, ffi.Pointer)>(); - - void _PyErr_WriteUnraisableMsg( - ffi.Pointer err_msg, - ffi.Pointer obj, - ) { - return __PyErr_WriteUnraisableMsg( - err_msg, - obj, - ); - } - - late final __PyErr_WriteUnraisableMsgPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('_PyErr_WriteUnraisableMsg'); - late final __PyErr_WriteUnraisableMsg = - __PyErr_WriteUnraisableMsgPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - void _Py_FatalErrorFunc( - ffi.Pointer func, - ffi.Pointer message, - ) { - return __Py_FatalErrorFunc( - func, - message, - ); - } - - late final __Py_FatalErrorFuncPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('_Py_FatalErrorFunc'); - late final __Py_FatalErrorFunc = __Py_FatalErrorFuncPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - void _Py_FatalErrorFormat( - ffi.Pointer func, - ffi.Pointer format, - ) { - return __Py_FatalErrorFormat( - func, - format, - ); - } - - late final __Py_FatalErrorFormatPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>('_Py_FatalErrorFormat'); - late final __Py_FatalErrorFormat = __Py_FatalErrorFormatPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyErr_SetImportErrorWithNameFrom( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return __PyErr_SetImportErrorWithNameFrom( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyErr_SetImportErrorWithNameFromPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyErr_SetImportErrorWithNameFrom'); - late final __PyErr_SetImportErrorWithNameFrom = - __PyErr_SetImportErrorWithNameFromPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyLong_FromLong( - int arg0, - ) { - return _PyLong_FromLong( - arg0, - ); - } - - late final _PyLong_FromLongPtr = - _lookup Function(ffi.Long)>>( - 'PyLong_FromLong'); - late final _PyLong_FromLong = - _PyLong_FromLongPtr.asFunction Function(int)>(); - - ffi.Pointer PyLong_FromUnsignedLong( - int arg0, - ) { - return _PyLong_FromUnsignedLong( - arg0, - ); - } - - late final _PyLong_FromUnsignedLongPtr = _lookup< - ffi.NativeFunction Function(ffi.UnsignedLong)>>( - 'PyLong_FromUnsignedLong'); - late final _PyLong_FromUnsignedLong = _PyLong_FromUnsignedLongPtr.asFunction< - ffi.Pointer Function(int)>(); - - ffi.Pointer PyLong_FromSize_t( - int arg0, - ) { - return _PyLong_FromSize_t( - arg0, - ); - } - - late final _PyLong_FromSize_tPtr = - _lookup Function(ffi.Size)>>( - 'PyLong_FromSize_t'); - late final _PyLong_FromSize_t = - _PyLong_FromSize_tPtr.asFunction Function(int)>(); - - ffi.Pointer PyLong_FromSsize_t( - int arg0, - ) { - return _PyLong_FromSsize_t( - arg0, - ); - } - - late final _PyLong_FromSsize_tPtr = - _lookup Function(Py_ssize_t)>>( - 'PyLong_FromSsize_t'); - late final _PyLong_FromSsize_t = - _PyLong_FromSsize_tPtr.asFunction Function(int)>(); - - ffi.Pointer PyLong_FromDouble( - double arg0, - ) { - return _PyLong_FromDouble( - arg0, - ); - } - - late final _PyLong_FromDoublePtr = - _lookup Function(ffi.Double)>>( - 'PyLong_FromDouble'); - late final _PyLong_FromDouble = _PyLong_FromDoublePtr.asFunction< - ffi.Pointer Function(double)>(); - - int PyLong_AsLong( - ffi.Pointer arg0, - ) { - return _PyLong_AsLong( - arg0, - ); - } - - late final _PyLong_AsLongPtr = - _lookup)>>( - 'PyLong_AsLong'); - late final _PyLong_AsLong = - _PyLong_AsLongPtr.asFunction)>(); - - int PyLong_AsLongAndOverflow( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyLong_AsLongAndOverflow( - arg0, - arg1, - ); - } - - late final _PyLong_AsLongAndOverflowPtr = _lookup< - ffi.NativeFunction< - ffi.Long Function(ffi.Pointer, - ffi.Pointer)>>('PyLong_AsLongAndOverflow'); - late final _PyLong_AsLongAndOverflow = _PyLong_AsLongAndOverflowPtr - .asFunction, ffi.Pointer)>(); - - int PyLong_AsSsize_t( - ffi.Pointer arg0, - ) { - return _PyLong_AsSsize_t( - arg0, - ); - } - - late final _PyLong_AsSsize_tPtr = - _lookup)>>( - 'PyLong_AsSsize_t'); - late final _PyLong_AsSsize_t = - _PyLong_AsSsize_tPtr.asFunction)>(); - - int PyLong_AsSize_t( - ffi.Pointer arg0, - ) { - return _PyLong_AsSize_t( - arg0, - ); - } - - late final _PyLong_AsSize_tPtr = - _lookup)>>( - 'PyLong_AsSize_t'); - late final _PyLong_AsSize_t = - _PyLong_AsSize_tPtr.asFunction)>(); - - int PyLong_AsUnsignedLong( - ffi.Pointer arg0, - ) { - return _PyLong_AsUnsignedLong( - arg0, - ); - } - - late final _PyLong_AsUnsignedLongPtr = _lookup< - ffi.NativeFunction)>>( - 'PyLong_AsUnsignedLong'); - late final _PyLong_AsUnsignedLong = _PyLong_AsUnsignedLongPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyLong_AsUnsignedLongMask( - ffi.Pointer arg0, - ) { - return _PyLong_AsUnsignedLongMask( - arg0, - ); - } - - late final _PyLong_AsUnsignedLongMaskPtr = _lookup< - ffi.NativeFunction)>>( - 'PyLong_AsUnsignedLongMask'); - late final _PyLong_AsUnsignedLongMask = _PyLong_AsUnsignedLongMaskPtr - .asFunction)>(); - - ffi.Pointer PyLong_GetInfo() { - return _PyLong_GetInfo(); - } - - late final _PyLong_GetInfoPtr = - _lookup Function()>>( - 'PyLong_GetInfo'); - late final _PyLong_GetInfo = - _PyLong_GetInfoPtr.asFunction Function()>(); - - double PyLong_AsDouble( - ffi.Pointer arg0, - ) { - return _PyLong_AsDouble( - arg0, - ); - } - - late final _PyLong_AsDoublePtr = - _lookup)>>( - 'PyLong_AsDouble'); - late final _PyLong_AsDouble = - _PyLong_AsDoublePtr.asFunction)>(); - - ffi.Pointer PyLong_FromVoidPtr( - ffi.Pointer arg0, - ) { - return _PyLong_FromVoidPtr( - arg0, - ); - } - - late final _PyLong_FromVoidPtrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyLong_FromVoidPtr'); - late final _PyLong_FromVoidPtr = _PyLong_FromVoidPtrPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyLong_AsVoidPtr( - ffi.Pointer arg0, - ) { - return _PyLong_AsVoidPtr( - arg0, - ); - } - - late final _PyLong_AsVoidPtrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyLong_AsVoidPtr'); - late final _PyLong_AsVoidPtr = _PyLong_AsVoidPtrPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyLong_FromLongLong( - int arg0, - ) { - return _PyLong_FromLongLong( - arg0, - ); - } - - late final _PyLong_FromLongLongPtr = - _lookup Function(ffi.LongLong)>>( - 'PyLong_FromLongLong'); - late final _PyLong_FromLongLong = - _PyLong_FromLongLongPtr.asFunction Function(int)>(); - - ffi.Pointer PyLong_FromUnsignedLongLong( - int arg0, - ) { - return _PyLong_FromUnsignedLongLong( - arg0, - ); - } - - late final _PyLong_FromUnsignedLongLongPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.UnsignedLongLong)>>('PyLong_FromUnsignedLongLong'); - late final _PyLong_FromUnsignedLongLong = _PyLong_FromUnsignedLongLongPtr - .asFunction Function(int)>(); - - int PyLong_AsLongLong( - ffi.Pointer arg0, - ) { - return _PyLong_AsLongLong( - arg0, - ); - } - - late final _PyLong_AsLongLongPtr = - _lookup)>>( - 'PyLong_AsLongLong'); - late final _PyLong_AsLongLong = - _PyLong_AsLongLongPtr.asFunction)>(); - - int PyLong_AsUnsignedLongLong( - ffi.Pointer arg0, - ) { - return _PyLong_AsUnsignedLongLong( - arg0, - ); - } - - late final _PyLong_AsUnsignedLongLongPtr = _lookup< - ffi.NativeFunction< - ffi.UnsignedLongLong Function( - ffi.Pointer)>>('PyLong_AsUnsignedLongLong'); - late final _PyLong_AsUnsignedLongLong = _PyLong_AsUnsignedLongLongPtr - .asFunction)>(); - - int PyLong_AsUnsignedLongLongMask( - ffi.Pointer arg0, - ) { - return _PyLong_AsUnsignedLongLongMask( - arg0, - ); - } - - late final _PyLong_AsUnsignedLongLongMaskPtr = _lookup< - ffi.NativeFunction< - ffi.UnsignedLongLong Function( - ffi.Pointer)>>('PyLong_AsUnsignedLongLongMask'); - late final _PyLong_AsUnsignedLongLongMask = _PyLong_AsUnsignedLongLongMaskPtr - .asFunction)>(); - - int PyLong_AsLongLongAndOverflow( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyLong_AsLongLongAndOverflow( - arg0, - arg1, - ); - } - - late final _PyLong_AsLongLongAndOverflowPtr = _lookup< - ffi.NativeFunction< - ffi.LongLong Function(ffi.Pointer, - ffi.Pointer)>>('PyLong_AsLongLongAndOverflow'); - late final _PyLong_AsLongLongAndOverflow = _PyLong_AsLongLongAndOverflowPtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer PyLong_FromString( - ffi.Pointer arg0, - ffi.Pointer> arg1, - int arg2, - ) { - return _PyLong_FromString( - arg0, - arg1, - arg2, - ); - } - - late final _PyLong_FromStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Int)>>('PyLong_FromString'); - late final _PyLong_FromString = _PyLong_FromStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer>, int)>(); - - int PyOS_strtoul( - ffi.Pointer arg0, - ffi.Pointer> arg1, - int arg2, - ) { - return _PyOS_strtoul( - arg0, - arg1, - arg2, - ); - } - - late final _PyOS_strtoulPtr = _lookup< - ffi.NativeFunction< - ffi.UnsignedLong Function(ffi.Pointer, - ffi.Pointer>, ffi.Int)>>('PyOS_strtoul'); - late final _PyOS_strtoul = _PyOS_strtoulPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer>, int)>(); - - int PyOS_strtol( - ffi.Pointer arg0, - ffi.Pointer> arg1, - int arg2, - ) { - return _PyOS_strtol( - arg0, - arg1, - arg2, - ); - } - - late final _PyOS_strtolPtr = _lookup< - ffi.NativeFunction< - ffi.Long Function(ffi.Pointer, - ffi.Pointer>, ffi.Int)>>('PyOS_strtol'); - late final _PyOS_strtol = _PyOS_strtolPtr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer>, int)>(); - - int _PyLong_AsInt( - ffi.Pointer arg0, - ) { - return __PyLong_AsInt( - arg0, - ); - } - - late final __PyLong_AsIntPtr = - _lookup)>>( - '_PyLong_AsInt'); - late final __PyLong_AsInt = - __PyLong_AsIntPtr.asFunction)>(); - - int _PyLong_UnsignedShort_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_UnsignedShort_Converter( - arg0, - arg1, - ); - } - - late final __PyLong_UnsignedShort_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_UnsignedShort_Converter'); - late final __PyLong_UnsignedShort_Converter = - __PyLong_UnsignedShort_ConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyLong_UnsignedInt_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_UnsignedInt_Converter( - arg0, - arg1, - ); - } - - late final __PyLong_UnsignedInt_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_UnsignedInt_Converter'); - late final __PyLong_UnsignedInt_Converter = __PyLong_UnsignedInt_ConverterPtr - .asFunction, ffi.Pointer)>(); - - int _PyLong_UnsignedLong_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_UnsignedLong_Converter( - arg0, - arg1, - ); - } - - late final __PyLong_UnsignedLong_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_UnsignedLong_Converter'); - late final __PyLong_UnsignedLong_Converter = - __PyLong_UnsignedLong_ConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyLong_UnsignedLongLong_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_UnsignedLongLong_Converter( - arg0, - arg1, - ); - } - - late final __PyLong_UnsignedLongLong_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_UnsignedLongLong_Converter'); - late final __PyLong_UnsignedLongLong_Converter = - __PyLong_UnsignedLongLong_ConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyLong_Size_t_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_Size_t_Converter( - arg0, - arg1, - ); - } - - late final __PyLong_Size_t_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_Size_t_Converter'); - late final __PyLong_Size_t_Converter = __PyLong_Size_t_ConverterPtr - .asFunction, ffi.Pointer)>(); - - double _PyLong_Frexp( - ffi.Pointer a, - ffi.Pointer e, - ) { - return __PyLong_Frexp( - a, - e, - ); - } - - late final __PyLong_FrexpPtr = _lookup< - ffi.NativeFunction< - ffi.Double Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_Frexp'); - late final __PyLong_Frexp = __PyLong_FrexpPtr.asFunction< - double Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyLong_FromUnicodeObject( - ffi.Pointer u, - int base, - ) { - return _PyLong_FromUnicodeObject( - u, - base, - ); - } - - late final _PyLong_FromUnicodeObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyLong_FromUnicodeObject'); - late final _PyLong_FromUnicodeObject = _PyLong_FromUnicodeObjectPtr - .asFunction Function(ffi.Pointer, int)>(); - - ffi.Pointer _PyLong_FromBytes( - ffi.Pointer arg0, - int arg1, - int arg2, - ) { - return __PyLong_FromBytes( - arg0, - arg1, - arg2, - ); - } - - late final __PyLong_FromBytesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Int)>>('_PyLong_FromBytes'); - late final __PyLong_FromBytes = __PyLong_FromBytesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - int _PyLong_Sign( - ffi.Pointer v, - ) { - return __PyLong_Sign( - v, - ); - } - - late final __PyLong_SignPtr = - _lookup)>>( - '_PyLong_Sign'); - late final __PyLong_Sign = - __PyLong_SignPtr.asFunction)>(); - - int _PyLong_NumBits( - ffi.Pointer v, - ) { - return __PyLong_NumBits( - v, - ); - } - - late final __PyLong_NumBitsPtr = - _lookup)>>( - '_PyLong_NumBits'); - late final __PyLong_NumBits = - __PyLong_NumBitsPtr.asFunction)>(); - - ffi.Pointer _PyLong_DivmodNear( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_DivmodNear( - arg0, - arg1, - ); - } - - late final __PyLong_DivmodNearPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_DivmodNear'); - late final __PyLong_DivmodNear = __PyLong_DivmodNearPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyLong_FromByteArray( - ffi.Pointer bytes, - int n, - int little_endian, - int is_signed, - ) { - return __PyLong_FromByteArray( - bytes, - n, - little_endian, - is_signed, - ); - } - - late final __PyLong_FromByteArrayPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Size, ffi.Int, ffi.Int)>>('_PyLong_FromByteArray'); - late final __PyLong_FromByteArray = __PyLong_FromByteArrayPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, int, int, int)>(); - - int _PyLong_AsByteArray( - ffi.Pointer v, - ffi.Pointer bytes, - int n, - int little_endian, - int is_signed, - ) { - return __PyLong_AsByteArray( - v, - bytes, - n, - little_endian, - is_signed, - ); - } - - late final __PyLong_AsByteArrayPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Size, - ffi.Int, - ffi.Int)>>('_PyLong_AsByteArray'); - late final __PyLong_AsByteArray = __PyLong_AsByteArrayPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - int, int, int)>(); - - ffi.Pointer _PyLong_Format( - ffi.Pointer obj, - int base, - ) { - return __PyLong_Format( - obj, - base, - ); - } - - late final __PyLong_FormatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('_PyLong_Format'); - late final __PyLong_Format = __PyLong_FormatPtr - .asFunction Function(ffi.Pointer, int)>(); - - ffi.Pointer _PyLong_GCD( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_GCD( - arg0, - arg1, - ); - } - - late final __PyLong_GCDPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('_PyLong_GCD'); - late final __PyLong_GCD = __PyLong_GCDPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyLong_Rshift( - ffi.Pointer arg0, - int arg1, - ) { - return __PyLong_Rshift( - arg0, - arg1, - ); - } - - late final __PyLong_RshiftPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Size)>>('_PyLong_Rshift'); - late final __PyLong_Rshift = __PyLong_RshiftPtr - .asFunction Function(ffi.Pointer, int)>(); - - ffi.Pointer _PyLong_Lshift( - ffi.Pointer arg0, - int arg1, - ) { - return __PyLong_Lshift( - arg0, - arg1, - ); - } - - late final __PyLong_LshiftPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Size)>>('_PyLong_Lshift'); - late final __PyLong_Lshift = __PyLong_LshiftPtr - .asFunction Function(ffi.Pointer, int)>(); - - int PyUnstable_Long_IsCompact( - ffi.Pointer op, - ) { - return _PyUnstable_Long_IsCompact( - op, - ); - } - - late final _PyUnstable_Long_IsCompactPtr = - _lookup)>>( - 'PyUnstable_Long_IsCompact'); - late final _PyUnstable_Long_IsCompact = _PyUnstable_Long_IsCompactPtr - .asFunction)>(); - - int PyUnstable_Long_CompactValue( - ffi.Pointer op, - ) { - return _PyUnstable_Long_CompactValue( - op, - ); - } - - late final _PyUnstable_Long_CompactValuePtr = _lookup< - ffi.NativeFunction)>>( - 'PyUnstable_Long_CompactValue'); - late final _PyUnstable_Long_CompactValue = _PyUnstable_Long_CompactValuePtr - .asFunction)>(); - - ffi.Pointer _PyLong_New( - int arg0, - ) { - return __PyLong_New( - arg0, - ); - } - - late final __PyLong_NewPtr = _lookup< - ffi.NativeFunction Function(Py_ssize_t)>>( - '_PyLong_New'); - late final __PyLong_New = - __PyLong_NewPtr.asFunction Function(int)>(); - - ffi.Pointer _PyLong_Copy( - ffi.Pointer src, - ) { - return __PyLong_Copy( - src, - ); - } - - late final __PyLong_CopyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyLong_Copy'); - late final __PyLong_Copy = __PyLong_CopyPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyLong_FromDigits( - int negative, - int digit_count, - ffi.Pointer digits, - ) { - return __PyLong_FromDigits( - negative, - digit_count, - digits, - ); - } - - late final __PyLong_FromDigitsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Int, Py_ssize_t, ffi.Pointer)>>('_PyLong_FromDigits'); - late final __PyLong_FromDigits = __PyLong_FromDigitsPtr.asFunction< - ffi.Pointer Function(int, int, ffi.Pointer)>(); - - late final ffi.Pointer __Py_FalseStruct = - _lookup('_Py_FalseStruct'); - - PyLongObject get _Py_FalseStruct => __Py_FalseStruct.ref; - - late final ffi.Pointer __Py_TrueStruct = - _lookup('_Py_TrueStruct'); - - PyLongObject get _Py_TrueStruct => __Py_TrueStruct.ref; - - int Py_IsTrue( - ffi.Pointer x, - ) { - return _Py_IsTrue( - x, - ); - } - - late final _Py_IsTruePtr = - _lookup)>>( - 'Py_IsTrue'); - late final _Py_IsTrue = - _Py_IsTruePtr.asFunction)>(); - - int Py_IsFalse( - ffi.Pointer x, - ) { - return _Py_IsFalse( - x, - ); - } - - late final _Py_IsFalsePtr = - _lookup)>>( - 'Py_IsFalse'); - late final _Py_IsFalse = - _Py_IsFalsePtr.asFunction)>(); - - ffi.Pointer PyBool_FromLong( - int arg0, - ) { - return _PyBool_FromLong( - arg0, - ); - } - - late final _PyBool_FromLongPtr = - _lookup Function(ffi.Long)>>( - 'PyBool_FromLong'); - late final _PyBool_FromLong = - _PyBool_FromLongPtr.asFunction Function(int)>(); - - late final ffi.Pointer _PyFloat_Type = - _lookup('PyFloat_Type'); - - PyTypeObject get PyFloat_Type => _PyFloat_Type.ref; - - double PyFloat_GetMax() { - return _PyFloat_GetMax(); - } - - late final _PyFloat_GetMaxPtr = - _lookup>('PyFloat_GetMax'); - late final _PyFloat_GetMax = - _PyFloat_GetMaxPtr.asFunction(); - - double PyFloat_GetMin() { - return _PyFloat_GetMin(); - } - - late final _PyFloat_GetMinPtr = - _lookup>('PyFloat_GetMin'); - late final _PyFloat_GetMin = - _PyFloat_GetMinPtr.asFunction(); - - ffi.Pointer PyFloat_GetInfo() { - return _PyFloat_GetInfo(); - } - - late final _PyFloat_GetInfoPtr = - _lookup Function()>>( - 'PyFloat_GetInfo'); - late final _PyFloat_GetInfo = - _PyFloat_GetInfoPtr.asFunction Function()>(); - - ffi.Pointer PyFloat_FromString( - ffi.Pointer arg0, - ) { - return _PyFloat_FromString( - arg0, - ); - } - - late final _PyFloat_FromStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFloat_FromString'); - late final _PyFloat_FromString = _PyFloat_FromStringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFloat_FromDouble( - double arg0, - ) { - return _PyFloat_FromDouble( - arg0, - ); - } - - late final _PyFloat_FromDoublePtr = - _lookup Function(ffi.Double)>>( - 'PyFloat_FromDouble'); - late final _PyFloat_FromDouble = _PyFloat_FromDoublePtr.asFunction< - ffi.Pointer Function(double)>(); - - double PyFloat_AsDouble( - ffi.Pointer arg0, - ) { - return _PyFloat_AsDouble( - arg0, - ); - } - - late final _PyFloat_AsDoublePtr = - _lookup)>>( - 'PyFloat_AsDouble'); - late final _PyFloat_AsDouble = - _PyFloat_AsDoublePtr.asFunction)>(); - - int PyFloat_Pack2( - double x, - ffi.Pointer p, - int le, - ) { - return _PyFloat_Pack2( - x, - p, - le, - ); - } - - late final _PyFloat_Pack2Ptr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Double, ffi.Pointer, ffi.Int)>>('PyFloat_Pack2'); - late final _PyFloat_Pack2 = _PyFloat_Pack2Ptr.asFunction< - int Function(double, ffi.Pointer, int)>(); - - int PyFloat_Pack4( - double x, - ffi.Pointer p, - int le, - ) { - return _PyFloat_Pack4( - x, - p, - le, - ); - } - - late final _PyFloat_Pack4Ptr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Double, ffi.Pointer, ffi.Int)>>('PyFloat_Pack4'); - late final _PyFloat_Pack4 = _PyFloat_Pack4Ptr.asFunction< - int Function(double, ffi.Pointer, int)>(); - - int PyFloat_Pack8( - double x, - ffi.Pointer p, - int le, - ) { - return _PyFloat_Pack8( - x, - p, - le, - ); - } - - late final _PyFloat_Pack8Ptr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Double, ffi.Pointer, ffi.Int)>>('PyFloat_Pack8'); - late final _PyFloat_Pack8 = _PyFloat_Pack8Ptr.asFunction< - int Function(double, ffi.Pointer, int)>(); - - double PyFloat_Unpack2( - ffi.Pointer p, - int le, - ) { - return _PyFloat_Unpack2( - p, - le, - ); - } - - late final _PyFloat_Unpack2Ptr = _lookup< - ffi - .NativeFunction, ffi.Int)>>( - 'PyFloat_Unpack2'); - late final _PyFloat_Unpack2 = _PyFloat_Unpack2Ptr.asFunction< - double Function(ffi.Pointer, int)>(); - - double PyFloat_Unpack4( - ffi.Pointer p, - int le, - ) { - return _PyFloat_Unpack4( - p, - le, - ); - } - - late final _PyFloat_Unpack4Ptr = _lookup< - ffi - .NativeFunction, ffi.Int)>>( - 'PyFloat_Unpack4'); - late final _PyFloat_Unpack4 = _PyFloat_Unpack4Ptr.asFunction< - double Function(ffi.Pointer, int)>(); - - double PyFloat_Unpack8( - ffi.Pointer p, - int le, - ) { - return _PyFloat_Unpack8( - p, - le, - ); - } - - late final _PyFloat_Unpack8Ptr = _lookup< - ffi - .NativeFunction, ffi.Int)>>( - 'PyFloat_Unpack8'); - late final _PyFloat_Unpack8 = _PyFloat_Unpack8Ptr.asFunction< - double Function(ffi.Pointer, int)>(); - - late final ffi.Pointer _PyComplex_Type = - _lookup('PyComplex_Type'); - - PyTypeObject get PyComplex_Type => _PyComplex_Type.ref; - - ffi.Pointer PyComplex_FromDoubles( - double real, - double imag, - ) { - return _PyComplex_FromDoubles( - real, - imag, - ); - } - - late final _PyComplex_FromDoublesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Double, ffi.Double)>>('PyComplex_FromDoubles'); - late final _PyComplex_FromDoubles = _PyComplex_FromDoublesPtr.asFunction< - ffi.Pointer Function(double, double)>(); - - double PyComplex_RealAsDouble( - ffi.Pointer op, - ) { - return _PyComplex_RealAsDouble( - op, - ); - } - - late final _PyComplex_RealAsDoublePtr = - _lookup)>>( - 'PyComplex_RealAsDouble'); - late final _PyComplex_RealAsDouble = _PyComplex_RealAsDoublePtr.asFunction< - double Function(ffi.Pointer)>(); - - double PyComplex_ImagAsDouble( - ffi.Pointer op, - ) { - return _PyComplex_ImagAsDouble( - op, - ); - } - - late final _PyComplex_ImagAsDoublePtr = - _lookup)>>( - 'PyComplex_ImagAsDouble'); - late final _PyComplex_ImagAsDouble = _PyComplex_ImagAsDoublePtr.asFunction< - double Function(ffi.Pointer)>(); - - Py_complex _Py_c_sum( - Py_complex arg0, - Py_complex arg1, - ) { - return __Py_c_sum( - arg0, - arg1, - ); - } - - late final __Py_c_sumPtr = - _lookup>( - '_Py_c_sum'); - late final __Py_c_sum = - __Py_c_sumPtr.asFunction(); - - Py_complex _Py_c_diff( - Py_complex arg0, - Py_complex arg1, - ) { - return __Py_c_diff( - arg0, - arg1, - ); - } - - late final __Py_c_diffPtr = - _lookup>( - '_Py_c_diff'); - late final __Py_c_diff = - __Py_c_diffPtr.asFunction(); - - Py_complex _Py_c_neg( - Py_complex arg0, - ) { - return __Py_c_neg( - arg0, - ); - } - - late final __Py_c_negPtr = - _lookup>('_Py_c_neg'); - late final __Py_c_neg = - __Py_c_negPtr.asFunction(); - - Py_complex _Py_c_prod( - Py_complex arg0, - Py_complex arg1, - ) { - return __Py_c_prod( - arg0, - arg1, - ); - } - - late final __Py_c_prodPtr = - _lookup>( - '_Py_c_prod'); - late final __Py_c_prod = - __Py_c_prodPtr.asFunction(); - - Py_complex _Py_c_quot( - Py_complex arg0, - Py_complex arg1, - ) { - return __Py_c_quot( - arg0, - arg1, - ); - } - - late final __Py_c_quotPtr = - _lookup>( - '_Py_c_quot'); - late final __Py_c_quot = - __Py_c_quotPtr.asFunction(); - - Py_complex _Py_c_pow( - Py_complex arg0, - Py_complex arg1, - ) { - return __Py_c_pow( - arg0, - arg1, - ); - } - - late final __Py_c_powPtr = - _lookup>( - '_Py_c_pow'); - late final __Py_c_pow = - __Py_c_powPtr.asFunction(); - - double _Py_c_abs( - Py_complex arg0, - ) { - return __Py_c_abs( - arg0, - ); - } - - late final __Py_c_absPtr = - _lookup>('_Py_c_abs'); - late final __Py_c_abs = - __Py_c_absPtr.asFunction(); - - ffi.Pointer PyComplex_FromCComplex( - Py_complex arg0, - ) { - return _PyComplex_FromCComplex( - arg0, - ); - } - - late final _PyComplex_FromCComplexPtr = - _lookup Function(Py_complex)>>( - 'PyComplex_FromCComplex'); - late final _PyComplex_FromCComplex = _PyComplex_FromCComplexPtr.asFunction< - ffi.Pointer Function(Py_complex)>(); - - Py_complex PyComplex_AsCComplex( - ffi.Pointer op, - ) { - return _PyComplex_AsCComplex( - op, - ); - } - - late final _PyComplex_AsCComplexPtr = - _lookup)>>( - 'PyComplex_AsCComplex'); - late final _PyComplex_AsCComplex = _PyComplex_AsCComplexPtr.asFunction< - Py_complex Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyRange_Type = - _lookup('PyRange_Type'); - - PyTypeObject get PyRange_Type => _PyRange_Type.ref; - - late final ffi.Pointer _PyRangeIter_Type = - _lookup('PyRangeIter_Type'); - - PyTypeObject get PyRangeIter_Type => _PyRangeIter_Type.ref; - - late final ffi.Pointer _PyLongRangeIter_Type = - _lookup('PyLongRangeIter_Type'); - - PyTypeObject get PyLongRangeIter_Type => _PyLongRangeIter_Type.ref; - - late final ffi.Pointer _PyMemoryView_Type = - _lookup('PyMemoryView_Type'); - - PyTypeObject get PyMemoryView_Type => _PyMemoryView_Type.ref; - - ffi.Pointer PyMemoryView_FromObject( - ffi.Pointer base, - ) { - return _PyMemoryView_FromObject( - base, - ); - } - - late final _PyMemoryView_FromObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMemoryView_FromObject'); - late final _PyMemoryView_FromObject = _PyMemoryView_FromObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyMemoryView_FromMemory( - ffi.Pointer mem, - int size, - int flags, - ) { - return _PyMemoryView_FromMemory( - mem, - size, - flags, - ); - } - - late final _PyMemoryView_FromMemoryPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - ffi.Int)>>('PyMemoryView_FromMemory'); - late final _PyMemoryView_FromMemory = _PyMemoryView_FromMemoryPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - ffi.Pointer PyMemoryView_FromBuffer( - ffi.Pointer info, - ) { - return _PyMemoryView_FromBuffer( - info, - ); - } - - late final _PyMemoryView_FromBufferPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMemoryView_FromBuffer'); - late final _PyMemoryView_FromBuffer = _PyMemoryView_FromBufferPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyMemoryView_GetContiguous( - ffi.Pointer base, - int buffertype, - int order, - ) { - return _PyMemoryView_GetContiguous( - base, - buffertype, - order, - ); - } - - late final _PyMemoryView_GetContiguousPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Int, - ffi.Char)>>('PyMemoryView_GetContiguous'); - late final _PyMemoryView_GetContiguous = - _PyMemoryView_GetContiguousPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - late final ffi.Pointer __PyManagedBuffer_Type = - _lookup('_PyManagedBuffer_Type'); - - PyTypeObject get _PyManagedBuffer_Type => __PyManagedBuffer_Type.ref; - - late final ffi.Pointer _PyTuple_Type = - _lookup('PyTuple_Type'); - - PyTypeObject get PyTuple_Type => _PyTuple_Type.ref; - - late final ffi.Pointer _PyTupleIter_Type = - _lookup('PyTupleIter_Type'); - - PyTypeObject get PyTupleIter_Type => _PyTupleIter_Type.ref; - - ffi.Pointer PyTuple_New( - int size, - ) { - return _PyTuple_New( - size, - ); - } - - late final _PyTuple_NewPtr = - _lookup Function(Py_ssize_t)>>( - 'PyTuple_New'); - late final _PyTuple_New = - _PyTuple_NewPtr.asFunction Function(int)>(); - - int PyTuple_Size( - ffi.Pointer arg0, - ) { - return _PyTuple_Size( - arg0, - ); - } - - late final _PyTuple_SizePtr = - _lookup)>>( - 'PyTuple_Size'); - late final _PyTuple_Size = - _PyTuple_SizePtr.asFunction)>(); - - ffi.Pointer PyTuple_GetItem( - ffi.Pointer arg0, - int arg1, - ) { - return _PyTuple_GetItem( - arg0, - arg1, - ); - } - - late final _PyTuple_GetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PyTuple_GetItem'); - late final _PyTuple_GetItem = _PyTuple_GetItemPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int PyTuple_SetItem( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ) { - return _PyTuple_SetItem( - arg0, - arg1, - arg2, - ); - } - - late final _PyTuple_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyTuple_SetItem'); - late final _PyTuple_SetItem = _PyTuple_SetItemPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyTuple_GetSlice( - ffi.Pointer arg0, - int arg1, - int arg2, - ) { - return _PyTuple_GetSlice( - arg0, - arg1, - arg2, - ); - } - - late final _PyTuple_GetSlicePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - Py_ssize_t)>>('PyTuple_GetSlice'); - late final _PyTuple_GetSlice = _PyTuple_GetSlicePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - ffi.Pointer PyTuple_Pack( - int arg0, - ) { - return _PyTuple_Pack( - arg0, - ); - } - - late final _PyTuple_PackPtr = - _lookup Function(Py_ssize_t)>>( - 'PyTuple_Pack'); - late final _PyTuple_Pack = - _PyTuple_PackPtr.asFunction Function(int)>(); - - int _PyTuple_Resize( - ffi.Pointer> arg0, - int arg1, - ) { - return __PyTuple_Resize( - arg0, - arg1, - ); - } - - late final __PyTuple_ResizePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer>, - Py_ssize_t)>>('_PyTuple_Resize'); - late final __PyTuple_Resize = __PyTuple_ResizePtr - .asFunction>, int)>(); - - void _PyTuple_MaybeUntrack( - ffi.Pointer arg0, - ) { - return __PyTuple_MaybeUntrack( - arg0, - ); - } - - late final __PyTuple_MaybeUntrackPtr = - _lookup)>>( - '_PyTuple_MaybeUntrack'); - late final __PyTuple_MaybeUntrack = __PyTuple_MaybeUntrackPtr - .asFunction)>(); - - void _PyTuple_DebugMallocStats( - ffi.Pointer out, - ) { - return __PyTuple_DebugMallocStats( - out, - ); - } - - late final __PyTuple_DebugMallocStatsPtr = - _lookup)>>( - '_PyTuple_DebugMallocStats'); - late final __PyTuple_DebugMallocStats = __PyTuple_DebugMallocStatsPtr - .asFunction)>(); - - late final ffi.Pointer _PyList_Type = - _lookup('PyList_Type'); - - PyTypeObject get PyList_Type => _PyList_Type.ref; - - late final ffi.Pointer _PyListIter_Type = - _lookup('PyListIter_Type'); - - PyTypeObject get PyListIter_Type => _PyListIter_Type.ref; - - late final ffi.Pointer _PyListRevIter_Type = - _lookup('PyListRevIter_Type'); - - PyTypeObject get PyListRevIter_Type => _PyListRevIter_Type.ref; - - ffi.Pointer PyList_New( - int size, - ) { - return _PyList_New( - size, - ); - } - - late final _PyList_NewPtr = - _lookup Function(Py_ssize_t)>>( - 'PyList_New'); - late final _PyList_New = - _PyList_NewPtr.asFunction Function(int)>(); - - int PyList_Size( - ffi.Pointer arg0, - ) { - return _PyList_Size( - arg0, - ); - } - - late final _PyList_SizePtr = - _lookup)>>( - 'PyList_Size'); - late final _PyList_Size = - _PyList_SizePtr.asFunction)>(); - - ffi.Pointer PyList_GetItem( - ffi.Pointer arg0, - int arg1, - ) { - return _PyList_GetItem( - arg0, - arg1, - ); - } - - late final _PyList_GetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PyList_GetItem'); - late final _PyList_GetItem = _PyList_GetItemPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int PyList_SetItem( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ) { - return _PyList_SetItem( - arg0, - arg1, - arg2, - ); - } - - late final _PyList_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyList_SetItem'); - late final _PyList_SetItem = _PyList_SetItemPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - int PyList_Insert( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ) { - return _PyList_Insert( - arg0, - arg1, - arg2, - ); - } - - late final _PyList_InsertPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyList_Insert'); - late final _PyList_Insert = _PyList_InsertPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - int PyList_Append( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyList_Append( - arg0, - arg1, - ); - } - - late final _PyList_AppendPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyList_Append'); - late final _PyList_Append = _PyList_AppendPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyList_GetSlice( - ffi.Pointer arg0, - int arg1, - int arg2, - ) { - return _PyList_GetSlice( - arg0, - arg1, - arg2, - ); - } - - late final _PyList_GetSlicePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - Py_ssize_t)>>('PyList_GetSlice'); - late final _PyList_GetSlice = _PyList_GetSlicePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - int PyList_SetSlice( - ffi.Pointer arg0, - int arg1, - int arg2, - ffi.Pointer arg3, - ) { - return _PyList_SetSlice( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _PyList_SetSlicePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, Py_ssize_t, - ffi.Pointer)>>('PyList_SetSlice'); - late final _PyList_SetSlice = _PyList_SetSlicePtr.asFunction< - int Function(ffi.Pointer, int, int, ffi.Pointer)>(); - - int PyList_Sort( - ffi.Pointer arg0, - ) { - return _PyList_Sort( - arg0, - ); - } - - late final _PyList_SortPtr = - _lookup)>>( - 'PyList_Sort'); - late final _PyList_Sort = - _PyList_SortPtr.asFunction)>(); - - int PyList_Reverse( - ffi.Pointer arg0, - ) { - return _PyList_Reverse( - arg0, - ); - } - - late final _PyList_ReversePtr = - _lookup)>>( - 'PyList_Reverse'); - late final _PyList_Reverse = - _PyList_ReversePtr.asFunction)>(); - - ffi.Pointer PyList_AsTuple( - ffi.Pointer arg0, - ) { - return _PyList_AsTuple( - arg0, - ); - } - - late final _PyList_AsTuplePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyList_AsTuple'); - late final _PyList_AsTuple = _PyList_AsTuplePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer _PyList_Extend( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyList_Extend( - arg0, - arg1, - ); - } - - late final __PyList_ExtendPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyList_Extend'); - late final __PyList_Extend = __PyList_ExtendPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - void _PyList_DebugMallocStats( - ffi.Pointer out, - ) { - return __PyList_DebugMallocStats( - out, - ); - } - - late final __PyList_DebugMallocStatsPtr = - _lookup)>>( - '_PyList_DebugMallocStats'); - late final __PyList_DebugMallocStats = __PyList_DebugMallocStatsPtr - .asFunction)>(); - - late final ffi.Pointer _PyDict_Type = - _lookup('PyDict_Type'); - - PyTypeObject get PyDict_Type => _PyDict_Type.ref; - - ffi.Pointer PyDict_New() { - return _PyDict_New(); - } - - late final _PyDict_NewPtr = - _lookup Function()>>( - 'PyDict_New'); - late final _PyDict_New = - _PyDict_NewPtr.asFunction Function()>(); - - ffi.Pointer PyDict_GetItem( - ffi.Pointer mp, - ffi.Pointer key, - ) { - return _PyDict_GetItem( - mp, - key, - ); - } - - late final _PyDict_GetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyDict_GetItem'); - late final _PyDict_GetItem = _PyDict_GetItemPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyDict_GetItemWithError( - ffi.Pointer mp, - ffi.Pointer key, - ) { - return _PyDict_GetItemWithError1( - mp, - key, - ); - } - - late final _PyDict_GetItemWithErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyDict_GetItemWithError'); - late final _PyDict_GetItemWithError1 = _PyDict_GetItemWithErrorPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyDict_SetItem( - ffi.Pointer mp, - ffi.Pointer key, - ffi.Pointer item, - ) { - return _PyDict_SetItem( - mp, - key, - item, - ); - } - - late final _PyDict_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyDict_SetItem'); - late final _PyDict_SetItem = _PyDict_SetItemPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyDict_DelItem( - ffi.Pointer mp, - ffi.Pointer key, - ) { - return _PyDict_DelItem( - mp, - key, - ); - } - - late final _PyDict_DelItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyDict_DelItem'); - late final _PyDict_DelItem = _PyDict_DelItemPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - void PyDict_Clear( - ffi.Pointer mp, - ) { - return _PyDict_Clear( - mp, - ); - } - - late final _PyDict_ClearPtr = - _lookup)>>( - 'PyDict_Clear'); - late final _PyDict_Clear = - _PyDict_ClearPtr.asFunction)>(); - - int PyDict_Next( - ffi.Pointer mp, - ffi.Pointer pos, - ffi.Pointer> key, - ffi.Pointer> value, - ) { - return _PyDict_Next1( - mp, - pos, - key, - value, - ); - } - - late final _PyDict_NextPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>)>>('PyDict_Next'); - late final _PyDict_Next1 = _PyDict_NextPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>)>(); - - ffi.Pointer PyDict_Keys( - ffi.Pointer mp, - ) { - return _PyDict_Keys( - mp, - ); - } - - late final _PyDict_KeysPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyDict_Keys'); - late final _PyDict_Keys = _PyDict_KeysPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyDict_Values( - ffi.Pointer mp, - ) { - return _PyDict_Values( - mp, - ); - } - - late final _PyDict_ValuesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyDict_Values'); - late final _PyDict_Values = _PyDict_ValuesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyDict_Items( - ffi.Pointer mp, - ) { - return _PyDict_Items( - mp, - ); - } - - late final _PyDict_ItemsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyDict_Items'); - late final _PyDict_Items = _PyDict_ItemsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyDict_Size( - ffi.Pointer mp, - ) { - return _PyDict_Size( - mp, - ); - } - - late final _PyDict_SizePtr = - _lookup)>>( - 'PyDict_Size'); - late final _PyDict_Size = - _PyDict_SizePtr.asFunction)>(); - - ffi.Pointer PyDict_Copy( - ffi.Pointer mp, - ) { - return _PyDict_Copy( - mp, - ); - } - - late final _PyDict_CopyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyDict_Copy'); - late final _PyDict_Copy = _PyDict_CopyPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyDict_Contains( - ffi.Pointer mp, - ffi.Pointer key, - ) { - return _PyDict_Contains( - mp, - key, - ); - } - - late final _PyDict_ContainsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyDict_Contains'); - late final _PyDict_Contains = _PyDict_ContainsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyDict_Update( - ffi.Pointer mp, - ffi.Pointer other, - ) { - return _PyDict_Update( - mp, - other, - ); - } - - late final _PyDict_UpdatePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyDict_Update'); - late final _PyDict_Update = _PyDict_UpdatePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyDict_Merge( - ffi.Pointer mp, - ffi.Pointer other, - int override, - ) { - return _PyDict_Merge( - mp, - other, - override, - ); - } - - late final _PyDict_MergePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyDict_Merge'); - late final _PyDict_Merge = _PyDict_MergePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyDict_MergeFromSeq2( - ffi.Pointer d, - ffi.Pointer seq2, - int override, - ) { - return _PyDict_MergeFromSeq2( - d, - seq2, - override, - ); - } - - late final _PyDict_MergeFromSeq2Ptr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyDict_MergeFromSeq2'); - late final _PyDict_MergeFromSeq2 = _PyDict_MergeFromSeq2Ptr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyDict_GetItemString( - ffi.Pointer dp, - ffi.Pointer key, - ) { - return _PyDict_GetItemString( - dp, - key, - ); - } - - late final _PyDict_GetItemStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyDict_GetItemString'); - late final _PyDict_GetItemString = _PyDict_GetItemStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyDict_SetItemString( - ffi.Pointer dp, - ffi.Pointer key, - ffi.Pointer item, - ) { - return _PyDict_SetItemString( - dp, - key, - item, - ); - } - - late final _PyDict_SetItemStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyDict_SetItemString'); - late final _PyDict_SetItemString = _PyDict_SetItemStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyDict_DelItemString( - ffi.Pointer dp, - ffi.Pointer key, - ) { - return _PyDict_DelItemString( - dp, - key, - ); - } - - late final _PyDict_DelItemStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyDict_DelItemString'); - late final _PyDict_DelItemString = _PyDict_DelItemStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_GenericGetDict( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyObject_GenericGetDict( - arg0, - arg1, - ); - } - - late final _PyObject_GenericGetDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_GenericGetDict'); - late final _PyObject_GenericGetDict = _PyObject_GenericGetDictPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyDictKeys_Type = - _lookup('PyDictKeys_Type'); - - PyTypeObject get PyDictKeys_Type => _PyDictKeys_Type.ref; - - late final ffi.Pointer _PyDictValues_Type = - _lookup('PyDictValues_Type'); - - PyTypeObject get PyDictValues_Type => _PyDictValues_Type.ref; - - late final ffi.Pointer _PyDictItems_Type = - _lookup('PyDictItems_Type'); - - PyTypeObject get PyDictItems_Type => _PyDictItems_Type.ref; - - late final ffi.Pointer _PyDictIterKey_Type = - _lookup('PyDictIterKey_Type'); - - PyTypeObject get PyDictIterKey_Type => _PyDictIterKey_Type.ref; - - late final ffi.Pointer _PyDictIterValue_Type = - _lookup('PyDictIterValue_Type'); - - PyTypeObject get PyDictIterValue_Type => _PyDictIterValue_Type.ref; - - late final ffi.Pointer _PyDictIterItem_Type = - _lookup('PyDictIterItem_Type'); - - PyTypeObject get PyDictIterItem_Type => _PyDictIterItem_Type.ref; - - late final ffi.Pointer _PyDictRevIterKey_Type = - _lookup('PyDictRevIterKey_Type'); - - PyTypeObject get PyDictRevIterKey_Type => _PyDictRevIterKey_Type.ref; - - late final ffi.Pointer _PyDictRevIterItem_Type = - _lookup('PyDictRevIterItem_Type'); - - PyTypeObject get PyDictRevIterItem_Type => _PyDictRevIterItem_Type.ref; - - late final ffi.Pointer _PyDictRevIterValue_Type = - _lookup('PyDictRevIterValue_Type'); - - PyTypeObject get PyDictRevIterValue_Type => _PyDictRevIterValue_Type.ref; - - ffi.Pointer _PyDict_GetItem_KnownHash( - ffi.Pointer mp, - ffi.Pointer key, - int hash, - ) { - return __PyDict_GetItem_KnownHash( - mp, - key, - hash, - ); - } - - late final __PyDict_GetItem_KnownHashPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, Py_hash_t)>>('_PyDict_GetItem_KnownHash'); - late final __PyDict_GetItem_KnownHash = - __PyDict_GetItem_KnownHashPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer _PyDict_GetItemWithError( - ffi.Pointer dp, - ffi.Pointer key, - ) { - return __PyDict_GetItemWithError( - dp, - key, - ); - } - - late final __PyDict_GetItemWithErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyDict_GetItemWithError'); - late final __PyDict_GetItemWithError = - __PyDict_GetItemWithErrorPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyDict_GetItemIdWithError( - ffi.Pointer dp, - ffi.Pointer<_Py_Identifier> key, - ) { - return __PyDict_GetItemIdWithError( - dp, - key, - ); - } - - late final __PyDict_GetItemIdWithErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyDict_GetItemIdWithError'); - late final __PyDict_GetItemIdWithError = - __PyDict_GetItemIdWithErrorPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - ffi.Pointer _PyDict_GetItemStringWithError( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyDict_GetItemStringWithError( - arg0, - arg1, - ); - } - - late final __PyDict_GetItemStringWithErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyDict_GetItemStringWithError'); - late final __PyDict_GetItemStringWithError = - __PyDict_GetItemStringWithErrorPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyDict_SetDefault( - ffi.Pointer mp, - ffi.Pointer key, - ffi.Pointer defaultobj, - ) { - return _PyDict_SetDefault( - mp, - key, - defaultobj, - ); - } - - late final _PyDict_SetDefaultPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyDict_SetDefault'); - late final _PyDict_SetDefault = _PyDict_SetDefaultPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int _PyDict_SetItem_KnownHash( - ffi.Pointer mp, - ffi.Pointer key, - ffi.Pointer item, - int hash, - ) { - return __PyDict_SetItem_KnownHash( - mp, - key, - item, - hash, - ); - } - - late final __PyDict_SetItem_KnownHashPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, Py_hash_t)>>('_PyDict_SetItem_KnownHash'); - late final __PyDict_SetItem_KnownHash = - __PyDict_SetItem_KnownHashPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, int)>(); - - int _PyDict_DelItem_KnownHash( - ffi.Pointer mp, - ffi.Pointer key, - int hash, - ) { - return __PyDict_DelItem_KnownHash( - mp, - key, - hash, - ); - } - - late final __PyDict_DelItem_KnownHashPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_hash_t)>>('_PyDict_DelItem_KnownHash'); - late final __PyDict_DelItem_KnownHash = - __PyDict_DelItem_KnownHashPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int _PyDict_DelItemIf( - ffi.Pointer mp, - ffi.Pointer key, - ffi.Pointer< - ffi.NativeFunction value)>> - predicate, - ) { - return __PyDict_DelItemIf( - mp, - key, - predicate, - ); - } - - late final __PyDict_DelItemIfPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer value)>>)>>( - '_PyDict_DelItemIf'); - late final __PyDict_DelItemIf = __PyDict_DelItemIfPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer value)>>)>(); - - int _PyDict_Next( - ffi.Pointer mp, - ffi.Pointer pos, - ffi.Pointer> key, - ffi.Pointer> value, - ffi.Pointer hash, - ) { - return __PyDict_Next( - mp, - pos, - key, - value, - hash, - ); - } - - late final __PyDict_NextPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer)>>('_PyDict_Next'); - late final __PyDict_Next = __PyDict_NextPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer)>(); - - int _PyDict_Contains_KnownHash( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return __PyDict_Contains_KnownHash( - arg0, - arg1, - arg2, - ); - } - - late final __PyDict_Contains_KnownHashPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_hash_t)>>('_PyDict_Contains_KnownHash'); - late final __PyDict_Contains_KnownHash = - __PyDict_Contains_KnownHashPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int _PyDict_ContainsId( - ffi.Pointer arg0, - ffi.Pointer<_Py_Identifier> arg1, - ) { - return __PyDict_ContainsId( - arg0, - arg1, - ); - } - - late final __PyDict_ContainsIdPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyDict_ContainsId'); - late final __PyDict_ContainsId = __PyDict_ContainsIdPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - ffi.Pointer _PyDict_NewPresized( - int minused, - ) { - return __PyDict_NewPresized( - minused, - ); - } - - late final __PyDict_NewPresizedPtr = - _lookup Function(Py_ssize_t)>>( - '_PyDict_NewPresized'); - late final __PyDict_NewPresized = - __PyDict_NewPresizedPtr.asFunction Function(int)>(); - - void _PyDict_MaybeUntrack( - ffi.Pointer mp, - ) { - return __PyDict_MaybeUntrack( - mp, - ); - } - - late final __PyDict_MaybeUntrackPtr = - _lookup)>>( - '_PyDict_MaybeUntrack'); - late final __PyDict_MaybeUntrack = __PyDict_MaybeUntrackPtr - .asFunction)>(); - - int _PyDict_HasOnlyStringKeys( - ffi.Pointer mp, - ) { - return __PyDict_HasOnlyStringKeys( - mp, - ); - } - - late final __PyDict_HasOnlyStringKeysPtr = - _lookup)>>( - '_PyDict_HasOnlyStringKeys'); - late final __PyDict_HasOnlyStringKeys = __PyDict_HasOnlyStringKeysPtr - .asFunction)>(); - - int _PyDict_SizeOf( - ffi.Pointer arg0, - ) { - return __PyDict_SizeOf( - arg0, - ); - } - - late final __PyDict_SizeOfPtr = _lookup< - ffi.NativeFunction)>>( - '_PyDict_SizeOf'); - late final __PyDict_SizeOf = - __PyDict_SizeOfPtr.asFunction)>(); - - ffi.Pointer _PyDict_Pop( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return __PyDict_Pop( - arg0, - arg1, - arg2, - ); - } - - late final __PyDict_PopPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('_PyDict_Pop'); - late final __PyDict_Pop = __PyDict_PopPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int _PyDict_MergeEx( - ffi.Pointer mp, - ffi.Pointer other, - int override, - ) { - return __PyDict_MergeEx( - mp, - other, - override, - ); - } - - late final __PyDict_MergeExPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('_PyDict_MergeEx'); - late final __PyDict_MergeEx = __PyDict_MergeExPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int _PyDict_SetItemId( - ffi.Pointer dp, - ffi.Pointer<_Py_Identifier> key, - ffi.Pointer item, - ) { - return __PyDict_SetItemId( - dp, - key, - item, - ); - } - - late final __PyDict_SetItemIdPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>, - ffi.Pointer)>>('_PyDict_SetItemId'); - late final __PyDict_SetItemId = __PyDict_SetItemIdPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>, - ffi.Pointer)>(); - - int _PyDict_DelItemId( - ffi.Pointer mp, - ffi.Pointer<_Py_Identifier> key, - ) { - return __PyDict_DelItemId( - mp, - key, - ); - } - - late final __PyDict_DelItemIdPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyDict_DelItemId'); - late final __PyDict_DelItemId = __PyDict_DelItemIdPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - void _PyDict_DebugMallocStats( - ffi.Pointer out, - ) { - return __PyDict_DebugMallocStats( - out, - ); - } - - late final __PyDict_DebugMallocStatsPtr = - _lookup)>>( - '_PyDict_DebugMallocStats'); - late final __PyDict_DebugMallocStats = __PyDict_DebugMallocStatsPtr - .asFunction)>(); - - ffi.Pointer _PyDictView_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyDictView_New( - arg0, - arg1, - ); - } - - late final __PyDictView_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyDictView_New'); - late final __PyDictView_New = __PyDictView_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyDictView_Intersect( - ffi.Pointer self, - ffi.Pointer other, - ) { - return __PyDictView_Intersect( - self, - other, - ); - } - - late final __PyDictView_IntersectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyDictView_Intersect'); - late final __PyDictView_Intersect = __PyDictView_IntersectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyDict_AddWatcher( - PyDict_WatchCallback callback, - ) { - return _PyDict_AddWatcher( - callback, - ); - } - - late final _PyDict_AddWatcherPtr = - _lookup>( - 'PyDict_AddWatcher'); - late final _PyDict_AddWatcher = - _PyDict_AddWatcherPtr.asFunction(); - - int PyDict_ClearWatcher( - int watcher_id, - ) { - return _PyDict_ClearWatcher( - watcher_id, - ); - } - - late final _PyDict_ClearWatcherPtr = - _lookup>( - 'PyDict_ClearWatcher'); - late final _PyDict_ClearWatcher = - _PyDict_ClearWatcherPtr.asFunction(); - - int PyDict_Watch( - int watcher_id, - ffi.Pointer dict, - ) { - return _PyDict_Watch( - watcher_id, - dict, - ); - } - - late final _PyDict_WatchPtr = _lookup< - ffi.NativeFunction)>>( - 'PyDict_Watch'); - late final _PyDict_Watch = - _PyDict_WatchPtr.asFunction)>(); - - int PyDict_Unwatch( - int watcher_id, - ffi.Pointer dict, - ) { - return _PyDict_Unwatch( - watcher_id, - dict, - ); - } - - late final _PyDict_UnwatchPtr = _lookup< - ffi.NativeFunction)>>( - 'PyDict_Unwatch'); - late final _PyDict_Unwatch = - _PyDict_UnwatchPtr.asFunction)>(); - - late final ffi.Pointer _PyODict_Type = - _lookup('PyODict_Type'); - - PyTypeObject get PyODict_Type => _PyODict_Type.ref; - - late final ffi.Pointer _PyODictIter_Type = - _lookup('PyODictIter_Type'); - - PyTypeObject get PyODictIter_Type => _PyODictIter_Type.ref; - - late final ffi.Pointer _PyODictKeys_Type = - _lookup('PyODictKeys_Type'); - - PyTypeObject get PyODictKeys_Type => _PyODictKeys_Type.ref; - - late final ffi.Pointer _PyODictItems_Type = - _lookup('PyODictItems_Type'); - - PyTypeObject get PyODictItems_Type => _PyODictItems_Type.ref; - - late final ffi.Pointer _PyODictValues_Type = - _lookup('PyODictValues_Type'); - - PyTypeObject get PyODictValues_Type => _PyODictValues_Type.ref; - - ffi.Pointer PyODict_New() { - return _PyODict_New(); - } - - late final _PyODict_NewPtr = - _lookup Function()>>( - 'PyODict_New'); - late final _PyODict_New = - _PyODict_NewPtr.asFunction Function()>(); - - int PyODict_SetItem( - ffi.Pointer od, - ffi.Pointer key, - ffi.Pointer item, - ) { - return _PyODict_SetItem( - od, - key, - item, - ); - } - - late final _PyODict_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyODict_SetItem'); - late final _PyODict_SetItem = _PyODict_SetItemPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyODict_DelItem( - ffi.Pointer od, - ffi.Pointer key, - ) { - return _PyODict_DelItem( - od, - key, - ); - } - - late final _PyODict_DelItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyODict_DelItem'); - late final _PyODict_DelItem = _PyODict_DelItemPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyEnum_Type = - _lookup('PyEnum_Type'); - - PyTypeObject get PyEnum_Type => _PyEnum_Type.ref; - - late final ffi.Pointer _PyReversed_Type = - _lookup('PyReversed_Type'); - - PyTypeObject get PyReversed_Type => _PyReversed_Type.ref; - - late final ffi.Pointer _PySet_Type = - _lookup('PySet_Type'); - - PyTypeObject get PySet_Type => _PySet_Type.ref; - - late final ffi.Pointer _PyFrozenSet_Type = - _lookup('PyFrozenSet_Type'); - - PyTypeObject get PyFrozenSet_Type => _PyFrozenSet_Type.ref; - - late final ffi.Pointer _PySetIter_Type = - _lookup('PySetIter_Type'); - - PyTypeObject get PySetIter_Type => _PySetIter_Type.ref; - - ffi.Pointer PySet_New( - ffi.Pointer arg0, - ) { - return _PySet_New( - arg0, - ); - } - - late final _PySet_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('PySet_New'); - late final _PySet_New = _PySet_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFrozenSet_New( - ffi.Pointer arg0, - ) { - return _PyFrozenSet_New( - arg0, - ); - } - - late final _PyFrozenSet_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrozenSet_New'); - late final _PyFrozenSet_New = _PyFrozenSet_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PySet_Add( - ffi.Pointer set1, - ffi.Pointer key, - ) { - return _PySet_Add( - set1, - key, - ); - } - - late final _PySet_AddPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PySet_Add'); - late final _PySet_Add = _PySet_AddPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PySet_Clear( - ffi.Pointer set1, - ) { - return _PySet_Clear( - set1, - ); - } - - late final _PySet_ClearPtr = - _lookup)>>( - 'PySet_Clear'); - late final _PySet_Clear = - _PySet_ClearPtr.asFunction)>(); - - int PySet_Contains( - ffi.Pointer anyset, - ffi.Pointer key, - ) { - return _PySet_Contains( - anyset, - key, - ); - } - - late final _PySet_ContainsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PySet_Contains'); - late final _PySet_Contains = _PySet_ContainsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PySet_Discard( - ffi.Pointer set1, - ffi.Pointer key, - ) { - return _PySet_Discard( - set1, - key, - ); - } - - late final _PySet_DiscardPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PySet_Discard'); - late final _PySet_Discard = _PySet_DiscardPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PySet_Pop( - ffi.Pointer set1, - ) { - return _PySet_Pop( - set1, - ); - } - - late final _PySet_PopPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('PySet_Pop'); - late final _PySet_Pop = _PySet_PopPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PySet_Size( - ffi.Pointer anyset, - ) { - return _PySet_Size( - anyset, - ); - } - - late final _PySet_SizePtr = - _lookup)>>( - 'PySet_Size'); - late final _PySet_Size = - _PySet_SizePtr.asFunction)>(); - - late final ffi.Pointer> __PySet_Dummy = - _lookup>('_PySet_Dummy'); - - ffi.Pointer get _PySet_Dummy => __PySet_Dummy.value; - - set _PySet_Dummy(ffi.Pointer value) => __PySet_Dummy.value = value; - - int _PySet_NextEntry( - ffi.Pointer set1, - ffi.Pointer pos, - ffi.Pointer> key, - ffi.Pointer hash, - ) { - return __PySet_NextEntry( - set1, - pos, - key, - hash, - ); - } - - late final __PySet_NextEntryPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('_PySet_NextEntry'); - late final __PySet_NextEntry = __PySet_NextEntryPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>, ffi.Pointer)>(); - - int _PySet_Update( - ffi.Pointer set1, - ffi.Pointer iterable, - ) { - return __PySet_Update( - set1, - iterable, - ); - } - - late final __PySet_UpdatePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('_PySet_Update'); - late final __PySet_Update = __PySet_UpdatePtr - .asFunction, ffi.Pointer)>(); - - late final ffi.Pointer _PyCFunction_Type = - _lookup('PyCFunction_Type'); - - PyTypeObject get PyCFunction_Type => _PyCFunction_Type.ref; - - PyCFunction PyCFunction_GetFunction( - ffi.Pointer arg0, - ) { - return _PyCFunction_GetFunction( - arg0, - ); - } - - late final _PyCFunction_GetFunctionPtr = - _lookup)>>( - 'PyCFunction_GetFunction'); - late final _PyCFunction_GetFunction = _PyCFunction_GetFunctionPtr.asFunction< - PyCFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyCFunction_GetSelf( - ffi.Pointer arg0, - ) { - return _PyCFunction_GetSelf( - arg0, - ); - } - - late final _PyCFunction_GetSelfPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCFunction_GetSelf'); - late final _PyCFunction_GetSelf = _PyCFunction_GetSelfPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyCFunction_GetFlags( - ffi.Pointer arg0, - ) { - return _PyCFunction_GetFlags( - arg0, - ); - } - - late final _PyCFunction_GetFlagsPtr = - _lookup)>>( - 'PyCFunction_GetFlags'); - late final _PyCFunction_GetFlags = _PyCFunction_GetFlagsPtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer PyCFunction_Call( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyCFunction_Call( - arg0, - arg1, - arg2, - ); - } - - late final _PyCFunction_CallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCFunction_Call'); - late final _PyCFunction_Call = _PyCFunction_CallPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCFunction_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyCFunction_New( - arg0, - arg1, - ); - } - - late final _PyCFunction_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyCFunction_New'); - late final _PyCFunction_New = _PyCFunction_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCFunction_NewEx( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyCFunction_NewEx( - arg0, - arg1, - arg2, - ); - } - - late final _PyCFunction_NewExPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCFunction_NewEx'); - late final _PyCFunction_NewEx = _PyCFunction_NewExPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCMethod_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return _PyCMethod_New( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _PyCMethod_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCMethod_New'); - late final _PyCMethod_New = _PyCMethod_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - late final ffi.Pointer _PyCMethod_Type = - _lookup('PyCMethod_Type'); - - PyTypeObject get PyCMethod_Type => _PyCMethod_Type.ref; - - late final ffi.Pointer _PyModule_Type = - _lookup('PyModule_Type'); - - PyTypeObject get PyModule_Type => _PyModule_Type.ref; - - ffi.Pointer PyModule_NewObject( - ffi.Pointer name, - ) { - return _PyModule_NewObject( - name, - ); - } - - late final _PyModule_NewObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_NewObject'); - late final _PyModule_NewObject = _PyModule_NewObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_New( - ffi.Pointer name, - ) { - return _PyModule_New( - name, - ); - } - - late final _PyModule_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_New'); - late final _PyModule_New = _PyModule_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_GetDict( - ffi.Pointer arg0, - ) { - return _PyModule_GetDict( - arg0, - ); - } - - late final _PyModule_GetDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetDict'); - late final _PyModule_GetDict = _PyModule_GetDictPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_GetNameObject( - ffi.Pointer arg0, - ) { - return _PyModule_GetNameObject( - arg0, - ); - } - - late final _PyModule_GetNameObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetNameObject'); - late final _PyModule_GetNameObject = _PyModule_GetNameObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_GetName( - ffi.Pointer arg0, - ) { - return _PyModule_GetName( - arg0, - ); - } - - late final _PyModule_GetNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetName'); - late final _PyModule_GetName = _PyModule_GetNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_GetFilename( - ffi.Pointer arg0, - ) { - return _PyModule_GetFilename( - arg0, - ); - } - - late final _PyModule_GetFilenamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetFilename'); - late final _PyModule_GetFilename = _PyModule_GetFilenamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_GetFilenameObject( - ffi.Pointer arg0, - ) { - return _PyModule_GetFilenameObject( - arg0, - ); - } - - late final _PyModule_GetFilenameObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetFilenameObject'); - late final _PyModule_GetFilenameObject = _PyModule_GetFilenameObjectPtr - .asFunction Function(ffi.Pointer)>(); - - void _PyModule_Clear( - ffi.Pointer arg0, - ) { - return __PyModule_Clear( - arg0, - ); - } - - late final __PyModule_ClearPtr = - _lookup)>>( - '_PyModule_Clear'); - late final __PyModule_Clear = - __PyModule_ClearPtr.asFunction)>(); - - void _PyModule_ClearDict( - ffi.Pointer arg0, - ) { - return __PyModule_ClearDict( - arg0, - ); - } - - late final __PyModule_ClearDictPtr = - _lookup)>>( - '_PyModule_ClearDict'); - late final __PyModule_ClearDict = __PyModule_ClearDictPtr - .asFunction)>(); - - int _PyModuleSpec_IsInitializing( - ffi.Pointer arg0, - ) { - return __PyModuleSpec_IsInitializing( - arg0, - ); - } - - late final __PyModuleSpec_IsInitializingPtr = - _lookup)>>( - '_PyModuleSpec_IsInitializing'); - late final __PyModuleSpec_IsInitializing = __PyModuleSpec_IsInitializingPtr - .asFunction)>(); - - ffi.Pointer PyModule_GetDef( - ffi.Pointer arg0, - ) { - return _PyModule_GetDef( - arg0, - ); - } - - late final _PyModule_GetDefPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetDef'); - late final _PyModule_GetDef = _PyModule_GetDefPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModule_GetState( - ffi.Pointer arg0, - ) { - return _PyModule_GetState( - arg0, - ); - } - - late final _PyModule_GetStatePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModule_GetState'); - late final _PyModule_GetState = _PyModule_GetStatePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyModuleDef_Init( - ffi.Pointer arg0, - ) { - return _PyModuleDef_Init( - arg0, - ); - } - - late final _PyModuleDef_InitPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyModuleDef_Init'); - late final _PyModuleDef_Init = _PyModuleDef_InitPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyModuleDef_Type = - _lookup('PyModuleDef_Type'); - - PyTypeObject get PyModuleDef_Type => _PyModuleDef_Type.ref; - - late final ffi.Pointer _PyFunction_Type = - _lookup('PyFunction_Type'); - - PyTypeObject get PyFunction_Type => _PyFunction_Type.ref; - - ffi.Pointer PyFunction_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyFunction_New( - arg0, - arg1, - ); - } - - late final _PyFunction_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyFunction_New'); - late final _PyFunction_New = _PyFunction_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyFunction_NewWithQualName( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyFunction_NewWithQualName( - arg0, - arg1, - arg2, - ); - } - - late final _PyFunction_NewWithQualNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyFunction_NewWithQualName'); - late final _PyFunction_NewWithQualName = - _PyFunction_NewWithQualNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyFunction_GetCode( - ffi.Pointer arg0, - ) { - return _PyFunction_GetCode( - arg0, - ); - } - - late final _PyFunction_GetCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetCode'); - late final _PyFunction_GetCode = _PyFunction_GetCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFunction_GetGlobals( - ffi.Pointer arg0, - ) { - return _PyFunction_GetGlobals( - arg0, - ); - } - - late final _PyFunction_GetGlobalsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetGlobals'); - late final _PyFunction_GetGlobals = _PyFunction_GetGlobalsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFunction_GetModule( - ffi.Pointer arg0, - ) { - return _PyFunction_GetModule( - arg0, - ); - } - - late final _PyFunction_GetModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetModule'); - late final _PyFunction_GetModule = _PyFunction_GetModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFunction_GetDefaults( - ffi.Pointer arg0, - ) { - return _PyFunction_GetDefaults( - arg0, - ); - } - - late final _PyFunction_GetDefaultsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetDefaults'); - late final _PyFunction_GetDefaults = _PyFunction_GetDefaultsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyFunction_SetDefaults( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyFunction_SetDefaults( - arg0, - arg1, - ); - } - - late final _PyFunction_SetDefaultsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyFunction_SetDefaults'); - late final _PyFunction_SetDefaults = _PyFunction_SetDefaultsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - void PyFunction_SetVectorcall( - ffi.Pointer arg0, - vectorcallfunc arg1, - ) { - return _PyFunction_SetVectorcall( - arg0, - arg1, - ); - } - - late final _PyFunction_SetVectorcallPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - vectorcallfunc)>>('PyFunction_SetVectorcall'); - late final _PyFunction_SetVectorcall = - _PyFunction_SetVectorcallPtr.asFunction< - void Function(ffi.Pointer, vectorcallfunc)>(); - - ffi.Pointer PyFunction_GetKwDefaults( - ffi.Pointer arg0, - ) { - return _PyFunction_GetKwDefaults( - arg0, - ); - } - - late final _PyFunction_GetKwDefaultsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetKwDefaults'); - late final _PyFunction_GetKwDefaults = _PyFunction_GetKwDefaultsPtr - .asFunction Function(ffi.Pointer)>(); - - int PyFunction_SetKwDefaults( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyFunction_SetKwDefaults( - arg0, - arg1, - ); - } - - late final _PyFunction_SetKwDefaultsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyFunction_SetKwDefaults'); - late final _PyFunction_SetKwDefaults = _PyFunction_SetKwDefaultsPtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer PyFunction_GetClosure( - ffi.Pointer arg0, - ) { - return _PyFunction_GetClosure( - arg0, - ); - } - - late final _PyFunction_GetClosurePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetClosure'); - late final _PyFunction_GetClosure = _PyFunction_GetClosurePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyFunction_SetClosure( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyFunction_SetClosure( - arg0, - arg1, - ); - } - - late final _PyFunction_SetClosurePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyFunction_SetClosure'); - late final _PyFunction_SetClosure = _PyFunction_SetClosurePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyFunction_GetAnnotations( - ffi.Pointer arg0, - ) { - return _PyFunction_GetAnnotations( - arg0, - ); - } - - late final _PyFunction_GetAnnotationsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFunction_GetAnnotations'); - late final _PyFunction_GetAnnotations = _PyFunction_GetAnnotationsPtr - .asFunction Function(ffi.Pointer)>(); - - int PyFunction_SetAnnotations( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyFunction_SetAnnotations( - arg0, - arg1, - ); - } - - late final _PyFunction_SetAnnotationsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyFunction_SetAnnotations'); - late final _PyFunction_SetAnnotations = _PyFunction_SetAnnotationsPtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer _PyFunction_Vectorcall( - ffi.Pointer func, - ffi.Pointer> stack, - int nargsf, - ffi.Pointer kwnames, - ) { - return __PyFunction_Vectorcall( - func, - stack, - nargsf, - kwnames, - ); - } - - late final __PyFunction_VectorcallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Size, - ffi.Pointer)>>('_PyFunction_Vectorcall'); - late final __PyFunction_Vectorcall = __PyFunction_VectorcallPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer>, int, ffi.Pointer)>(); - - late final ffi.Pointer _PyClassMethod_Type = - _lookup('PyClassMethod_Type'); - - PyTypeObject get PyClassMethod_Type => _PyClassMethod_Type.ref; - - late final ffi.Pointer _PyStaticMethod_Type = - _lookup('PyStaticMethod_Type'); - - PyTypeObject get PyStaticMethod_Type => _PyStaticMethod_Type.ref; - - ffi.Pointer PyClassMethod_New( - ffi.Pointer arg0, - ) { - return _PyClassMethod_New( - arg0, - ); - } - - late final _PyClassMethod_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyClassMethod_New'); - late final _PyClassMethod_New = _PyClassMethod_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyStaticMethod_New( - ffi.Pointer arg0, - ) { - return _PyStaticMethod_New( - arg0, - ); - } - - late final _PyStaticMethod_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyStaticMethod_New'); - late final _PyStaticMethod_New = _PyStaticMethod_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyFunction_AddWatcher( - PyFunction_WatchCallback callback, - ) { - return _PyFunction_AddWatcher( - callback, - ); - } - - late final _PyFunction_AddWatcherPtr = - _lookup>( - 'PyFunction_AddWatcher'); - late final _PyFunction_AddWatcher = _PyFunction_AddWatcherPtr.asFunction< - int Function(PyFunction_WatchCallback)>(); - - int PyFunction_ClearWatcher( - int watcher_id, - ) { - return _PyFunction_ClearWatcher( - watcher_id, - ); - } - - late final _PyFunction_ClearWatcherPtr = - _lookup>( - 'PyFunction_ClearWatcher'); - late final _PyFunction_ClearWatcher = - _PyFunction_ClearWatcherPtr.asFunction(); - - late final ffi.Pointer _PyMethod_Type = - _lookup('PyMethod_Type'); - - PyTypeObject get PyMethod_Type => _PyMethod_Type.ref; - - ffi.Pointer PyMethod_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyMethod_New( - arg0, - arg1, - ); - } - - late final _PyMethod_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyMethod_New'); - late final _PyMethod_New = _PyMethod_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyMethod_Function( - ffi.Pointer arg0, - ) { - return _PyMethod_Function( - arg0, - ); - } - - late final _PyMethod_FunctionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMethod_Function'); - late final _PyMethod_Function = _PyMethod_FunctionPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyMethod_Self( - ffi.Pointer arg0, - ) { - return _PyMethod_Self( - arg0, - ); - } - - late final _PyMethod_SelfPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMethod_Self'); - late final _PyMethod_Self = _PyMethod_SelfPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyInstanceMethod_Type = - _lookup('PyInstanceMethod_Type'); - - PyTypeObject get PyInstanceMethod_Type => _PyInstanceMethod_Type.ref; - - ffi.Pointer PyInstanceMethod_New( - ffi.Pointer arg0, - ) { - return _PyInstanceMethod_New( - arg0, - ); - } - - late final _PyInstanceMethod_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyInstanceMethod_New'); - late final _PyInstanceMethod_New = _PyInstanceMethod_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyInstanceMethod_Function( - ffi.Pointer arg0, - ) { - return _PyInstanceMethod_Function( - arg0, - ); - } - - late final _PyInstanceMethod_FunctionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyInstanceMethod_Function'); - late final _PyInstanceMethod_Function = _PyInstanceMethod_FunctionPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyFile_FromFd( - int arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - int arg3, - ffi.Pointer arg4, - ffi.Pointer arg5, - ffi.Pointer arg6, - int arg7, - ) { - return _PyFile_FromFd( - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - ); - } - - late final _PyFile_FromFdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int)>>('PyFile_FromFd'); - late final _PyFile_FromFd = _PyFile_FromFdPtr.asFunction< - ffi.Pointer Function( - int, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int)>(); - - ffi.Pointer PyFile_GetLine( - ffi.Pointer arg0, - int arg1, - ) { - return _PyFile_GetLine( - arg0, - arg1, - ); - } - - late final _PyFile_GetLinePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyFile_GetLine'); - late final _PyFile_GetLine = _PyFile_GetLinePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int PyFile_WriteObject( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyFile_WriteObject( - arg0, - arg1, - arg2, - ); - } - - late final _PyFile_WriteObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyFile_WriteObject'); - late final _PyFile_WriteObject = _PyFile_WriteObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyFile_WriteString( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyFile_WriteString( - arg0, - arg1, - ); - } - - late final _PyFile_WriteStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyFile_WriteString'); - late final _PyFile_WriteString = _PyFile_WriteStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyObject_AsFileDescriptor( - ffi.Pointer arg0, - ) { - return _PyObject_AsFileDescriptor( - arg0, - ); - } - - late final _PyObject_AsFileDescriptorPtr = - _lookup)>>( - 'PyObject_AsFileDescriptor'); - late final _PyObject_AsFileDescriptor = _PyObject_AsFileDescriptorPtr - .asFunction)>(); - - late final ffi.Pointer> _Py_FileSystemDefaultEncoding = - _lookup>('Py_FileSystemDefaultEncoding'); - - ffi.Pointer get Py_FileSystemDefaultEncoding => - _Py_FileSystemDefaultEncoding.value; - - set Py_FileSystemDefaultEncoding(ffi.Pointer value) => - _Py_FileSystemDefaultEncoding.value = value; - - late final ffi.Pointer> - _Py_FileSystemDefaultEncodeErrors = - _lookup>('Py_FileSystemDefaultEncodeErrors'); - - ffi.Pointer get Py_FileSystemDefaultEncodeErrors => - _Py_FileSystemDefaultEncodeErrors.value; - - set Py_FileSystemDefaultEncodeErrors(ffi.Pointer value) => - _Py_FileSystemDefaultEncodeErrors.value = value; - - late final ffi.Pointer _Py_HasFileSystemDefaultEncoding = - _lookup('Py_HasFileSystemDefaultEncoding'); - - int get Py_HasFileSystemDefaultEncoding => - _Py_HasFileSystemDefaultEncoding.value; - - set Py_HasFileSystemDefaultEncoding(int value) => - _Py_HasFileSystemDefaultEncoding.value = value; - - late final ffi.Pointer _Py_UTF8Mode = - _lookup('Py_UTF8Mode'); - - int get Py_UTF8Mode => _Py_UTF8Mode.value; - - set Py_UTF8Mode(int value) => _Py_UTF8Mode.value = value; - - ffi.Pointer Py_UniversalNewlineFgets( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return _Py_UniversalNewlineFgets( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _Py_UniversalNewlineFgetsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('Py_UniversalNewlineFgets'); - late final _Py_UniversalNewlineFgets = - _Py_UniversalNewlineFgetsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _Py_UniversalNewlineFgetsWithSize( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ffi.Pointer arg4, - ) { - return __Py_UniversalNewlineFgetsWithSize( - arg0, - arg1, - arg2, - arg3, - arg4, - ); - } - - late final __Py_UniversalNewlineFgetsWithSizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_Py_UniversalNewlineFgetsWithSize'); - late final __Py_UniversalNewlineFgetsWithSize = - __Py_UniversalNewlineFgetsWithSizePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyFile_NewStdPrinter( - int arg0, - ) { - return _PyFile_NewStdPrinter( - arg0, - ); - } - - late final _PyFile_NewStdPrinterPtr = - _lookup Function(ffi.Int)>>( - 'PyFile_NewStdPrinter'); - late final _PyFile_NewStdPrinter = _PyFile_NewStdPrinterPtr.asFunction< - ffi.Pointer Function(int)>(); - - late final ffi.Pointer _PyStdPrinter_Type = - _lookup('PyStdPrinter_Type'); - - PyTypeObject get PyStdPrinter_Type => _PyStdPrinter_Type.ref; - - ffi.Pointer PyFile_OpenCode( - ffi.Pointer utf8path, - ) { - return _PyFile_OpenCode( - utf8path, - ); - } - - late final _PyFile_OpenCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFile_OpenCode'); - late final _PyFile_OpenCode = _PyFile_OpenCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFile_OpenCodeObject( - ffi.Pointer path, - ) { - return _PyFile_OpenCodeObject( - path, - ); - } - - late final _PyFile_OpenCodeObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFile_OpenCodeObject'); - late final _PyFile_OpenCodeObject = _PyFile_OpenCodeObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyFile_SetOpenCodeHook( - Py_OpenCodeHookFunction hook, - ffi.Pointer userData, - ) { - return _PyFile_SetOpenCodeHook( - hook, - userData, - ); - } - - late final _PyFile_SetOpenCodeHookPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(Py_OpenCodeHookFunction, - ffi.Pointer)>>('PyFile_SetOpenCodeHook'); - late final _PyFile_SetOpenCodeHook = _PyFile_SetOpenCodeHookPtr.asFunction< - int Function(Py_OpenCodeHookFunction, ffi.Pointer)>(); - - int _PyLong_FileDescriptor_Converter( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyLong_FileDescriptor_Converter( - arg0, - arg1, - ); - } - - late final __PyLong_FileDescriptor_ConverterPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyLong_FileDescriptor_Converter'); - late final __PyLong_FileDescriptor_Converter = - __PyLong_FileDescriptor_ConverterPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyCapsule_Type = - _lookup('PyCapsule_Type'); - - PyTypeObject get PyCapsule_Type => _PyCapsule_Type.ref; - - ffi.Pointer PyCapsule_New( - ffi.Pointer pointer, - ffi.Pointer name, - PyCapsule_Destructor destructor, - ) { - return _PyCapsule_New( - pointer, - name, - destructor, - ); - } - - late final _PyCapsule_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, PyCapsule_Destructor)>>('PyCapsule_New'); - late final _PyCapsule_New = _PyCapsule_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, PyCapsule_Destructor)>(); - - ffi.Pointer PyCapsule_GetPointer( - ffi.Pointer capsule, - ffi.Pointer name, - ) { - return _PyCapsule_GetPointer( - capsule, - name, - ); - } - - late final _PyCapsule_GetPointerPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyCapsule_GetPointer'); - late final _PyCapsule_GetPointer = _PyCapsule_GetPointerPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - PyCapsule_Destructor PyCapsule_GetDestructor( - ffi.Pointer capsule, - ) { - return _PyCapsule_GetDestructor( - capsule, - ); - } - - late final _PyCapsule_GetDestructorPtr = _lookup< - ffi.NativeFunction< - PyCapsule_Destructor Function( - ffi.Pointer)>>('PyCapsule_GetDestructor'); - late final _PyCapsule_GetDestructor = _PyCapsule_GetDestructorPtr.asFunction< - PyCapsule_Destructor Function(ffi.Pointer)>(); - - ffi.Pointer PyCapsule_GetName( - ffi.Pointer capsule, - ) { - return _PyCapsule_GetName( - capsule, - ); - } - - late final _PyCapsule_GetNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCapsule_GetName'); - late final _PyCapsule_GetName = _PyCapsule_GetNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCapsule_GetContext( - ffi.Pointer capsule, - ) { - return _PyCapsule_GetContext( - capsule, - ); - } - - late final _PyCapsule_GetContextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCapsule_GetContext'); - late final _PyCapsule_GetContext = _PyCapsule_GetContextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyCapsule_IsValid( - ffi.Pointer capsule, - ffi.Pointer name, - ) { - return _PyCapsule_IsValid( - capsule, - name, - ); - } - - late final _PyCapsule_IsValidPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyCapsule_IsValid'); - late final _PyCapsule_IsValid = _PyCapsule_IsValidPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyCapsule_SetPointer( - ffi.Pointer capsule, - ffi.Pointer pointer, - ) { - return _PyCapsule_SetPointer( - capsule, - pointer, - ); - } - - late final _PyCapsule_SetPointerPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyCapsule_SetPointer'); - late final _PyCapsule_SetPointer = _PyCapsule_SetPointerPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyCapsule_SetDestructor( - ffi.Pointer capsule, - PyCapsule_Destructor destructor, - ) { - return _PyCapsule_SetDestructor( - capsule, - destructor, - ); - } - - late final _PyCapsule_SetDestructorPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - PyCapsule_Destructor)>>('PyCapsule_SetDestructor'); - late final _PyCapsule_SetDestructor = _PyCapsule_SetDestructorPtr.asFunction< - int Function(ffi.Pointer, PyCapsule_Destructor)>(); - - int PyCapsule_SetName( - ffi.Pointer capsule, - ffi.Pointer name, - ) { - return _PyCapsule_SetName( - capsule, - name, - ); - } - - late final _PyCapsule_SetNamePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyCapsule_SetName'); - late final _PyCapsule_SetName = _PyCapsule_SetNamePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyCapsule_SetContext( - ffi.Pointer capsule, - ffi.Pointer context, - ) { - return _PyCapsule_SetContext( - capsule, - context, - ); - } - - late final _PyCapsule_SetContextPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyCapsule_SetContext'); - late final _PyCapsule_SetContext = _PyCapsule_SetContextPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCapsule_Import( - ffi.Pointer name, - int no_block, - ) { - return _PyCapsule_Import( - name, - no_block, - ); - } - - late final _PyCapsule_ImportPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyCapsule_Import'); - late final _PyCapsule_Import = _PyCapsule_ImportPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - late final ffi.Pointer _PyCode_Type = - _lookup('PyCode_Type'); - - PyTypeObject get PyCode_Type => _PyCode_Type.ref; - - ffi.Pointer PyUnstable_Code_New( - int arg0, - int arg1, - int arg2, - int arg3, - int arg4, - ffi.Pointer arg5, - ffi.Pointer arg6, - ffi.Pointer arg7, - ffi.Pointer arg8, - ffi.Pointer arg9, - ffi.Pointer arg10, - ffi.Pointer arg11, - ffi.Pointer arg12, - ffi.Pointer arg13, - int arg14, - ffi.Pointer arg15, - ffi.Pointer arg16, - ) { - return _PyUnstable_Code_New( - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - ); - } - - late final _PyUnstable_Code_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('PyUnstable_Code_New'); - late final _PyUnstable_Code_New = _PyUnstable_Code_NewPtr.asFunction< - ffi.Pointer Function( - int, - int, - int, - int, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyUnstable_Code_NewWithPosOnlyArgs( - int arg0, - int arg1, - int arg2, - int arg3, - int arg4, - int arg5, - ffi.Pointer arg6, - ffi.Pointer arg7, - ffi.Pointer arg8, - ffi.Pointer arg9, - ffi.Pointer arg10, - ffi.Pointer arg11, - ffi.Pointer arg12, - ffi.Pointer arg13, - ffi.Pointer arg14, - int arg15, - ffi.Pointer arg16, - ffi.Pointer arg17, - ) { - return _PyUnstable_Code_NewWithPosOnlyArgs( - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - ); - } - - late final _PyUnstable_Code_NewWithPosOnlyArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('PyUnstable_Code_NewWithPosOnlyArgs'); - late final _PyUnstable_Code_NewWithPosOnlyArgs = - _PyUnstable_Code_NewWithPosOnlyArgsPtr.asFunction< - ffi.Pointer Function( - int, - int, - int, - int, - int, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyCode_NewEmpty( - ffi.Pointer filename, - ffi.Pointer funcname, - int firstlineno, - ) { - return _PyCode_NewEmpty( - filename, - funcname, - firstlineno, - ); - } - - late final _PyCode_NewEmptyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('PyCode_NewEmpty'); - late final _PyCode_NewEmpty = _PyCode_NewEmptyPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - int PyCode_Addr2Line( - ffi.Pointer arg0, - int arg1, - ) { - return _PyCode_Addr2Line( - arg0, - arg1, - ); - } - - late final _PyCode_Addr2LinePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Int)>>('PyCode_Addr2Line'); - late final _PyCode_Addr2Line = _PyCode_Addr2LinePtr.asFunction< - int Function(ffi.Pointer, int)>(); - - int PyCode_Addr2Location( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ffi.Pointer arg4, - ffi.Pointer arg5, - ) { - return _PyCode_Addr2Location( - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - ); - } - - late final _PyCode_Addr2LocationPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCode_Addr2Location'); - late final _PyCode_Addr2Location = _PyCode_Addr2LocationPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer, - ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); - - int PyCode_AddWatcher( - PyCode_WatchCallback callback, - ) { - return _PyCode_AddWatcher( - callback, - ); - } - - late final _PyCode_AddWatcherPtr = - _lookup>( - 'PyCode_AddWatcher'); - late final _PyCode_AddWatcher = - _PyCode_AddWatcherPtr.asFunction(); - - int PyCode_ClearWatcher( - int watcher_id, - ) { - return _PyCode_ClearWatcher( - watcher_id, - ); - } - - late final _PyCode_ClearWatcherPtr = - _lookup>( - 'PyCode_ClearWatcher'); - late final _PyCode_ClearWatcher = - _PyCode_ClearWatcherPtr.asFunction(); - - int _PyCode_CheckLineNumber( - int lasti, - ffi.Pointer bounds, - ) { - return __PyCode_CheckLineNumber( - lasti, - bounds, - ); - } - - late final __PyCode_CheckLineNumberPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Int, - ffi.Pointer)>>('_PyCode_CheckLineNumber'); - late final __PyCode_CheckLineNumber = __PyCode_CheckLineNumberPtr - .asFunction)>(); - - ffi.Pointer _PyCode_ConstantKey( - ffi.Pointer obj, - ) { - return __PyCode_ConstantKey( - obj, - ); - } - - late final __PyCode_ConstantKeyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyCode_ConstantKey'); - late final __PyCode_ConstantKey = __PyCode_ConstantKeyPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyCode_Optimize( - ffi.Pointer code, - ffi.Pointer consts, - ffi.Pointer names, - ffi.Pointer lnotab, - ) { - return _PyCode_Optimize( - code, - consts, - names, - lnotab, - ); - } - - late final _PyCode_OptimizePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCode_Optimize'); - late final _PyCode_Optimize = _PyCode_OptimizePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - int PyUnstable_Code_GetExtra( - ffi.Pointer code, - int index, - ffi.Pointer> extra, - ) { - return _PyUnstable_Code_GetExtra( - code, - index, - extra, - ); - } - - late final _PyUnstable_Code_GetExtraPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer>)>>('PyUnstable_Code_GetExtra'); - late final _PyUnstable_Code_GetExtra = - _PyUnstable_Code_GetExtraPtr.asFunction< - int Function(ffi.Pointer, int, - ffi.Pointer>)>(); - - int PyUnstable_Code_SetExtra( - ffi.Pointer code, - int index, - ffi.Pointer extra, - ) { - return _PyUnstable_Code_SetExtra( - code, - index, - extra, - ); - } - - late final _PyUnstable_Code_SetExtraPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyUnstable_Code_SetExtra'); - late final _PyUnstable_Code_SetExtra = - _PyUnstable_Code_SetExtraPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyCode_GetCode( - ffi.Pointer code, - ) { - return _PyCode_GetCode( - code, - ); - } - - late final _PyCode_GetCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCode_GetCode'); - late final _PyCode_GetCode = _PyCode_GetCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCode_GetVarnames( - ffi.Pointer code, - ) { - return _PyCode_GetVarnames( - code, - ); - } - - late final _PyCode_GetVarnamesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCode_GetVarnames'); - late final _PyCode_GetVarnames = _PyCode_GetVarnamesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCode_GetCellvars( - ffi.Pointer code, - ) { - return _PyCode_GetCellvars( - code, - ); - } - - late final _PyCode_GetCellvarsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCode_GetCellvars'); - late final _PyCode_GetCellvars = _PyCode_GetCellvarsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCode_GetFreevars( - ffi.Pointer code, - ) { - return _PyCode_GetFreevars( - code, - ); - } - - late final _PyCode_GetFreevarsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCode_GetFreevars'); - late final _PyCode_GetFreevars = _PyCode_GetFreevarsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyFrame_GetLineNumber( - ffi.Pointer arg0, - ) { - return _PyFrame_GetLineNumber( - arg0, - ); - } - - late final _PyFrame_GetLineNumberPtr = - _lookup)>>( - 'PyFrame_GetLineNumber'); - late final _PyFrame_GetLineNumber = _PyFrame_GetLineNumberPtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetCode( - ffi.Pointer frame, - ) { - return _PyFrame_GetCode( - frame, - ); - } - - late final _PyFrame_GetCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrame_GetCode'); - late final _PyFrame_GetCode = _PyFrame_GetCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyFrame_Type = - _lookup('PyFrame_Type'); - - PyTypeObject get PyFrame_Type => _PyFrame_Type.ref; - - ffi.Pointer PyFrame_GetBack( - ffi.Pointer frame, - ) { - return _PyFrame_GetBack( - frame, - ); - } - - late final _PyFrame_GetBackPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrame_GetBack'); - late final _PyFrame_GetBack = _PyFrame_GetBackPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetLocals( - ffi.Pointer frame, - ) { - return _PyFrame_GetLocals( - frame, - ); - } - - late final _PyFrame_GetLocalsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrame_GetLocals'); - late final _PyFrame_GetLocals = _PyFrame_GetLocalsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetGlobals( - ffi.Pointer frame, - ) { - return _PyFrame_GetGlobals( - frame, - ); - } - - late final _PyFrame_GetGlobalsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrame_GetGlobals'); - late final _PyFrame_GetGlobals = _PyFrame_GetGlobalsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetBuiltins( - ffi.Pointer frame, - ) { - return _PyFrame_GetBuiltins( - frame, - ); - } - - late final _PyFrame_GetBuiltinsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrame_GetBuiltins'); - late final _PyFrame_GetBuiltins = _PyFrame_GetBuiltinsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetGenerator( - ffi.Pointer frame, - ) { - return _PyFrame_GetGenerator( - frame, - ); - } - - late final _PyFrame_GetGeneratorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyFrame_GetGenerator'); - late final _PyFrame_GetGenerator = _PyFrame_GetGeneratorPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyFrame_GetLasti( - ffi.Pointer frame, - ) { - return _PyFrame_GetLasti( - frame, - ); - } - - late final _PyFrame_GetLastiPtr = - _lookup)>>( - 'PyFrame_GetLasti'); - late final _PyFrame_GetLasti = _PyFrame_GetLastiPtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetVar( - ffi.Pointer frame, - ffi.Pointer name, - ) { - return _PyFrame_GetVar( - frame, - name, - ); - } - - late final _PyFrame_GetVarPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyFrame_GetVar'); - late final _PyFrame_GetVar = _PyFrame_GetVarPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyFrame_GetVarString( - ffi.Pointer frame, - ffi.Pointer name, - ) { - return _PyFrame_GetVarString( - frame, - name, - ); - } - - late final _PyFrame_GetVarStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyFrame_GetVarString'); - late final _PyFrame_GetVarString = _PyFrame_GetVarStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyUnstable_InterpreterFrame_GetCode( - ffi.Pointer<_PyInterpreterFrame> frame, - ) { - return _PyUnstable_InterpreterFrame_GetCode( - frame, - ); - } - - late final _PyUnstable_InterpreterFrame_GetCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_PyInterpreterFrame>)>>( - 'PyUnstable_InterpreterFrame_GetCode'); - late final _PyUnstable_InterpreterFrame_GetCode = - _PyUnstable_InterpreterFrame_GetCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_PyInterpreterFrame>)>(); - - int PyUnstable_InterpreterFrame_GetLasti( - ffi.Pointer<_PyInterpreterFrame> frame, - ) { - return _PyUnstable_InterpreterFrame_GetLasti( - frame, - ); - } - - late final _PyUnstable_InterpreterFrame_GetLastiPtr = _lookup< - ffi - .NativeFunction)>>( - 'PyUnstable_InterpreterFrame_GetLasti'); - late final _PyUnstable_InterpreterFrame_GetLasti = - _PyUnstable_InterpreterFrame_GetLastiPtr.asFunction< - int Function(ffi.Pointer<_PyInterpreterFrame>)>(); - - int PyUnstable_InterpreterFrame_GetLine( - ffi.Pointer<_PyInterpreterFrame> frame, - ) { - return _PyUnstable_InterpreterFrame_GetLine( - frame, - ); - } - - late final _PyUnstable_InterpreterFrame_GetLinePtr = _lookup< - ffi - .NativeFunction)>>( - 'PyUnstable_InterpreterFrame_GetLine'); - late final _PyUnstable_InterpreterFrame_GetLine = - _PyUnstable_InterpreterFrame_GetLinePtr.asFunction< - int Function(ffi.Pointer<_PyInterpreterFrame>)>(); - - int PyTraceBack_Here( - ffi.Pointer arg0, - ) { - return _PyTraceBack_Here( - arg0, - ); - } - - late final _PyTraceBack_HerePtr = - _lookup)>>( - 'PyTraceBack_Here'); - late final _PyTraceBack_Here = _PyTraceBack_HerePtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyTraceBack_Print( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyTraceBack_Print( - arg0, - arg1, - ); - } - - late final _PyTraceBack_PrintPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyTraceBack_Print'); - late final _PyTraceBack_Print = _PyTraceBack_PrintPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyTraceBack_Type = - _lookup('PyTraceBack_Type'); - - PyTypeObject get PyTraceBack_Type => _PyTraceBack_Type.ref; - - int _Py_DisplaySourceLine( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - int arg3, - ffi.Pointer arg4, - ffi.Pointer> arg5, - ) { - return __Py_DisplaySourceLine( - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - ); - } - - late final __Py_DisplaySourceLinePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Int, - ffi.Pointer, - ffi.Pointer>)>>('_Py_DisplaySourceLine'); - late final __Py_DisplaySourceLine = __Py_DisplaySourceLinePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, int, - ffi.Pointer, ffi.Pointer>)>(); - - void _PyTraceback_Add( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return __PyTraceback_Add( - arg0, - arg1, - arg2, - ); - } - - late final __PyTraceback_AddPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('_PyTraceback_Add'); - late final __PyTraceback_Add = __PyTraceback_AddPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, int)>(); - - late final ffi.Pointer __Py_EllipsisObject = - _lookup('_Py_EllipsisObject'); - - PyObject get _Py_EllipsisObject => __Py_EllipsisObject.ref; - - late final ffi.Pointer _PySlice_Type = - _lookup('PySlice_Type'); - - PyTypeObject get PySlice_Type => _PySlice_Type.ref; - - late final ffi.Pointer _PyEllipsis_Type = - _lookup('PyEllipsis_Type'); - - PyTypeObject get PyEllipsis_Type => _PyEllipsis_Type.ref; - - ffi.Pointer PySlice_New( - ffi.Pointer start, - ffi.Pointer stop, - ffi.Pointer step, - ) { - return _PySlice_New( - start, - stop, - step, - ); - } - - late final _PySlice_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PySlice_New'); - late final _PySlice_New = _PySlice_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PySlice_FromIndices( - int start, - int stop, - ) { - return __PySlice_FromIndices( - start, - stop, - ); - } - - late final __PySlice_FromIndicesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - Py_ssize_t, Py_ssize_t)>>('_PySlice_FromIndices'); - late final __PySlice_FromIndices = __PySlice_FromIndicesPtr - .asFunction Function(int, int)>(); - - int _PySlice_GetLongIndices( - ffi.Pointer self, - ffi.Pointer length, - ffi.Pointer> start_ptr, - ffi.Pointer> stop_ptr, - ffi.Pointer> step_ptr, - ) { - return __PySlice_GetLongIndices( - self, - length, - start_ptr, - stop_ptr, - step_ptr, - ); - } - - late final __PySlice_GetLongIndicesPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>>('_PySlice_GetLongIndices'); - late final __PySlice_GetLongIndices = __PySlice_GetLongIndicesPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer>, - ffi.Pointer>)>(); - - int PySlice_GetIndices( - ffi.Pointer r, - int length, - ffi.Pointer start, - ffi.Pointer stop, - ffi.Pointer step, - ) { - return _PySlice_GetIndices( - r, - length, - start, - stop, - step, - ); - } - - late final _PySlice_GetIndicesPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PySlice_GetIndices'); - late final _PySlice_GetIndices = _PySlice_GetIndicesPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int PySlice_GetIndicesEx( - ffi.Pointer r, - int length, - ffi.Pointer start, - ffi.Pointer stop, - ffi.Pointer step, - ffi.Pointer slicelength, - ) { - return _PySlice_GetIndicesEx( - r, - length, - start, - stop, - step, - slicelength, - ); - } - - late final _PySlice_GetIndicesExPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PySlice_GetIndicesEx'); - late final _PySlice_GetIndicesEx = _PySlice_GetIndicesExPtr.asFunction< - int Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - int PySlice_Unpack( - ffi.Pointer slice, - ffi.Pointer start, - ffi.Pointer stop, - ffi.Pointer step, - ) { - return _PySlice_Unpack( - slice, - start, - stop, - step, - ); - } - - late final _PySlice_UnpackPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PySlice_Unpack'); - late final _PySlice_Unpack = _PySlice_UnpackPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int PySlice_AdjustIndices( - int length, - ffi.Pointer start, - ffi.Pointer stop, - int step, - ) { - return _PySlice_AdjustIndices( - length, - start, - stop, - step, - ); - } - - late final _PySlice_AdjustIndicesPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(Py_ssize_t, ffi.Pointer, - ffi.Pointer, Py_ssize_t)>>('PySlice_AdjustIndices'); - late final _PySlice_AdjustIndices = _PySlice_AdjustIndicesPtr.asFunction< - int Function( - int, ffi.Pointer, ffi.Pointer, int)>(); - - late final ffi.Pointer _PyCell_Type = - _lookup('PyCell_Type'); - - PyTypeObject get PyCell_Type => _PyCell_Type.ref; - - ffi.Pointer PyCell_New( - ffi.Pointer arg0, - ) { - return _PyCell_New( - arg0, - ); - } - - late final _PyCell_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('PyCell_New'); - late final _PyCell_New = _PyCell_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCell_Get( - ffi.Pointer arg0, - ) { - return _PyCell_Get( - arg0, - ); - } - - late final _PyCell_GetPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer)>>('PyCell_Get'); - late final _PyCell_Get = _PyCell_GetPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyCell_Set( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyCell_Set( - arg0, - arg1, - ); - } - - late final _PyCell_SetPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyCell_Set'); - late final _PyCell_Set = _PyCell_SetPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PySeqIter_Type = - _lookup('PySeqIter_Type'); - - PyTypeObject get PySeqIter_Type => _PySeqIter_Type.ref; - - late final ffi.Pointer _PyCallIter_Type = - _lookup('PyCallIter_Type'); - - PyTypeObject get PyCallIter_Type => _PyCallIter_Type.ref; - - ffi.Pointer PySeqIter_New( - ffi.Pointer arg0, - ) { - return _PySeqIter_New( - arg0, - ); - } - - late final _PySeqIter_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PySeqIter_New'); - late final _PySeqIter_New = _PySeqIter_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCallIter_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyCallIter_New( - arg0, - arg1, - ); - } - - late final _PyCallIter_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyCallIter_New'); - late final _PyCallIter_New = _PyCallIter_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyGen_Type = - _lookup('PyGen_Type'); - - PyTypeObject get PyGen_Type => _PyGen_Type.ref; - - ffi.Pointer PyGen_New( - ffi.Pointer arg0, - ) { - return _PyGen_New( - arg0, - ); - } - - late final _PyGen_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyGen_New'); - late final _PyGen_New = _PyGen_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyGen_NewWithQualName( - ffi.Pointer arg0, - ffi.Pointer name, - ffi.Pointer qualname, - ) { - return _PyGen_NewWithQualName( - arg0, - name, - qualname, - ); - } - - late final _PyGen_NewWithQualNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyGen_NewWithQualName'); - late final _PyGen_NewWithQualName = _PyGen_NewWithQualNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int _PyGen_SetStopIterationValue( - ffi.Pointer arg0, - ) { - return __PyGen_SetStopIterationValue( - arg0, - ); - } - - late final __PyGen_SetStopIterationValuePtr = - _lookup)>>( - '_PyGen_SetStopIterationValue'); - late final __PyGen_SetStopIterationValue = __PyGen_SetStopIterationValuePtr - .asFunction)>(); - - int _PyGen_FetchStopIterationValue( - ffi.Pointer> arg0, - ) { - return __PyGen_FetchStopIterationValue( - arg0, - ); - } - - late final __PyGen_FetchStopIterationValuePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer>)>>( - '_PyGen_FetchStopIterationValue'); - late final __PyGen_FetchStopIterationValue = - __PyGen_FetchStopIterationValuePtr - .asFunction>)>(); - - void _PyGen_Finalize( - ffi.Pointer self, - ) { - return __PyGen_Finalize( - self, - ); - } - - late final __PyGen_FinalizePtr = - _lookup)>>( - '_PyGen_Finalize'); - late final __PyGen_Finalize = - __PyGen_FinalizePtr.asFunction)>(); - - ffi.Pointer PyGen_GetCode( - ffi.Pointer gen, - ) { - return _PyGen_GetCode( - gen, - ); - } - - late final _PyGen_GetCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyGen_GetCode'); - late final _PyGen_GetCode = _PyGen_GetCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyCoro_Type = - _lookup('PyCoro_Type'); - - PyTypeObject get PyCoro_Type => _PyCoro_Type.ref; - - late final ffi.Pointer __PyCoroWrapper_Type = - _lookup('_PyCoroWrapper_Type'); - - PyTypeObject get _PyCoroWrapper_Type => __PyCoroWrapper_Type.ref; - - ffi.Pointer PyCoro_New( - ffi.Pointer arg0, - ffi.Pointer name, - ffi.Pointer qualname, - ) { - return _PyCoro_New( - arg0, - name, - qualname, - ); - } - - late final _PyCoro_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PyCoro_New'); - late final _PyCoro_New = _PyCoro_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyAsyncGen_Type = - _lookup('PyAsyncGen_Type'); - - PyTypeObject get PyAsyncGen_Type => _PyAsyncGen_Type.ref; - - late final ffi.Pointer __PyAsyncGenASend_Type = - _lookup('_PyAsyncGenASend_Type'); - - PyTypeObject get _PyAsyncGenASend_Type => __PyAsyncGenASend_Type.ref; - - late final ffi.Pointer __PyAsyncGenWrappedValue_Type = - _lookup('_PyAsyncGenWrappedValue_Type'); - - PyTypeObject get _PyAsyncGenWrappedValue_Type => - __PyAsyncGenWrappedValue_Type.ref; - - late final ffi.Pointer __PyAsyncGenAThrow_Type = - _lookup('_PyAsyncGenAThrow_Type'); - - PyTypeObject get _PyAsyncGenAThrow_Type => __PyAsyncGenAThrow_Type.ref; - - ffi.Pointer PyAsyncGen_New( - ffi.Pointer arg0, - ffi.Pointer name, - ffi.Pointer qualname, - ) { - return _PyAsyncGen_New( - arg0, - name, - qualname, - ); - } - - late final _PyAsyncGen_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PyAsyncGen_New'); - late final _PyAsyncGen_New = _PyAsyncGen_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _PyClassMethodDescr_Type = - _lookup('PyClassMethodDescr_Type'); - - PyTypeObject get PyClassMethodDescr_Type => _PyClassMethodDescr_Type.ref; - - late final ffi.Pointer _PyGetSetDescr_Type = - _lookup('PyGetSetDescr_Type'); - - PyTypeObject get PyGetSetDescr_Type => _PyGetSetDescr_Type.ref; - - late final ffi.Pointer _PyMemberDescr_Type = - _lookup('PyMemberDescr_Type'); - - PyTypeObject get PyMemberDescr_Type => _PyMemberDescr_Type.ref; - - late final ffi.Pointer _PyMethodDescr_Type = - _lookup('PyMethodDescr_Type'); - - PyTypeObject get PyMethodDescr_Type => _PyMethodDescr_Type.ref; - - late final ffi.Pointer _PyWrapperDescr_Type = - _lookup('PyWrapperDescr_Type'); - - PyTypeObject get PyWrapperDescr_Type => _PyWrapperDescr_Type.ref; - - late final ffi.Pointer _PyDictProxy_Type = - _lookup('PyDictProxy_Type'); - - PyTypeObject get PyDictProxy_Type => _PyDictProxy_Type.ref; - - late final ffi.Pointer _PyProperty_Type = - _lookup('PyProperty_Type'); - - PyTypeObject get PyProperty_Type => _PyProperty_Type.ref; - - ffi.Pointer PyDescr_NewMethod( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyDescr_NewMethod( - arg0, - arg1, - ); - } - - late final _PyDescr_NewMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyDescr_NewMethod'); - late final _PyDescr_NewMethod = _PyDescr_NewMethodPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyDescr_NewClassMethod( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyDescr_NewClassMethod( - arg0, - arg1, - ); - } - - late final _PyDescr_NewClassMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyDescr_NewClassMethod'); - late final _PyDescr_NewClassMethod = _PyDescr_NewClassMethodPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyDescr_NewMember( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyDescr_NewMember( - arg0, - arg1, - ); - } - - late final _PyDescr_NewMemberPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyDescr_NewMember'); - late final _PyDescr_NewMember = _PyDescr_NewMemberPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyDescr_NewGetSet( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyDescr_NewGetSet( - arg0, - arg1, - ); - } - - late final _PyDescr_NewGetSetPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyDescr_NewGetSet'); - late final _PyDescr_NewGetSet = _PyDescr_NewGetSetPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyDictProxy_New( - ffi.Pointer arg0, - ) { - return _PyDictProxy_New( - arg0, - ); - } - - late final _PyDictProxy_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyDictProxy_New'); - late final _PyDictProxy_New = _PyDictProxy_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyWrapper_New( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyWrapper_New( - arg0, - arg1, - ); - } - - late final _PyWrapper_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyWrapper_New'); - late final _PyWrapper_New = _PyWrapper_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyMember_GetOne( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyMember_GetOne( - arg0, - arg1, - ); - } - - late final _PyMember_GetOnePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyMember_GetOne'); - late final _PyMember_GetOne = _PyMember_GetOnePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyMember_SetOne( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyMember_SetOne( - arg0, - arg1, - arg2, - ); - } - - late final _PyMember_SetOnePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyMember_SetOne'); - late final _PyMember_SetOne = _PyMember_SetOnePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final ffi.Pointer __PyMethodWrapper_Type = - _lookup('_PyMethodWrapper_Type'); - - PyTypeObject get _PyMethodWrapper_Type => __PyMethodWrapper_Type.ref; - - ffi.Pointer PyDescr_NewWrapper( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyDescr_NewWrapper( - arg0, - arg1, - arg2, - ); - } - - late final _PyDescr_NewWrapperPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyDescr_NewWrapper'); - late final _PyDescr_NewWrapper = _PyDescr_NewWrapperPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int PyDescr_IsData( - ffi.Pointer arg0, - ) { - return _PyDescr_IsData( - arg0, - ); - } - - late final _PyDescr_IsDataPtr = - _lookup)>>( - 'PyDescr_IsData'); - late final _PyDescr_IsData = - _PyDescr_IsDataPtr.asFunction)>(); - - ffi.Pointer Py_GenericAlias( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _Py_GenericAlias( - arg0, - arg1, - ); - } - - late final _Py_GenericAliasPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('Py_GenericAlias'); - late final _Py_GenericAlias = _Py_GenericAliasPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer _Py_GenericAliasType = - _lookup('Py_GenericAliasType'); - - PyTypeObject get Py_GenericAliasType => _Py_GenericAliasType.ref; - - int PyErr_WarnEx( - ffi.Pointer category, - ffi.Pointer message, - int stack_level, - ) { - return _PyErr_WarnEx( - category, - message, - stack_level, - ); - } - - late final _PyErr_WarnExPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t)>>('PyErr_WarnEx'); - late final _PyErr_WarnEx = _PyErr_WarnExPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyErr_WarnFormat( - ffi.Pointer category, - int stack_level, - ffi.Pointer format, - ) { - return _PyErr_WarnFormat( - category, - stack_level, - format, - ); - } - - late final _PyErr_WarnFormatPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyErr_WarnFormat'); - late final _PyErr_WarnFormat = _PyErr_WarnFormatPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - int PyErr_ResourceWarning( - ffi.Pointer source, - int stack_level, - ffi.Pointer format, - ) { - return _PyErr_ResourceWarning( - source, - stack_level, - format, - ); - } - - late final _PyErr_ResourceWarningPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyErr_ResourceWarning'); - late final _PyErr_ResourceWarning = _PyErr_ResourceWarningPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - int PyErr_WarnExplicit( - ffi.Pointer category, - ffi.Pointer message, - ffi.Pointer filename, - int lineno, - ffi.Pointer module, - ffi.Pointer registry, - ) { - return _PyErr_WarnExplicit( - category, - message, - filename, - lineno, - module, - registry, - ); - } - - late final _PyErr_WarnExplicitPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('PyErr_WarnExplicit'); - late final _PyErr_WarnExplicit = _PyErr_WarnExplicitPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer)>(); - - int PyErr_WarnExplicitObject( - ffi.Pointer category, - ffi.Pointer message, - ffi.Pointer filename, - int lineno, - ffi.Pointer module, - ffi.Pointer registry, - ) { - return _PyErr_WarnExplicitObject( - category, - message, - filename, - lineno, - module, - registry, - ); - } - - late final _PyErr_WarnExplicitObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('PyErr_WarnExplicitObject'); - late final _PyErr_WarnExplicitObject = - _PyErr_WarnExplicitObjectPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer)>(); - - int PyErr_WarnExplicitFormat( - ffi.Pointer category, - ffi.Pointer filename, - int lineno, - ffi.Pointer module, - ffi.Pointer registry, - ffi.Pointer format, - ) { - return _PyErr_WarnExplicitFormat( - category, - filename, - lineno, - module, - registry, - format, - ); - } - - late final _PyErr_WarnExplicitFormatPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyErr_WarnExplicitFormat'); - late final _PyErr_WarnExplicitFormat = - _PyErr_WarnExplicitFormatPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - late final ffi.Pointer __PyWeakref_RefType = - _lookup('_PyWeakref_RefType'); - - PyTypeObject get _PyWeakref_RefType => __PyWeakref_RefType.ref; - - late final ffi.Pointer __PyWeakref_ProxyType = - _lookup('_PyWeakref_ProxyType'); - - PyTypeObject get _PyWeakref_ProxyType => __PyWeakref_ProxyType.ref; - - late final ffi.Pointer __PyWeakref_CallableProxyType = - _lookup('_PyWeakref_CallableProxyType'); - - PyTypeObject get _PyWeakref_CallableProxyType => - __PyWeakref_CallableProxyType.ref; - - ffi.Pointer PyWeakref_NewRef( - ffi.Pointer ob, - ffi.Pointer callback, - ) { - return _PyWeakref_NewRef( - ob, - callback, - ); - } - - late final _PyWeakref_NewRefPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyWeakref_NewRef'); - late final _PyWeakref_NewRef = _PyWeakref_NewRefPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyWeakref_NewProxy( - ffi.Pointer ob, - ffi.Pointer callback, - ) { - return _PyWeakref_NewProxy( - ob, - callback, - ); - } - - late final _PyWeakref_NewProxyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyWeakref_NewProxy'); - late final _PyWeakref_NewProxy = _PyWeakref_NewProxyPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyWeakref_GetObject( - ffi.Pointer ref, - ) { - return _PyWeakref_GetObject( - ref, - ); - } - - late final _PyWeakref_GetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyWeakref_GetObject'); - late final _PyWeakref_GetObject = _PyWeakref_GetObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int _PyWeakref_GetWeakrefCount( - ffi.Pointer head, - ) { - return __PyWeakref_GetWeakrefCount( - head, - ); - } - - late final __PyWeakref_GetWeakrefCountPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyWeakref_GetWeakrefCount'); - late final __PyWeakref_GetWeakrefCount = __PyWeakref_GetWeakrefCountPtr - .asFunction)>(); - - void _PyWeakref_ClearRef( - ffi.Pointer self, - ) { - return __PyWeakref_ClearRef( - self, - ); - } - - late final __PyWeakref_ClearRefPtr = _lookup< - ffi.NativeFunction)>>( - '_PyWeakref_ClearRef'); - late final __PyWeakref_ClearRef = __PyWeakref_ClearRefPtr - .asFunction)>(); - - late final ffi.Pointer> _PyStructSequence_UnnamedField = - _lookup>('PyStructSequence_UnnamedField'); - - ffi.Pointer get PyStructSequence_UnnamedField => - _PyStructSequence_UnnamedField.value; - - set PyStructSequence_UnnamedField(ffi.Pointer value) => - _PyStructSequence_UnnamedField.value = value; - - void PyStructSequence_InitType( - ffi.Pointer type, - ffi.Pointer desc, - ) { - return _PyStructSequence_InitType( - type, - desc, - ); - } - - late final _PyStructSequence_InitTypePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Pointer)>>( - 'PyStructSequence_InitType'); - late final _PyStructSequence_InitType = - _PyStructSequence_InitTypePtr.asFunction< - void Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyStructSequence_InitType2( - ffi.Pointer type, - ffi.Pointer desc, - ) { - return _PyStructSequence_InitType2( - type, - desc, - ); - } - - late final _PyStructSequence_InitType2Ptr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>( - 'PyStructSequence_InitType2'); - late final _PyStructSequence_InitType2 = - _PyStructSequence_InitType2Ptr.asFunction< - int Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyStructSequence_NewType( - ffi.Pointer desc, - ) { - return _PyStructSequence_NewType( - desc, - ); - } - - late final _PyStructSequence_NewTypePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyStructSequence_NewType'); - late final _PyStructSequence_NewType = - _PyStructSequence_NewTypePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer)>(); - - ffi.Pointer PyStructSequence_New( - ffi.Pointer type, - ) { - return _PyStructSequence_New( - type, - ); - } - - late final _PyStructSequence_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyStructSequence_New'); - late final _PyStructSequence_New = _PyStructSequence_NewPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - void PyStructSequence_SetItem( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ) { - return _PyStructSequence_SetItem( - arg0, - arg1, - arg2, - ); - } - - late final _PyStructSequence_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PyStructSequence_SetItem'); - late final _PyStructSequence_SetItem = - _PyStructSequence_SetItemPtr.asFunction< - void Function(ffi.Pointer, int, ffi.Pointer)>(); - - ffi.Pointer PyStructSequence_GetItem( - ffi.Pointer arg0, - int arg1, - ) { - return _PyStructSequence_GetItem( - arg0, - arg1, - ); - } - - late final _PyStructSequence_GetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PyStructSequence_GetItem'); - late final _PyStructSequence_GetItem = _PyStructSequence_GetItemPtr - .asFunction Function(ffi.Pointer, int)>(); - - late final ffi.Pointer _PyPickleBuffer_Type = - _lookup('PyPickleBuffer_Type'); - - PyTypeObject get PyPickleBuffer_Type => _PyPickleBuffer_Type.ref; - - ffi.Pointer PyPickleBuffer_FromObject( - ffi.Pointer arg0, - ) { - return _PyPickleBuffer_FromObject( - arg0, - ); - } - - late final _PyPickleBuffer_FromObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyPickleBuffer_FromObject'); - late final _PyPickleBuffer_FromObject = _PyPickleBuffer_FromObjectPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyPickleBuffer_GetBuffer( - ffi.Pointer arg0, - ) { - return _PyPickleBuffer_GetBuffer( - arg0, - ); - } - - late final _PyPickleBuffer_GetBufferPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyPickleBuffer_GetBuffer'); - late final _PyPickleBuffer_GetBuffer = _PyPickleBuffer_GetBufferPtr - .asFunction Function(ffi.Pointer)>(); - - int PyPickleBuffer_Release( - ffi.Pointer arg0, - ) { - return _PyPickleBuffer_Release( - arg0, - ); - } - - late final _PyPickleBuffer_ReleasePtr = - _lookup)>>( - 'PyPickleBuffer_Release'); - late final _PyPickleBuffer_Release = _PyPickleBuffer_ReleasePtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer _PyLong_FromTime_t( - int sec, - ) { - return __PyLong_FromTime_t( - sec, - ); - } - - late final __PyLong_FromTime_tPtr = - _lookup Function(time_t)>>( - '_PyLong_FromTime_t'); - late final __PyLong_FromTime_t = - __PyLong_FromTime_tPtr.asFunction Function(int)>(); - - int _PyLong_AsTime_t( - ffi.Pointer obj, - ) { - return __PyLong_AsTime_t( - obj, - ); - } - - late final __PyLong_AsTime_tPtr = - _lookup)>>( - '_PyLong_AsTime_t'); - late final __PyLong_AsTime_t = - __PyLong_AsTime_tPtr.asFunction)>(); - - int _PyTime_ObjectToTime_t( - ffi.Pointer obj, - ffi.Pointer sec, - int arg2, - ) { - return __PyTime_ObjectToTime_t( - obj, - sec, - arg2, - ); - } - - late final __PyTime_ObjectToTime_tPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int32)>>('_PyTime_ObjectToTime_t'); - late final __PyTime_ObjectToTime_t = __PyTime_ObjectToTime_tPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int _PyTime_ObjectToTimeval( - ffi.Pointer obj, - ffi.Pointer sec, - ffi.Pointer usec, - int arg3, - ) { - return __PyTime_ObjectToTimeval( - obj, - sec, - usec, - arg3, - ); - } - - late final __PyTime_ObjectToTimevalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Int32)>>('_PyTime_ObjectToTimeval'); - late final __PyTime_ObjectToTimeval = __PyTime_ObjectToTimevalPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, int)>(); - - int _PyTime_ObjectToTimespec( - ffi.Pointer obj, - ffi.Pointer sec, - ffi.Pointer nsec, - int arg3, - ) { - return __PyTime_ObjectToTimespec( - obj, - sec, - nsec, - arg3, - ); - } - - late final __PyTime_ObjectToTimespecPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Int32)>>('_PyTime_ObjectToTimespec'); - late final __PyTime_ObjectToTimespec = - __PyTime_ObjectToTimespecPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, int)>(); - - int _PyTime_FromSeconds( - int seconds, - ) { - return __PyTime_FromSeconds( - seconds, - ); - } - - late final __PyTime_FromSecondsPtr = - _lookup>( - '_PyTime_FromSeconds'); - late final __PyTime_FromSeconds = - __PyTime_FromSecondsPtr.asFunction(); - - int _PyTime_FromNanoseconds( - int ns, - ) { - return __PyTime_FromNanoseconds( - ns, - ); - } - - late final __PyTime_FromNanosecondsPtr = - _lookup>( - '_PyTime_FromNanoseconds'); - late final __PyTime_FromNanoseconds = - __PyTime_FromNanosecondsPtr.asFunction(); - - int _PyTime_FromMicrosecondsClamp( - int us, - ) { - return __PyTime_FromMicrosecondsClamp( - us, - ); - } - - late final __PyTime_FromMicrosecondsClampPtr = - _lookup>( - '_PyTime_FromMicrosecondsClamp'); - late final __PyTime_FromMicrosecondsClamp = - __PyTime_FromMicrosecondsClampPtr.asFunction(); - - int _PyTime_FromNanosecondsObject( - ffi.Pointer<_PyTime_t> t, - ffi.Pointer obj, - ) { - return __PyTime_FromNanosecondsObject( - t, - obj, - ); - } - - late final __PyTime_FromNanosecondsObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyTime_t>, - ffi.Pointer)>>('_PyTime_FromNanosecondsObject'); - late final __PyTime_FromNanosecondsObject = - __PyTime_FromNanosecondsObjectPtr.asFunction< - int Function(ffi.Pointer<_PyTime_t>, ffi.Pointer)>(); - - int _PyTime_FromSecondsObject( - ffi.Pointer<_PyTime_t> t, - ffi.Pointer obj, - int round, - ) { - return __PyTime_FromSecondsObject( - t, - obj, - round, - ); - } - - late final __PyTime_FromSecondsObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyTime_t>, ffi.Pointer, - ffi.Int32)>>('_PyTime_FromSecondsObject'); - late final __PyTime_FromSecondsObject = - __PyTime_FromSecondsObjectPtr.asFunction< - int Function(ffi.Pointer<_PyTime_t>, ffi.Pointer, int)>(); - - int _PyTime_FromMillisecondsObject( - ffi.Pointer<_PyTime_t> t, - ffi.Pointer obj, - int round, - ) { - return __PyTime_FromMillisecondsObject( - t, - obj, - round, - ); - } - - late final __PyTime_FromMillisecondsObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyTime_t>, ffi.Pointer, - ffi.Int32)>>('_PyTime_FromMillisecondsObject'); - late final __PyTime_FromMillisecondsObject = - __PyTime_FromMillisecondsObjectPtr.asFunction< - int Function(ffi.Pointer<_PyTime_t>, ffi.Pointer, int)>(); - - double _PyTime_AsSecondsDouble( - int t, - ) { - return __PyTime_AsSecondsDouble( - t, - ); - } - - late final __PyTime_AsSecondsDoublePtr = - _lookup>( - '_PyTime_AsSecondsDouble'); - late final __PyTime_AsSecondsDouble = - __PyTime_AsSecondsDoublePtr.asFunction(); - - int _PyTime_AsMilliseconds( - int t, - int round, - ) { - return __PyTime_AsMilliseconds( - t, - round, - ); - } - - late final __PyTime_AsMillisecondsPtr = - _lookup>( - '_PyTime_AsMilliseconds'); - late final __PyTime_AsMilliseconds = - __PyTime_AsMillisecondsPtr.asFunction(); - - int _PyTime_AsMicroseconds( - int t, - int round, - ) { - return __PyTime_AsMicroseconds( - t, - round, - ); - } - - late final __PyTime_AsMicrosecondsPtr = - _lookup>( - '_PyTime_AsMicroseconds'); - late final __PyTime_AsMicroseconds = - __PyTime_AsMicrosecondsPtr.asFunction(); - - int _PyTime_AsNanoseconds( - int t, - ) { - return __PyTime_AsNanoseconds( - t, - ); - } - - late final __PyTime_AsNanosecondsPtr = - _lookup>( - '_PyTime_AsNanoseconds'); - late final __PyTime_AsNanoseconds = - __PyTime_AsNanosecondsPtr.asFunction(); - - ffi.Pointer _PyTime_AsNanosecondsObject( - int t, - ) { - return __PyTime_AsNanosecondsObject( - t, - ); - } - - late final __PyTime_AsNanosecondsObjectPtr = - _lookup Function(_PyTime_t)>>( - '_PyTime_AsNanosecondsObject'); - late final __PyTime_AsNanosecondsObject = __PyTime_AsNanosecondsObjectPtr - .asFunction Function(int)>(); - - int _PyTime_FromTimeval( - ffi.Pointer<_PyTime_t> tp, - ffi.Pointer tv, - ) { - return __PyTime_FromTimeval( - tp, - tv, - ); - } - - late final __PyTime_FromTimevalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyTime_t>, - ffi.Pointer)>>('_PyTime_FromTimeval'); - late final __PyTime_FromTimeval = __PyTime_FromTimevalPtr - .asFunction, ffi.Pointer)>(); - - int _PyTime_AsTimeval( - int t, - ffi.Pointer tv, - int round, - ) { - return __PyTime_AsTimeval( - t, - tv, - round, - ); - } - - late final __PyTime_AsTimevalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(_PyTime_t, ffi.Pointer, - ffi.Int32)>>('_PyTime_AsTimeval'); - late final __PyTime_AsTimeval = __PyTime_AsTimevalPtr - .asFunction, int)>(); - - void _PyTime_AsTimeval_clamp( - int t, - ffi.Pointer tv, - int round, - ) { - return __PyTime_AsTimeval_clamp( - t, - tv, - round, - ); - } - - late final __PyTime_AsTimeval_clampPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(_PyTime_t, ffi.Pointer, - ffi.Int32)>>('_PyTime_AsTimeval_clamp'); - late final __PyTime_AsTimeval_clamp = __PyTime_AsTimeval_clampPtr - .asFunction, int)>(); - - int _PyTime_AsTimevalTime_t( - int t, - ffi.Pointer secs, - ffi.Pointer us, - int round, - ) { - return __PyTime_AsTimevalTime_t( - t, - secs, - us, - round, - ); - } - - late final __PyTime_AsTimevalTime_tPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(_PyTime_t, ffi.Pointer, ffi.Pointer, - ffi.Int32)>>('_PyTime_AsTimevalTime_t'); - late final __PyTime_AsTimevalTime_t = __PyTime_AsTimevalTime_tPtr.asFunction< - int Function(int, ffi.Pointer, ffi.Pointer, int)>(); - - int _PyTime_FromTimespec( - ffi.Pointer<_PyTime_t> tp, - ffi.Pointer ts, - ) { - return __PyTime_FromTimespec( - tp, - ts, - ); - } - - late final __PyTime_FromTimespecPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer<_PyTime_t>, - ffi.Pointer)>>('_PyTime_FromTimespec'); - late final __PyTime_FromTimespec = __PyTime_FromTimespecPtr.asFunction< - int Function(ffi.Pointer<_PyTime_t>, ffi.Pointer)>(); - - int _PyTime_AsTimespec( - int t, - ffi.Pointer ts, - ) { - return __PyTime_AsTimespec( - t, - ts, - ); - } - - late final __PyTime_AsTimespecPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyTime_AsTimespec'); - late final __PyTime_AsTimespec = __PyTime_AsTimespecPtr - .asFunction)>(); - - void _PyTime_AsTimespec_clamp( - int t, - ffi.Pointer ts, - ) { - return __PyTime_AsTimespec_clamp( - t, - ts, - ); - } - - late final __PyTime_AsTimespec_clampPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyTime_AsTimespec_clamp'); - late final __PyTime_AsTimespec_clamp = __PyTime_AsTimespec_clampPtr - .asFunction)>(); - - int _PyTime_Add( - int t1, - int t2, - ) { - return __PyTime_Add( - t1, - t2, - ); - } - - late final __PyTime_AddPtr = - _lookup>( - '_PyTime_Add'); - late final __PyTime_Add = - __PyTime_AddPtr.asFunction(); - - int _PyTime_MulDiv( - int ticks, - int mul, - int div, - ) { - return __PyTime_MulDiv( - ticks, - mul, - div, - ); - } - - late final __PyTime_MulDivPtr = _lookup< - ffi - .NativeFunction<_PyTime_t Function(_PyTime_t, _PyTime_t, _PyTime_t)>>( - '_PyTime_MulDiv'); - late final __PyTime_MulDiv = - __PyTime_MulDivPtr.asFunction(); - - int _PyTime_GetSystemClock() { - return __PyTime_GetSystemClock(); - } - - late final __PyTime_GetSystemClockPtr = - _lookup>( - '_PyTime_GetSystemClock'); - late final __PyTime_GetSystemClock = - __PyTime_GetSystemClockPtr.asFunction(); - - int _PyTime_GetSystemClockWithInfo( - ffi.Pointer<_PyTime_t> t, - ffi.Pointer<_Py_clock_info_t> info, - ) { - return __PyTime_GetSystemClockWithInfo( - t, - info, - ); - } - - late final __PyTime_GetSystemClockWithInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer<_PyTime_t>, ffi.Pointer<_Py_clock_info_t>)>>( - '_PyTime_GetSystemClockWithInfo'); - late final __PyTime_GetSystemClockWithInfo = - __PyTime_GetSystemClockWithInfoPtr.asFunction< - int Function( - ffi.Pointer<_PyTime_t>, ffi.Pointer<_Py_clock_info_t>)>(); - - int _PyTime_GetMonotonicClock() { - return __PyTime_GetMonotonicClock(); - } - - late final __PyTime_GetMonotonicClockPtr = - _lookup>( - '_PyTime_GetMonotonicClock'); - late final __PyTime_GetMonotonicClock = - __PyTime_GetMonotonicClockPtr.asFunction(); - - int _PyTime_GetMonotonicClockWithInfo( - ffi.Pointer<_PyTime_t> t, - ffi.Pointer<_Py_clock_info_t> info, - ) { - return __PyTime_GetMonotonicClockWithInfo( - t, - info, - ); - } - - late final __PyTime_GetMonotonicClockWithInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer<_PyTime_t>, ffi.Pointer<_Py_clock_info_t>)>>( - '_PyTime_GetMonotonicClockWithInfo'); - late final __PyTime_GetMonotonicClockWithInfo = - __PyTime_GetMonotonicClockWithInfoPtr.asFunction< - int Function( - ffi.Pointer<_PyTime_t>, ffi.Pointer<_Py_clock_info_t>)>(); - - int _PyTime_localtime( - int t, - ffi.Pointer tm, - ) { - return __PyTime_localtime( - t, - tm, - ); - } - - late final __PyTime_localtimePtr = - _lookup)>>( - '_PyTime_localtime'); - late final __PyTime_localtime = - __PyTime_localtimePtr.asFunction)>(); - - int _PyTime_gmtime( - int t, - ffi.Pointer tm, - ) { - return __PyTime_gmtime( - t, - tm, - ); - } - - late final __PyTime_gmtimePtr = - _lookup)>>( - '_PyTime_gmtime'); - late final __PyTime_gmtime = - __PyTime_gmtimePtr.asFunction)>(); - - int _PyTime_GetPerfCounter() { - return __PyTime_GetPerfCounter(); - } - - late final __PyTime_GetPerfCounterPtr = - _lookup>( - '_PyTime_GetPerfCounter'); - late final __PyTime_GetPerfCounter = - __PyTime_GetPerfCounterPtr.asFunction(); - - int _PyTime_GetPerfCounterWithInfo( - ffi.Pointer<_PyTime_t> t, - ffi.Pointer<_Py_clock_info_t> info, - ) { - return __PyTime_GetPerfCounterWithInfo( - t, - info, - ); - } - - late final __PyTime_GetPerfCounterWithInfoPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer<_PyTime_t>, ffi.Pointer<_Py_clock_info_t>)>>( - '_PyTime_GetPerfCounterWithInfo'); - late final __PyTime_GetPerfCounterWithInfo = - __PyTime_GetPerfCounterWithInfoPtr.asFunction< - int Function( - ffi.Pointer<_PyTime_t>, ffi.Pointer<_Py_clock_info_t>)>(); - - int _PyDeadline_Init( - int timeout, - ) { - return __PyDeadline_Init( - timeout, - ); - } - - late final __PyDeadline_InitPtr = - _lookup>( - '_PyDeadline_Init'); - late final __PyDeadline_Init = - __PyDeadline_InitPtr.asFunction(); - - int _PyDeadline_Get( - int deadline, - ) { - return __PyDeadline_Get( - deadline, - ); - } - - late final __PyDeadline_GetPtr = - _lookup>( - '_PyDeadline_Get'); - late final __PyDeadline_Get = - __PyDeadline_GetPtr.asFunction(); - - int PyCodec_Register( - ffi.Pointer search_function, - ) { - return _PyCodec_Register( - search_function, - ); - } - - late final _PyCodec_RegisterPtr = - _lookup)>>( - 'PyCodec_Register'); - late final _PyCodec_Register = - _PyCodec_RegisterPtr.asFunction)>(); - - int PyCodec_Unregister( - ffi.Pointer search_function, - ) { - return _PyCodec_Unregister( - search_function, - ); - } - - late final _PyCodec_UnregisterPtr = - _lookup)>>( - 'PyCodec_Unregister'); - late final _PyCodec_Unregister = - _PyCodec_UnregisterPtr.asFunction)>(); - - ffi.Pointer _PyCodec_Lookup( - ffi.Pointer encoding, - ) { - return __PyCodec_Lookup( - encoding, - ); - } - - late final __PyCodec_LookupPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyCodec_Lookup'); - late final __PyCodec_Lookup = __PyCodec_LookupPtr - .asFunction Function(ffi.Pointer)>(); - - int _PyCodec_Forget( - ffi.Pointer encoding, - ) { - return __PyCodec_Forget( - encoding, - ); - } - - late final __PyCodec_ForgetPtr = - _lookup)>>( - '_PyCodec_Forget'); - late final __PyCodec_Forget = - __PyCodec_ForgetPtr.asFunction)>(); - - int PyCodec_KnownEncoding( - ffi.Pointer encoding, - ) { - return _PyCodec_KnownEncoding( - encoding, - ); - } - - late final _PyCodec_KnownEncodingPtr = - _lookup)>>( - 'PyCodec_KnownEncoding'); - late final _PyCodec_KnownEncoding = _PyCodec_KnownEncodingPtr.asFunction< - int Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_Encode( - ffi.Pointer object, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyCodec_Encode( - object, - encoding, - errors, - ); - } - - late final _PyCodec_EncodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PyCodec_Encode'); - late final _PyCodec_Encode = _PyCodec_EncodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCodec_Decode( - ffi.Pointer object, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyCodec_Decode( - object, - encoding, - errors, - ); - } - - late final _PyCodec_DecodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PyCodec_Decode'); - late final _PyCodec_Decode = _PyCodec_DecodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyCodec_LookupTextEncoding( - ffi.Pointer encoding, - ffi.Pointer alternate_command, - ) { - return __PyCodec_LookupTextEncoding( - encoding, - alternate_command, - ); - } - - late final __PyCodec_LookupTextEncodingPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyCodec_LookupTextEncoding'); - late final __PyCodec_LookupTextEncoding = - __PyCodec_LookupTextEncodingPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyCodec_EncodeText( - ffi.Pointer object, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return __PyCodec_EncodeText( - object, - encoding, - errors, - ); - } - - late final __PyCodec_EncodeTextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyCodec_EncodeText'); - late final __PyCodec_EncodeText = __PyCodec_EncodeTextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyCodec_DecodeText( - ffi.Pointer object, - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return __PyCodec_DecodeText( - object, - encoding, - errors, - ); - } - - late final __PyCodec_DecodeTextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyCodec_DecodeText'); - late final __PyCodec_DecodeText = __PyCodec_DecodeTextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyCodecInfo_GetIncrementalDecoder( - ffi.Pointer codec_info, - ffi.Pointer errors, - ) { - return __PyCodecInfo_GetIncrementalDecoder( - codec_info, - errors, - ); - } - - late final __PyCodecInfo_GetIncrementalDecoderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyCodecInfo_GetIncrementalDecoder'); - late final __PyCodecInfo_GetIncrementalDecoder = - __PyCodecInfo_GetIncrementalDecoderPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyCodecInfo_GetIncrementalEncoder( - ffi.Pointer codec_info, - ffi.Pointer errors, - ) { - return __PyCodecInfo_GetIncrementalEncoder( - codec_info, - errors, - ); - } - - late final __PyCodecInfo_GetIncrementalEncoderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyCodecInfo_GetIncrementalEncoder'); - late final __PyCodecInfo_GetIncrementalEncoder = - __PyCodecInfo_GetIncrementalEncoderPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCodec_Encoder( - ffi.Pointer encoding, - ) { - return _PyCodec_Encoder( - encoding, - ); - } - - late final _PyCodec_EncoderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_Encoder'); - late final _PyCodec_Encoder = _PyCodec_EncoderPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_Decoder( - ffi.Pointer encoding, - ) { - return _PyCodec_Decoder( - encoding, - ); - } - - late final _PyCodec_DecoderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_Decoder'); - late final _PyCodec_Decoder = _PyCodec_DecoderPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_IncrementalEncoder( - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyCodec_IncrementalEncoder( - encoding, - errors, - ); - } - - late final _PyCodec_IncrementalEncoderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyCodec_IncrementalEncoder'); - late final _PyCodec_IncrementalEncoder = - _PyCodec_IncrementalEncoderPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCodec_IncrementalDecoder( - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _PyCodec_IncrementalDecoder( - encoding, - errors, - ); - } - - late final _PyCodec_IncrementalDecoderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyCodec_IncrementalDecoder'); - late final _PyCodec_IncrementalDecoder = - _PyCodec_IncrementalDecoderPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCodec_StreamReader( - ffi.Pointer encoding, - ffi.Pointer stream, - ffi.Pointer errors, - ) { - return _PyCodec_StreamReader( - encoding, - stream, - errors, - ); - } - - late final _PyCodec_StreamReaderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCodec_StreamReader'); - late final _PyCodec_StreamReader = _PyCodec_StreamReaderPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCodec_StreamWriter( - ffi.Pointer encoding, - ffi.Pointer stream, - ffi.Pointer errors, - ) { - return _PyCodec_StreamWriter( - encoding, - stream, - errors, - ); - } - - late final _PyCodec_StreamWriterPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyCodec_StreamWriter'); - late final _PyCodec_StreamWriter = _PyCodec_StreamWriterPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int PyCodec_RegisterError( - ffi.Pointer name, - ffi.Pointer error, - ) { - return _PyCodec_RegisterError( - name, - error, - ); - } - - late final _PyCodec_RegisterErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyCodec_RegisterError'); - late final _PyCodec_RegisterError = _PyCodec_RegisterErrorPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyCodec_LookupError( - ffi.Pointer name, - ) { - return _PyCodec_LookupError( - name, - ); - } - - late final _PyCodec_LookupErrorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_LookupError'); - late final _PyCodec_LookupError = _PyCodec_LookupErrorPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_StrictErrors( - ffi.Pointer exc, - ) { - return _PyCodec_StrictErrors( - exc, - ); - } - - late final _PyCodec_StrictErrorsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_StrictErrors'); - late final _PyCodec_StrictErrors = _PyCodec_StrictErrorsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_IgnoreErrors( - ffi.Pointer exc, - ) { - return _PyCodec_IgnoreErrors( - exc, - ); - } - - late final _PyCodec_IgnoreErrorsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_IgnoreErrors'); - late final _PyCodec_IgnoreErrors = _PyCodec_IgnoreErrorsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_ReplaceErrors( - ffi.Pointer exc, - ) { - return _PyCodec_ReplaceErrors( - exc, - ); - } - - late final _PyCodec_ReplaceErrorsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_ReplaceErrors'); - late final _PyCodec_ReplaceErrors = _PyCodec_ReplaceErrorsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_XMLCharRefReplaceErrors( - ffi.Pointer exc, - ) { - return _PyCodec_XMLCharRefReplaceErrors( - exc, - ); - } - - late final _PyCodec_XMLCharRefReplaceErrorsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_XMLCharRefReplaceErrors'); - late final _PyCodec_XMLCharRefReplaceErrors = - _PyCodec_XMLCharRefReplaceErrorsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_BackslashReplaceErrors( - ffi.Pointer exc, - ) { - return _PyCodec_BackslashReplaceErrors( - exc, - ); - } - - late final _PyCodec_BackslashReplaceErrorsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_BackslashReplaceErrors'); - late final _PyCodec_BackslashReplaceErrors = - _PyCodec_BackslashReplaceErrorsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyCodec_NameReplaceErrors( - ffi.Pointer exc, - ) { - return _PyCodec_NameReplaceErrors( - exc, - ); - } - - late final _PyCodec_NameReplaceErrorsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyCodec_NameReplaceErrors'); - late final _PyCodec_NameReplaceErrors = _PyCodec_NameReplaceErrorsPtr - .asFunction Function(ffi.Pointer)>(); - - late final ffi.Pointer> _Py_hexdigits = - _lookup>('Py_hexdigits'); - - ffi.Pointer get Py_hexdigits => _Py_hexdigits.value; - - set Py_hexdigits(ffi.Pointer value) => _Py_hexdigits.value = value; - - void PyThread_init_thread() { - return _PyThread_init_thread(); - } - - late final _PyThread_init_threadPtr = - _lookup>('PyThread_init_thread'); - late final _PyThread_init_thread = - _PyThread_init_threadPtr.asFunction(); - - int PyThread_start_new_thread( - ffi.Pointer)>> - arg0, - ffi.Pointer arg1, - ) { - return _PyThread_start_new_thread( - arg0, - arg1, - ); - } - - late final _PyThread_start_new_threadPtr = _lookup< - ffi.NativeFunction< - ffi.UnsignedLong Function( - ffi.Pointer< - ffi.NativeFunction)>>, - ffi.Pointer)>>('PyThread_start_new_thread'); - late final _PyThread_start_new_thread = - _PyThread_start_new_threadPtr.asFunction< - int Function( - ffi.Pointer< - ffi.NativeFunction)>>, - ffi.Pointer)>(); - - void PyThread_exit_thread() { - return _PyThread_exit_thread(); - } - - late final _PyThread_exit_threadPtr = - _lookup>('PyThread_exit_thread'); - late final _PyThread_exit_thread = - _PyThread_exit_threadPtr.asFunction(); - - int PyThread_get_thread_ident() { - return _PyThread_get_thread_ident(); - } - - late final _PyThread_get_thread_identPtr = - _lookup>( - 'PyThread_get_thread_ident'); - late final _PyThread_get_thread_ident = - _PyThread_get_thread_identPtr.asFunction(); - - int PyThread_get_thread_native_id() { - return _PyThread_get_thread_native_id(); - } - - late final _PyThread_get_thread_native_idPtr = - _lookup>( - 'PyThread_get_thread_native_id'); - late final _PyThread_get_thread_native_id = - _PyThread_get_thread_native_idPtr.asFunction(); - - PyThread_type_lock PyThread_allocate_lock() { - return _PyThread_allocate_lock(); - } - - late final _PyThread_allocate_lockPtr = - _lookup>( - 'PyThread_allocate_lock'); - late final _PyThread_allocate_lock = - _PyThread_allocate_lockPtr.asFunction(); - - void PyThread_free_lock( - PyThread_type_lock arg0, - ) { - return _PyThread_free_lock( - arg0, - ); - } - - late final _PyThread_free_lockPtr = - _lookup>( - 'PyThread_free_lock'); - late final _PyThread_free_lock = - _PyThread_free_lockPtr.asFunction(); - - int PyThread_acquire_lock( - PyThread_type_lock arg0, - int arg1, - ) { - return _PyThread_acquire_lock( - arg0, - arg1, - ); - } - - late final _PyThread_acquire_lockPtr = _lookup< - ffi.NativeFunction>( - 'PyThread_acquire_lock'); - late final _PyThread_acquire_lock = _PyThread_acquire_lockPtr.asFunction< - int Function(PyThread_type_lock, int)>(); - - int PyThread_acquire_lock_timed( - PyThread_type_lock arg0, - int microseconds, - int intr_flag, - ) { - return _PyThread_acquire_lock_timed( - arg0, - microseconds, - intr_flag, - ); - } - - late final _PyThread_acquire_lock_timedPtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(PyThread_type_lock, ffi.LongLong, - ffi.Int)>>('PyThread_acquire_lock_timed'); - late final _PyThread_acquire_lock_timed = _PyThread_acquire_lock_timedPtr - .asFunction(); - - void PyThread_release_lock( - PyThread_type_lock arg0, - ) { - return _PyThread_release_lock( - arg0, - ); - } - - late final _PyThread_release_lockPtr = - _lookup>( - 'PyThread_release_lock'); - late final _PyThread_release_lock = - _PyThread_release_lockPtr.asFunction(); - - int PyThread_get_stacksize() { - return _PyThread_get_stacksize(); - } - - late final _PyThread_get_stacksizePtr = - _lookup>( - 'PyThread_get_stacksize'); - late final _PyThread_get_stacksize = - _PyThread_get_stacksizePtr.asFunction(); - - int PyThread_set_stacksize( - int arg0, - ) { - return _PyThread_set_stacksize( - arg0, - ); - } - - late final _PyThread_set_stacksizePtr = - _lookup>( - 'PyThread_set_stacksize'); - late final _PyThread_set_stacksize = - _PyThread_set_stacksizePtr.asFunction(); - - ffi.Pointer PyThread_GetInfo() { - return _PyThread_GetInfo(); - } - - late final _PyThread_GetInfoPtr = - _lookup Function()>>( - 'PyThread_GetInfo'); - late final _PyThread_GetInfo = - _PyThread_GetInfoPtr.asFunction Function()>(); - - int PyThread_create_key() { - return _PyThread_create_key(); - } - - late final _PyThread_create_keyPtr = - _lookup>('PyThread_create_key'); - late final _PyThread_create_key = - _PyThread_create_keyPtr.asFunction(); - - void PyThread_delete_key( - int key, - ) { - return _PyThread_delete_key( - key, - ); - } - - late final _PyThread_delete_keyPtr = - _lookup>( - 'PyThread_delete_key'); - late final _PyThread_delete_key = - _PyThread_delete_keyPtr.asFunction(); - - int PyThread_set_key_value( - int key, - ffi.Pointer value, - ) { - return _PyThread_set_key_value( - key, - value, - ); - } - - late final _PyThread_set_key_valuePtr = _lookup< - ffi.NativeFunction)>>( - 'PyThread_set_key_value'); - late final _PyThread_set_key_value = _PyThread_set_key_valuePtr.asFunction< - int Function(int, ffi.Pointer)>(); - - ffi.Pointer PyThread_get_key_value( - int key, - ) { - return _PyThread_get_key_value( - key, - ); - } - - late final _PyThread_get_key_valuePtr = - _lookup Function(ffi.Int)>>( - 'PyThread_get_key_value'); - late final _PyThread_get_key_value = _PyThread_get_key_valuePtr.asFunction< - ffi.Pointer Function(int)>(); - - void PyThread_delete_key_value( - int key, - ) { - return _PyThread_delete_key_value( - key, - ); - } - - late final _PyThread_delete_key_valuePtr = - _lookup>( - 'PyThread_delete_key_value'); - late final _PyThread_delete_key_value = - _PyThread_delete_key_valuePtr.asFunction(); - - void PyThread_ReInitTLS() { - return _PyThread_ReInitTLS(); - } - - late final _PyThread_ReInitTLSPtr = - _lookup>('PyThread_ReInitTLS'); - late final _PyThread_ReInitTLS = - _PyThread_ReInitTLSPtr.asFunction(); - - ffi.Pointer PyThread_tss_alloc() { - return _PyThread_tss_alloc(); - } - - late final _PyThread_tss_allocPtr = - _lookup Function()>>( - 'PyThread_tss_alloc'); - late final _PyThread_tss_alloc = - _PyThread_tss_allocPtr.asFunction Function()>(); - - void PyThread_tss_free( - ffi.Pointer key, - ) { - return _PyThread_tss_free( - key, - ); - } - - late final _PyThread_tss_freePtr = - _lookup)>>( - 'PyThread_tss_free'); - late final _PyThread_tss_free = - _PyThread_tss_freePtr.asFunction)>(); - - int PyThread_tss_is_created( - ffi.Pointer key, - ) { - return _PyThread_tss_is_created( - key, - ); - } - - late final _PyThread_tss_is_createdPtr = - _lookup)>>( - 'PyThread_tss_is_created'); - late final _PyThread_tss_is_created = _PyThread_tss_is_createdPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyThread_tss_create( - ffi.Pointer key, - ) { - return _PyThread_tss_create( - key, - ); - } - - late final _PyThread_tss_createPtr = - _lookup)>>( - 'PyThread_tss_create'); - late final _PyThread_tss_create = - _PyThread_tss_createPtr.asFunction)>(); - - void PyThread_tss_delete( - ffi.Pointer key, - ) { - return _PyThread_tss_delete( - key, - ); - } - - late final _PyThread_tss_deletePtr = - _lookup)>>( - 'PyThread_tss_delete'); - late final _PyThread_tss_delete = _PyThread_tss_deletePtr.asFunction< - void Function(ffi.Pointer)>(); - - int PyThread_tss_set( - ffi.Pointer key, - ffi.Pointer value, - ) { - return _PyThread_tss_set( - key, - value, - ); - } - - late final _PyThread_tss_setPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyThread_tss_set'); - late final _PyThread_tss_set = _PyThread_tss_setPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyThread_tss_get( - ffi.Pointer key, - ) { - return _PyThread_tss_get( - key, - ); - } - - late final _PyThread_tss_getPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyThread_tss_get'); - late final _PyThread_tss_get = _PyThread_tss_getPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int _PyThread_at_fork_reinit( - ffi.Pointer lock, - ) { - return __PyThread_at_fork_reinit( - lock, - ); - } - - late final __PyThread_at_fork_reinitPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyThread_at_fork_reinit'); - late final __PyThread_at_fork_reinit = __PyThread_at_fork_reinitPtr - .asFunction)>(); - - late final ffi.Pointer _PyContext_Type = - _lookup('PyContext_Type'); - - PyTypeObject get PyContext_Type => _PyContext_Type.ref; - - late final ffi.Pointer _PyContextVar_Type = - _lookup('PyContextVar_Type'); - - PyTypeObject get PyContextVar_Type => _PyContextVar_Type.ref; - - late final ffi.Pointer _PyContextToken_Type = - _lookup('PyContextToken_Type'); - - PyTypeObject get PyContextToken_Type => _PyContextToken_Type.ref; - - ffi.Pointer PyContext_New() { - return _PyContext_New(); - } - - late final _PyContext_NewPtr = - _lookup Function()>>( - 'PyContext_New'); - late final _PyContext_New = - _PyContext_NewPtr.asFunction Function()>(); - - ffi.Pointer PyContext_Copy( - ffi.Pointer arg0, - ) { - return _PyContext_Copy( - arg0, - ); - } - - late final _PyContext_CopyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyContext_Copy'); - late final _PyContext_Copy = _PyContext_CopyPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyContext_CopyCurrent() { - return _PyContext_CopyCurrent(); - } - - late final _PyContext_CopyCurrentPtr = - _lookup Function()>>( - 'PyContext_CopyCurrent'); - late final _PyContext_CopyCurrent = - _PyContext_CopyCurrentPtr.asFunction Function()>(); - - int PyContext_Enter( - ffi.Pointer arg0, - ) { - return _PyContext_Enter( - arg0, - ); - } - - late final _PyContext_EnterPtr = - _lookup)>>( - 'PyContext_Enter'); - late final _PyContext_Enter = - _PyContext_EnterPtr.asFunction)>(); - - int PyContext_Exit( - ffi.Pointer arg0, - ) { - return _PyContext_Exit( - arg0, - ); - } - - late final _PyContext_ExitPtr = - _lookup)>>( - 'PyContext_Exit'); - late final _PyContext_Exit = - _PyContext_ExitPtr.asFunction)>(); - - ffi.Pointer PyContextVar_New( - ffi.Pointer name, - ffi.Pointer default_value, - ) { - return _PyContextVar_New( - name, - default_value, - ); - } - - late final _PyContextVar_NewPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyContextVar_New'); - late final _PyContextVar_New = _PyContextVar_NewPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyContextVar_Get( - ffi.Pointer var1, - ffi.Pointer default_value, - ffi.Pointer> value, - ) { - return _PyContextVar_Get( - var1, - default_value, - value, - ); - } - - late final _PyContextVar_GetPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>>('PyContextVar_Get'); - late final _PyContextVar_Get = _PyContextVar_GetPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>(); - - ffi.Pointer PyContextVar_Set( - ffi.Pointer var1, - ffi.Pointer value, - ) { - return _PyContextVar_Set( - var1, - value, - ); - } - - late final _PyContextVar_SetPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyContextVar_Set'); - late final _PyContextVar_Set = _PyContextVar_SetPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyContextVar_Reset( - ffi.Pointer var1, - ffi.Pointer token, - ) { - return _PyContextVar_Reset( - var1, - token, - ); - } - - late final _PyContextVar_ResetPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyContextVar_Reset'); - late final _PyContextVar_Reset = _PyContextVar_ResetPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyContext_NewHamtForTests() { - return __PyContext_NewHamtForTests(); - } - - late final __PyContext_NewHamtForTestsPtr = - _lookup Function()>>( - '_PyContext_NewHamtForTests'); - late final __PyContext_NewHamtForTests = __PyContext_NewHamtForTestsPtr - .asFunction Function()>(); - - int PyArg_Parse( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyArg_Parse( - arg0, - arg1, - ); - } - - late final _PyArg_ParsePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyArg_Parse'); - late final _PyArg_Parse = _PyArg_ParsePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyArg_ParseTuple( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyArg_ParseTuple( - arg0, - arg1, - ); - } - - late final _PyArg_ParseTuplePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyArg_ParseTuple'); - late final _PyArg_ParseTuple = _PyArg_ParseTuplePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyArg_ParseTupleAndKeywords( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer> arg3, - ) { - return _PyArg_ParseTupleAndKeywords( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _PyArg_ParseTupleAndKeywordsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer>)>>( - 'PyArg_ParseTupleAndKeywords'); - late final _PyArg_ParseTupleAndKeywords = - _PyArg_ParseTupleAndKeywordsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer>)>(); - - int PyArg_VaParse( - ffi.Pointer arg0, - ffi.Pointer arg1, - va_list arg2, - ) { - return _PyArg_VaParse( - arg0, - arg1, - arg2, - ); - } - - late final _PyArg_VaParsePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - va_list)>>('PyArg_VaParse'); - late final _PyArg_VaParse = _PyArg_VaParsePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, va_list)>(); - - int PyArg_VaParseTupleAndKeywords( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer> arg3, - va_list arg4, - ) { - return _PyArg_VaParseTupleAndKeywords( - arg0, - arg1, - arg2, - arg3, - arg4, - ); - } - - late final _PyArg_VaParseTupleAndKeywordsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - va_list)>>('PyArg_VaParseTupleAndKeywords'); - late final _PyArg_VaParseTupleAndKeywords = - _PyArg_VaParseTupleAndKeywordsPtr.asFunction< - int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - va_list)>(); - - int PyArg_ValidateKeywordArguments( - ffi.Pointer arg0, - ) { - return _PyArg_ValidateKeywordArguments( - arg0, - ); - } - - late final _PyArg_ValidateKeywordArgumentsPtr = - _lookup)>>( - 'PyArg_ValidateKeywordArguments'); - late final _PyArg_ValidateKeywordArguments = - _PyArg_ValidateKeywordArgumentsPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyArg_UnpackTuple( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - int arg3, - ) { - return _PyArg_UnpackTuple( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final _PyArg_UnpackTuplePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t, Py_ssize_t)>>('PyArg_UnpackTuple'); - late final _PyArg_UnpackTuple = _PyArg_UnpackTuplePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, int)>(); - - ffi.Pointer Py_BuildValue( - ffi.Pointer arg0, - ) { - return _Py_BuildValue( - arg0, - ); - } - - late final _Py_BuildValuePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('Py_BuildValue'); - late final _Py_BuildValue = _Py_BuildValuePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer _Py_BuildValue_SizeT( - ffi.Pointer arg0, - ) { - return __Py_BuildValue_SizeT( - arg0, - ); - } - - late final __Py_BuildValue_SizeTPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_Py_BuildValue_SizeT'); - late final __Py_BuildValue_SizeT = __Py_BuildValue_SizeTPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer Py_VaBuildValue( - ffi.Pointer arg0, - va_list arg1, - ) { - return _Py_VaBuildValue( - arg0, - arg1, - ); - } - - late final _Py_VaBuildValuePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, va_list)>>('Py_VaBuildValue'); - late final _Py_VaBuildValue = _Py_VaBuildValuePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, va_list)>(); - - int PyModule_AddObjectRef( - ffi.Pointer mod, - ffi.Pointer name, - ffi.Pointer value, - ) { - return _PyModule_AddObjectRef( - mod, - name, - value, - ); - } - - late final _PyModule_AddObjectRefPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyModule_AddObjectRef'); - late final _PyModule_AddObjectRef = _PyModule_AddObjectRefPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyModule_AddObject( - ffi.Pointer mod, - ffi.Pointer arg1, - ffi.Pointer value, - ) { - return _PyModule_AddObject( - mod, - arg1, - value, - ); - } - - late final _PyModule_AddObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyModule_AddObject'); - late final _PyModule_AddObject = _PyModule_AddObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyModule_AddIntConstant( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyModule_AddIntConstant( - arg0, - arg1, - arg2, - ); - } - - late final _PyModule_AddIntConstantPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Long)>>('PyModule_AddIntConstant'); - late final _PyModule_AddIntConstant = _PyModule_AddIntConstantPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyModule_AddStringConstant( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyModule_AddStringConstant( - arg0, - arg1, - arg2, - ); - } - - late final _PyModule_AddStringConstantPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyModule_AddStringConstant'); - late final _PyModule_AddStringConstant = - _PyModule_AddStringConstantPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyModule_AddType( - ffi.Pointer module, - ffi.Pointer type, - ) { - return _PyModule_AddType( - module, - type, - ); - } - - late final _PyModule_AddTypePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyModule_AddType'); - late final _PyModule_AddType = _PyModule_AddTypePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyModule_SetDocString( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyModule_SetDocString( - arg0, - arg1, - ); - } - - late final _PyModule_SetDocStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyModule_SetDocString'); - late final _PyModule_SetDocString = _PyModule_SetDocStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyModule_AddFunctions( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyModule_AddFunctions( - arg0, - arg1, - ); - } - - late final _PyModule_AddFunctionsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyModule_AddFunctions'); - late final _PyModule_AddFunctions = _PyModule_AddFunctionsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyModule_ExecDef( - ffi.Pointer module, - ffi.Pointer def, - ) { - return _PyModule_ExecDef( - module, - def, - ); - } - - late final _PyModule_ExecDefPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyModule_ExecDef'); - late final _PyModule_ExecDef = _PyModule_ExecDefPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyModule_Create2( - ffi.Pointer arg0, - int apiver, - ) { - return _PyModule_Create2( - arg0, - apiver, - ); - } - - late final _PyModule_Create2Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyModule_Create2'); - late final _PyModule_Create2 = _PyModule_Create2Ptr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyModule_FromDefAndSpec2( - ffi.Pointer def, - ffi.Pointer spec, - int module_api_version, - ) { - return _PyModule_FromDefAndSpec2( - def, - spec, - module_api_version, - ); - } - - late final _PyModule_FromDefAndSpec2Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('PyModule_FromDefAndSpec2'); - late final _PyModule_FromDefAndSpec2 = - _PyModule_FromDefAndSpec2Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer _Py_VaBuildValue_SizeT( - ffi.Pointer arg0, - va_list arg1, - ) { - return __Py_VaBuildValue_SizeT( - arg0, - arg1, - ); - } - - late final __Py_VaBuildValue_SizeTPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, va_list)>>('_Py_VaBuildValue_SizeT'); - late final __Py_VaBuildValue_SizeT = __Py_VaBuildValue_SizeTPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, va_list)>(); - - ffi.Pointer> _Py_VaBuildStack_SizeT( - ffi.Pointer> small_stack, - int small_stack_len, - ffi.Pointer format, - va_list va, - ffi.Pointer p_nargs, - ) { - return __Py_VaBuildStack_SizeT( - small_stack, - small_stack_len, - format, - va, - p_nargs, - ); - } - - late final __Py_VaBuildStack_SizeTPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer, - va_list, - ffi.Pointer)>>('_Py_VaBuildStack_SizeT'); - late final __Py_VaBuildStack_SizeT = __Py_VaBuildStack_SizeTPtr.asFunction< - ffi.Pointer> Function( - ffi.Pointer>, - int, - ffi.Pointer, - va_list, - ffi.Pointer)>(); - - int _PyArg_UnpackStack( - ffi.Pointer> args, - int nargs, - ffi.Pointer name, - int min, - int max, - ) { - return __PyArg_UnpackStack( - args, - nargs, - name, - min, - max, - ); - } - - late final __PyArg_UnpackStackPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer, - Py_ssize_t, - Py_ssize_t)>>('_PyArg_UnpackStack'); - late final __PyArg_UnpackStack = __PyArg_UnpackStackPtr.asFunction< - int Function(ffi.Pointer>, int, - ffi.Pointer, int, int)>(); - - int _PyArg_NoKeywords( - ffi.Pointer funcname, - ffi.Pointer kwargs, - ) { - return __PyArg_NoKeywords( - funcname, - kwargs, - ); - } - - late final __PyArg_NoKeywordsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyArg_NoKeywords'); - late final __PyArg_NoKeywords = __PyArg_NoKeywordsPtr - .asFunction, ffi.Pointer)>(); - - int _PyArg_NoKwnames( - ffi.Pointer funcname, - ffi.Pointer kwnames, - ) { - return __PyArg_NoKwnames( - funcname, - kwnames, - ); - } - - late final __PyArg_NoKwnamesPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyArg_NoKwnames'); - late final __PyArg_NoKwnames = __PyArg_NoKwnamesPtr - .asFunction, ffi.Pointer)>(); - - int _PyArg_NoPositional( - ffi.Pointer funcname, - ffi.Pointer args, - ) { - return __PyArg_NoPositional( - funcname, - args, - ); - } - - late final __PyArg_NoPositionalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyArg_NoPositional'); - late final __PyArg_NoPositional = __PyArg_NoPositionalPtr - .asFunction, ffi.Pointer)>(); - - void _PyArg_BadArgument( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return __PyArg_BadArgument( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyArg_BadArgumentPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyArg_BadArgument'); - late final __PyArg_BadArgument = __PyArg_BadArgumentPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - int _PyArg_CheckPositional( - ffi.Pointer arg0, - int arg1, - int arg2, - int arg3, - ) { - return __PyArg_CheckPositional( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyArg_CheckPositionalPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, Py_ssize_t, - Py_ssize_t)>>('_PyArg_CheckPositional'); - late final __PyArg_CheckPositional = __PyArg_CheckPositionalPtr - .asFunction, int, int, int)>(); - - ffi.Pointer> _Py_VaBuildStack( - ffi.Pointer> small_stack, - int small_stack_len, - ffi.Pointer format, - va_list va, - ffi.Pointer p_nargs, - ) { - return __Py_VaBuildStack( - small_stack, - small_stack_len, - format, - va, - p_nargs, - ); - } - - late final __Py_VaBuildStackPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer, - va_list, - ffi.Pointer)>>('_Py_VaBuildStack'); - late final __Py_VaBuildStack = __Py_VaBuildStackPtr.asFunction< - ffi.Pointer> Function( - ffi.Pointer>, - int, - ffi.Pointer, - va_list, - ffi.Pointer)>(); - - int _PyArg_ParseTupleAndKeywordsFast( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer<_PyArg_Parser> arg2, - ) { - return __PyArg_ParseTupleAndKeywordsFast( - arg0, - arg1, - arg2, - ); - } - - late final __PyArg_ParseTupleAndKeywordsFastPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer<_PyArg_Parser>)>>('_PyArg_ParseTupleAndKeywordsFast'); - late final __PyArg_ParseTupleAndKeywordsFast = - __PyArg_ParseTupleAndKeywordsFastPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer<_PyArg_Parser>)>(); - - int _PyArg_ParseStack( - ffi.Pointer> args, - int nargs, - ffi.Pointer format, - ) { - return __PyArg_ParseStack( - args, - nargs, - format, - ); - } - - late final __PyArg_ParseStackPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer>, Py_ssize_t, - ffi.Pointer)>>('_PyArg_ParseStack'); - late final __PyArg_ParseStack = __PyArg_ParseStackPtr.asFunction< - int Function( - ffi.Pointer>, int, ffi.Pointer)>(); - - int _PyArg_ParseStackAndKeywords( - ffi.Pointer> args, - int nargs, - ffi.Pointer kwnames, - ffi.Pointer<_PyArg_Parser> arg3, - ) { - return __PyArg_ParseStackAndKeywords( - args, - nargs, - kwnames, - arg3, - ); - } - - late final __PyArg_ParseStackAndKeywordsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer<_PyArg_Parser>)>>('_PyArg_ParseStackAndKeywords'); - late final __PyArg_ParseStackAndKeywords = - __PyArg_ParseStackAndKeywordsPtr.asFunction< - int Function(ffi.Pointer>, int, - ffi.Pointer, ffi.Pointer<_PyArg_Parser>)>(); - - int _PyArg_VaParseTupleAndKeywordsFast( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer<_PyArg_Parser> arg2, - va_list arg3, - ) { - return __PyArg_VaParseTupleAndKeywordsFast( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyArg_VaParseTupleAndKeywordsFastPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer<_PyArg_Parser>, - va_list)>>('_PyArg_VaParseTupleAndKeywordsFast'); - late final __PyArg_VaParseTupleAndKeywordsFast = - __PyArg_VaParseTupleAndKeywordsFastPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer<_PyArg_Parser>, va_list)>(); - - ffi.Pointer> _PyArg_UnpackKeywords( - ffi.Pointer> args, - int nargs, - ffi.Pointer kwargs, - ffi.Pointer kwnames, - ffi.Pointer<_PyArg_Parser> parser, - int minpos, - int maxpos, - int minkw, - ffi.Pointer> buf, - ) { - return __PyArg_UnpackKeywords( - args, - nargs, - kwargs, - kwnames, - parser, - minpos, - maxpos, - minkw, - buf, - ); - } - - late final __PyArg_UnpackKeywordsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer<_PyArg_Parser>, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Pointer>)>>('_PyArg_UnpackKeywords'); - late final __PyArg_UnpackKeywords = __PyArg_UnpackKeywordsPtr.asFunction< - ffi.Pointer> Function( - ffi.Pointer>, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer<_PyArg_Parser>, - int, - int, - int, - ffi.Pointer>)>(); - - ffi.Pointer> _PyArg_UnpackKeywordsWithVararg( - ffi.Pointer> args, - int nargs, - ffi.Pointer kwargs, - ffi.Pointer kwnames, - ffi.Pointer<_PyArg_Parser> parser, - int minpos, - int maxpos, - int minkw, - int vararg, - ffi.Pointer> buf, - ) { - return __PyArg_UnpackKeywordsWithVararg( - args, - nargs, - kwargs, - kwnames, - parser, - minpos, - maxpos, - minkw, - vararg, - buf, - ); - } - - late final __PyArg_UnpackKeywordsWithVarargPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer<_PyArg_Parser>, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Int, - ffi.Pointer>)>>( - '_PyArg_UnpackKeywordsWithVararg'); - late final __PyArg_UnpackKeywordsWithVararg = - __PyArg_UnpackKeywordsWithVarargPtr.asFunction< - ffi.Pointer> Function( - ffi.Pointer>, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer<_PyArg_Parser>, - int, - int, - int, - int, - ffi.Pointer>)>(); - - ffi.Pointer _PyModule_CreateInitialized( - ffi.Pointer arg0, - int apiver, - ) { - return __PyModule_CreateInitialized( - arg0, - apiver, - ); - } - - late final __PyModule_CreateInitializedPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Int)>>('_PyModule_CreateInitialized'); - late final __PyModule_CreateInitialized = - __PyModule_CreateInitializedPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int _PyModule_Add( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return __PyModule_Add( - arg0, - arg1, - arg2, - ); - } - - late final __PyModule_AddPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('_PyModule_Add'); - late final __PyModule_Add = __PyModule_AddPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyCompile_OpcodeStackEffect( - int opcode, - int oparg, - ) { - return _PyCompile_OpcodeStackEffect( - opcode, - oparg, - ); - } - - late final _PyCompile_OpcodeStackEffectPtr = - _lookup>( - 'PyCompile_OpcodeStackEffect'); - late final _PyCompile_OpcodeStackEffect = - _PyCompile_OpcodeStackEffectPtr.asFunction(); - - int PyCompile_OpcodeStackEffectWithJump( - int opcode, - int oparg, - int jump, - ) { - return _PyCompile_OpcodeStackEffectWithJump( - opcode, - oparg, - jump, - ); - } - - late final _PyCompile_OpcodeStackEffectWithJumpPtr = - _lookup>( - 'PyCompile_OpcodeStackEffectWithJump'); - late final _PyCompile_OpcodeStackEffectWithJump = - _PyCompile_OpcodeStackEffectWithJumpPtr.asFunction< - int Function(int, int, int)>(); - - ffi.Pointer Py_CompileString( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _Py_CompileString( - arg0, - arg1, - arg2, - ); - } - - late final _Py_CompileStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Int)>>('Py_CompileString'); - late final _Py_CompileString = _Py_CompileStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, int)>(); - - void PyErr_Print() { - return _PyErr_Print(); - } - - late final _PyErr_PrintPtr = - _lookup>('PyErr_Print'); - late final _PyErr_Print = _PyErr_PrintPtr.asFunction(); - - void PyErr_PrintEx( - int arg0, - ) { - return _PyErr_PrintEx( - arg0, - ); - } - - late final _PyErr_PrintExPtr = - _lookup>('PyErr_PrintEx'); - late final _PyErr_PrintEx = - _PyErr_PrintExPtr.asFunction(); - - void PyErr_Display( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyErr_Display( - arg0, - arg1, - arg2, - ); - } - - late final _PyErr_DisplayPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyErr_Display'); - late final _PyErr_Display = _PyErr_DisplayPtr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - void PyErr_DisplayException( - ffi.Pointer arg0, - ) { - return _PyErr_DisplayException( - arg0, - ); - } - - late final _PyErr_DisplayExceptionPtr = - _lookup)>>( - 'PyErr_DisplayException'); - late final _PyErr_DisplayException = _PyErr_DisplayExceptionPtr.asFunction< - void Function(ffi.Pointer)>(); - - late final ffi.Pointer>> - _PyOS_InputHook = - _lookup>>( - 'PyOS_InputHook'); - - ffi.Pointer> get PyOS_InputHook => - _PyOS_InputHook.value; - - set PyOS_InputHook( - ffi.Pointer> value) => - _PyOS_InputHook.value = value; - - int PyRun_SimpleStringFlags( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyRun_SimpleStringFlags( - arg0, - arg1, - ); - } - - late final _PyRun_SimpleStringFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyRun_SimpleStringFlags'); - late final _PyRun_SimpleStringFlags = _PyRun_SimpleStringFlagsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyRun_SimpleFileObject( - ffi.Pointer fp, - ffi.Pointer filename, - int closeit, - ffi.Pointer flags, - ) { - return __PyRun_SimpleFileObject( - fp, - filename, - closeit, - flags, - ); - } - - late final __PyRun_SimpleFileObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, ffi.Int, - ffi.Pointer)>>('_PyRun_SimpleFileObject'); - late final __PyRun_SimpleFileObject = __PyRun_SimpleFileObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, - ffi.Pointer)>(); - - int PyRun_AnyFileExFlags( - ffi.Pointer fp, - ffi.Pointer filename, - int closeit, - ffi.Pointer flags, - ) { - return _PyRun_AnyFileExFlags( - fp, - filename, - closeit, - flags, - ); - } - - late final _PyRun_AnyFileExFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, ffi.Int, - ffi.Pointer)>>('PyRun_AnyFileExFlags'); - late final _PyRun_AnyFileExFlags = _PyRun_AnyFileExFlagsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, - ffi.Pointer)>(); - - int _PyRun_AnyFileObject( - ffi.Pointer fp, - ffi.Pointer filename, - int closeit, - ffi.Pointer flags, - ) { - return __PyRun_AnyFileObject( - fp, - filename, - closeit, - flags, - ); - } - - late final __PyRun_AnyFileObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, ffi.Int, - ffi.Pointer)>>('_PyRun_AnyFileObject'); - late final __PyRun_AnyFileObject = __PyRun_AnyFileObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, - ffi.Pointer)>(); - - int PyRun_SimpleFileExFlags( - ffi.Pointer fp, - ffi.Pointer filename, - int closeit, - ffi.Pointer flags, - ) { - return _PyRun_SimpleFileExFlags( - fp, - filename, - closeit, - flags, - ); - } - - late final _PyRun_SimpleFileExFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, ffi.Int, - ffi.Pointer)>>('PyRun_SimpleFileExFlags'); - late final _PyRun_SimpleFileExFlags = _PyRun_SimpleFileExFlagsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int, - ffi.Pointer)>(); - - int PyRun_InteractiveOneFlags( - ffi.Pointer fp, - ffi.Pointer filename, - ffi.Pointer flags, - ) { - return _PyRun_InteractiveOneFlags( - fp, - filename, - flags, - ); - } - - late final _PyRun_InteractiveOneFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyRun_InteractiveOneFlags'); - late final _PyRun_InteractiveOneFlags = - _PyRun_InteractiveOneFlagsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyRun_InteractiveOneObject( - ffi.Pointer fp, - ffi.Pointer filename, - ffi.Pointer flags, - ) { - return _PyRun_InteractiveOneObject( - fp, - filename, - flags, - ); - } - - late final _PyRun_InteractiveOneObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyRun_InteractiveOneObject'); - late final _PyRun_InteractiveOneObject = - _PyRun_InteractiveOneObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyRun_InteractiveLoopFlags( - ffi.Pointer fp, - ffi.Pointer filename, - ffi.Pointer flags, - ) { - return _PyRun_InteractiveLoopFlags( - fp, - filename, - flags, - ); - } - - late final _PyRun_InteractiveLoopFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyRun_InteractiveLoopFlags'); - late final _PyRun_InteractiveLoopFlags = - _PyRun_InteractiveLoopFlagsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int _PyRun_InteractiveLoopObject( - ffi.Pointer fp, - ffi.Pointer filename, - ffi.Pointer flags, - ) { - return __PyRun_InteractiveLoopObject( - fp, - filename, - flags, - ); - } - - late final __PyRun_InteractiveLoopObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('_PyRun_InteractiveLoopObject'); - late final __PyRun_InteractiveLoopObject = - __PyRun_InteractiveLoopObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyRun_StringFlags( - ffi.Pointer arg0, - int arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ffi.Pointer arg4, - ) { - return _PyRun_StringFlags( - arg0, - arg1, - arg2, - arg3, - arg4, - ); - } - - late final _PyRun_StringFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyRun_StringFlags'); - late final _PyRun_StringFlags = _PyRun_StringFlagsPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyRun_FileExFlags( - ffi.Pointer fp, - ffi.Pointer filename, - int start, - ffi.Pointer globals, - ffi.Pointer locals, - int closeit, - ffi.Pointer flags, - ) { - return _PyRun_FileExFlags( - fp, - filename, - start, - globals, - locals, - closeit, - flags, - ); - } - - late final _PyRun_FileExFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer)>>('PyRun_FileExFlags'); - late final _PyRun_FileExFlags = _PyRun_FileExFlagsPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer)>(); - - ffi.Pointer Py_CompileStringExFlags( - ffi.Pointer str, - ffi.Pointer filename, - int start, - ffi.Pointer flags, - int optimize, - ) { - return _Py_CompileStringExFlags( - str, - filename, - start, - flags, - optimize, - ); - } - - late final _Py_CompileStringExFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Int)>>('Py_CompileStringExFlags'); - late final _Py_CompileStringExFlags = _Py_CompileStringExFlagsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, int, ffi.Pointer, int)>(); - - ffi.Pointer Py_CompileStringObject( - ffi.Pointer str, - ffi.Pointer filename, - int start, - ffi.Pointer flags, - int optimize, - ) { - return _Py_CompileStringObject( - str, - filename, - start, - flags, - optimize, - ); - } - - late final _Py_CompileStringObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Int)>>('Py_CompileStringObject'); - late final _Py_CompileStringObject = _Py_CompileStringObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, int, ffi.Pointer, int)>(); - - ffi.Pointer _Py_SourceAsString( - ffi.Pointer cmd, - ffi.Pointer funcname, - ffi.Pointer what, - ffi.Pointer cf, - ffi.Pointer> cmd_copy, - ) { - return __Py_SourceAsString( - cmd, - funcname, - what, - cf, - cmd_copy, - ); - } - - late final __Py_SourceAsStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>)>>('_Py_SourceAsString'); - late final __Py_SourceAsString = __Py_SourceAsStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>)>(); - - ffi.Pointer PyRun_String( - ffi.Pointer str, - int s, - ffi.Pointer g, - ffi.Pointer l, - ) { - return _PyRun_String( - str, - s, - g, - l, - ); - } - - late final _PyRun_StringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Int, - ffi.Pointer, ffi.Pointer)>>('PyRun_String'); - late final _PyRun_String = _PyRun_StringPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, - ffi.Pointer, ffi.Pointer)>(); - - int PyRun_AnyFile( - ffi.Pointer fp, - ffi.Pointer name, - ) { - return _PyRun_AnyFile( - fp, - name, - ); - } - - late final _PyRun_AnyFilePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyRun_AnyFile'); - late final _PyRun_AnyFile = _PyRun_AnyFilePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyRun_AnyFileEx( - ffi.Pointer fp, - ffi.Pointer name, - int closeit, - ) { - return _PyRun_AnyFileEx( - fp, - name, - closeit, - ); - } - - late final _PyRun_AnyFileExPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyRun_AnyFileEx'); - late final _PyRun_AnyFileEx = _PyRun_AnyFileExPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyRun_AnyFileFlags( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyRun_AnyFileFlags( - arg0, - arg1, - arg2, - ); - } - - late final _PyRun_AnyFileFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyRun_AnyFileFlags'); - late final _PyRun_AnyFileFlags = _PyRun_AnyFileFlagsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyRun_SimpleString( - ffi.Pointer s, - ) { - return _PyRun_SimpleString( - s, - ); - } - - late final _PyRun_SimpleStringPtr = - _lookup)>>( - 'PyRun_SimpleString'); - late final _PyRun_SimpleString = - _PyRun_SimpleStringPtr.asFunction)>(); - - int PyRun_SimpleFile( - ffi.Pointer f, - ffi.Pointer p, - ) { - return _PyRun_SimpleFile( - f, - p, - ); - } - - late final _PyRun_SimpleFilePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyRun_SimpleFile'); - late final _PyRun_SimpleFile = _PyRun_SimpleFilePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyRun_SimpleFileEx( - ffi.Pointer f, - ffi.Pointer p, - int c, - ) { - return _PyRun_SimpleFileEx( - f, - p, - c, - ); - } - - late final _PyRun_SimpleFileExPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('PyRun_SimpleFileEx'); - late final _PyRun_SimpleFileEx = _PyRun_SimpleFileExPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyRun_InteractiveOne( - ffi.Pointer f, - ffi.Pointer p, - ) { - return _PyRun_InteractiveOne( - f, - p, - ); - } - - late final _PyRun_InteractiveOnePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyRun_InteractiveOne'); - late final _PyRun_InteractiveOne = _PyRun_InteractiveOnePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyRun_InteractiveLoop( - ffi.Pointer f, - ffi.Pointer p, - ) { - return _PyRun_InteractiveLoop( - f, - p, - ); - } - - late final _PyRun_InteractiveLoopPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyRun_InteractiveLoop'); - late final _PyRun_InteractiveLoop = _PyRun_InteractiveLoopPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyRun_File( - ffi.Pointer fp, - ffi.Pointer p, - int s, - ffi.Pointer g, - ffi.Pointer l, - ) { - return _PyRun_File( - fp, - p, - s, - g, - l, - ); - } - - late final _PyRun_FilePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('PyRun_File'); - late final _PyRun_File = _PyRun_FilePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Pointer, - int, ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyRun_FileEx( - ffi.Pointer fp, - ffi.Pointer p, - int s, - ffi.Pointer g, - ffi.Pointer l, - int c, - ) { - return _PyRun_FileEx( - fp, - p, - s, - g, - l, - c, - ); - } - - late final _PyRun_FileExPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Int)>>('PyRun_FileEx'); - late final _PyRun_FileEx = _PyRun_FileExPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Pointer, - int, ffi.Pointer, ffi.Pointer, int)>(); - - ffi.Pointer PyRun_FileFlags( - ffi.Pointer fp, - ffi.Pointer p, - int s, - ffi.Pointer g, - ffi.Pointer l, - ffi.Pointer flags, - ) { - return _PyRun_FileFlags( - fp, - p, - s, - g, - l, - flags, - ); - } - - late final _PyRun_FileFlagsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyRun_FileFlags'); - late final _PyRun_FileFlags = _PyRun_FileFlagsPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyOS_Readline( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyOS_Readline( - arg0, - arg1, - arg2, - ); - } - - late final _PyOS_ReadlinePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyOS_Readline'); - late final _PyOS_Readline = _PyOS_ReadlinePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer> __PyOS_ReadlineTState = - _lookup>('_PyOS_ReadlineTState'); - - ffi.Pointer get _PyOS_ReadlineTState => - __PyOS_ReadlineTState.value; - - set _PyOS_ReadlineTState(ffi.Pointer value) => - __PyOS_ReadlineTState.value = value; - - late final ffi.Pointer< - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>> - _PyOS_ReadlineFunctionPointer = _lookup< - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>>('PyOS_ReadlineFunctionPointer'); - - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, ffi.Pointer)>> - get PyOS_ReadlineFunctionPointer => _PyOS_ReadlineFunctionPointer.value; - - set PyOS_ReadlineFunctionPointer( - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>> - value) => - _PyOS_ReadlineFunctionPointer.value = value; - - void Py_Initialize() { - return _Py_Initialize(); - } - - late final _Py_InitializePtr = - _lookup>('Py_Initialize'); - late final _Py_Initialize = _Py_InitializePtr.asFunction(); - - void Py_InitializeEx( - int arg0, - ) { - return _Py_InitializeEx( - arg0, - ); - } - - late final _Py_InitializeExPtr = - _lookup>( - 'Py_InitializeEx'); - late final _Py_InitializeEx = - _Py_InitializeExPtr.asFunction(); - - void Py_Finalize() { - return _Py_Finalize(); - } - - late final _Py_FinalizePtr = - _lookup>('Py_Finalize'); - late final _Py_Finalize = _Py_FinalizePtr.asFunction(); - - int Py_FinalizeEx() { - return _Py_FinalizeEx(); - } - - late final _Py_FinalizeExPtr = - _lookup>('Py_FinalizeEx'); - late final _Py_FinalizeEx = _Py_FinalizeExPtr.asFunction(); - - int Py_IsInitialized() { - return _Py_IsInitialized(); - } - - late final _Py_IsInitializedPtr = - _lookup>('Py_IsInitialized'); - late final _Py_IsInitialized = - _Py_IsInitializedPtr.asFunction(); - - ffi.Pointer Py_NewInterpreter() { - return _Py_NewInterpreter(); - } - - late final _Py_NewInterpreterPtr = - _lookup Function()>>( - 'Py_NewInterpreter'); - late final _Py_NewInterpreter = - _Py_NewInterpreterPtr.asFunction Function()>(); - - void Py_EndInterpreter( - ffi.Pointer arg0, - ) { - return _Py_EndInterpreter( - arg0, - ); - } - - late final _Py_EndInterpreterPtr = _lookup< - ffi.NativeFunction)>>( - 'Py_EndInterpreter'); - late final _Py_EndInterpreter = _Py_EndInterpreterPtr.asFunction< - void Function(ffi.Pointer)>(); - - int Py_AtExit( - ffi.Pointer> func, - ) { - return _Py_AtExit1( - func, - ); - } - - late final _Py_AtExitPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer>)>>( - 'Py_AtExit'); - late final _Py_AtExit1 = _Py_AtExitPtr.asFunction< - int Function(ffi.Pointer>)>(); - - void Py_Exit( - int arg0, - ) { - return _Py_Exit( - arg0, - ); - } - - late final _Py_ExitPtr = - _lookup>('Py_Exit'); - late final _Py_Exit = _Py_ExitPtr.asFunction(); - - int Py_Main( - int argc, - ffi.Pointer> argv, - ) { - return _Py_Main( - argc, - argv, - ); - } - - late final _Py_MainPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Int, ffi.Pointer>)>>('Py_Main'); - late final _Py_Main = _Py_MainPtr.asFunction< - int Function(int, ffi.Pointer>)>(); - - int Py_BytesMain( - int argc, - ffi.Pointer> argv, - ) { - return _Py_BytesMain( - argc, - argv, - ); - } - - late final _Py_BytesMainPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Int, ffi.Pointer>)>>('Py_BytesMain'); - late final _Py_BytesMain = _Py_BytesMainPtr.asFunction< - int Function(int, ffi.Pointer>)>(); - - void Py_SetProgramName( - ffi.Pointer arg0, - ) { - return _Py_SetProgramName( - arg0, - ); - } - - late final _Py_SetProgramNamePtr = - _lookup)>>( - 'Py_SetProgramName'); - late final _Py_SetProgramName = - _Py_SetProgramNamePtr.asFunction)>(); - - ffi.Pointer Py_GetProgramName() { - return _Py_GetProgramName(); - } - - late final _Py_GetProgramNamePtr = - _lookup Function()>>( - 'Py_GetProgramName'); - late final _Py_GetProgramName = - _Py_GetProgramNamePtr.asFunction Function()>(); - - void Py_SetPythonHome( - ffi.Pointer arg0, - ) { - return _Py_SetPythonHome( - arg0, - ); - } - - late final _Py_SetPythonHomePtr = - _lookup)>>( - 'Py_SetPythonHome'); - late final _Py_SetPythonHome = - _Py_SetPythonHomePtr.asFunction)>(); - - ffi.Pointer Py_GetPythonHome() { - return _Py_GetPythonHome(); - } - - late final _Py_GetPythonHomePtr = - _lookup Function()>>( - 'Py_GetPythonHome'); - late final _Py_GetPythonHome = - _Py_GetPythonHomePtr.asFunction Function()>(); - - ffi.Pointer Py_GetProgramFullPath() { - return _Py_GetProgramFullPath(); - } - - late final _Py_GetProgramFullPathPtr = - _lookup Function()>>( - 'Py_GetProgramFullPath'); - late final _Py_GetProgramFullPath = - _Py_GetProgramFullPathPtr.asFunction Function()>(); - - ffi.Pointer Py_GetPrefix() { - return _Py_GetPrefix(); - } - - late final _Py_GetPrefixPtr = - _lookup Function()>>( - 'Py_GetPrefix'); - late final _Py_GetPrefix = - _Py_GetPrefixPtr.asFunction Function()>(); - - ffi.Pointer Py_GetExecPrefix() { - return _Py_GetExecPrefix(); - } - - late final _Py_GetExecPrefixPtr = - _lookup Function()>>( - 'Py_GetExecPrefix'); - late final _Py_GetExecPrefix = - _Py_GetExecPrefixPtr.asFunction Function()>(); - - ffi.Pointer Py_GetPath() { - return _Py_GetPath(); - } - - late final _Py_GetPathPtr = - _lookup Function()>>( - 'Py_GetPath'); - late final _Py_GetPath = - _Py_GetPathPtr.asFunction Function()>(); - - void Py_SetPath( - ffi.Pointer arg0, - ) { - return _Py_SetPath( - arg0, - ); - } - - late final _Py_SetPathPtr = - _lookup)>>( - 'Py_SetPath'); - late final _Py_SetPath = - _Py_SetPathPtr.asFunction)>(); - - ffi.Pointer Py_GetVersion() { - return _Py_GetVersion(); - } - - late final _Py_GetVersionPtr = - _lookup Function()>>( - 'Py_GetVersion'); - late final _Py_GetVersion = - _Py_GetVersionPtr.asFunction Function()>(); - - ffi.Pointer Py_GetPlatform() { - return _Py_GetPlatform(); - } - - late final _Py_GetPlatformPtr = - _lookup Function()>>( - 'Py_GetPlatform'); - late final _Py_GetPlatform = - _Py_GetPlatformPtr.asFunction Function()>(); - - ffi.Pointer Py_GetCopyright() { - return _Py_GetCopyright(); - } - - late final _Py_GetCopyrightPtr = - _lookup Function()>>( - 'Py_GetCopyright'); - late final _Py_GetCopyright = - _Py_GetCopyrightPtr.asFunction Function()>(); - - ffi.Pointer Py_GetCompiler() { - return _Py_GetCompiler(); - } - - late final _Py_GetCompilerPtr = - _lookup Function()>>( - 'Py_GetCompiler'); - late final _Py_GetCompiler = - _Py_GetCompilerPtr.asFunction Function()>(); - - ffi.Pointer Py_GetBuildInfo() { - return _Py_GetBuildInfo(); - } - - late final _Py_GetBuildInfoPtr = - _lookup Function()>>( - 'Py_GetBuildInfo'); - late final _Py_GetBuildInfo = - _Py_GetBuildInfoPtr.asFunction Function()>(); - - PyOS_sighandler_t PyOS_getsig( - int arg0, - ) { - return _PyOS_getsig( - arg0, - ); - } - - late final _PyOS_getsigPtr = - _lookup>( - 'PyOS_getsig'); - late final _PyOS_getsig = - _PyOS_getsigPtr.asFunction(); - - PyOS_sighandler_t PyOS_setsig( - int arg0, - PyOS_sighandler_t arg1, - ) { - return _PyOS_setsig( - arg0, - arg1, - ); - } - - late final _PyOS_setsigPtr = _lookup< - ffi.NativeFunction< - PyOS_sighandler_t Function( - ffi.Int, PyOS_sighandler_t)>>('PyOS_setsig'); - late final _PyOS_setsig = _PyOS_setsigPtr.asFunction< - PyOS_sighandler_t Function(int, PyOS_sighandler_t)>(); - - late final ffi.Pointer _Py_Version = - _lookup('Py_Version'); - - int get Py_Version => _Py_Version.value; - - set Py_Version(int value) => _Py_Version.value = value; - - int Py_FrozenMain( - int argc, - ffi.Pointer> argv, - ) { - return _Py_FrozenMain( - argc, - argv, - ); - } - - late final _Py_FrozenMainPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Int, ffi.Pointer>)>>('Py_FrozenMain'); - late final _Py_FrozenMain = _Py_FrozenMainPtr.asFunction< - int Function(int, ffi.Pointer>)>(); - - int Py_SetStandardStreamEncoding( - ffi.Pointer encoding, - ffi.Pointer errors, - ) { - return _Py_SetStandardStreamEncoding( - encoding, - errors, - ); - } - - late final _Py_SetStandardStreamEncodingPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('Py_SetStandardStreamEncoding'); - late final _Py_SetStandardStreamEncoding = _Py_SetStandardStreamEncodingPtr - .asFunction, ffi.Pointer)>(); - - PyStatus Py_PreInitialize( - ffi.Pointer src_config, - ) { - return _Py_PreInitialize( - src_config, - ); - } - - late final _Py_PreInitializePtr = - _lookup)>>( - 'Py_PreInitialize'); - late final _Py_PreInitialize = _Py_PreInitializePtr.asFunction< - PyStatus Function(ffi.Pointer)>(); - - PyStatus Py_PreInitializeFromBytesArgs( - ffi.Pointer src_config, - int argc, - ffi.Pointer> argv, - ) { - return _Py_PreInitializeFromBytesArgs( - src_config, - argc, - argv, - ); - } - - late final _Py_PreInitializeFromBytesArgsPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer>)>>( - 'Py_PreInitializeFromBytesArgs'); - late final _Py_PreInitializeFromBytesArgs = - _Py_PreInitializeFromBytesArgsPtr.asFunction< - PyStatus Function(ffi.Pointer, int, - ffi.Pointer>)>(); - - PyStatus Py_PreInitializeFromArgs( - ffi.Pointer src_config, - int argc, - ffi.Pointer> argv, - ) { - return _Py_PreInitializeFromArgs( - src_config, - argc, - argv, - ); - } - - late final _Py_PreInitializeFromArgsPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer>)>>( - 'Py_PreInitializeFromArgs'); - late final _Py_PreInitializeFromArgs = - _Py_PreInitializeFromArgsPtr.asFunction< - PyStatus Function(ffi.Pointer, int, - ffi.Pointer>)>(); - - int _Py_IsCoreInitialized() { - return __Py_IsCoreInitialized(); - } - - late final __Py_IsCoreInitializedPtr = - _lookup>('_Py_IsCoreInitialized'); - late final __Py_IsCoreInitialized = - __Py_IsCoreInitializedPtr.asFunction(); - - PyStatus Py_InitializeFromConfig( - ffi.Pointer config, - ) { - return _Py_InitializeFromConfig( - config, - ); - } - - late final _Py_InitializeFromConfigPtr = - _lookup)>>( - 'Py_InitializeFromConfig'); - late final _Py_InitializeFromConfig = _Py_InitializeFromConfigPtr.asFunction< - PyStatus Function(ffi.Pointer)>(); - - PyStatus _Py_InitializeMain() { - return __Py_InitializeMain(); - } - - late final __Py_InitializeMainPtr = - _lookup>('_Py_InitializeMain'); - late final __Py_InitializeMain = - __Py_InitializeMainPtr.asFunction(); - - int Py_RunMain() { - return _Py_RunMain(); - } - - late final _Py_RunMainPtr = - _lookup>('Py_RunMain'); - late final _Py_RunMain = _Py_RunMainPtr.asFunction(); - - void Py_ExitStatusException( - PyStatus err, - ) { - return _Py_ExitStatusException( - err, - ); - } - - late final _Py_ExitStatusExceptionPtr = - _lookup>( - 'Py_ExitStatusException'); - late final _Py_ExitStatusException = - _Py_ExitStatusExceptionPtr.asFunction(); - - void _Py_RestoreSignals() { - return __Py_RestoreSignals(); - } - - late final __Py_RestoreSignalsPtr = - _lookup>('_Py_RestoreSignals'); - late final __Py_RestoreSignals = - __Py_RestoreSignalsPtr.asFunction(); - - int Py_FdIsInteractive( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _Py_FdIsInteractive1( - arg0, - arg1, - ); - } - - late final _Py_FdIsInteractivePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('Py_FdIsInteractive'); - late final _Py_FdIsInteractive1 = _Py_FdIsInteractivePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _Py_FdIsInteractive( - ffi.Pointer fp, - ffi.Pointer filename, - ) { - return __Py_FdIsInteractive( - fp, - filename, - ); - } - - late final __Py_FdIsInteractivePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_Py_FdIsInteractive'); - late final __Py_FdIsInteractive = __Py_FdIsInteractivePtr - .asFunction, ffi.Pointer)>(); - - void _Py_SetProgramFullPath( - ffi.Pointer arg0, - ) { - return __Py_SetProgramFullPath( - arg0, - ); - } - - late final __Py_SetProgramFullPathPtr = - _lookup)>>( - '_Py_SetProgramFullPath'); - late final __Py_SetProgramFullPath = __Py_SetProgramFullPathPtr - .asFunction)>(); - - ffi.Pointer _Py_gitidentifier() { - return __Py_gitidentifier(); - } - - late final __Py_gitidentifierPtr = - _lookup Function()>>( - '_Py_gitidentifier'); - late final __Py_gitidentifier = - __Py_gitidentifierPtr.asFunction Function()>(); - - ffi.Pointer _Py_gitversion() { - return __Py_gitversion(); - } - - late final __Py_gitversionPtr = - _lookup Function()>>( - '_Py_gitversion'); - late final __Py_gitversion = - __Py_gitversionPtr.asFunction Function()>(); - - int _Py_IsFinalizing() { - return __Py_IsFinalizing(); - } - - late final __Py_IsFinalizingPtr = - _lookup>('_Py_IsFinalizing'); - late final __Py_IsFinalizing = - __Py_IsFinalizingPtr.asFunction(); - - int _Py_IsInterpreterFinalizing( - ffi.Pointer interp, - ) { - return __Py_IsInterpreterFinalizing( - interp, - ); - } - - late final __Py_IsInterpreterFinalizingPtr = _lookup< - ffi - .NativeFunction)>>( - '_Py_IsInterpreterFinalizing'); - late final __Py_IsInterpreterFinalizing = __Py_IsInterpreterFinalizingPtr - .asFunction)>(); - - int _PyOS_URandom( - ffi.Pointer buffer, - int size, - ) { - return __PyOS_URandom( - buffer, - size, - ); - } - - late final __PyOS_URandomPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - '_PyOS_URandom'); - late final __PyOS_URandom = - __PyOS_URandomPtr.asFunction, int)>(); - - int _PyOS_URandomNonblock( - ffi.Pointer buffer, - int size, - ) { - return __PyOS_URandomNonblock( - buffer, - size, - ); - } - - late final __PyOS_URandomNonblockPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - '_PyOS_URandomNonblock'); - late final __PyOS_URandomNonblock = __PyOS_URandomNonblockPtr - .asFunction, int)>(); - - int _Py_CoerceLegacyLocale( - int warn, - ) { - return __Py_CoerceLegacyLocale( - warn, - ); - } - - late final __Py_CoerceLegacyLocalePtr = - _lookup>( - '_Py_CoerceLegacyLocale'); - late final __Py_CoerceLegacyLocale = - __Py_CoerceLegacyLocalePtr.asFunction(); - - int _Py_LegacyLocaleDetected( - int warn, - ) { - return __Py_LegacyLocaleDetected( - warn, - ); - } - - late final __Py_LegacyLocaleDetectedPtr = - _lookup>( - '_Py_LegacyLocaleDetected'); - late final __Py_LegacyLocaleDetected = - __Py_LegacyLocaleDetectedPtr.asFunction(); - - ffi.Pointer _Py_SetLocaleFromEnv( - int category, - ) { - return __Py_SetLocaleFromEnv( - category, - ); - } - - late final __Py_SetLocaleFromEnvPtr = - _lookup Function(ffi.Int)>>( - '_Py_SetLocaleFromEnv'); - late final __Py_SetLocaleFromEnv = __Py_SetLocaleFromEnvPtr - .asFunction Function(int)>(); - - PyStatus Py_NewInterpreterFromConfig( - ffi.Pointer> tstate_p, - ffi.Pointer config, - ) { - return _Py_NewInterpreterFromConfig( - tstate_p, - config, - ); - } - - late final _Py_NewInterpreterFromConfigPtr = _lookup< - ffi.NativeFunction< - PyStatus Function(ffi.Pointer>, - ffi.Pointer)>>( - 'Py_NewInterpreterFromConfig'); - late final _Py_NewInterpreterFromConfig = - _Py_NewInterpreterFromConfigPtr.asFunction< - PyStatus Function(ffi.Pointer>, - ffi.Pointer)>(); - - int _Py_AtExit( - ffi.Pointer arg0, - atexit_datacallbackfunc arg1, - ffi.Pointer arg2, - ) { - return __Py_AtExit( - arg0, - arg1, - arg2, - ); - } - - late final __Py_AtExitPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - atexit_datacallbackfunc, ffi.Pointer)>>('_Py_AtExit'); - late final __Py_AtExit = __Py_AtExitPtr.asFunction< - int Function(ffi.Pointer, atexit_datacallbackfunc, - ffi.Pointer)>(); - - ffi.Pointer PyEval_EvalCode( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ) { - return _PyEval_EvalCode( - arg0, - arg1, - arg2, - ); - } - - late final _PyEval_EvalCodePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyEval_EvalCode'); - late final _PyEval_EvalCode = _PyEval_EvalCodePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyEval_EvalCodeEx( - ffi.Pointer co, - ffi.Pointer globals, - ffi.Pointer locals, - ffi.Pointer> args, - int argc, - ffi.Pointer> kwds, - int kwdc, - ffi.Pointer> defs, - int defc, - ffi.Pointer kwdefs, - ffi.Pointer closure, - ) { - return _PyEval_EvalCodeEx( - co, - globals, - locals, - args, - argc, - kwds, - kwdc, - defs, - defc, - kwdefs, - closure, - ); - } - - late final _PyEval_EvalCodeExPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.Int, - ffi.Pointer>, - ffi.Int, - ffi.Pointer>, - ffi.Int, - ffi.Pointer, - ffi.Pointer)>>('PyEval_EvalCodeEx'); - late final _PyEval_EvalCodeEx = _PyEval_EvalCodeExPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - int, - ffi.Pointer>, - int, - ffi.Pointer>, - int, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyEval_CallObjectWithKeywords( - ffi.Pointer callable, - ffi.Pointer args, - ffi.Pointer kwargs, - ) { - return _PyEval_CallObjectWithKeywords( - callable, - args, - kwargs, - ); - } - - late final _PyEval_CallObjectWithKeywordsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyEval_CallObjectWithKeywords'); - late final _PyEval_CallObjectWithKeywords = - _PyEval_CallObjectWithKeywordsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyEval_CallFunction( - ffi.Pointer callable, - ffi.Pointer format, - ) { - return _PyEval_CallFunction( - callable, - format, - ); - } - - late final _PyEval_CallFunctionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyEval_CallFunction'); - late final _PyEval_CallFunction = _PyEval_CallFunctionPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyEval_CallMethod( - ffi.Pointer obj, - ffi.Pointer name, - ffi.Pointer format, - ) { - return _PyEval_CallMethod( - obj, - name, - format, - ); - } - - late final _PyEval_CallMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyEval_CallMethod'); - late final _PyEval_CallMethod = _PyEval_CallMethodPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyEval_GetBuiltins() { - return _PyEval_GetBuiltins(); - } - - late final _PyEval_GetBuiltinsPtr = - _lookup Function()>>( - 'PyEval_GetBuiltins'); - late final _PyEval_GetBuiltins = - _PyEval_GetBuiltinsPtr.asFunction Function()>(); - - ffi.Pointer PyEval_GetGlobals() { - return _PyEval_GetGlobals(); - } - - late final _PyEval_GetGlobalsPtr = - _lookup Function()>>( - 'PyEval_GetGlobals'); - late final _PyEval_GetGlobals = - _PyEval_GetGlobalsPtr.asFunction Function()>(); - - ffi.Pointer PyEval_GetLocals() { - return _PyEval_GetLocals(); - } - - late final _PyEval_GetLocalsPtr = - _lookup Function()>>( - 'PyEval_GetLocals'); - late final _PyEval_GetLocals = - _PyEval_GetLocalsPtr.asFunction Function()>(); - - ffi.Pointer PyEval_GetFrame() { - return _PyEval_GetFrame(); - } - - late final _PyEval_GetFramePtr = - _lookup Function()>>( - 'PyEval_GetFrame'); - late final _PyEval_GetFrame = - _PyEval_GetFramePtr.asFunction Function()>(); - - int Py_AddPendingCall( - ffi.Pointer)>> - func, - ffi.Pointer arg, - ) { - return _Py_AddPendingCall( - func, - arg, - ); - } - - late final _Py_AddPendingCallPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer< - ffi.NativeFunction)>>, - ffi.Pointer)>>('Py_AddPendingCall'); - late final _Py_AddPendingCall = _Py_AddPendingCallPtr.asFunction< - int Function( - ffi.Pointer< - ffi.NativeFunction)>>, - ffi.Pointer)>(); - - int Py_MakePendingCalls() { - return _Py_MakePendingCalls(); - } - - late final _Py_MakePendingCallsPtr = - _lookup>('Py_MakePendingCalls'); - late final _Py_MakePendingCalls = - _Py_MakePendingCallsPtr.asFunction(); - - void Py_SetRecursionLimit( - int arg0, - ) { - return _Py_SetRecursionLimit( - arg0, - ); - } - - late final _Py_SetRecursionLimitPtr = - _lookup>( - 'Py_SetRecursionLimit'); - late final _Py_SetRecursionLimit = - _Py_SetRecursionLimitPtr.asFunction(); - - int Py_GetRecursionLimit() { - return _Py_GetRecursionLimit(); - } - - late final _Py_GetRecursionLimitPtr = - _lookup>('Py_GetRecursionLimit'); - late final _Py_GetRecursionLimit = - _Py_GetRecursionLimitPtr.asFunction(); - - int Py_EnterRecursiveCall( - ffi.Pointer where, - ) { - return _Py_EnterRecursiveCall( - where, - ); - } - - late final _Py_EnterRecursiveCallPtr = - _lookup)>>( - 'Py_EnterRecursiveCall'); - late final _Py_EnterRecursiveCall = _Py_EnterRecursiveCallPtr.asFunction< - int Function(ffi.Pointer)>(); - - void Py_LeaveRecursiveCall() { - return _Py_LeaveRecursiveCall(); - } - - late final _Py_LeaveRecursiveCallPtr = - _lookup>('Py_LeaveRecursiveCall'); - late final _Py_LeaveRecursiveCall = - _Py_LeaveRecursiveCallPtr.asFunction(); - - ffi.Pointer PyEval_GetFuncName( - ffi.Pointer arg0, - ) { - return _PyEval_GetFuncName( - arg0, - ); - } - - late final _PyEval_GetFuncNamePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyEval_GetFuncName'); - late final _PyEval_GetFuncName = _PyEval_GetFuncNamePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyEval_GetFuncDesc( - ffi.Pointer arg0, - ) { - return _PyEval_GetFuncDesc( - arg0, - ); - } - - late final _PyEval_GetFuncDescPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyEval_GetFuncDesc'); - late final _PyEval_GetFuncDesc = _PyEval_GetFuncDescPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyEval_EvalFrame( - ffi.Pointer arg0, - ) { - return _PyEval_EvalFrame( - arg0, - ); - } - - late final _PyEval_EvalFramePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyEval_EvalFrame'); - late final _PyEval_EvalFrame = _PyEval_EvalFramePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyEval_EvalFrameEx( - ffi.Pointer f, - int exc, - ) { - return _PyEval_EvalFrameEx( - f, - exc, - ); - } - - late final _PyEval_EvalFrameExPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyEval_EvalFrameEx'); - late final _PyEval_EvalFrameEx = _PyEval_EvalFrameExPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PyEval_SaveThread() { - return _PyEval_SaveThread(); - } - - late final _PyEval_SaveThreadPtr = - _lookup Function()>>( - 'PyEval_SaveThread'); - late final _PyEval_SaveThread = - _PyEval_SaveThreadPtr.asFunction Function()>(); - - void PyEval_RestoreThread( - ffi.Pointer arg0, - ) { - return _PyEval_RestoreThread( - arg0, - ); - } - - late final _PyEval_RestoreThreadPtr = _lookup< - ffi.NativeFunction)>>( - 'PyEval_RestoreThread'); - late final _PyEval_RestoreThread = _PyEval_RestoreThreadPtr.asFunction< - void Function(ffi.Pointer)>(); - - int PyEval_ThreadsInitialized() { - return _PyEval_ThreadsInitialized(); - } - - late final _PyEval_ThreadsInitializedPtr = - _lookup>( - 'PyEval_ThreadsInitialized'); - late final _PyEval_ThreadsInitialized = - _PyEval_ThreadsInitializedPtr.asFunction(); - - void PyEval_InitThreads() { - return _PyEval_InitThreads(); - } - - late final _PyEval_InitThreadsPtr = - _lookup>('PyEval_InitThreads'); - late final _PyEval_InitThreads = - _PyEval_InitThreadsPtr.asFunction(); - - void PyEval_AcquireLock() { - return _PyEval_AcquireLock(); - } - - late final _PyEval_AcquireLockPtr = - _lookup>('PyEval_AcquireLock'); - late final _PyEval_AcquireLock = - _PyEval_AcquireLockPtr.asFunction(); - - void PyEval_ReleaseLock() { - return _PyEval_ReleaseLock(); - } - - late final _PyEval_ReleaseLockPtr = - _lookup>('PyEval_ReleaseLock'); - late final _PyEval_ReleaseLock = - _PyEval_ReleaseLockPtr.asFunction(); - - void PyEval_AcquireThread( - ffi.Pointer tstate, - ) { - return _PyEval_AcquireThread( - tstate, - ); - } - - late final _PyEval_AcquireThreadPtr = _lookup< - ffi.NativeFunction)>>( - 'PyEval_AcquireThread'); - late final _PyEval_AcquireThread = _PyEval_AcquireThreadPtr.asFunction< - void Function(ffi.Pointer)>(); - - void PyEval_ReleaseThread( - ffi.Pointer tstate, - ) { - return _PyEval_ReleaseThread( - tstate, - ); - } - - late final _PyEval_ReleaseThreadPtr = _lookup< - ffi.NativeFunction)>>( - 'PyEval_ReleaseThread'); - late final _PyEval_ReleaseThread = _PyEval_ReleaseThreadPtr.asFunction< - void Function(ffi.Pointer)>(); - - void PyEval_SetProfile( - Py_tracefunc arg0, - ffi.Pointer arg1, - ) { - return _PyEval_SetProfile1( - arg0, - arg1, - ); - } - - late final _PyEval_SetProfilePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - Py_tracefunc, ffi.Pointer)>>('PyEval_SetProfile'); - late final _PyEval_SetProfile1 = _PyEval_SetProfilePtr.asFunction< - void Function(Py_tracefunc, ffi.Pointer)>(); - - void PyEval_SetProfileAllThreads( - Py_tracefunc arg0, - ffi.Pointer arg1, - ) { - return _PyEval_SetProfileAllThreads( - arg0, - arg1, - ); - } - - late final _PyEval_SetProfileAllThreadsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(Py_tracefunc, - ffi.Pointer)>>('PyEval_SetProfileAllThreads'); - late final _PyEval_SetProfileAllThreads = _PyEval_SetProfileAllThreadsPtr - .asFunction)>(); - - int _PyEval_SetProfile( - ffi.Pointer tstate, - Py_tracefunc func, - ffi.Pointer arg, - ) { - return __PyEval_SetProfile( - tstate, - func, - arg, - ); - } - - late final __PyEval_SetProfilePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_tracefunc, - ffi.Pointer)>>('_PyEval_SetProfile'); - late final __PyEval_SetProfile = __PyEval_SetProfilePtr.asFunction< - int Function( - ffi.Pointer, Py_tracefunc, ffi.Pointer)>(); - - void PyEval_SetTrace( - Py_tracefunc arg0, - ffi.Pointer arg1, - ) { - return _PyEval_SetTrace1( - arg0, - arg1, - ); - } - - late final _PyEval_SetTracePtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - Py_tracefunc, ffi.Pointer)>>('PyEval_SetTrace'); - late final _PyEval_SetTrace1 = _PyEval_SetTracePtr.asFunction< - void Function(Py_tracefunc, ffi.Pointer)>(); - - void PyEval_SetTraceAllThreads( - Py_tracefunc arg0, - ffi.Pointer arg1, - ) { - return _PyEval_SetTraceAllThreads( - arg0, - arg1, - ); - } - - late final _PyEval_SetTraceAllThreadsPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(Py_tracefunc, - ffi.Pointer)>>('PyEval_SetTraceAllThreads'); - late final _PyEval_SetTraceAllThreads = _PyEval_SetTraceAllThreadsPtr - .asFunction)>(); - - int _PyEval_SetTrace( - ffi.Pointer tstate, - Py_tracefunc func, - ffi.Pointer arg, - ) { - return __PyEval_SetTrace( - tstate, - func, - arg, - ); - } - - late final __PyEval_SetTracePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_tracefunc, - ffi.Pointer)>>('_PyEval_SetTrace'); - late final __PyEval_SetTrace = __PyEval_SetTracePtr.asFunction< - int Function( - ffi.Pointer, Py_tracefunc, ffi.Pointer)>(); - - ffi.Pointer _PyEval_GetBuiltin( - ffi.Pointer arg0, - ) { - return __PyEval_GetBuiltin( - arg0, - ); - } - - late final __PyEval_GetBuiltinPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyEval_GetBuiltin'); - late final __PyEval_GetBuiltin = __PyEval_GetBuiltinPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer _PyEval_GetBuiltinId( - ffi.Pointer<_Py_Identifier> arg0, - ) { - return __PyEval_GetBuiltinId( - arg0, - ); - } - - late final __PyEval_GetBuiltinIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_Py_Identifier>)>>('_PyEval_GetBuiltinId'); - late final __PyEval_GetBuiltinId = __PyEval_GetBuiltinIdPtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_Py_Identifier>)>(); - - int PyEval_MergeCompilerFlags( - ffi.Pointer cf, - ) { - return _PyEval_MergeCompilerFlags( - cf, - ); - } - - late final _PyEval_MergeCompilerFlagsPtr = _lookup< - ffi.NativeFunction)>>( - 'PyEval_MergeCompilerFlags'); - late final _PyEval_MergeCompilerFlags = _PyEval_MergeCompilerFlagsPtr - .asFunction)>(); - - ffi.Pointer _PyEval_EvalFrameDefault( - ffi.Pointer tstate, - ffi.Pointer<_PyInterpreterFrame> f, - int exc, - ) { - return __PyEval_EvalFrameDefault( - tstate, - f, - exc, - ); - } - - late final __PyEval_EvalFrameDefaultPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer<_PyInterpreterFrame>, - ffi.Int)>>('_PyEval_EvalFrameDefault'); - late final __PyEval_EvalFrameDefault = - __PyEval_EvalFrameDefaultPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_PyInterpreterFrame>, int)>(); - - void _PyEval_SetSwitchInterval( - int microseconds, - ) { - return __PyEval_SetSwitchInterval( - microseconds, - ); - } - - late final __PyEval_SetSwitchIntervalPtr = - _lookup>( - '_PyEval_SetSwitchInterval'); - late final __PyEval_SetSwitchInterval = - __PyEval_SetSwitchIntervalPtr.asFunction(); - - int _PyEval_GetSwitchInterval() { - return __PyEval_GetSwitchInterval(); - } - - late final __PyEval_GetSwitchIntervalPtr = - _lookup>( - '_PyEval_GetSwitchInterval'); - late final __PyEval_GetSwitchInterval = - __PyEval_GetSwitchIntervalPtr.asFunction(); - - int _PyEval_MakePendingCalls( - ffi.Pointer arg0, - ) { - return __PyEval_MakePendingCalls( - arg0, - ); - } - - late final __PyEval_MakePendingCallsPtr = - _lookup)>>( - '_PyEval_MakePendingCalls'); - late final __PyEval_MakePendingCalls = __PyEval_MakePendingCallsPtr - .asFunction)>(); - - int PyUnstable_Eval_RequestCodeExtraIndex( - freefunc arg0, - ) { - return _PyUnstable_Eval_RequestCodeExtraIndex( - arg0, - ); - } - - late final _PyUnstable_Eval_RequestCodeExtraIndexPtr = - _lookup>( - 'PyUnstable_Eval_RequestCodeExtraIndex'); - late final _PyUnstable_Eval_RequestCodeExtraIndex = - _PyUnstable_Eval_RequestCodeExtraIndexPtr.asFunction< - int Function(freefunc)>(); - - int _PyEval_SliceIndex( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyEval_SliceIndex( - arg0, - arg1, - ); - } - - late final __PyEval_SliceIndexPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyEval_SliceIndex'); - late final __PyEval_SliceIndex = __PyEval_SliceIndexPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int _PyEval_SliceIndexNotNone( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyEval_SliceIndexNotNone( - arg0, - arg1, - ); - } - - late final __PyEval_SliceIndexNotNonePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyEval_SliceIndexNotNone'); - late final __PyEval_SliceIndexNotNone = - __PyEval_SliceIndexNotNonePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PySys_GetObject( - ffi.Pointer arg0, - ) { - return _PySys_GetObject( - arg0, - ); - } - - late final _PySys_GetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PySys_GetObject'); - late final _PySys_GetObject = _PySys_GetObjectPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PySys_SetObject( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PySys_SetObject( - arg0, - arg1, - ); - } - - late final _PySys_SetObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PySys_SetObject'); - late final _PySys_SetObject = _PySys_SetObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - void PySys_SetArgv( - int arg0, - ffi.Pointer> arg1, - ) { - return _PySys_SetArgv( - arg0, - arg1, - ); - } - - late final _PySys_SetArgvPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Int, ffi.Pointer>)>>('PySys_SetArgv'); - late final _PySys_SetArgv = _PySys_SetArgvPtr.asFunction< - void Function(int, ffi.Pointer>)>(); - - void PySys_SetArgvEx( - int arg0, - ffi.Pointer> arg1, - int arg2, - ) { - return _PySys_SetArgvEx( - arg0, - arg1, - arg2, - ); - } - - late final _PySys_SetArgvExPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Int, ffi.Pointer>, - ffi.Int)>>('PySys_SetArgvEx'); - late final _PySys_SetArgvEx = _PySys_SetArgvExPtr.asFunction< - void Function(int, ffi.Pointer>, int)>(); - - void PySys_SetPath( - ffi.Pointer arg0, - ) { - return _PySys_SetPath( - arg0, - ); - } - - late final _PySys_SetPathPtr = - _lookup)>>( - 'PySys_SetPath'); - late final _PySys_SetPath = - _PySys_SetPathPtr.asFunction)>(); - - void PySys_WriteStdout( - ffi.Pointer format, - ) { - return _PySys_WriteStdout( - format, - ); - } - - late final _PySys_WriteStdoutPtr = - _lookup)>>( - 'PySys_WriteStdout'); - late final _PySys_WriteStdout = - _PySys_WriteStdoutPtr.asFunction)>(); - - void PySys_WriteStderr( - ffi.Pointer format, - ) { - return _PySys_WriteStderr( - format, - ); - } - - late final _PySys_WriteStderrPtr = - _lookup)>>( - 'PySys_WriteStderr'); - late final _PySys_WriteStderr = - _PySys_WriteStderrPtr.asFunction)>(); - - void PySys_FormatStdout( - ffi.Pointer format, - ) { - return _PySys_FormatStdout( - format, - ); - } - - late final _PySys_FormatStdoutPtr = - _lookup)>>( - 'PySys_FormatStdout'); - late final _PySys_FormatStdout = - _PySys_FormatStdoutPtr.asFunction)>(); - - void PySys_FormatStderr( - ffi.Pointer format, - ) { - return _PySys_FormatStderr( - format, - ); - } - - late final _PySys_FormatStderrPtr = - _lookup)>>( - 'PySys_FormatStderr'); - late final _PySys_FormatStderr = - _PySys_FormatStderrPtr.asFunction)>(); - - void PySys_ResetWarnOptions() { - return _PySys_ResetWarnOptions(); - } - - late final _PySys_ResetWarnOptionsPtr = - _lookup>( - 'PySys_ResetWarnOptions'); - late final _PySys_ResetWarnOptions = - _PySys_ResetWarnOptionsPtr.asFunction(); - - void PySys_AddWarnOption( - ffi.Pointer arg0, - ) { - return _PySys_AddWarnOption( - arg0, - ); - } - - late final _PySys_AddWarnOptionPtr = - _lookup)>>( - 'PySys_AddWarnOption'); - late final _PySys_AddWarnOption = _PySys_AddWarnOptionPtr.asFunction< - void Function(ffi.Pointer)>(); - - void PySys_AddWarnOptionUnicode( - ffi.Pointer arg0, - ) { - return _PySys_AddWarnOptionUnicode( - arg0, - ); - } - - late final _PySys_AddWarnOptionUnicodePtr = - _lookup)>>( - 'PySys_AddWarnOptionUnicode'); - late final _PySys_AddWarnOptionUnicode = _PySys_AddWarnOptionUnicodePtr - .asFunction)>(); - - int PySys_HasWarnOptions() { - return _PySys_HasWarnOptions(); - } - - late final _PySys_HasWarnOptionsPtr = - _lookup>('PySys_HasWarnOptions'); - late final _PySys_HasWarnOptions = - _PySys_HasWarnOptionsPtr.asFunction(); - - void PySys_AddXOption( - ffi.Pointer arg0, - ) { - return _PySys_AddXOption( - arg0, - ); - } - - late final _PySys_AddXOptionPtr = - _lookup)>>( - 'PySys_AddXOption'); - late final _PySys_AddXOption = - _PySys_AddXOptionPtr.asFunction)>(); - - ffi.Pointer PySys_GetXOptions() { - return _PySys_GetXOptions(); - } - - late final _PySys_GetXOptionsPtr = - _lookup Function()>>( - 'PySys_GetXOptions'); - late final _PySys_GetXOptions = - _PySys_GetXOptionsPtr.asFunction Function()>(); - - int PyUnstable_PerfMapState_Init() { - return _PyUnstable_PerfMapState_Init(); - } - - late final _PyUnstable_PerfMapState_InitPtr = - _lookup>( - 'PyUnstable_PerfMapState_Init'); - late final _PyUnstable_PerfMapState_Init = - _PyUnstable_PerfMapState_InitPtr.asFunction(); - - int PyUnstable_WritePerfMapEntry( - ffi.Pointer code_addr, - int code_size, - ffi.Pointer entry_name, - ) { - return _PyUnstable_WritePerfMapEntry( - code_addr, - code_size, - entry_name, - ); - } - - late final _PyUnstable_WritePerfMapEntryPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.UnsignedInt, - ffi.Pointer)>>('PyUnstable_WritePerfMapEntry'); - late final _PyUnstable_WritePerfMapEntry = - _PyUnstable_WritePerfMapEntryPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - void PyUnstable_PerfMapState_Fini() { - return _PyUnstable_PerfMapState_Fini(); - } - - late final _PyUnstable_PerfMapState_FiniPtr = - _lookup>( - 'PyUnstable_PerfMapState_Fini'); - late final _PyUnstable_PerfMapState_Fini = - _PyUnstable_PerfMapState_FiniPtr.asFunction(); - - ffi.Pointer _PySys_GetAttr( - ffi.Pointer tstate, - ffi.Pointer name, - ) { - return __PySys_GetAttr( - tstate, - name, - ); - } - - late final __PySys_GetAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PySys_GetAttr'); - late final __PySys_GetAttr = __PySys_GetAttrPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int _PySys_GetSizeOf( - ffi.Pointer arg0, - ) { - return __PySys_GetSizeOf( - arg0, - ); - } - - late final __PySys_GetSizeOfPtr = - _lookup)>>( - '_PySys_GetSizeOf'); - late final __PySys_GetSizeOf = - __PySys_GetSizeOfPtr.asFunction)>(); - - int PySys_Audit( - ffi.Pointer event, - ffi.Pointer argFormat, - ) { - return _PySys_Audit( - event, - argFormat, - ); - } - - late final _PySys_AuditPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PySys_Audit'); - late final _PySys_Audit = _PySys_AuditPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PySys_AddAuditHook( - Py_AuditHookFunction arg0, - ffi.Pointer arg1, - ) { - return _PySys_AddAuditHook( - arg0, - arg1, - ); - } - - late final _PySys_AddAuditHookPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(Py_AuditHookFunction, - ffi.Pointer)>>('PySys_AddAuditHook'); - late final _PySys_AddAuditHook = _PySys_AddAuditHookPtr.asFunction< - int Function(Py_AuditHookFunction, ffi.Pointer)>(); - - ffi.Pointer PyOS_FSPath( - ffi.Pointer path, - ) { - return _PyOS_FSPath( - path, - ); - } - - late final _PyOS_FSPathPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyOS_FSPath'); - late final _PyOS_FSPath = _PyOS_FSPathPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyOS_InterruptOccurred() { - return _PyOS_InterruptOccurred(); - } - - late final _PyOS_InterruptOccurredPtr = - _lookup>('PyOS_InterruptOccurred'); - late final _PyOS_InterruptOccurred = - _PyOS_InterruptOccurredPtr.asFunction(); - - void PyOS_BeforeFork() { - return _PyOS_BeforeFork(); - } - - late final _PyOS_BeforeForkPtr = - _lookup>('PyOS_BeforeFork'); - late final _PyOS_BeforeFork = - _PyOS_BeforeForkPtr.asFunction(); - - void PyOS_AfterFork_Parent() { - return _PyOS_AfterFork_Parent(); - } - - late final _PyOS_AfterFork_ParentPtr = - _lookup>('PyOS_AfterFork_Parent'); - late final _PyOS_AfterFork_Parent = - _PyOS_AfterFork_ParentPtr.asFunction(); - - void PyOS_AfterFork_Child() { - return _PyOS_AfterFork_Child(); - } - - late final _PyOS_AfterFork_ChildPtr = - _lookup>('PyOS_AfterFork_Child'); - late final _PyOS_AfterFork_Child = - _PyOS_AfterFork_ChildPtr.asFunction(); - - void PyOS_AfterFork() { - return _PyOS_AfterFork(); - } - - late final _PyOS_AfterForkPtr = - _lookup>('PyOS_AfterFork'); - late final _PyOS_AfterFork = _PyOS_AfterForkPtr.asFunction(); - - int _PyOS_IsMainThread() { - return __PyOS_IsMainThread(); - } - - late final __PyOS_IsMainThreadPtr = - _lookup>('_PyOS_IsMainThread'); - late final __PyOS_IsMainThread = - __PyOS_IsMainThreadPtr.asFunction(); - - int PyImport_GetMagicNumber() { - return _PyImport_GetMagicNumber(); - } - - late final _PyImport_GetMagicNumberPtr = - _lookup>( - 'PyImport_GetMagicNumber'); - late final _PyImport_GetMagicNumber = - _PyImport_GetMagicNumberPtr.asFunction(); - - ffi.Pointer PyImport_GetMagicTag() { - return _PyImport_GetMagicTag(); - } - - late final _PyImport_GetMagicTagPtr = - _lookup Function()>>( - 'PyImport_GetMagicTag'); - late final _PyImport_GetMagicTag = - _PyImport_GetMagicTagPtr.asFunction Function()>(); - - ffi.Pointer PyImport_ExecCodeModule( - ffi.Pointer name, - ffi.Pointer co, - ) { - return _PyImport_ExecCodeModule( - name, - co, - ); - } - - late final _PyImport_ExecCodeModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyImport_ExecCodeModule'); - late final _PyImport_ExecCodeModule = _PyImport_ExecCodeModulePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyImport_ExecCodeModuleEx( - ffi.Pointer name, - ffi.Pointer co, - ffi.Pointer pathname, - ) { - return _PyImport_ExecCodeModuleEx( - name, - co, - pathname, - ); - } - - late final _PyImport_ExecCodeModuleExPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyImport_ExecCodeModuleEx'); - late final _PyImport_ExecCodeModuleEx = - _PyImport_ExecCodeModuleExPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyImport_ExecCodeModuleWithPathnames( - ffi.Pointer name, - ffi.Pointer co, - ffi.Pointer pathname, - ffi.Pointer cpathname, - ) { - return _PyImport_ExecCodeModuleWithPathnames( - name, - co, - pathname, - cpathname, - ); - } - - late final _PyImport_ExecCodeModuleWithPathnamesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyImport_ExecCodeModuleWithPathnames'); - late final _PyImport_ExecCodeModuleWithPathnames = - _PyImport_ExecCodeModuleWithPathnamesPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyImport_ExecCodeModuleObject( - ffi.Pointer name, - ffi.Pointer co, - ffi.Pointer pathname, - ffi.Pointer cpathname, - ) { - return _PyImport_ExecCodeModuleObject( - name, - co, - pathname, - cpathname, - ); - } - - late final _PyImport_ExecCodeModuleObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyImport_ExecCodeModuleObject'); - late final _PyImport_ExecCodeModuleObject = - _PyImport_ExecCodeModuleObjectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer PyImport_GetModuleDict() { - return _PyImport_GetModuleDict(); - } - - late final _PyImport_GetModuleDictPtr = - _lookup Function()>>( - 'PyImport_GetModuleDict'); - late final _PyImport_GetModuleDict = - _PyImport_GetModuleDictPtr.asFunction Function()>(); - - ffi.Pointer PyImport_GetModule( - ffi.Pointer name, - ) { - return _PyImport_GetModule( - name, - ); - } - - late final _PyImport_GetModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_GetModule'); - late final _PyImport_GetModule = _PyImport_GetModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_AddModuleObject( - ffi.Pointer name, - ) { - return _PyImport_AddModuleObject( - name, - ); - } - - late final _PyImport_AddModuleObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_AddModuleObject'); - late final _PyImport_AddModuleObject = _PyImport_AddModuleObjectPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_AddModule( - ffi.Pointer name, - ) { - return _PyImport_AddModule( - name, - ); - } - - late final _PyImport_AddModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_AddModule'); - late final _PyImport_AddModule = _PyImport_AddModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_ImportModule( - ffi.Pointer name, - ) { - return _PyImport_ImportModule( - name, - ); - } - - late final _PyImport_ImportModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_ImportModule'); - late final _PyImport_ImportModule = _PyImport_ImportModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_ImportModuleNoBlock( - ffi.Pointer name, - ) { - return _PyImport_ImportModuleNoBlock( - name, - ); - } - - late final _PyImport_ImportModuleNoBlockPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_ImportModuleNoBlock'); - late final _PyImport_ImportModuleNoBlock = _PyImport_ImportModuleNoBlockPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_ImportModuleLevel( - ffi.Pointer name, - ffi.Pointer globals, - ffi.Pointer locals, - ffi.Pointer fromlist, - int level, - ) { - return _PyImport_ImportModuleLevel( - name, - globals, - locals, - fromlist, - level, - ); - } - - late final _PyImport_ImportModuleLevelPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int)>>('PyImport_ImportModuleLevel'); - late final _PyImport_ImportModuleLevel = - _PyImport_ImportModuleLevelPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int)>(); - - ffi.Pointer PyImport_ImportModuleLevelObject( - ffi.Pointer name, - ffi.Pointer globals, - ffi.Pointer locals, - ffi.Pointer fromlist, - int level, - ) { - return _PyImport_ImportModuleLevelObject( - name, - globals, - locals, - fromlist, - level, - ); - } - - late final _PyImport_ImportModuleLevelObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Int)>>('PyImport_ImportModuleLevelObject'); - late final _PyImport_ImportModuleLevelObject = - _PyImport_ImportModuleLevelObjectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - int)>(); - - ffi.Pointer PyImport_GetImporter( - ffi.Pointer path, - ) { - return _PyImport_GetImporter( - path, - ); - } - - late final _PyImport_GetImporterPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_GetImporter'); - late final _PyImport_GetImporter = _PyImport_GetImporterPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_Import( - ffi.Pointer name, - ) { - return _PyImport_Import( - name, - ); - } - - late final _PyImport_ImportPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_Import'); - late final _PyImport_Import = _PyImport_ImportPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyImport_ReloadModule( - ffi.Pointer m, - ) { - return _PyImport_ReloadModule( - m, - ); - } - - late final _PyImport_ReloadModulePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyImport_ReloadModule'); - late final _PyImport_ReloadModule = _PyImport_ReloadModulePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyImport_ImportFrozenModuleObject( - ffi.Pointer name, - ) { - return _PyImport_ImportFrozenModuleObject( - name, - ); - } - - late final _PyImport_ImportFrozenModuleObjectPtr = - _lookup)>>( - 'PyImport_ImportFrozenModuleObject'); - late final _PyImport_ImportFrozenModuleObject = - _PyImport_ImportFrozenModuleObjectPtr.asFunction< - int Function(ffi.Pointer)>(); - - int PyImport_ImportFrozenModule( - ffi.Pointer name, - ) { - return _PyImport_ImportFrozenModule( - name, - ); - } - - late final _PyImport_ImportFrozenModulePtr = - _lookup)>>( - 'PyImport_ImportFrozenModule'); - late final _PyImport_ImportFrozenModule = _PyImport_ImportFrozenModulePtr - .asFunction)>(); - - int PyImport_AppendInittab( - ffi.Pointer name, - ffi.Pointer Function()>> initfunc, - ) { - return _PyImport_AppendInittab( - name, - initfunc, - ); - } - - late final _PyImport_AppendInittabPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction Function()>>)>>( - 'PyImport_AppendInittab'); - late final _PyImport_AppendInittab = _PyImport_AppendInittabPtr.asFunction< - int Function(ffi.Pointer, - ffi.Pointer Function()>>)>(); - - ffi.Pointer PyInit__imp() { - return _PyInit__imp(); - } - - late final _PyInit__impPtr = - _lookup Function()>>( - 'PyInit__imp'); - late final _PyInit__imp = - _PyInit__impPtr.asFunction Function()>(); - - int _PyImport_IsInitialized( - ffi.Pointer arg0, - ) { - return __PyImport_IsInitialized( - arg0, - ); - } - - late final __PyImport_IsInitializedPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyImport_IsInitialized'); - late final __PyImport_IsInitialized = __PyImport_IsInitializedPtr - .asFunction)>(); - - ffi.Pointer _PyImport_GetModuleId( - ffi.Pointer<_Py_Identifier> name, - ) { - return __PyImport_GetModuleId( - name, - ); - } - - late final __PyImport_GetModuleIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer<_Py_Identifier>)>>('_PyImport_GetModuleId'); - late final __PyImport_GetModuleId = __PyImport_GetModuleIdPtr.asFunction< - ffi.Pointer Function(ffi.Pointer<_Py_Identifier>)>(); - - int _PyImport_SetModule( - ffi.Pointer name, - ffi.Pointer module, - ) { - return __PyImport_SetModule( - name, - module, - ); - } - - late final __PyImport_SetModulePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyImport_SetModule'); - late final __PyImport_SetModule = __PyImport_SetModulePtr - .asFunction, ffi.Pointer)>(); - - int _PyImport_SetModuleString( - ffi.Pointer name, - ffi.Pointer module, - ) { - return __PyImport_SetModuleString( - name, - module, - ); - } - - late final __PyImport_SetModuleStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyImport_SetModuleString'); - late final __PyImport_SetModuleString = __PyImport_SetModuleStringPtr - .asFunction, ffi.Pointer)>(); - - void _PyImport_AcquireLock( - ffi.Pointer interp, - ) { - return __PyImport_AcquireLock( - interp, - ); - } - - late final __PyImport_AcquireLockPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyImport_AcquireLock'); - late final __PyImport_AcquireLock = __PyImport_AcquireLockPtr - .asFunction)>(); - - int _PyImport_ReleaseLock( - ffi.Pointer interp, - ) { - return __PyImport_ReleaseLock( - interp, - ); - } - - late final __PyImport_ReleaseLockPtr = _lookup< - ffi - .NativeFunction)>>( - '_PyImport_ReleaseLock'); - late final __PyImport_ReleaseLock = __PyImport_ReleaseLockPtr - .asFunction)>(); - - int _PyImport_FixupBuiltin( - ffi.Pointer mod, - ffi.Pointer name, - ffi.Pointer modules, - ) { - return __PyImport_FixupBuiltin( - mod, - name, - modules, - ); - } - - late final __PyImport_FixupBuiltinPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('_PyImport_FixupBuiltin'); - late final __PyImport_FixupBuiltin = __PyImport_FixupBuiltinPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int _PyImport_FixupExtensionObject( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2, - ffi.Pointer arg3, - ) { - return __PyImport_FixupExtensionObject( - arg0, - arg1, - arg2, - arg3, - ); - } - - late final __PyImport_FixupExtensionObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyImport_FixupExtensionObject'); - late final __PyImport_FixupExtensionObject = - __PyImport_FixupExtensionObjectPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final ffi.Pointer> _PyImport_Inittab = - _lookup>('PyImport_Inittab'); - - ffi.Pointer<_inittab> get PyImport_Inittab => _PyImport_Inittab.value; - - set PyImport_Inittab(ffi.Pointer<_inittab> value) => - _PyImport_Inittab.value = value; - - int PyImport_ExtendInittab( - ffi.Pointer<_inittab> newtab, - ) { - return _PyImport_ExtendInittab( - newtab, - ); - } - - late final _PyImport_ExtendInittabPtr = - _lookup)>>( - 'PyImport_ExtendInittab'); - late final _PyImport_ExtendInittab = _PyImport_ExtendInittabPtr.asFunction< - int Function(ffi.Pointer<_inittab>)>(); - - late final ffi.Pointer> _PyImport_FrozenModules = - _lookup>('PyImport_FrozenModules'); - - ffi.Pointer<_frozen> get PyImport_FrozenModules => - _PyImport_FrozenModules.value; - - set PyImport_FrozenModules(ffi.Pointer<_frozen> value) => - _PyImport_FrozenModules.value = value; - - ffi.Pointer _PyImport_GetModuleAttr( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyImport_GetModuleAttr( - arg0, - arg1, - ); - } - - late final __PyImport_GetModuleAttrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyImport_GetModuleAttr'); - late final __PyImport_GetModuleAttr = __PyImport_GetModuleAttrPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyImport_GetModuleAttrString( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __PyImport_GetModuleAttrString( - arg0, - arg1, - ); - } - - late final __PyImport_GetModuleAttrStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyImport_GetModuleAttrString'); - late final __PyImport_GetModuleAttrString = - __PyImport_GetModuleAttrStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_CallNoArgs( - ffi.Pointer func, - ) { - return _PyObject_CallNoArgs( - func, - ); - } - - late final _PyObject_CallNoArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_CallNoArgs'); - late final _PyObject_CallNoArgs = _PyObject_CallNoArgsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_Call( - ffi.Pointer callable, - ffi.Pointer args, - ffi.Pointer kwargs, - ) { - return _PyObject_Call( - callable, - args, - kwargs, - ); - } - - late final _PyObject_CallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PyObject_Call'); - late final _PyObject_Call = _PyObject_CallPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_CallObject( - ffi.Pointer callable, - ffi.Pointer args, - ) { - return _PyObject_CallObject( - callable, - args, - ); - } - - late final _PyObject_CallObjectPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_CallObject'); - late final _PyObject_CallObject = _PyObject_CallObjectPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_CallFunction( - ffi.Pointer callable, - ffi.Pointer format, - ) { - return _PyObject_CallFunction( - callable, - format, - ); - } - - late final _PyObject_CallFunctionPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_CallFunction'); - late final _PyObject_CallFunction = _PyObject_CallFunctionPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_CallMethod( - ffi.Pointer obj, - ffi.Pointer name, - ffi.Pointer format, - ) { - return _PyObject_CallMethod1( - obj, - name, - format, - ); - } - - late final _PyObject_CallMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyObject_CallMethod'); - late final _PyObject_CallMethod1 = _PyObject_CallMethodPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyObject_CallFunction_SizeT( - ffi.Pointer callable, - ffi.Pointer format, - ) { - return __PyObject_CallFunction_SizeT( - callable, - format, - ); - } - - late final __PyObject_CallFunction_SizeTPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('_PyObject_CallFunction_SizeT'); - late final __PyObject_CallFunction_SizeT = - __PyObject_CallFunction_SizeTPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyObject_CallMethod_SizeT( - ffi.Pointer obj, - ffi.Pointer name, - ffi.Pointer format, - ) { - return __PyObject_CallMethod_SizeT( - obj, - name, - format, - ); - } - - late final __PyObject_CallMethod_SizeTPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyObject_CallMethod_SizeT'); - late final __PyObject_CallMethod_SizeT = - __PyObject_CallMethod_SizeTPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_CallFunctionObjArgs( - ffi.Pointer callable, - ) { - return _PyObject_CallFunctionObjArgs( - callable, - ); - } - - late final _PyObject_CallFunctionObjArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_CallFunctionObjArgs'); - late final _PyObject_CallFunctionObjArgs = _PyObject_CallFunctionObjArgsPtr - .asFunction Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_CallMethodObjArgs( - ffi.Pointer obj, - ffi.Pointer name, - ) { - return _PyObject_CallMethodObjArgs( - obj, - name, - ); - } - - late final _PyObject_CallMethodObjArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_CallMethodObjArgs'); - late final _PyObject_CallMethodObjArgs = - _PyObject_CallMethodObjArgsPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyVectorcall_NARGS( - int nargsf, - ) { - return _PyVectorcall_NARGS( - nargsf, - ); - } - - late final _PyVectorcall_NARGSPtr = - _lookup>( - 'PyVectorcall_NARGS'); - late final _PyVectorcall_NARGS = - _PyVectorcall_NARGSPtr.asFunction(); - - ffi.Pointer PyVectorcall_Call( - ffi.Pointer callable, - ffi.Pointer tuple, - ffi.Pointer dict, - ) { - return _PyVectorcall_Call( - callable, - tuple, - dict, - ); - } - - late final _PyVectorcall_CallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyVectorcall_Call'); - late final _PyVectorcall_Call = _PyVectorcall_CallPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_Vectorcall( - ffi.Pointer callable, - ffi.Pointer> args, - int nargsf, - ffi.Pointer kwnames, - ) { - return _PyObject_Vectorcall( - callable, - args, - nargsf, - kwnames, - ); - } - - late final _PyObject_VectorcallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Size, - ffi.Pointer)>>('PyObject_Vectorcall'); - late final _PyObject_Vectorcall = _PyObject_VectorcallPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer>, int, ffi.Pointer)>(); - - ffi.Pointer PyObject_VectorcallMethod( - ffi.Pointer name, - ffi.Pointer> args, - int nargsf, - ffi.Pointer kwnames, - ) { - return _PyObject_VectorcallMethod( - name, - args, - nargsf, - kwnames, - ); - } - - late final _PyObject_VectorcallMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Size, - ffi.Pointer)>>('PyObject_VectorcallMethod'); - late final _PyObject_VectorcallMethod = - _PyObject_VectorcallMethodPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - int, - ffi.Pointer)>(); - - ffi.Pointer PyObject_Type( - ffi.Pointer o, - ) { - return _PyObject_Type( - o, - ); - } - - late final _PyObject_TypePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_Type'); - late final _PyObject_Type = _PyObject_TypePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyObject_Size( - ffi.Pointer o, - ) { - return _PyObject_Size( - o, - ); - } - - late final _PyObject_SizePtr = - _lookup)>>( - 'PyObject_Size'); - late final _PyObject_Size = - _PyObject_SizePtr.asFunction)>(); - - int PyObject_Length( - ffi.Pointer o, - ) { - return _PyObject_Length( - o, - ); - } - - late final _PyObject_LengthPtr = - _lookup)>>( - 'PyObject_Length'); - late final _PyObject_Length = - _PyObject_LengthPtr.asFunction)>(); - - ffi.Pointer PyObject_GetItem( - ffi.Pointer o, - ffi.Pointer key, - ) { - return _PyObject_GetItem( - o, - key, - ); - } - - late final _PyObject_GetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_GetItem'); - late final _PyObject_GetItem = _PyObject_GetItemPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyObject_SetItem( - ffi.Pointer o, - ffi.Pointer key, - ffi.Pointer v, - ) { - return _PyObject_SetItem( - o, - key, - v, - ); - } - - late final _PyObject_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyObject_SetItem'); - late final _PyObject_SetItem = _PyObject_SetItemPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyObject_DelItemString( - ffi.Pointer o, - ffi.Pointer key, - ) { - return _PyObject_DelItemString( - o, - key, - ); - } - - late final _PyObject_DelItemStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_DelItemString'); - late final _PyObject_DelItemString = _PyObject_DelItemStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyObject_DelItem( - ffi.Pointer o, - ffi.Pointer key, - ) { - return _PyObject_DelItem( - o, - key, - ); - } - - late final _PyObject_DelItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_DelItem'); - late final _PyObject_DelItem = _PyObject_DelItemPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyObject_AsCharBuffer( - ffi.Pointer obj, - ffi.Pointer> buffer, - ffi.Pointer buffer_len, - ) { - return _PyObject_AsCharBuffer( - obj, - buffer, - buffer_len, - ); - } - - late final _PyObject_AsCharBufferPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyObject_AsCharBuffer'); - late final _PyObject_AsCharBuffer = _PyObject_AsCharBufferPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer>, - ffi.Pointer)>(); - - int PyObject_CheckReadBuffer( - ffi.Pointer obj, - ) { - return _PyObject_CheckReadBuffer( - obj, - ); - } - - late final _PyObject_CheckReadBufferPtr = - _lookup)>>( - 'PyObject_CheckReadBuffer'); - late final _PyObject_CheckReadBuffer = _PyObject_CheckReadBufferPtr - .asFunction)>(); - - int PyObject_AsReadBuffer( - ffi.Pointer obj, - ffi.Pointer> buffer, - ffi.Pointer buffer_len, - ) { - return _PyObject_AsReadBuffer( - obj, - buffer, - buffer_len, - ); - } - - late final _PyObject_AsReadBufferPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyObject_AsReadBuffer'); - late final _PyObject_AsReadBuffer = _PyObject_AsReadBufferPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer>, - ffi.Pointer)>(); - - int PyObject_AsWriteBuffer( - ffi.Pointer obj, - ffi.Pointer> buffer, - ffi.Pointer buffer_len, - ) { - return _PyObject_AsWriteBuffer( - obj, - buffer, - buffer_len, - ); - } - - late final _PyObject_AsWriteBufferPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyObject_AsWriteBuffer'); - late final _PyObject_AsWriteBuffer = _PyObject_AsWriteBufferPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer>, - ffi.Pointer)>(); - - ffi.Pointer PyObject_Format( - ffi.Pointer obj, - ffi.Pointer format_spec, - ) { - return _PyObject_Format( - obj, - format_spec, - ); - } - - late final _PyObject_FormatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_Format'); - late final _PyObject_Format = _PyObject_FormatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyObject_GetIter( - ffi.Pointer arg0, - ) { - return _PyObject_GetIter( - arg0, - ); - } - - late final _PyObject_GetIterPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_GetIter'); - late final _PyObject_GetIter = _PyObject_GetIterPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_GetAIter( - ffi.Pointer arg0, - ) { - return _PyObject_GetAIter( - arg0, - ); - } - - late final _PyObject_GetAIterPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyObject_GetAIter'); - late final _PyObject_GetAIter = _PyObject_GetAIterPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyIter_Check( - ffi.Pointer arg0, - ) { - return _PyIter_Check( - arg0, - ); - } - - late final _PyIter_CheckPtr = - _lookup)>>( - 'PyIter_Check'); - late final _PyIter_Check = - _PyIter_CheckPtr.asFunction)>(); - - int PyAIter_Check( - ffi.Pointer arg0, - ) { - return _PyAIter_Check( - arg0, - ); - } - - late final _PyAIter_CheckPtr = - _lookup)>>( - 'PyAIter_Check'); - late final _PyAIter_Check = - _PyAIter_CheckPtr.asFunction)>(); - - ffi.Pointer PyIter_Next( - ffi.Pointer arg0, - ) { - return _PyIter_Next( - arg0, - ); - } - - late final _PyIter_NextPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyIter_Next'); - late final _PyIter_Next = _PyIter_NextPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyIter_Send( - ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer> arg2, - ) { - return _PyIter_Send( - arg0, - arg1, - arg2, - ); - } - - late final _PyIter_SendPtr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>>('PyIter_Send'); - late final _PyIter_Send = _PyIter_SendPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer>)>(); - - int PyNumber_Check( - ffi.Pointer o, - ) { - return _PyNumber_Check( - o, - ); - } - - late final _PyNumber_CheckPtr = - _lookup)>>( - 'PyNumber_Check'); - late final _PyNumber_Check = - _PyNumber_CheckPtr.asFunction)>(); - - ffi.Pointer PyNumber_Add( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Add( - o1, - o2, - ); - } - - late final _PyNumber_AddPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyNumber_Add'); - late final _PyNumber_Add = _PyNumber_AddPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Subtract( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Subtract( - o1, - o2, - ); - } - - late final _PyNumber_SubtractPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_Subtract'); - late final _PyNumber_Subtract = _PyNumber_SubtractPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Multiply( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Multiply( - o1, - o2, - ); - } - - late final _PyNumber_MultiplyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_Multiply'); - late final _PyNumber_Multiply = _PyNumber_MultiplyPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_MatrixMultiply( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_MatrixMultiply( - o1, - o2, - ); - } - - late final _PyNumber_MatrixMultiplyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_MatrixMultiply'); - late final _PyNumber_MatrixMultiply = _PyNumber_MatrixMultiplyPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_FloorDivide( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_FloorDivide( - o1, - o2, - ); - } - - late final _PyNumber_FloorDividePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_FloorDivide'); - late final _PyNumber_FloorDivide = _PyNumber_FloorDividePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_TrueDivide( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_TrueDivide( - o1, - o2, - ); - } - - late final _PyNumber_TrueDividePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_TrueDivide'); - late final _PyNumber_TrueDivide = _PyNumber_TrueDividePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Remainder( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Remainder( - o1, - o2, - ); - } - - late final _PyNumber_RemainderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_Remainder'); - late final _PyNumber_Remainder = _PyNumber_RemainderPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Divmod( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Divmod( - o1, - o2, - ); - } - - late final _PyNumber_DivmodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_Divmod'); - late final _PyNumber_Divmod = _PyNumber_DivmodPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Power( - ffi.Pointer o1, - ffi.Pointer o2, - ffi.Pointer o3, - ) { - return _PyNumber_Power( - o1, - o2, - o3, - ); - } - - late final _PyNumber_PowerPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>('PyNumber_Power'); - late final _PyNumber_Power = _PyNumber_PowerPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Negative( - ffi.Pointer o, - ) { - return _PyNumber_Negative( - o, - ); - } - - late final _PyNumber_NegativePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Negative'); - late final _PyNumber_Negative = _PyNumber_NegativePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyNumber_Positive( - ffi.Pointer o, - ) { - return _PyNumber_Positive( - o, - ); - } - - late final _PyNumber_PositivePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Positive'); - late final _PyNumber_Positive = _PyNumber_PositivePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyNumber_Absolute( - ffi.Pointer o, - ) { - return _PyNumber_Absolute( - o, - ); - } - - late final _PyNumber_AbsolutePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Absolute'); - late final _PyNumber_Absolute = _PyNumber_AbsolutePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyNumber_Invert( - ffi.Pointer o, - ) { - return _PyNumber_Invert( - o, - ); - } - - late final _PyNumber_InvertPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Invert'); - late final _PyNumber_Invert = _PyNumber_InvertPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyNumber_Lshift( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Lshift( - o1, - o2, - ); - } - - late final _PyNumber_LshiftPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_Lshift'); - late final _PyNumber_Lshift = _PyNumber_LshiftPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Rshift( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Rshift( - o1, - o2, - ); - } - - late final _PyNumber_RshiftPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_Rshift'); - late final _PyNumber_Rshift = _PyNumber_RshiftPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_And( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_And( - o1, - o2, - ); - } - - late final _PyNumber_AndPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyNumber_And'); - late final _PyNumber_And = _PyNumber_AndPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Xor( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Xor( - o1, - o2, - ); - } - - late final _PyNumber_XorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyNumber_Xor'); - late final _PyNumber_Xor = _PyNumber_XorPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Or( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_Or( - o1, - o2, - ); - } - - late final _PyNumber_OrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('PyNumber_Or'); - late final _PyNumber_Or = _PyNumber_OrPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyIndex_Check( - ffi.Pointer arg0, - ) { - return _PyIndex_Check( - arg0, - ); - } - - late final _PyIndex_CheckPtr = - _lookup)>>( - 'PyIndex_Check'); - late final _PyIndex_Check = - _PyIndex_CheckPtr.asFunction)>(); - - ffi.Pointer PyNumber_Index( - ffi.Pointer o, - ) { - return _PyNumber_Index1( - o, - ); - } - - late final _PyNumber_IndexPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Index'); - late final _PyNumber_Index1 = _PyNumber_IndexPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - int PyNumber_AsSsize_t( - ffi.Pointer o, - ffi.Pointer exc, - ) { - return _PyNumber_AsSsize_t( - o, - exc, - ); - } - - late final _PyNumber_AsSsize_tPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_AsSsize_t'); - late final _PyNumber_AsSsize_t = _PyNumber_AsSsize_tPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_Long( - ffi.Pointer o, - ) { - return _PyNumber_Long( - o, - ); - } - - late final _PyNumber_LongPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Long'); - late final _PyNumber_Long = _PyNumber_LongPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyNumber_Float( - ffi.Pointer o, - ) { - return _PyNumber_Float( - o, - ); - } - - late final _PyNumber_FloatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyNumber_Float'); - late final _PyNumber_Float = _PyNumber_FloatPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceAdd( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceAdd( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceAddPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceAdd'); - late final _PyNumber_InPlaceAdd = _PyNumber_InPlaceAddPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceSubtract( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceSubtract( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceSubtractPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceSubtract'); - late final _PyNumber_InPlaceSubtract = - _PyNumber_InPlaceSubtractPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceMultiply( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceMultiply( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceMultiplyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceMultiply'); - late final _PyNumber_InPlaceMultiply = - _PyNumber_InPlaceMultiplyPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceMatrixMultiply( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceMatrixMultiply( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceMatrixMultiplyPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceMatrixMultiply'); - late final _PyNumber_InPlaceMatrixMultiply = - _PyNumber_InPlaceMatrixMultiplyPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceFloorDivide( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceFloorDivide( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceFloorDividePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceFloorDivide'); - late final _PyNumber_InPlaceFloorDivide = - _PyNumber_InPlaceFloorDividePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceTrueDivide( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceTrueDivide( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceTrueDividePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceTrueDivide'); - late final _PyNumber_InPlaceTrueDivide = - _PyNumber_InPlaceTrueDividePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceRemainder( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceRemainder( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceRemainderPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceRemainder'); - late final _PyNumber_InPlaceRemainder = - _PyNumber_InPlaceRemainderPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlacePower( - ffi.Pointer o1, - ffi.Pointer o2, - ffi.Pointer o3, - ) { - return _PyNumber_InPlacePower( - o1, - o2, - o3, - ); - } - - late final _PyNumber_InPlacePowerPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlacePower'); - late final _PyNumber_InPlacePower = _PyNumber_InPlacePowerPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceLshift( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceLshift( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceLshiftPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceLshift'); - late final _PyNumber_InPlaceLshift = _PyNumber_InPlaceLshiftPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceRshift( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceRshift( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceRshiftPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceRshift'); - late final _PyNumber_InPlaceRshift = _PyNumber_InPlaceRshiftPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceAnd( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceAnd( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceAndPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceAnd'); - late final _PyNumber_InPlaceAnd = _PyNumber_InPlaceAndPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceXor( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceXor( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceXorPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceXor'); - late final _PyNumber_InPlaceXor = _PyNumber_InPlaceXorPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_InPlaceOr( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PyNumber_InPlaceOr( - o1, - o2, - ); - } - - late final _PyNumber_InPlaceOrPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyNumber_InPlaceOr'); - late final _PyNumber_InPlaceOr = _PyNumber_InPlaceOrPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyNumber_ToBase( - ffi.Pointer n, - int base, - ) { - return _PyNumber_ToBase( - n, - base, - ); - } - - late final _PyNumber_ToBasePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Int)>>('PyNumber_ToBase'); - late final _PyNumber_ToBase = _PyNumber_ToBasePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - int PySequence_Check( - ffi.Pointer o, - ) { - return _PySequence_Check( - o, - ); - } - - late final _PySequence_CheckPtr = - _lookup)>>( - 'PySequence_Check'); - late final _PySequence_Check = - _PySequence_CheckPtr.asFunction)>(); - - int PySequence_Size( - ffi.Pointer o, - ) { - return _PySequence_Size( - o, - ); - } - - late final _PySequence_SizePtr = - _lookup)>>( - 'PySequence_Size'); - late final _PySequence_Size = - _PySequence_SizePtr.asFunction)>(); - - int PySequence_Length( - ffi.Pointer o, - ) { - return _PySequence_Length( - o, - ); - } - - late final _PySequence_LengthPtr = - _lookup)>>( - 'PySequence_Length'); - late final _PySequence_Length = - _PySequence_LengthPtr.asFunction)>(); - - ffi.Pointer PySequence_Concat( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PySequence_Concat( - o1, - o2, - ); - } - - late final _PySequence_ConcatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PySequence_Concat'); - late final _PySequence_Concat = _PySequence_ConcatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PySequence_Repeat( - ffi.Pointer o, - int count, - ) { - return _PySequence_Repeat( - o, - count, - ); - } - - late final _PySequence_RepeatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PySequence_Repeat'); - late final _PySequence_Repeat = _PySequence_RepeatPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PySequence_GetItem( - ffi.Pointer o, - int i, - ) { - return _PySequence_GetItem( - o, - i, - ); - } - - late final _PySequence_GetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PySequence_GetItem'); - late final _PySequence_GetItem = _PySequence_GetItemPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int)>(); - - ffi.Pointer PySequence_GetSlice( - ffi.Pointer o, - int i1, - int i2, - ) { - return _PySequence_GetSlice( - o, - i1, - i2, - ); - } - - late final _PySequence_GetSlicePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t, - Py_ssize_t)>>('PySequence_GetSlice'); - late final _PySequence_GetSlice = _PySequence_GetSlicePtr.asFunction< - ffi.Pointer Function(ffi.Pointer, int, int)>(); - - int PySequence_SetItem( - ffi.Pointer o, - int i, - ffi.Pointer v, - ) { - return _PySequence_SetItem( - o, - i, - v, - ); - } - - late final _PySequence_SetItemPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - ffi.Pointer)>>('PySequence_SetItem'); - late final _PySequence_SetItem = _PySequence_SetItemPtr.asFunction< - int Function(ffi.Pointer, int, ffi.Pointer)>(); - - int PySequence_DelItem( - ffi.Pointer o, - int i, - ) { - return _PySequence_DelItem( - o, - i, - ); - } - - late final _PySequence_DelItemPtr = _lookup< - ffi - .NativeFunction, Py_ssize_t)>>( - 'PySequence_DelItem'); - late final _PySequence_DelItem = _PySequence_DelItemPtr.asFunction< - int Function(ffi.Pointer, int)>(); - - int PySequence_SetSlice( - ffi.Pointer o, - int i1, - int i2, - ffi.Pointer v, - ) { - return _PySequence_SetSlice( - o, - i1, - i2, - v, - ); - } - - late final _PySequence_SetSlicePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, Py_ssize_t, - ffi.Pointer)>>('PySequence_SetSlice'); - late final _PySequence_SetSlice = _PySequence_SetSlicePtr.asFunction< - int Function(ffi.Pointer, int, int, ffi.Pointer)>(); - - int PySequence_DelSlice( - ffi.Pointer o, - int i1, - int i2, - ) { - return _PySequence_DelSlice( - o, - i1, - i2, - ); - } - - late final _PySequence_DelSlicePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, Py_ssize_t, - Py_ssize_t)>>('PySequence_DelSlice'); - late final _PySequence_DelSlice = _PySequence_DelSlicePtr.asFunction< - int Function(ffi.Pointer, int, int)>(); - - ffi.Pointer PySequence_Tuple( - ffi.Pointer o, - ) { - return _PySequence_Tuple( - o, - ); - } - - late final _PySequence_TuplePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PySequence_Tuple'); - late final _PySequence_Tuple = _PySequence_TuplePtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PySequence_List( - ffi.Pointer o, - ) { - return _PySequence_List( - o, - ); - } - - late final _PySequence_ListPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PySequence_List'); - late final _PySequence_List = _PySequence_ListPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PySequence_Fast( - ffi.Pointer o, - ffi.Pointer m, - ) { - return _PySequence_Fast( - o, - m, - ); - } - - late final _PySequence_FastPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PySequence_Fast'); - late final _PySequence_Fast = _PySequence_FastPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PySequence_Count( - ffi.Pointer o, - ffi.Pointer value, - ) { - return _PySequence_Count( - o, - value, - ); - } - - late final _PySequence_CountPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, - ffi.Pointer)>>('PySequence_Count'); - late final _PySequence_Count = _PySequence_CountPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PySequence_Contains( - ffi.Pointer seq, - ffi.Pointer ob, - ) { - return _PySequence_Contains( - seq, - ob, - ); - } - - late final _PySequence_ContainsPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PySequence_Contains'); - late final _PySequence_Contains = _PySequence_ContainsPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PySequence_In( - ffi.Pointer o, - ffi.Pointer value, - ) { - return _PySequence_In( - o, - value, - ); - } - - late final _PySequence_InPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PySequence_In'); - late final _PySequence_In = _PySequence_InPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PySequence_Index( - ffi.Pointer o, - ffi.Pointer value, - ) { - return _PySequence_Index( - o, - value, - ); - } - - late final _PySequence_IndexPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, - ffi.Pointer)>>('PySequence_Index'); - late final _PySequence_Index = _PySequence_IndexPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PySequence_InPlaceConcat( - ffi.Pointer o1, - ffi.Pointer o2, - ) { - return _PySequence_InPlaceConcat( - o1, - o2, - ); - } - - late final _PySequence_InPlaceConcatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PySequence_InPlaceConcat'); - late final _PySequence_InPlaceConcat = - _PySequence_InPlaceConcatPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PySequence_InPlaceRepeat( - ffi.Pointer o, - int count, - ) { - return _PySequence_InPlaceRepeat( - o, - count, - ); - } - - late final _PySequence_InPlaceRepeatPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>('PySequence_InPlaceRepeat'); - late final _PySequence_InPlaceRepeat = _PySequence_InPlaceRepeatPtr - .asFunction Function(ffi.Pointer, int)>(); - - int PyMapping_Check( - ffi.Pointer o, - ) { - return _PyMapping_Check( - o, - ); - } - - late final _PyMapping_CheckPtr = - _lookup)>>( - 'PyMapping_Check'); - late final _PyMapping_Check = - _PyMapping_CheckPtr.asFunction)>(); - - int PyMapping_Size( - ffi.Pointer o, - ) { - return _PyMapping_Size( - o, - ); - } - - late final _PyMapping_SizePtr = - _lookup)>>( - 'PyMapping_Size'); - late final _PyMapping_Size = - _PyMapping_SizePtr.asFunction)>(); - - int PyMapping_Length( - ffi.Pointer o, - ) { - return _PyMapping_Length( - o, - ); - } - - late final _PyMapping_LengthPtr = - _lookup)>>( - 'PyMapping_Length'); - late final _PyMapping_Length = - _PyMapping_LengthPtr.asFunction)>(); - - int PyMapping_HasKeyString( - ffi.Pointer o, - ffi.Pointer key, - ) { - return _PyMapping_HasKeyString( - o, - key, - ); - } - - late final _PyMapping_HasKeyStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyMapping_HasKeyString'); - late final _PyMapping_HasKeyString = _PyMapping_HasKeyStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyMapping_HasKey( - ffi.Pointer o, - ffi.Pointer key, - ) { - return _PyMapping_HasKey( - o, - key, - ); - } - - late final _PyMapping_HasKeyPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyMapping_HasKey'); - late final _PyMapping_HasKey = _PyMapping_HasKeyPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer PyMapping_Keys( - ffi.Pointer o, - ) { - return _PyMapping_Keys( - o, - ); - } - - late final _PyMapping_KeysPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMapping_Keys'); - late final _PyMapping_Keys = _PyMapping_KeysPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyMapping_Values( - ffi.Pointer o, - ) { - return _PyMapping_Values( - o, - ); - } - - late final _PyMapping_ValuesPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMapping_Values'); - late final _PyMapping_Values = _PyMapping_ValuesPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyMapping_Items( - ffi.Pointer o, - ) { - return _PyMapping_Items( - o, - ); - } - - late final _PyMapping_ItemsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('PyMapping_Items'); - late final _PyMapping_Items = _PyMapping_ItemsPtr.asFunction< - ffi.Pointer Function(ffi.Pointer)>(); - - ffi.Pointer PyMapping_GetItemString( - ffi.Pointer o, - ffi.Pointer key, - ) { - return _PyMapping_GetItemString( - o, - key, - ); - } - - late final _PyMapping_GetItemStringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyMapping_GetItemString'); - late final _PyMapping_GetItemString = _PyMapping_GetItemStringPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyMapping_SetItemString( - ffi.Pointer o, - ffi.Pointer key, - ffi.Pointer value, - ) { - return _PyMapping_SetItemString( - o, - key, - value, - ); - } - - late final _PyMapping_SetItemStringPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('PyMapping_SetItemString'); - late final _PyMapping_SetItemString = _PyMapping_SetItemStringPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int PyObject_IsInstance( - ffi.Pointer object, - ffi.Pointer typeorclass, - ) { - return _PyObject_IsInstance( - object, - typeorclass, - ); - } - - late final _PyObject_IsInstancePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_IsInstance'); - late final _PyObject_IsInstance = _PyObject_IsInstancePtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - int PyObject_IsSubclass( - ffi.Pointer object, - ffi.Pointer typeorclass, - ) { - return _PyObject_IsSubclass( - object, - typeorclass, - ); - } - - late final _PyObject_IsSubclassPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_IsSubclass'); - late final _PyObject_IsSubclass = _PyObject_IsSubclassPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyStack_AsDict( - ffi.Pointer> values, - ffi.Pointer kwnames, - ) { - return __PyStack_AsDict( - values, - kwnames, - ); - } - - late final __PyStack_AsDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer>, - ffi.Pointer)>>('_PyStack_AsDict'); - late final __PyStack_AsDict = __PyStack_AsDictPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer>, ffi.Pointer)>(); - - ffi.Pointer _Py_CheckFunctionResult( - ffi.Pointer tstate, - ffi.Pointer callable, - ffi.Pointer result, - ffi.Pointer where, - ) { - return __Py_CheckFunctionResult( - tstate, - callable, - result, - where, - ); - } - - late final __Py_CheckFunctionResultPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_Py_CheckFunctionResult'); - late final __Py_CheckFunctionResult = __Py_CheckFunctionResultPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - ffi.Pointer _PyObject_MakeTpCall( - ffi.Pointer tstate, - ffi.Pointer callable, - ffi.Pointer> args, - int nargs, - ffi.Pointer keywords, - ) { - return __PyObject_MakeTpCall( - tstate, - callable, - args, - nargs, - keywords, - ); - } - - late final __PyObject_MakeTpCallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - Py_ssize_t, - ffi.Pointer)>>('_PyObject_MakeTpCall'); - late final __PyObject_MakeTpCall = __PyObject_MakeTpCallPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - int, - ffi.Pointer)>(); - - vectorcallfunc PyVectorcall_Function( - ffi.Pointer callable, - ) { - return _PyVectorcall_Function( - callable, - ); - } - - late final _PyVectorcall_FunctionPtr = _lookup< - ffi.NativeFunction)>>( - 'PyVectorcall_Function'); - late final _PyVectorcall_Function = _PyVectorcall_FunctionPtr.asFunction< - vectorcallfunc Function(ffi.Pointer)>(); - - ffi.Pointer PyObject_VectorcallDict( - ffi.Pointer callable, - ffi.Pointer> args, - int nargsf, - ffi.Pointer kwargs, - ) { - return _PyObject_VectorcallDict( - callable, - args, - nargsf, - kwargs, - ); - } - - late final _PyObject_VectorcallDictPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Size, - ffi.Pointer)>>('PyObject_VectorcallDict'); - late final _PyObject_VectorcallDict = _PyObject_VectorcallDictPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer>, int, ffi.Pointer)>(); - - ffi.Pointer _PyObject_FastCall( - ffi.Pointer func, - ffi.Pointer> args, - int nargs, - ) { - return __PyObject_FastCall( - func, - args, - nargs, - ); - } - - late final __PyObject_FastCallPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer>, - Py_ssize_t)>>('_PyObject_FastCall'); - late final __PyObject_FastCall = __PyObject_FastCallPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer>, int)>(); - - ffi.Pointer PyObject_CallOneArg( - ffi.Pointer func, - ffi.Pointer arg, - ) { - return _PyObject_CallOneArg( - func, - arg, - ); - } - - late final _PyObject_CallOneArgPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('PyObject_CallOneArg'); - late final _PyObject_CallOneArg = _PyObject_CallOneArgPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyObject_CallMethod( - ffi.Pointer obj, - ffi.Pointer name, - ffi.Pointer format, - ) { - return __PyObject_CallMethod( - obj, - name, - format, - ); - } - - late final __PyObject_CallMethodPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('_PyObject_CallMethod'); - late final __PyObject_CallMethod = __PyObject_CallMethodPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyObject_CallMethodId( - ffi.Pointer obj, - ffi.Pointer<_Py_Identifier> name, - ffi.Pointer format, - ) { - return __PyObject_CallMethodId( - obj, - name, - format, - ); - } - - late final __PyObject_CallMethodIdPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer<_Py_Identifier>, - ffi.Pointer)>>('_PyObject_CallMethodId'); - late final __PyObject_CallMethodId = __PyObject_CallMethodIdPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>, ffi.Pointer)>(); - - ffi.Pointer _PyObject_CallMethodId_SizeT( - ffi.Pointer obj, - ffi.Pointer<_Py_Identifier> name, - ffi.Pointer format, - ) { - return __PyObject_CallMethodId_SizeT( - obj, - name, - format, - ); - } - - late final __PyObject_CallMethodId_SizeTPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - ffi.Pointer<_Py_Identifier>, - ffi.Pointer)>>('_PyObject_CallMethodId_SizeT'); - late final __PyObject_CallMethodId_SizeT = - __PyObject_CallMethodId_SizeTPtr.asFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>, ffi.Pointer)>(); - - ffi.Pointer _PyObject_CallMethodIdObjArgs( - ffi.Pointer obj, - ffi.Pointer<_Py_Identifier> name, - ) { - return __PyObject_CallMethodIdObjArgs( - obj, - name, - ); - } - - late final __PyObject_CallMethodIdObjArgsPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_Py_Identifier>)>>('_PyObject_CallMethodIdObjArgs'); - late final __PyObject_CallMethodIdObjArgs = - __PyObject_CallMethodIdObjArgsPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer<_Py_Identifier>)>(); - - int _PyObject_HasLen( - ffi.Pointer o, - ) { - return __PyObject_HasLen( - o, - ); - } - - late final __PyObject_HasLenPtr = - _lookup)>>( - '_PyObject_HasLen'); - late final __PyObject_HasLen = - __PyObject_HasLenPtr.asFunction)>(); - - int PyObject_LengthHint( - ffi.Pointer o, - int arg1, - ) { - return _PyObject_LengthHint( - o, - arg1, - ); - } - - late final _PyObject_LengthHintPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function( - ffi.Pointer, Py_ssize_t)>>('PyObject_LengthHint'); - late final _PyObject_LengthHint = _PyObject_LengthHintPtr.asFunction< - int Function(ffi.Pointer, int)>(); - - int _PySequence_IterSearch( - ffi.Pointer seq, - ffi.Pointer obj, - int operation, - ) { - return __PySequence_IterSearch( - seq, - obj, - operation, - ); - } - - late final __PySequence_IterSearchPtr = _lookup< - ffi.NativeFunction< - Py_ssize_t Function(ffi.Pointer, ffi.Pointer, - ffi.Int)>>('_PySequence_IterSearch'); - late final __PySequence_IterSearch = __PySequence_IterSearchPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int _PyObject_RealIsInstance( - ffi.Pointer inst, - ffi.Pointer cls, - ) { - return __PyObject_RealIsInstance( - inst, - cls, - ); - } - - late final __PyObject_RealIsInstancePtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyObject_RealIsInstance'); - late final __PyObject_RealIsInstance = __PyObject_RealIsInstancePtr - .asFunction, ffi.Pointer)>(); - - int _PyObject_RealIsSubclass( - ffi.Pointer derived, - ffi.Pointer cls, - ) { - return __PyObject_RealIsSubclass( - derived, - cls, - ); - } - - late final __PyObject_RealIsSubclassPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_PyObject_RealIsSubclass'); - late final __PyObject_RealIsSubclass = __PyObject_RealIsSubclassPtr - .asFunction, ffi.Pointer)>(); - - ffi.Pointer> _PySequence_BytesToCharpArray( - ffi.Pointer self, - ) { - return __PySequence_BytesToCharpArray( - self, - ); - } - - late final __PySequence_BytesToCharpArrayPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer> Function( - ffi.Pointer)>>('_PySequence_BytesToCharpArray'); - late final __PySequence_BytesToCharpArray = - __PySequence_BytesToCharpArrayPtr.asFunction< - ffi.Pointer> Function(ffi.Pointer)>(); - - void _Py_FreeCharPArray( - ffi.Pointer> array, - ) { - return __Py_FreeCharPArray( - array, - ); - } - - late final __Py_FreeCharPArrayPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer>)>>('_Py_FreeCharPArray'); - late final __Py_FreeCharPArray = __Py_FreeCharPArrayPtr - .asFunction>)>(); - - void _Py_add_one_to_index_F( - int nd, - ffi.Pointer index, - ffi.Pointer shape, - ) { - return __Py_add_one_to_index_F( - nd, - index, - shape, - ); - } - - late final __Py_add_one_to_index_FPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Int, ffi.Pointer, - ffi.Pointer)>>('_Py_add_one_to_index_F'); - late final __Py_add_one_to_index_F = __Py_add_one_to_index_FPtr.asFunction< - void Function(int, ffi.Pointer, ffi.Pointer)>(); - - void _Py_add_one_to_index_C( - int nd, - ffi.Pointer index, - ffi.Pointer shape, - ) { - return __Py_add_one_to_index_C( - nd, - index, - shape, - ); - } - - late final __Py_add_one_to_index_CPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Int, ffi.Pointer, - ffi.Pointer)>>('_Py_add_one_to_index_C'); - late final __Py_add_one_to_index_C = __Py_add_one_to_index_CPtr.asFunction< - void Function(int, ffi.Pointer, ffi.Pointer)>(); - - int _Py_convert_optional_to_ssize_t( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return __Py_convert_optional_to_ssize_t( - arg0, - arg1, - ); - } - - late final __Py_convert_optional_to_ssize_tPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, - ffi.Pointer)>>('_Py_convert_optional_to_ssize_t'); - late final __Py_convert_optional_to_ssize_t = - __Py_convert_optional_to_ssize_tPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _PyNumber_Index( - ffi.Pointer o, - ) { - return __PyNumber_Index( - o, - ); - } - - late final __PyNumber_IndexPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyNumber_Index'); - late final __PyNumber_Index = __PyNumber_IndexPtr - .asFunction Function(ffi.Pointer)>(); - - late final ffi.Pointer _PyFilter_Type = - _lookup('PyFilter_Type'); - - PyTypeObject get PyFilter_Type => _PyFilter_Type.ref; - - late final ffi.Pointer _PyMap_Type = - _lookup('PyMap_Type'); - - PyTypeObject get PyMap_Type => _PyMap_Type.ref; - - late final ffi.Pointer _PyZip_Type = - _lookup('PyZip_Type'); - - PyTypeObject get PyZip_Type => _PyZip_Type.ref; - - late final ffi.Pointer> __Py_ctype_table = - _lookup>('_Py_ctype_table'); - - ffi.Pointer get _Py_ctype_table => __Py_ctype_table.value; - - set _Py_ctype_table(ffi.Pointer value) => - __Py_ctype_table.value = value; - - late final ffi.Pointer> __Py_ctype_tolower = - _lookup>('_Py_ctype_tolower'); - - ffi.Pointer get _Py_ctype_tolower => - __Py_ctype_tolower.value; - - set _Py_ctype_tolower(ffi.Pointer value) => - __Py_ctype_tolower.value = value; - - late final ffi.Pointer> __Py_ctype_toupper = - _lookup>('_Py_ctype_toupper'); - - ffi.Pointer get _Py_ctype_toupper => - __Py_ctype_toupper.value; - - set _Py_ctype_toupper(ffi.Pointer value) => - __Py_ctype_toupper.value = value; - - double PyOS_string_to_double( - ffi.Pointer str, - ffi.Pointer> endptr, - ffi.Pointer overflow_exception, - ) { - return _PyOS_string_to_double( - str, - endptr, - overflow_exception, - ); - } - - late final _PyOS_string_to_doublePtr = _lookup< - ffi.NativeFunction< - ffi.Double Function( - ffi.Pointer, - ffi.Pointer>, - ffi.Pointer)>>('PyOS_string_to_double'); - late final _PyOS_string_to_double = _PyOS_string_to_doublePtr.asFunction< - double Function(ffi.Pointer, ffi.Pointer>, - ffi.Pointer)>(); - - ffi.Pointer PyOS_double_to_string( - double val, - int format_code, - int precision, - int flags, - ffi.Pointer type, - ) { - return _PyOS_double_to_string( - val, - format_code, - precision, - flags, - type, - ); - } - - late final _PyOS_double_to_stringPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Double, ffi.Char, ffi.Int, ffi.Int, - ffi.Pointer)>>('PyOS_double_to_string'); - late final _PyOS_double_to_string = _PyOS_double_to_stringPtr.asFunction< - ffi.Pointer Function( - double, int, int, int, ffi.Pointer)>(); - - ffi.Pointer _Py_string_to_number_with_underscores( - ffi.Pointer str, - int len, - ffi.Pointer what, - ffi.Pointer obj, - ffi.Pointer arg, - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t, ffi.Pointer)>> - innerfunc, - ) { - return __Py_string_to_number_with_underscores( - str, - len, - what, - obj, - arg, - innerfunc, - ); - } - - late final __Py_string_to_number_with_underscoresPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, - Py_ssize_t, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - Py_ssize_t, ffi.Pointer)>>)>>( - '_Py_string_to_number_with_underscores'); - late final __Py_string_to_number_with_underscores = - __Py_string_to_number_with_underscoresPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, - int, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - Py_ssize_t, ffi.Pointer)>>)>(); - - double _Py_parse_inf_or_nan( - ffi.Pointer p, - ffi.Pointer> endptr, - ) { - return __Py_parse_inf_or_nan( - p, - endptr, - ); - } - - late final __Py_parse_inf_or_nanPtr = _lookup< - ffi.NativeFunction< - ffi.Double Function(ffi.Pointer, - ffi.Pointer>)>>('_Py_parse_inf_or_nan'); - late final __Py_parse_inf_or_nan = __Py_parse_inf_or_nanPtr.asFunction< - double Function( - ffi.Pointer, ffi.Pointer>)>(); - - int PyOS_mystrnicmp( - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2, - ) { - return _PyOS_mystrnicmp( - arg0, - arg1, - arg2, - ); - } - - late final _PyOS_mystrnicmpPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - Py_ssize_t)>>('PyOS_mystrnicmp'); - late final _PyOS_mystrnicmp = _PyOS_mystrnicmpPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, int)>(); - - int PyOS_mystricmp( - ffi.Pointer arg0, - ffi.Pointer arg1, - ) { - return _PyOS_mystricmp( - arg0, - arg1, - ); - } - - late final _PyOS_mystricmpPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer)>>('PyOS_mystricmp'); - late final _PyOS_mystricmp = _PyOS_mystricmpPtr.asFunction< - int Function(ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer Py_DecodeLocale( - ffi.Pointer arg, - ffi.Pointer size, - ) { - return _Py_DecodeLocale( - arg, - size, - ); - } - - late final _Py_DecodeLocalePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('Py_DecodeLocale'); - late final _Py_DecodeLocale = _Py_DecodeLocalePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer Py_EncodeLocale( - ffi.Pointer text, - ffi.Pointer error_pos, - ) { - return _Py_EncodeLocale( - text, - error_pos, - ); - } - - late final _Py_EncodeLocalePtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer)>>('Py_EncodeLocale'); - late final _Py_EncodeLocale = _Py_EncodeLocalePtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _Py_fopen_obj( - ffi.Pointer path, - ffi.Pointer mode, - ) { - return __Py_fopen_obj( - path, - mode, - ); - } - - late final __Py_fopen_objPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('_Py_fopen_obj'); - late final __Py_fopen_obj = __Py_fopen_objPtr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - int PyTraceMalloc_Track( - int domain, - int ptr, - int size, - ) { - return _PyTraceMalloc_Track( - domain, - ptr, - size, - ); - } - - late final _PyTraceMalloc_TrackPtr = _lookup< - ffi.NativeFunction< - ffi.Int Function( - ffi.UnsignedInt, ffi.UintPtr, ffi.Size)>>('PyTraceMalloc_Track'); - late final _PyTraceMalloc_Track = - _PyTraceMalloc_TrackPtr.asFunction(); - - int PyTraceMalloc_Untrack( - int domain, - int ptr, - ) { - return _PyTraceMalloc_Untrack( - domain, - ptr, - ); - } - - late final _PyTraceMalloc_UntrackPtr = _lookup< - ffi.NativeFunction>( - 'PyTraceMalloc_Untrack'); - late final _PyTraceMalloc_Untrack = - _PyTraceMalloc_UntrackPtr.asFunction(); - - ffi.Pointer _PyTraceMalloc_GetTraceback( - int domain, - int ptr, - ) { - return __PyTraceMalloc_GetTraceback( - domain, - ptr, - ); - } - - late final __PyTraceMalloc_GetTracebackPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.UnsignedInt, ffi.UintPtr)>>('_PyTraceMalloc_GetTraceback'); - late final __PyTraceMalloc_GetTraceback = __PyTraceMalloc_GetTracebackPtr - .asFunction Function(int, int)>(); - - int _PyTraceMalloc_IsTracing() { - return __PyTraceMalloc_IsTracing(); - } - - late final __PyTraceMalloc_IsTracingPtr = - _lookup>( - '_PyTraceMalloc_IsTracing'); - late final __PyTraceMalloc_IsTracing = - __PyTraceMalloc_IsTracingPtr.asFunction(); - - void _PyTraceMalloc_ClearTraces() { - return __PyTraceMalloc_ClearTraces(); - } - - late final __PyTraceMalloc_ClearTracesPtr = - _lookup>( - '_PyTraceMalloc_ClearTraces'); - late final __PyTraceMalloc_ClearTraces = - __PyTraceMalloc_ClearTracesPtr.asFunction(); - - ffi.Pointer _PyTraceMalloc_GetTraces() { - return __PyTraceMalloc_GetTraces(); - } - - late final __PyTraceMalloc_GetTracesPtr = - _lookup Function()>>( - '_PyTraceMalloc_GetTraces'); - late final __PyTraceMalloc_GetTraces = __PyTraceMalloc_GetTracesPtr - .asFunction Function()>(); - - ffi.Pointer _PyTraceMalloc_GetObjectTraceback( - ffi.Pointer obj, - ) { - return __PyTraceMalloc_GetObjectTraceback( - obj, - ); - } - - late final __PyTraceMalloc_GetObjectTracebackPtr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer)>>('_PyTraceMalloc_GetObjectTraceback'); - late final __PyTraceMalloc_GetObjectTraceback = - __PyTraceMalloc_GetObjectTracebackPtr - .asFunction Function(ffi.Pointer)>(); - - int _PyTraceMalloc_Init() { - return __PyTraceMalloc_Init(); - } - - late final __PyTraceMalloc_InitPtr = - _lookup>('_PyTraceMalloc_Init'); - late final __PyTraceMalloc_Init = - __PyTraceMalloc_InitPtr.asFunction(); - - int _PyTraceMalloc_Start( - int max_nframe, - ) { - return __PyTraceMalloc_Start( - max_nframe, - ); - } - - late final __PyTraceMalloc_StartPtr = - _lookup>( - '_PyTraceMalloc_Start'); - late final __PyTraceMalloc_Start = - __PyTraceMalloc_StartPtr.asFunction(); - - void _PyTraceMalloc_Stop() { - return __PyTraceMalloc_Stop(); - } - - late final __PyTraceMalloc_StopPtr = - _lookup>('_PyTraceMalloc_Stop'); - late final __PyTraceMalloc_Stop = - __PyTraceMalloc_StopPtr.asFunction(); - - int _PyTraceMalloc_GetTracebackLimit() { - return __PyTraceMalloc_GetTracebackLimit(); - } - - late final __PyTraceMalloc_GetTracebackLimitPtr = - _lookup>( - '_PyTraceMalloc_GetTracebackLimit'); - late final __PyTraceMalloc_GetTracebackLimit = - __PyTraceMalloc_GetTracebackLimitPtr.asFunction(); - - int _PyTraceMalloc_GetMemory() { - return __PyTraceMalloc_GetMemory(); - } - - late final __PyTraceMalloc_GetMemoryPtr = - _lookup>( - '_PyTraceMalloc_GetMemory'); - late final __PyTraceMalloc_GetMemory = - __PyTraceMalloc_GetMemoryPtr.asFunction(); - - ffi.Pointer _PyTraceMalloc_GetTracedMemory() { - return __PyTraceMalloc_GetTracedMemory(); - } - - late final __PyTraceMalloc_GetTracedMemoryPtr = - _lookup Function()>>( - '_PyTraceMalloc_GetTracedMemory'); - late final __PyTraceMalloc_GetTracedMemory = - __PyTraceMalloc_GetTracedMemoryPtr - .asFunction Function()>(); - - void _PyTraceMalloc_ResetPeak() { - return __PyTraceMalloc_ResetPeak(); - } - - late final __PyTraceMalloc_ResetPeakPtr = - _lookup>( - '_PyTraceMalloc_ResetPeak'); - late final __PyTraceMalloc_ResetPeak = - __PyTraceMalloc_ResetPeakPtr.asFunction(); -} - -abstract class PyMemAllocatorDomain { - static const int PYMEM_DOMAIN_RAW = 0; - static const int PYMEM_DOMAIN_MEM = 1; - static const int PYMEM_DOMAIN_OBJ = 2; -} - -abstract class PyMemAllocatorName { - static const int PYMEM_ALLOCATOR_NOT_SET = 0; - static const int PYMEM_ALLOCATOR_DEFAULT = 1; - static const int PYMEM_ALLOCATOR_DEBUG = 2; - static const int PYMEM_ALLOCATOR_MALLOC = 3; - static const int PYMEM_ALLOCATOR_MALLOC_DEBUG = 4; - static const int PYMEM_ALLOCATOR_PYMALLOC = 5; - static const int PYMEM_ALLOCATOR_PYMALLOC_DEBUG = 6; -} - -final class PyMemAllocatorEx extends ffi.Struct { - external ffi.Pointer ctx; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer ctx, ffi.Size size)>> malloc; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer ctx, ffi.Size nelem, ffi.Size elsize)>> - calloc; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer ctx, - ffi.Pointer ptr, ffi.Size new_size)>> realloc; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer ctx, ffi.Pointer ptr)>> free; -} - -final class PyModuleDef extends ffi.Struct { - external PyModuleDef_Base m_base; - - external ffi.Pointer m_name; - - external ffi.Pointer m_doc; - - @Py_ssize_t() - external int m_size; - - external ffi.Pointer m_methods; - - external ffi.Pointer m_slots; - - external traverseproc m_traverse; - - external inquiry m_clear; - - external freefunc m_free; -} - -final class PyModuleDef_Base extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer Function()>> - m_init; - - @Py_ssize_t() - external int m_index; - - external ffi.Pointer m_copy; -} - -typedef PyObject = _object; - -final class _object extends ffi.Struct { - external UnnamedUnion1 unnamed; - - external ffi.Pointer ob_type; -} - -final class UnnamedUnion1 extends ffi.Union { - @Py_ssize_t() - external int ob_refcnt; - - @ffi.Array.multi([2]) - external ffi.Array ob_refcnt_split; -} - -typedef Py_ssize_t = ssize_t; -typedef ssize_t = __darwin_ssize_t; -typedef __darwin_ssize_t = ffi.Long; -typedef PyTypeObject = _typeobject; - -final class _typeobject extends ffi.Struct { - external PyVarObject ob_base; - - external ffi.Pointer tp_name; - - @Py_ssize_t() - external int tp_basicsize; - - @Py_ssize_t() - external int tp_itemsize; - - external destructor tp_dealloc; - - @Py_ssize_t() - external int tp_vectorcall_offset; - - external getattrfunc tp_getattr; - - external setattrfunc tp_setattr; - - external ffi.Pointer tp_as_async; - - external reprfunc tp_repr; - - external ffi.Pointer tp_as_number; - - external ffi.Pointer tp_as_sequence; - - external ffi.Pointer tp_as_mapping; - - external hashfunc tp_hash; - - external ternaryfunc tp_call; - - external reprfunc tp_str; - - external getattrofunc tp_getattro; - - external setattrofunc tp_setattro; - - external ffi.Pointer tp_as_buffer; - - @ffi.UnsignedLong() - external int tp_flags; - - external ffi.Pointer tp_doc; - - external traverseproc tp_traverse; - - external inquiry tp_clear; - - external richcmpfunc tp_richcompare; - - @Py_ssize_t() - external int tp_weaklistoffset; - - external getiterfunc tp_iter; - - external iternextfunc tp_iternext; - - external ffi.Pointer tp_methods; - - external ffi.Pointer tp_members; - - external ffi.Pointer tp_getset; - - external ffi.Pointer tp_base; - - external ffi.Pointer tp_dict; - - external descrgetfunc tp_descr_get; - - external descrsetfunc tp_descr_set; - - @Py_ssize_t() - external int tp_dictoffset; - - external initproc tp_init; - - external allocfunc tp_alloc; - - external newfunc tp_new; - - external freefunc tp_free; - - external inquiry tp_is_gc; - - external ffi.Pointer tp_bases; - - external ffi.Pointer tp_mro; - - external ffi.Pointer tp_cache; - - external ffi.Pointer tp_subclasses; - - external ffi.Pointer tp_weaklist; - - external destructor tp_del; - - @ffi.UnsignedInt() - external int tp_version_tag; - - external destructor tp_finalize; - - external vectorcallfunc tp_vectorcall; - - @ffi.UnsignedChar() - external int tp_watched; -} - -final class PyVarObject extends ffi.Struct { - external PyObject1 ob_base; - - @Py_ssize_t() - external int ob_size; -} - -typedef PyObject1 = _object; -typedef destructor = ffi - .Pointer)>>; -typedef getattrfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>; -typedef setattrfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; - -final class PyAsyncMethods extends ffi.Struct { - external unaryfunc am_await; - - external unaryfunc am_aiter; - - external unaryfunc am_anext; - - external sendfunc am_send; -} - -typedef unaryfunc = ffi.Pointer< - ffi - .NativeFunction Function(ffi.Pointer)>>; -typedef sendfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int32 Function( - ffi.Pointer iter, - ffi.Pointer value, - ffi.Pointer> result)>>; - -abstract class PySendResult { - static const int PYGEN_RETURN = 0; - static const int PYGEN_ERROR = -1; - static const int PYGEN_NEXT = 1; -} - -typedef reprfunc = ffi.Pointer< - ffi - .NativeFunction Function(ffi.Pointer)>>; - -final class PyNumberMethods extends ffi.Struct { - external binaryfunc nb_add; - - external binaryfunc nb_subtract; - - external binaryfunc nb_multiply; - - external binaryfunc nb_remainder; - - external binaryfunc nb_divmod; - - external ternaryfunc nb_power; - - external unaryfunc nb_negative; - - external unaryfunc nb_positive; - - external unaryfunc nb_absolute; - - external inquiry nb_bool; - - external unaryfunc nb_invert; - - external binaryfunc nb_lshift; - - external binaryfunc nb_rshift; - - external binaryfunc nb_and; - - external binaryfunc nb_xor; - - external binaryfunc nb_or; - - external unaryfunc nb_int; - - external ffi.Pointer nb_reserved; - - external unaryfunc nb_float; - - external binaryfunc nb_inplace_add; - - external binaryfunc nb_inplace_subtract; - - external binaryfunc nb_inplace_multiply; - - external binaryfunc nb_inplace_remainder; - - external ternaryfunc nb_inplace_power; - - external binaryfunc nb_inplace_lshift; - - external binaryfunc nb_inplace_rshift; - - external binaryfunc nb_inplace_and; - - external binaryfunc nb_inplace_xor; - - external binaryfunc nb_inplace_or; - - external binaryfunc nb_floor_divide; - - external binaryfunc nb_true_divide; - - external binaryfunc nb_inplace_floor_divide; - - external binaryfunc nb_inplace_true_divide; - - external unaryfunc nb_index; - - external binaryfunc nb_matrix_multiply; - - external binaryfunc nb_inplace_matrix_multiply; -} - -typedef binaryfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>; -typedef ternaryfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>; -typedef inquiry - = ffi.Pointer)>>; - -final class PySequenceMethods extends ffi.Struct { - external lenfunc sq_length; - - external binaryfunc sq_concat; - - external ssizeargfunc sq_repeat; - - external ssizeargfunc sq_item; - - external ffi.Pointer was_sq_slice; - - external ssizeobjargproc sq_ass_item; - - external ffi.Pointer was_sq_ass_slice; - - external objobjproc sq_contains; - - external binaryfunc sq_inplace_concat; - - external ssizeargfunc sq_inplace_repeat; -} - -typedef lenfunc = ffi - .Pointer)>>; -typedef ssizeargfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, Py_ssize_t)>>; -typedef ssizeobjargproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, Py_ssize_t, ffi.Pointer)>>; -typedef objobjproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer)>>; - -final class PyMappingMethods extends ffi.Struct { - external lenfunc mp_length; - - external binaryfunc mp_subscript; - - external objobjargproc mp_ass_subscript; -} - -typedef objobjargproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; -typedef hashfunc = ffi - .Pointer)>>; -typedef Py_hash_t = Py_ssize_t; -typedef getattrofunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>; -typedef setattrofunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; - -final class PyBufferProcs extends ffi.Struct { - external getbufferproc bf_getbuffer; - - external releasebufferproc bf_releasebuffer; -} - -typedef getbufferproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer, ffi.Int)>>; - -final class Py_buffer extends ffi.Struct { - external ffi.Pointer buf; - - external ffi.Pointer obj; - - @Py_ssize_t() - external int len; - - @Py_ssize_t() - external int itemsize; - - @ffi.Int() - external int readonly; - - @ffi.Int() - external int ndim; - - external ffi.Pointer format; - - external ffi.Pointer shape; - - external ffi.Pointer strides; - - external ffi.Pointer suboffsets; - - external ffi.Pointer internal; -} - -typedef releasebufferproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer)>>; -typedef traverseproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, visitproc, ffi.Pointer)>>; -typedef visitproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer)>>; -typedef richcmpfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer, ffi.Int)>>; -typedef getiterfunc = ffi.Pointer< - ffi - .NativeFunction Function(ffi.Pointer)>>; -typedef iternextfunc = ffi.Pointer< - ffi - .NativeFunction Function(ffi.Pointer)>>; - -final class PyMethodDef extends ffi.Struct { - external ffi.Pointer ml_name; - - external PyCFunction ml_meth; - - @ffi.Int() - external int ml_flags; - - external ffi.Pointer ml_doc; -} - -typedef PyCFunction = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>; - -final class PyMemberDef extends ffi.Struct { - external ffi.Pointer name; - - @ffi.Int() - external int type; - - @Py_ssize_t() - external int offset; - - @ffi.Int() - external int flags; - - external ffi.Pointer doc; -} - -final class PyGetSetDef extends ffi.Struct { - external ffi.Pointer name; - - external getter get1; - - external setter set1; - - external ffi.Pointer doc; - - external ffi.Pointer closure; -} - -typedef getter = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>; -typedef setter = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; -typedef PyTypeObject1 = _typeobject; -typedef descrgetfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>; -typedef descrsetfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; -typedef initproc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; -typedef allocfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, Py_ssize_t)>>; -typedef newfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer, ffi.Pointer)>>; -typedef freefunc - = ffi.Pointer)>>; -typedef vectorcallfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer callable, - ffi.Pointer> args, - ffi.Size nargsf, - ffi.Pointer kwnames)>>; - -final class PyModuleDef_Slot extends ffi.Struct { - @ffi.Int() - external int slot; - - external ffi.Pointer value; -} - -final class _longobject extends ffi.Struct { - external PyObject ob_base; - - external _PyLongValue long_value; -} - -final class _PyLongValue extends ffi.Struct { - @ffi.UintPtr() - external int lv_tag; - - @ffi.Array.multi([1]) - external ffi.Array ob_digit; -} - -typedef digit = ffi.Uint32; - -final class PyCodeObject extends ffi.Struct { - external PyVarObject ob_base; - - external ffi.Pointer co_consts; - - external ffi.Pointer co_names; - - external ffi.Pointer co_exceptiontable; - - @ffi.Int() - external int co_flags; - - @ffi.Int() - external int co_argcount; - - @ffi.Int() - external int co_posonlyargcount; - - @ffi.Int() - external int co_kwonlyargcount; - - @ffi.Int() - external int co_stacksize; - - @ffi.Int() - external int co_firstlineno; - - @ffi.Int() - external int co_nlocalsplus; - - @ffi.Int() - external int co_framesize; - - @ffi.Int() - external int co_nlocals; - - @ffi.Int() - external int co_ncellvars; - - @ffi.Int() - external int co_nfreevars; - - @ffi.Uint32() - external int co_version; - - external ffi.Pointer co_localsplusnames; - - external ffi.Pointer co_localspluskinds; - - external ffi.Pointer co_filename; - - external ffi.Pointer co_name; - - external ffi.Pointer co_qualname; - - external ffi.Pointer co_linetable; - - external ffi.Pointer co_weakreflist; - - external ffi.Pointer<_PyCoCached> _co_cached; - - @ffi.Uint64() - external int _co_instrumentation_version; - - external ffi.Pointer<_PyCoMonitoringData> _co_monitoring; - - @ffi.Int() - external int _co_firsttraceable; - - external ffi.Pointer co_extra; - - @ffi.Array.multi([1]) - external ffi.Array co_code_adaptive; -} - -final class _PyCoCached extends ffi.Struct { - external ffi.Pointer _co_code; - - external ffi.Pointer _co_varnames; - - external ffi.Pointer _co_cellvars; - - external ffi.Pointer _co_freevars; -} - -final class _PyCoMonitoringData extends ffi.Struct { - external _Py_LocalMonitors local_monitors; - - external _Py_LocalMonitors active_monitors; - - external ffi.Pointer tools; - - external ffi.Pointer<_PyCoLineInstrumentationData> lines; - - external ffi.Pointer line_tools; - - external ffi.Pointer per_instruction_opcodes; - - external ffi.Pointer per_instruction_tools; -} - -final class _Py_LocalMonitors extends ffi.Struct { - @ffi.Array.multi([15]) - external ffi.Array tools; -} - -final class _PyCoLineInstrumentationData extends ffi.Struct { - @ffi.Uint8() - external int original_opcode; - - @ffi.Int8() - external int line_delta; -} - -final class _frame extends ffi.Opaque {} - -final class _ts extends ffi.Opaque {} - -final class _is extends ffi.Opaque {} - -final class PyType_Slot extends ffi.Struct { - @ffi.Int() - external int slot; - - external ffi.Pointer pfunc; -} - -final class PyType_Spec extends ffi.Struct { - external ffi.Pointer name; - - @ffi.Int() - external int basicsize; - - @ffi.Int() - external int itemsize; - - @ffi.UnsignedInt() - external int flags; - - external ffi.Pointer slots; -} - -final class _Py_Identifier extends ffi.Struct { - external ffi.Pointer string; - - @Py_ssize_t() - external int index; -} - -final class _specialization_cache extends ffi.Struct { - external ffi.Pointer getitem; - - @ffi.Uint32() - external int getitem_version; -} - -final class _heaptypeobject extends ffi.Struct { - external PyTypeObject ht_type; - - external PyAsyncMethods as_async; - - external PyNumberMethods as_number; - - external PyMappingMethods as_mapping; - - external PySequenceMethods as_sequence; - - external PyBufferProcs as_buffer; - - external ffi.Pointer ht_name; - - external ffi.Pointer ht_slots; - - external ffi.Pointer ht_qualname; - - external ffi.Pointer<_dictkeysobject> ht_cached_keys; - - external ffi.Pointer ht_module; - - external ffi.Pointer _ht_tpname; - - external _specialization_cache _spec_cache; -} - -final class _dictkeysobject extends ffi.Opaque {} - -typedef FILE = __sFILE; - -final class __sFILE extends ffi.Struct { - external ffi.Pointer _p; - - @ffi.Int() - external int _r; - - @ffi.Int() - external int _w; - - @ffi.Short() - external int _flags; - - @ffi.Short() - external int _file; - - external __sbuf _bf; - - @ffi.Int() - external int _lbfsize; - - external ffi.Pointer _cookie; - - external ffi - .Pointer)>> - _close; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer, ffi.Int)>> _read; - - external ffi.Pointer< - ffi.NativeFunction< - fpos_t Function(ffi.Pointer, fpos_t, ffi.Int)>> _seek; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function( - ffi.Pointer, ffi.Pointer, ffi.Int)>> _write; - - external __sbuf _ub; - - external ffi.Pointer<__sFILEX> _extra; - - @ffi.Int() - external int _ur; - - @ffi.Array.multi([3]) - external ffi.Array _ubuf; - - @ffi.Array.multi([1]) - external ffi.Array _nbuf; - - external __sbuf _lb; - - @ffi.Int() - external int _blksize; - - @fpos_t() - external int _offset; -} - -final class __sbuf extends ffi.Struct { - external ffi.Pointer _base; - - @ffi.Int() - external int _size; -} - -typedef fpos_t = __darwin_off_t; -typedef __darwin_off_t = __int64_t; -typedef __int64_t = ffi.LongLong; - -final class __sFILEX extends ffi.Opaque {} - -typedef PyThreadState = _ts; -typedef PyType_WatchCallback = ffi - .Pointer)>>; -typedef gcvisitobjects_t = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer)>>; - -final class PyObjectArenaAllocator extends ffi.Struct { - external ffi.Pointer ctx; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer ctx, ffi.Size size)>> alloc; - - external ffi.Pointer< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer ctx, - ffi.Pointer ptr, ffi.Size size)>> free; -} - -final class _Py_HashSecret_t extends ffi.Union { - @ffi.Array.multi([24]) - external ffi.Array uc; - - external UnnamedStruct2 fnv; - - external UnnamedStruct3 siphash; - - external UnnamedStruct4 djbx33a; - - external UnnamedStruct5 expat; -} - -final class UnnamedStruct2 extends ffi.Struct { - @Py_hash_t() - external int prefix; - - @Py_hash_t() - external int suffix; -} - -final class UnnamedStruct3 extends ffi.Struct { - @ffi.Uint64() - external int k0; - - @ffi.Uint64() - external int k1; -} - -final class UnnamedStruct4 extends ffi.Struct { - @ffi.Array.multi([16]) - external ffi.Array padding; - - @Py_hash_t() - external int suffix; -} - -final class UnnamedStruct5 extends ffi.Struct { - @ffi.Array.multi([16]) - external ffi.Array padding; - - @Py_hash_t() - external int hashsalt; -} - -final class PyHash_FuncDef extends ffi.Struct { - external ffi.Pointer< - ffi.NativeFunction< - Py_hash_t Function(ffi.Pointer, Py_ssize_t)>> hash; - - external ffi.Pointer name; - - @ffi.Int() - external int hash_bits; - - @ffi.Int() - external int seed_bits; -} - -final class PyByteArrayObject extends ffi.Struct { - external PyVarObject ob_base; - - @Py_ssize_t() - external int ob_alloc; - - external ffi.Pointer ob_bytes; - - external ffi.Pointer ob_start; - - @Py_ssize_t() - external int ob_exports; -} - -typedef va_list = __builtin_va_list; -typedef __builtin_va_list = ffi.Pointer; - -final class PyBytesObject extends ffi.Struct { - external PyVarObject ob_base; - - @Py_hash_t() - external int ob_shash; - - @ffi.Array.multi([1]) - external ffi.Array ob_sval; -} - -final class _PyBytesWriter extends ffi.Struct { - external ffi.Pointer buffer; - - @Py_ssize_t() - external int allocated; - - @Py_ssize_t() - external int min_size; - - @ffi.Int() - external int use_bytearray; - - @ffi.Int() - external int overallocate; - - @ffi.Int() - external int use_small_buffer; - - @ffi.Array.multi([512]) - external ffi.Array small_buffer; -} - -typedef Py_UCS4 = ffi.Uint32; - -final class PyASCIIObject extends ffi.Opaque {} - -final class PyCompactUnicodeObject extends ffi.Opaque {} - -final class PyUnicodeObject extends ffi.Opaque {} - -abstract class PyUnicode_Kind { - static const int PyUnicode_1BYTE_KIND = 1; - static const int PyUnicode_2BYTE_KIND = 2; - static const int PyUnicode_4BYTE_KIND = 4; -} - -final class _PyUnicodeWriter extends ffi.Struct { - external ffi.Pointer buffer; - - external ffi.Pointer data; - - @ffi.Int() - external int kind; - - @Py_UCS4() - external int maxchar; - - @Py_ssize_t() - external int size; - - @Py_ssize_t() - external int pos; - - @Py_ssize_t() - external int min_length; - - @Py_UCS4() - external int min_char; - - @ffi.UnsignedChar() - external int overallocate; - - @ffi.UnsignedChar() - external int readonly; -} - -final class PyStatus extends ffi.Struct { - @ffi.Int32() - external int _type; - - external ffi.Pointer func; - - external ffi.Pointer err_msg; - - @ffi.Int() - external int exitcode; -} - -final class PyWideStringList extends ffi.Struct { - @Py_ssize_t() - external int length; - - external ffi.Pointer> items; -} - -final class PyPreConfig extends ffi.Struct { - @ffi.Int() - external int _config_init; - - @ffi.Int() - external int parse_argv; - - @ffi.Int() - external int isolated; - - @ffi.Int() - external int use_environment; - - @ffi.Int() - external int configure_locale; - - @ffi.Int() - external int coerce_c_locale; - - @ffi.Int() - external int coerce_c_locale_warn; - - @ffi.Int() - external int utf8_mode; - - @ffi.Int() - external int dev_mode; - - @ffi.Int() - external int allocator; -} - -final class PyConfig extends ffi.Struct { - @ffi.Int() - external int _config_init; - - @ffi.Int() - external int isolated; - - @ffi.Int() - external int use_environment; - - @ffi.Int() - external int dev_mode; - - @ffi.Int() - external int install_signal_handlers; - - @ffi.Int() - external int use_hash_seed; - - @ffi.UnsignedLong() - external int hash_seed; - - @ffi.Int() - external int faulthandler; - - @ffi.Int() - external int tracemalloc; - - @ffi.Int() - external int perf_profiling; - - @ffi.Int() - external int import_time; - - @ffi.Int() - external int code_debug_ranges; - - @ffi.Int() - external int show_ref_count; - - @ffi.Int() - external int dump_refs; - - external ffi.Pointer dump_refs_file; - - @ffi.Int() - external int malloc_stats; - - external ffi.Pointer filesystem_encoding; - - external ffi.Pointer filesystem_errors; - - external ffi.Pointer pycache_prefix; - - @ffi.Int() - external int parse_argv; - - external PyWideStringList orig_argv; - - external PyWideStringList argv; - - external PyWideStringList xoptions; - - external PyWideStringList warnoptions; - - @ffi.Int() - external int site_import; - - @ffi.Int() - external int bytes_warning; - - @ffi.Int() - external int warn_default_encoding; - - @ffi.Int() - external int inspect; - - @ffi.Int() - external int interactive; - - @ffi.Int() - external int optimization_level; - - @ffi.Int() - external int parser_debug; - - @ffi.Int() - external int write_bytecode; - - @ffi.Int() - external int verbose; - - @ffi.Int() - external int quiet; - - @ffi.Int() - external int user_site_directory; - - @ffi.Int() - external int configure_c_stdio; - - @ffi.Int() - external int buffered_stdio; - - external ffi.Pointer stdio_encoding; - - external ffi.Pointer stdio_errors; - - external ffi.Pointer check_hash_pycs_mode; - - @ffi.Int() - external int use_frozen_modules; - - @ffi.Int() - external int safe_path; - - @ffi.Int() - external int int_max_str_digits; - - @ffi.Int() - external int pathconfig_warnings; - - external ffi.Pointer program_name; - - external ffi.Pointer pythonpath_env; - - external ffi.Pointer home; - - external ffi.Pointer platlibdir; - - @ffi.Int() - external int module_search_paths_set; - - external PyWideStringList module_search_paths; - - external ffi.Pointer stdlib_dir; - - external ffi.Pointer executable; - - external ffi.Pointer base_executable; - - external ffi.Pointer prefix; - - external ffi.Pointer base_prefix; - - external ffi.Pointer exec_prefix; - - external ffi.Pointer base_exec_prefix; - - @ffi.Int() - external int skip_source_first_line; - - external ffi.Pointer run_command; - - external ffi.Pointer run_module; - - external ffi.Pointer run_filename; - - @ffi.Int() - external int _install_importlib; - - @ffi.Int() - external int _init_main; - - @ffi.Int() - external int _is_python_build; -} - -typedef PyInterpreterState = _is; -typedef PyFrameObject = _frame; - -abstract class PyGILState_STATE { - static const int PyGILState_LOCKED = 0; - static const int PyGILState_UNLOCKED = 1; -} - -final class _PyCFrame extends ffi.Struct { - external ffi.Pointer<_PyInterpreterFrame> current_frame; - - external ffi.Pointer<_PyCFrame> previous; -} - -final class _PyInterpreterFrame extends ffi.Opaque {} - -final class _err_stackitem extends ffi.Struct { - external ffi.Pointer exc_value; - - external ffi.Pointer<_err_stackitem> previous_item; -} - -final class _stack_chunk extends ffi.Struct { - external ffi.Pointer<_stack_chunk> previous; - - @ffi.Size() - external int size; - - @ffi.Size() - external int top; - - @ffi.Array.multi([1]) - external ffi.Array> data; -} - -final class _py_trashcan extends ffi.Struct { - @ffi.Int() - external int delete_nesting; - - external ffi.Pointer delete_later; -} - -typedef _PyFrameEvalFunction = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer, - ffi.Pointer<_PyInterpreterFrame>, ffi.Int)>>; - -final class _xid extends ffi.Struct { - external ffi.Pointer data; - - external ffi.Pointer obj; - - @ffi.Int64() - external int interp; - - external xid_newobjectfunc new_object; - - external xid_freefunc free; -} - -typedef xid_newobjectfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer<_PyCrossInterpreterData>)>>; -typedef _PyCrossInterpreterData = _xid; -typedef xid_freefunc - = ffi.Pointer)>>; -typedef crossinterpdatafunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer<_PyCrossInterpreterData>)>>; - -final class PyBaseExceptionObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; -} - -final class PyBaseExceptionGroupObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer msg; - - external ffi.Pointer excs; -} - -final class PySyntaxErrorObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer msg; - - external ffi.Pointer filename; - - external ffi.Pointer lineno; - - external ffi.Pointer offset; - - external ffi.Pointer end_lineno; - - external ffi.Pointer end_offset; - - external ffi.Pointer text; - - external ffi.Pointer print_file_and_line; -} - -final class PyImportErrorObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer msg; - - external ffi.Pointer name; - - external ffi.Pointer path; - - external ffi.Pointer name_from; -} - -final class PyUnicodeErrorObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer encoding; - - external ffi.Pointer object; - - @Py_ssize_t() - external int start; - - @Py_ssize_t() - external int end; - - external ffi.Pointer reason; -} - -final class PySystemExitObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer code; -} - -final class PyOSErrorObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer myerrno; - - external ffi.Pointer strerror; - - external ffi.Pointer filename; - - external ffi.Pointer filename2; - - @Py_ssize_t() - external int written; -} - -final class PyStopIterationObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer value; -} - -final class PyNameErrorObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer name; -} - -final class PyAttributeErrorObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dict; - - external ffi.Pointer args; - - external ffi.Pointer notes; - - external ffi.Pointer traceback; - - external ffi.Pointer context; - - external ffi.Pointer cause; - - @ffi.Char() - external int suppress_context; - - external ffi.Pointer obj; - - external ffi.Pointer name; -} - -typedef _PyErr_StackItem = _err_stackitem; -typedef PyLongObject = _longobject; - -final class PyFloatObject extends ffi.Struct { - external PyObject ob_base; - - @ffi.Double() - external double ob_fval; -} - -final class Py_complex extends ffi.Struct { - @ffi.Double() - external double real; - - @ffi.Double() - external double imag; -} - -final class PyComplexObject extends ffi.Struct { - external PyObject ob_base; - - external Py_complex cval; -} - -final class _PyManagedBufferObject extends ffi.Struct { - external PyObject ob_base; - - @ffi.Int() - external int flags; - - @Py_ssize_t() - external int exports; - - external Py_buffer master; -} - -final class PyMemoryViewObject extends ffi.Struct { - external PyVarObject ob_base; - - external ffi.Pointer<_PyManagedBufferObject> mbuf; - - @Py_hash_t() - external int hash; - - @ffi.Int() - external int flags; - - @Py_ssize_t() - external int exports; - - external Py_buffer view; - - external ffi.Pointer weakreflist; - - @ffi.Array.multi([1]) - external ffi.Array ob_array; -} - -final class PyTupleObject extends ffi.Struct { - external PyVarObject ob_base; - - @ffi.Array.multi([1]) - external ffi.Array> ob_item; -} - -final class PyListObject extends ffi.Struct { - external PyVarObject ob_base; - - external ffi.Pointer> ob_item; - - @Py_ssize_t() - external int allocated; -} - -final class _dictvalues extends ffi.Opaque {} - -final class PyDictObject extends ffi.Struct { - external PyObject ob_base; - - @Py_ssize_t() - external int ma_used; - - @ffi.Uint64() - external int ma_version_tag; - - external ffi.Pointer ma_keys; - - external ffi.Pointer ma_values; -} - -typedef PyDictKeysObject = _dictkeysobject; -typedef PyDictValues = _dictvalues; - -final class _PyDictViewObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer dv_dict; -} - -abstract class PyDict_WatchEvent { - static const int PyDict_EVENT_ADDED = 0; - static const int PyDict_EVENT_MODIFIED = 1; - static const int PyDict_EVENT_DELETED = 2; - static const int PyDict_EVENT_CLONED = 3; - static const int PyDict_EVENT_CLEARED = 4; - static const int PyDict_EVENT_DEALLOCATED = 5; -} - -typedef PyDict_WatchCallback = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Int32 event, ffi.Pointer dict, - ffi.Pointer key, ffi.Pointer new_value)>>; - -final class _odictobject extends ffi.Opaque {} - -final class setentry extends ffi.Struct { - external ffi.Pointer key; - - @Py_hash_t() - external int hash; -} - -final class PySetObject extends ffi.Struct { - external PyObject ob_base; - - @Py_ssize_t() - external int fill; - - @Py_ssize_t() - external int used; - - @Py_ssize_t() - external int mask; - - external ffi.Pointer table; - - @Py_hash_t() - external int hash; - - @Py_ssize_t() - external int finger; - - @ffi.Array.multi([8]) - external ffi.Array smalltable; - - external ffi.Pointer weakreflist; -} - -final class PyCFunctionObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer m_ml; - - external ffi.Pointer m_self; - - external ffi.Pointer m_module; - - external ffi.Pointer m_weakreflist; - - external vectorcallfunc vectorcall; -} - -final class PyCMethodObject extends ffi.Struct { - external PyCFunctionObject func; - - external ffi.Pointer mm_class; -} - -final class PyFrameConstructor extends ffi.Struct { - external ffi.Pointer fc_globals; - - external ffi.Pointer fc_builtins; - - external ffi.Pointer fc_name; - - external ffi.Pointer fc_qualname; - - external ffi.Pointer fc_code; - - external ffi.Pointer fc_defaults; - - external ffi.Pointer fc_kwdefaults; - - external ffi.Pointer fc_closure; -} - -final class PyFunctionObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer func_globals; - - external ffi.Pointer func_builtins; - - external ffi.Pointer func_name; - - external ffi.Pointer func_qualname; - - external ffi.Pointer func_code; - - external ffi.Pointer func_defaults; - - external ffi.Pointer func_kwdefaults; - - external ffi.Pointer func_closure; - - external ffi.Pointer func_doc; - - external ffi.Pointer func_dict; - - external ffi.Pointer func_weakreflist; - - external ffi.Pointer func_module; - - external ffi.Pointer func_annotations; - - external ffi.Pointer func_typeparams; - - external vectorcallfunc vectorcall; - - @ffi.Uint32() - external int func_version; -} - -abstract class PyFunction_WatchEvent { - static const int PyFunction_EVENT_CREATE = 0; - static const int PyFunction_EVENT_DESTROY = 1; - static const int PyFunction_EVENT_MODIFY_CODE = 2; - static const int PyFunction_EVENT_MODIFY_DEFAULTS = 3; - static const int PyFunction_EVENT_MODIFY_KWDEFAULTS = 4; -} - -typedef PyFunction_WatchCallback = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Int32 event, ffi.Pointer func, - ffi.Pointer new_value)>>; - -final class PyMethodObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer im_func; - - external ffi.Pointer im_self; - - external ffi.Pointer im_weakreflist; - - external vectorcallfunc vectorcall; -} - -final class PyInstanceMethodObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer func; -} - -typedef Py_OpenCodeHookFunction = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>; -typedef PyCapsule_Destructor - = ffi.Pointer)>>; - -final class _Py_GlobalMonitors extends ffi.Struct { - @ffi.Array.multi([15]) - external ffi.Array tools; -} - -final class _Py_CODEUNIT extends ffi.Union { - @ffi.Uint16() - external int cache; - - external UnnamedStruct7 op; -} - -final class UnnamedStruct7 extends ffi.Struct { - @ffi.Uint8() - external int code; - - @ffi.Uint8() - external int arg; -} - -abstract class PyCodeEvent { - static const int PY_CODE_EVENT_CREATE = 0; - static const int PY_CODE_EVENT_DESTROY = 1; -} - -typedef PyCode_WatchCallback = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Int32 event, ffi.Pointer co)>>; - -final class _opaque extends ffi.Struct { - @ffi.Int() - external int computed_line; - - external ffi.Pointer lo_next; - - external ffi.Pointer limit; -} - -final class _line_offsets extends ffi.Struct { - @ffi.Int() - external int ar_start; - - @ffi.Int() - external int ar_end; - - @ffi.Int() - external int ar_line; - - external _opaque opaque; -} - -typedef PyCodeAddressRange = _line_offsets; - -abstract class _PyCodeLocationInfoKind { - static const int PY_CODE_LOCATION_INFO_SHORT0 = 0; - static const int PY_CODE_LOCATION_INFO_ONE_LINE0 = 10; - static const int PY_CODE_LOCATION_INFO_ONE_LINE1 = 11; - static const int PY_CODE_LOCATION_INFO_ONE_LINE2 = 12; - static const int PY_CODE_LOCATION_INFO_NO_COLUMNS = 13; - static const int PY_CODE_LOCATION_INFO_LONG = 14; - static const int PY_CODE_LOCATION_INFO_NONE = 15; -} - -final class _traceback extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer tb_next; - - external ffi.Pointer tb_frame; - - @ffi.Int() - external int tb_lasti; - - @ffi.Int() - external int tb_lineno; -} - -typedef PyTracebackObject = _traceback; - -final class PySliceObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer start; - - external ffi.Pointer stop; - - external ffi.Pointer step; -} - -final class PyCellObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer ob_ref; -} - -final class PyGenObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer gi_weakreflist; - - external ffi.Pointer gi_name; - - external ffi.Pointer gi_qualname; - - external _PyErr_StackItem gi_exc_state; - - external ffi.Pointer gi_origin_or_finalizer; - - @ffi.Char() - external int gi_hooks_inited; - - @ffi.Char() - external int gi_closed; - - @ffi.Char() - external int gi_running_async; - - @ffi.Int8() - external int gi_frame_state; - - @ffi.Array.multi([1]) - external ffi.Array> gi_iframe; -} - -final class PyCoroObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer cr_weakreflist; - - external ffi.Pointer cr_name; - - external ffi.Pointer cr_qualname; - - external _PyErr_StackItem cr_exc_state; - - external ffi.Pointer cr_origin_or_finalizer; - - @ffi.Char() - external int cr_hooks_inited; - - @ffi.Char() - external int cr_closed; - - @ffi.Char() - external int cr_running_async; - - @ffi.Int8() - external int cr_frame_state; - - @ffi.Array.multi([1]) - external ffi.Array> cr_iframe; -} - -final class PyAsyncGenObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer ag_weakreflist; - - external ffi.Pointer ag_name; - - external ffi.Pointer ag_qualname; - - external _PyErr_StackItem ag_exc_state; - - external ffi.Pointer ag_origin_or_finalizer; - - @ffi.Char() - external int ag_hooks_inited; - - @ffi.Char() - external int ag_closed; - - @ffi.Char() - external int ag_running_async; - - @ffi.Int8() - external int ag_frame_state; - - @ffi.Array.multi([1]) - external ffi.Array> ag_iframe; -} - -final class wrapperbase extends ffi.Struct { - external ffi.Pointer name; - - @ffi.Int() - external int offset; - - external ffi.Pointer function; - - external wrapperfunc wrapper; - - external ffi.Pointer doc; - - @ffi.Int() - external int flags; - - external ffi.Pointer name_strobj; -} - -typedef wrapperfunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Pointer Function(ffi.Pointer self, - ffi.Pointer args, ffi.Pointer wrapped)>>; - -final class PyDescrObject extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer d_type; - - external ffi.Pointer d_name; - - external ffi.Pointer d_qualname; -} - -final class PyMethodDescrObject extends ffi.Struct { - external PyDescrObject d_common; - - external ffi.Pointer d_method; - - external vectorcallfunc vectorcall; -} - -final class PyMemberDescrObject extends ffi.Struct { - external PyDescrObject d_common; - - external ffi.Pointer d_member; -} - -final class PyGetSetDescrObject extends ffi.Struct { - external PyDescrObject d_common; - - external ffi.Pointer d_getset; -} - -final class PyWrapperDescrObject extends ffi.Struct { - external PyDescrObject d_common; - - external ffi.Pointer d_base; - - external ffi.Pointer d_wrapped; -} - -final class _PyWeakReference extends ffi.Struct { - external PyObject ob_base; - - external ffi.Pointer wr_object; - - external ffi.Pointer wr_callback; - - @Py_hash_t() - external int hash; - - external ffi.Pointer wr_prev; - - external ffi.Pointer wr_next; - - external vectorcallfunc vectorcall; -} - -typedef PyWeakReference = _PyWeakReference; - -final class PyStructSequence_Field extends ffi.Struct { - external ffi.Pointer name; - - external ffi.Pointer doc; -} - -final class PyStructSequence_Desc extends ffi.Struct { - external ffi.Pointer name; - - external ffi.Pointer doc; - - external ffi.Pointer fields; - - @ffi.Int() - external int n_in_sequence; -} - -final class timeval extends ffi.Struct { - @__darwin_time_t() - external int tv_sec; - - @__darwin_suseconds_t() - external int tv_usec; -} - -typedef __darwin_time_t = ffi.Long; -typedef __darwin_suseconds_t = __int32_t; -typedef __int32_t = ffi.Int; - -abstract class _PyTime_round_t { - static const int _PyTime_ROUND_FLOOR = 0; - static const int _PyTime_ROUND_CEILING = 1; - static const int _PyTime_ROUND_HALF_EVEN = 2; - static const int _PyTime_ROUND_UP = 3; - static const int _PyTime_ROUND_TIMEOUT = 3; -} - -typedef time_t = __darwin_time_t; -typedef _PyTime_t = ffi.Int64; - -final class timespec extends ffi.Struct { - @__darwin_time_t() - external int tv_sec; - - @ffi.Long() - external int tv_nsec; -} - -final class _Py_clock_info_t extends ffi.Struct { - external ffi.Pointer implementation; - - @ffi.Int() - external int monotonic; - - @ffi.Int() - external int adjustable; - - @ffi.Double() - external double resolution; -} - -final class tm extends ffi.Struct { - @ffi.Int() - external int tm_sec; - - @ffi.Int() - external int tm_min; - - @ffi.Int() - external int tm_hour; - - @ffi.Int() - external int tm_mday; - - @ffi.Int() - external int tm_mon; - - @ffi.Int() - external int tm_year; - - @ffi.Int() - external int tm_wday; - - @ffi.Int() - external int tm_yday; - - @ffi.Int() - external int tm_isdst; - - @ffi.Long() - external int tm_gmtoff; - - external ffi.Pointer tm_zone; -} - -abstract class PyLockStatus { - static const int PY_LOCK_FAILURE = 0; - static const int PY_LOCK_ACQUIRED = 1; - static const int PY_LOCK_INTR = 2; -} - -typedef PyThread_type_lock = ffi.Pointer; - -final class _Py_tss_t extends ffi.Struct { - @ffi.Int() - external int _is_initialized; - - @pthread_key_t() - external int _key; -} - -typedef pthread_key_t = __darwin_pthread_key_t; -typedef __darwin_pthread_key_t = ffi.UnsignedLong; -typedef Py_tss_t = _Py_tss_t; - -final class _pycontextobject extends ffi.Opaque {} - -final class _pycontextvarobject extends ffi.Opaque {} - -final class _pycontexttokenobject extends ffi.Opaque {} - -final class _PyArg_Parser extends ffi.Struct { - @ffi.Int() - external int initialized; - - external ffi.Pointer format; - - external ffi.Pointer> keywords; - - external ffi.Pointer fname; - - external ffi.Pointer custom_msg; - - @ffi.Int() - external int pos; - - @ffi.Int() - external int min; - - @ffi.Int() - external int max; - - external ffi.Pointer kwtuple; - - external ffi.Pointer<_PyArg_Parser> next; -} - -final class PyCompilerFlags extends ffi.Struct { - @ffi.Int() - external int cf_flags; - - @ffi.Int() - external int cf_feature_version; -} - -final class _PyCompilerSrcLocation extends ffi.Struct { - @ffi.Int() - external int lineno; - - @ffi.Int() - external int end_lineno; - - @ffi.Int() - external int col_offset; - - @ffi.Int() - external int end_col_offset; -} - -final class PyFutureFeatures extends ffi.Struct { - @ffi.Int() - external int ff_features; - - external _PyCompilerSrcLocation ff_location; -} - -typedef PyOS_sighandler_t - = ffi.Pointer>; - -final class PyInterpreterConfig extends ffi.Struct { - @ffi.Int() - external int use_main_obmalloc; - - @ffi.Int() - external int allow_fork; - - @ffi.Int() - external int allow_exec; - - @ffi.Int() - external int allow_threads; - - @ffi.Int() - external int allow_daemon_threads; - - @ffi.Int() - external int check_multi_interp_extensions; - - @ffi.Int() - external int gil; -} - -typedef atexit_datacallbackfunc - = ffi.Pointer)>>; -typedef Py_tracefunc = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Int, ffi.Pointer)>>; - -final class PerfMapState extends ffi.Struct { - external ffi.Pointer perf_map; - - external PyThread_type_lock map_lock; -} - -typedef Py_AuditHookFunction = ffi.Pointer< - ffi.NativeFunction< - ffi.Int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>; - -final class _inittab extends ffi.Struct { - external ffi.Pointer name; - - external ffi.Pointer Function()>> - initfunc; -} - -final class _frozen extends ffi.Struct { - external ffi.Pointer name; - - external ffi.Pointer code; - - @ffi.Int() - external int size; - - @ffi.Int() - external int is_package; - - external ffi.Pointer Function()>> - get_code; -} - -const int _PyStatus_TYPE_OK = 0; - -const int _PyStatus_TYPE_ERROR = 1; - -const int _PyStatus_TYPE_EXIT = 2; - -const int PY_RELEASE_LEVEL_ALPHA = 10; - -const int PY_RELEASE_LEVEL_BETA = 11; - -const int PY_RELEASE_LEVEL_GAMMA = 12; - -const int PY_RELEASE_LEVEL_FINAL = 15; - -const int PY_MAJOR_VERSION = 3; - -const int PY_MINOR_VERSION = 12; - -const int PY_MICRO_VERSION = 3; - -const int PY_RELEASE_LEVEL = 15; - -const int PY_RELEASE_SERIAL = 0; - -const String PY_VERSION = '3.12.3'; - -const int PY_VERSION_HEX = 51119088; - -const int ALIGNOF_LONG = 8; - -const int ALIGNOF_MAX_ALIGN_T = 8; - -const int ALIGNOF_SIZE_T = 8; - -const int ANDROID_API_LEVEL = 21; - -const int ENABLE_IPV6 = 1; - -const int HAVE_ACCEPT = 1; - -const int HAVE_ACCEPT4 = 1; - -const int HAVE_ACOSH = 1; - -const int HAVE_ADDRINFO = 1; - -const int HAVE_ALARM = 1; - -const int HAVE_ALLOCA_H = 1; - -const int HAVE_ASINH = 1; - -const int HAVE_ASM_TYPES_H = 1; - -const int HAVE_ATANH = 1; - -const int HAVE_BIND = 1; - -const int HAVE_BROKEN_SEM_GETVALUE = 1; - -const int HAVE_BUILTIN_ATOMIC = 1; - -const int HAVE_CHMOD = 1; - -const int HAVE_CHOWN = 1; - -const int HAVE_CHROOT = 1; - -const int HAVE_CLOCK = 1; - -const int HAVE_CLOCK_GETRES = 1; - -const int HAVE_CLOCK_GETTIME = 1; - -const int HAVE_CLOCK_NANOSLEEP = 1; - -const int HAVE_CLOCK_SETTIME = 1; - -const int HAVE_CONNECT = 1; - -const int HAVE_DECL_RTLD_DEEPBIND = 0; - -const int HAVE_DECL_RTLD_GLOBAL = 1; - -const int HAVE_DECL_RTLD_LAZY = 1; - -const int HAVE_DECL_RTLD_LOCAL = 1; - -const int HAVE_DECL_RTLD_MEMBER = 0; - -const int HAVE_DECL_RTLD_NODELETE = 1; - -const int HAVE_DECL_RTLD_NOLOAD = 1; - -const int HAVE_DECL_RTLD_NOW = 1; - -const int HAVE_DEVICE_MACROS = 1; - -const int HAVE_DIRENT_D_TYPE = 1; - -const int HAVE_DIRENT_H = 1; - -const int HAVE_DIRFD = 1; - -const int HAVE_DLFCN_H = 1; - -const int HAVE_DLOPEN = 1; - -const int HAVE_DUP = 1; - -const int HAVE_DUP2 = 1; - -const int HAVE_DUP3 = 1; - -const int HAVE_DYNAMIC_LOADING = 1; - -const int HAVE_ENDIAN_H = 1; - -const int HAVE_EPOLL = 1; - -const int HAVE_EPOLL_CREATE1 = 1; - -const int HAVE_ERF = 1; - -const int HAVE_ERFC = 1; - -const int HAVE_ERRNO_H = 1; - -const int HAVE_EVENTFD = 1; - -const int HAVE_EXECV = 1; - -const int HAVE_EXPM1 = 1; - -const int HAVE_FACCESSAT = 1; - -const int HAVE_FCHDIR = 1; - -const int HAVE_FCHMOD = 1; - -const int HAVE_FCHMODAT = 1; - -const int HAVE_FCHOWN = 1; - -const int HAVE_FCHOWNAT = 1; - -const int HAVE_FCNTL_H = 1; - -const int HAVE_FDATASYNC = 1; - -const int HAVE_FDOPENDIR = 1; - -const int HAVE_FFI_CLOSURE_ALLOC = 1; - -const int HAVE_FFI_PREP_CIF_VAR = 1; - -const int HAVE_FFI_PREP_CLOSURE_LOC = 1; - -const int HAVE_FLOCK = 1; - -const int HAVE_FORK = 1; - -const int HAVE_FPATHCONF = 1; - -const int HAVE_FSEEKO = 1; - -const int HAVE_FSTATAT = 1; - -const int HAVE_FSTATVFS = 1; - -const int HAVE_FSYNC = 1; - -const int HAVE_FTELLO = 1; - -const int HAVE_FTRUNCATE = 1; - -const int HAVE_FUTIMENS = 1; - -const int HAVE_GAI_STRERROR = 1; - -const int HAVE_GCC_UINT128_T = 1; - -const int HAVE_GETADDRINFO = 1; - -const int HAVE_GETC_UNLOCKED = 1; - -const int HAVE_GETEGID = 1; - -const int HAVE_GETEUID = 1; - -const int HAVE_GETGID = 1; - -const int HAVE_GETGRGID = 1; - -const int HAVE_GETGROUPLIST = 1; - -const int HAVE_GETGROUPS = 1; - -const int HAVE_GETHOSTBYADDR = 1; - -const int HAVE_GETHOSTBYNAME = 1; - -const int HAVE_GETHOSTBYNAME_R = 1; - -const int HAVE_GETHOSTBYNAME_R_6_ARG = 1; - -const int HAVE_GETHOSTNAME = 1; - -const int HAVE_GETITIMER = 1; - -const int HAVE_GETLOGIN = 1; - -const int HAVE_GETNAMEINFO = 1; - -const int HAVE_GETPAGESIZE = 1; - -const int HAVE_GETPEERNAME = 1; - -const int HAVE_GETPGID = 1; - -const int HAVE_GETPGRP = 1; - -const int HAVE_GETPID = 1; - -const int HAVE_GETPPID = 1; - -const int HAVE_GETPRIORITY = 1; - -const int HAVE_GETPROTOBYNAME = 1; - -const int HAVE_GETPWNAM_R = 1; - -const int HAVE_GETPWUID = 1; - -const int HAVE_GETPWUID_R = 1; - -const int HAVE_GETRANDOM_SYSCALL = 1; - -const int HAVE_GETRESGID = 1; - -const int HAVE_GETRESUID = 1; - -const int HAVE_GETRUSAGE = 1; - -const int HAVE_GETSERVBYNAME = 1; - -const int HAVE_GETSERVBYPORT = 1; - -const int HAVE_GETSID = 1; - -const int HAVE_GETSOCKNAME = 1; - -const int HAVE_GETUID = 1; - -const int HAVE_GRP_H = 1; - -const int HAVE_HSTRERROR = 1; - -const int HAVE_HTOLE64 = 1; - -const int HAVE_INET_ATON = 1; - -const int HAVE_INET_NTOA = 1; - -const int HAVE_INET_PTON = 1; - -const int HAVE_INITGROUPS = 1; - -const int HAVE_INTTYPES_H = 1; - -const int HAVE_KILL = 1; - -const int HAVE_KILLPG = 1; - -const int HAVE_LANGINFO_H = 1; - -const int HAVE_LCHOWN = 1; - -const int HAVE_LIBDL = 1; - -const int HAVE_LINK = 1; - -const int HAVE_LINKAT = 1; - -const int HAVE_LINUX_AUXVEC_H = 1; - -const int HAVE_LINUX_CAN_BCM_H = 1; - -const int HAVE_LINUX_CAN_H = 1; - -const int HAVE_LINUX_CAN_J1939_H = 1; - -const int HAVE_LINUX_CAN_RAW_FD_FRAMES = 1; - -const int HAVE_LINUX_CAN_RAW_H = 1; - -const int HAVE_LINUX_CAN_RAW_JOIN_FILTERS = 1; - -const int HAVE_LINUX_FS_H = 1; - -const int HAVE_LINUX_LIMITS_H = 1; - -const int HAVE_LINUX_MEMFD_H = 1; - -const int HAVE_LINUX_NETLINK_H = 1; - -const int HAVE_LINUX_QRTR_H = 1; - -const int HAVE_LINUX_RANDOM_H = 1; - -const int HAVE_LINUX_SOUNDCARD_H = 1; - -const int HAVE_LINUX_TIPC_H = 1; - -const int HAVE_LINUX_VM_SOCKETS_H = 1; - -const int HAVE_LINUX_WAIT_H = 1; - -const int HAVE_LISTEN = 1; - -const int HAVE_LOG1P = 1; - -const int HAVE_LOG2 = 1; - -const int HAVE_LONG_DOUBLE = 1; - -const int HAVE_LSTAT = 1; - -const int HAVE_MADVISE = 1; - -const int HAVE_MAKEDEV = 1; - -const int HAVE_MBRTOWC = 1; - -const int HAVE_MEMRCHR = 1; - -const int HAVE_MKDIRAT = 1; - -const int HAVE_MKFIFO = 1; - -const int HAVE_MKNOD = 1; - -const int HAVE_MKNODAT = 1; - -const int HAVE_MKTIME = 1; - -const int HAVE_MMAP = 1; - -const int HAVE_MREMAP = 1; - -const int HAVE_NANOSLEEP = 1; - -const int HAVE_NETDB_H = 1; - -const int HAVE_NETINET_IN_H = 1; - -const int HAVE_NETPACKET_PACKET_H = 1; - -const int HAVE_NET_ETHERNET_H = 1; - -const int HAVE_NET_IF_H = 1; - -const int HAVE_NICE = 1; - -const int HAVE_OPENAT = 1; - -const int HAVE_OPENDIR = 1; - -const int HAVE_PATHCONF = 1; - -const int HAVE_PAUSE = 1; - -const int HAVE_PIPE = 1; - -const int HAVE_PIPE2 = 1; - -const int HAVE_POLL = 1; - -const int HAVE_POLL_H = 1; - -const int HAVE_POSIX_FADVISE = 1; - -const int HAVE_POSIX_FALLOCATE = 1; - -const int HAVE_PREAD = 1; - -const int HAVE_PRLIMIT = 1; - -const int HAVE_PROTOTYPES = 1; - -const int HAVE_PTHREAD_CONDATTR_SETCLOCK = 1; - -const int HAVE_PTHREAD_GETCPUCLOCKID = 1; - -const int HAVE_PTHREAD_H = 1; - -const int HAVE_PTHREAD_KILL = 1; - -const int HAVE_PTHREAD_SIGMASK = 1; - -const int HAVE_PTY_H = 1; - -const int HAVE_PWRITE = 1; - -const int HAVE_READLINK = 1; - -const int HAVE_READLINKAT = 1; - -const int HAVE_READV = 1; - -const int HAVE_REALPATH = 1; - -const int HAVE_RECVFROM = 1; - -const int HAVE_RENAMEAT = 1; - -const int HAVE_SCHED_GET_PRIORITY_MAX = 1; - -const int HAVE_SCHED_H = 1; - -const int HAVE_SCHED_RR_GET_INTERVAL = 1; - -const int HAVE_SCHED_SETAFFINITY = 1; - -const int HAVE_SCHED_SETPARAM = 1; - -const int HAVE_SCHED_SETSCHEDULER = 1; - -const int HAVE_SEM_GETVALUE = 1; - -const int HAVE_SEM_OPEN = 1; - -const int HAVE_SEM_TIMEDWAIT = 1; - -const int HAVE_SEM_UNLINK = 1; - -const int HAVE_SENDFILE = 1; - -const int HAVE_SENDTO = 1; - -const int HAVE_SETEGID = 1; - -const int HAVE_SETEUID = 1; - -const int HAVE_SETGID = 1; - -const int HAVE_SETGROUPS = 1; - -const int HAVE_SETITIMER = 1; - -const int HAVE_SETJMP_H = 1; - -const int HAVE_SETLOCALE = 1; - -const int HAVE_SETNS = 1; - -const int HAVE_SETPGID = 1; - -const int HAVE_SETPGRP = 1; - -const int HAVE_SETPRIORITY = 1; - -const int HAVE_SETREGID = 1; - -const int HAVE_SETRESGID = 1; - -const int HAVE_SETRESUID = 1; - -const int HAVE_SETREUID = 1; - -const int HAVE_SETSID = 1; - -const int HAVE_SETSOCKOPT = 1; - -const int HAVE_SETUID = 1; - -const int HAVE_SETVBUF = 1; - -const int HAVE_SHUTDOWN = 1; - -const int HAVE_SIGACTION = 1; - -const int HAVE_SIGALTSTACK = 1; - -const int HAVE_SIGFILLSET = 1; - -const int HAVE_SIGINFO_T_SI_BAND = 1; - -const int HAVE_SIGINTERRUPT = 1; - -const int HAVE_SIGNAL_H = 1; - -const int HAVE_SIGPENDING = 1; - -const int HAVE_SIGWAIT = 1; - -const int HAVE_SNPRINTF = 1; - -const int HAVE_SOCKADDR_ALG = 1; - -const int HAVE_SOCKADDR_STORAGE = 1; - -const int HAVE_SOCKET = 1; - -const int HAVE_SOCKETPAIR = 1; - -const int HAVE_SPAWN_H = 1; - -const int HAVE_SPLICE = 1; - -const int HAVE_SSIZE_T = 1; - -const int HAVE_STATVFS = 1; - -const int HAVE_STAT_TV_NSEC = 1; - -const int HAVE_STDINT_H = 1; - -const int HAVE_STDIO_H = 1; - -const int HAVE_STDLIB_H = 1; - -const int HAVE_STD_ATOMIC = 1; - -const int HAVE_STRFTIME = 1; - -const int HAVE_STRINGS_H = 1; - -const int HAVE_STRING_H = 1; - -const int HAVE_STRLCPY = 1; - -const int HAVE_STRSIGNAL = 1; - -const int HAVE_STRUCT_PASSWD_PW_GECOS = 1; - -const int HAVE_STRUCT_PASSWD_PW_PASSWD = 1; - -const int HAVE_STRUCT_STAT_ST_BLKSIZE = 1; - -const int HAVE_STRUCT_STAT_ST_BLOCKS = 1; - -const int HAVE_STRUCT_STAT_ST_RDEV = 1; - -const int HAVE_STRUCT_TM_TM_ZONE = 1; - -const int HAVE_SYMLINK = 1; - -const int HAVE_SYMLINKAT = 1; - -const int HAVE_SYNC = 1; - -const int HAVE_SYSCONF = 1; - -const int HAVE_SYSEXITS_H = 1; - -const int HAVE_SYSLOG_H = 1; - -const int HAVE_SYSTEM = 1; - -const int HAVE_SYS_AUXV_H = 1; - -const int HAVE_SYS_ENDIAN_H = 1; - -const int HAVE_SYS_EPOLL_H = 1; - -const int HAVE_SYS_EVENTFD_H = 1; - -const int HAVE_SYS_FILE_H = 1; - -const int HAVE_SYS_IOCTL_H = 1; - -const int HAVE_SYS_MMAN_H = 1; - -const int HAVE_SYS_PARAM_H = 1; - -const int HAVE_SYS_POLL_H = 1; - -const int HAVE_SYS_RANDOM_H = 1; - -const int HAVE_SYS_RESOURCE_H = 1; - -const int HAVE_SYS_SELECT_H = 1; - -const int HAVE_SYS_SENDFILE_H = 1; - -const int HAVE_SYS_SOCKET_H = 1; - -const int HAVE_SYS_STATVFS_H = 1; - -const int HAVE_SYS_STAT_H = 1; - -const int HAVE_SYS_SYSCALL_H = 1; - -const int HAVE_SYS_SYSMACROS_H = 1; - -const int HAVE_SYS_TIMES_H = 1; - -const int HAVE_SYS_TIME_H = 1; - -const int HAVE_SYS_TYPES_H = 1; - -const int HAVE_SYS_UIO_H = 1; - -const int HAVE_SYS_UN_H = 1; - -const int HAVE_SYS_UTSNAME_H = 1; - -const int HAVE_SYS_WAIT_H = 1; - -const int HAVE_SYS_XATTR_H = 1; - -const int HAVE_TCGETPGRP = 1; - -const int HAVE_TCSETPGRP = 1; - -const int HAVE_TEMPNAM = 1; - -const int HAVE_TERMIOS_H = 1; - -const int HAVE_TIMEGM = 1; - -const int HAVE_TIMES = 1; - -const int HAVE_TMPFILE = 1; - -const int HAVE_TMPNAM = 1; - -const int HAVE_TM_ZONE = 1; - -const int HAVE_TRUNCATE = 1; - -const int HAVE_TTYNAME = 1; - -const int HAVE_UMASK = 1; - -const int HAVE_UNAME = 1; - -const int HAVE_UNISTD_H = 1; - -const int HAVE_UNLINKAT = 1; - -const int HAVE_UNSHARE = 1; - -const int HAVE_UTIMENSAT = 1; - -const int HAVE_UTIMES = 1; - -const int HAVE_UTIME_H = 1; - -const int HAVE_UTMP_H = 1; - -const int HAVE_VFORK = 1; - -const int HAVE_WAIT = 1; - -const int HAVE_WAIT4 = 1; - -const int HAVE_WAITID = 1; - -const int HAVE_WAITPID = 1; - -const int HAVE_WCHAR_H = 1; - -const int HAVE_WCSCOLL = 1; - -const int HAVE_WCSFTIME = 1; - -const int HAVE_WCSXFRM = 1; - -const int HAVE_WMEMCMP = 1; - -const int HAVE_WRITEV = 1; - -const int HAVE_ZLIB_COPY = 1; - -const int HAVE_ZLIB_H = 1; - -const int MAJOR_IN_SYSMACROS = 1; - -const int PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT = 1; - -const String PY_BUILTIN_HASHLIB_HASHES = 'md5,sha1,sha2,sha3,blake2'; - -const int PY_COERCE_C_LOCALE = 1; - -const int PY_SSL_DEFAULT_CIPHERS = 1; - -const int PY_SUPPORT_TIER = 0; - -const int Py_ENABLE_SHARED = 1; - -const int SIZEOF_DOUBLE = 8; - -const int SIZEOF_FLOAT = 4; - -const int SIZEOF_FPOS_T = 8; - -const int SIZEOF_INT = 4; - -const int SIZEOF_LONG = 8; - -const int SIZEOF_LONG_DOUBLE = 8; - -const int SIZEOF_LONG_LONG = 8; - -const int SIZEOF_OFF_T = 8; - -const int SIZEOF_PID_T = 4; - -const int SIZEOF_PTHREAD_KEY_T = 4; - -const int SIZEOF_PTHREAD_T = 8; - -const int SIZEOF_SHORT = 2; - -const int SIZEOF_SIZE_T = 8; - -const int SIZEOF_TIME_T = 8; - -const int SIZEOF_UINTPTR_T = 8; - -const int SIZEOF_VOID_P = 8; - -const int SIZEOF_WCHAR_T = 4; - -const int SIZEOF__BOOL = 1; - -const int STDC_HEADERS = 1; - -const int SYS_SELECT_WITH_SYS_TIME = 1; - -const int _ALL_SOURCE = 1; - -const int _DARWIN_C_SOURCE = 1; - -const int __EXTENSIONS__ = 1; - -const int _GNU_SOURCE = 1; - -const int _HPUX_ALT_XOPEN_SOCKET_API = 1; - -const int _NETBSD_SOURCE = 1; - -const int _OPENBSD_SOURCE = 1; - -const int _POSIX_PTHREAD_SEMANTICS = 1; - -const int __STDC_WANT_IEC_60559_ATTRIBS_EXT__ = 1; - -const int __STDC_WANT_IEC_60559_BFP_EXT__ = 1; - -const int __STDC_WANT_IEC_60559_DFP_EXT__ = 1; - -const int __STDC_WANT_IEC_60559_FUNCS_EXT__ = 1; - -const int __STDC_WANT_IEC_60559_TYPES_EXT__ = 1; - -const int __STDC_WANT_LIB_EXT2__ = 1; - -const int __STDC_WANT_MATH_SPEC_FUNCS__ = 1; - -const int _TANDEM_SOURCE = 1; - -const int _XOPEN_SOURCE = 700; - -const int WITH_DECIMAL_CONTEXTVAR = 1; - -const int WITH_DOC_STRINGS = 1; - -const int WITH_FREELISTS = 1; - -const int WITH_PYMALLOC = 1; - -const int _POSIX_C_SOURCE = 200809; - -const String _PYTHONFRAMEWORK = ''; - -const int _REENTRANT = 1; - -const int _XOPEN_SOURCE_EXTENDED = 1; - -const int __BSD_VISIBLE = 1; - -const int HAVE_LONG_LONG = 1; - -const int PY_LLONG_MIN = -9223372036854775808; - -const int PY_LLONG_MAX = 9223372036854775807; - -const int PY_ULLONG_MAX = -1; - -const int PYLONG_BITS_IN_DIGIT = 30; - -const int PY_SSIZE_T_MAX = 9223372036854775807; - -const int PY_SSIZE_T_MIN = -9223372036854775808; - -const int SIZEOF_PY_HASH_T = 8; - -const int SIZEOF_PY_UHASH_T = 8; - -const int PY_SIZE_MAX = -1; - -const String PY_FORMAT_SIZE_T = 'z'; - -const int PY_BIG_ENDIAN = 0; - -const int PY_LITTLE_ENDIAN = 1; - -const int PY_DWORD_MAX = 4294967295; - -const double Py_MATH_PIl = 3.141592653589793; - -const double Py_MATH_PI = 3.141592653589793; - -const double Py_MATH_El = 2.718281828459045; - -const double Py_MATH_E = 2.718281828459045; - -const double Py_MATH_TAU = 6.283185307179586; - -const double Py_INFINITY = double.infinity; - -const double Py_HUGE_VAL = double.infinity; - -const double Py_NAN = double.nan; - -const int PyBUF_MAX_NDIM = 64; - -const int PyBUF_SIMPLE = 0; - -const int PyBUF_WRITABLE = 1; - -const int PyBUF_WRITEABLE = 1; - -const int PyBUF_FORMAT = 4; - -const int PyBUF_ND = 8; - -const int PyBUF_STRIDES = 24; - -const int PyBUF_C_CONTIGUOUS = 56; - -const int PyBUF_F_CONTIGUOUS = 88; - -const int PyBUF_ANY_CONTIGUOUS = 152; - -const int PyBUF_INDIRECT = 280; - -const int PyBUF_CONTIG = 9; - -const int PyBUF_CONTIG_RO = 8; - -const int PyBUF_STRIDED = 25; - -const int PyBUF_STRIDED_RO = 24; - -const int PyBUF_RECORDS = 29; - -const int PyBUF_RECORDS_RO = 28; - -const int PyBUF_FULL = 285; - -const int PyBUF_FULL_RO = 284; - -const int PyBUF_READ = 256; - -const int PyBUF_WRITE = 512; - -const int _Py_IMMORTAL_REFCNT = 4294967295; - -const int Py_INVALID_SIZE = -1; - -const int Py_PRINT_RAW = 1; - -const int _Py_TPFLAGS_STATIC_BUILTIN = 2; - -const int Py_TPFLAGS_MANAGED_WEAKREF = 8; - -const int Py_TPFLAGS_MANAGED_DICT = 16; - -const int Py_TPFLAGS_PREHEADER = 24; - -const int Py_TPFLAGS_SEQUENCE = 32; - -const int Py_TPFLAGS_MAPPING = 64; - -const int Py_TPFLAGS_DISALLOW_INSTANTIATION = 128; - -const int Py_TPFLAGS_IMMUTABLETYPE = 256; - -const int Py_TPFLAGS_HEAPTYPE = 512; - -const int Py_TPFLAGS_BASETYPE = 1024; - -const int Py_TPFLAGS_HAVE_VECTORCALL = 2048; - -const int _Py_TPFLAGS_HAVE_VECTORCALL = 2048; - -const int Py_TPFLAGS_READY = 4096; - -const int Py_TPFLAGS_READYING = 8192; - -const int Py_TPFLAGS_HAVE_GC = 16384; - -const int Py_TPFLAGS_HAVE_STACKLESS_EXTENSION = 0; - -const int Py_TPFLAGS_METHOD_DESCRIPTOR = 131072; - -const int Py_TPFLAGS_VALID_VERSION_TAG = 524288; - -const int Py_TPFLAGS_IS_ABSTRACT = 1048576; - -const int _Py_TPFLAGS_MATCH_SELF = 4194304; - -const int Py_TPFLAGS_ITEMS_AT_END = 8388608; - -const int Py_TPFLAGS_LONG_SUBCLASS = 16777216; - -const int Py_TPFLAGS_LIST_SUBCLASS = 33554432; - -const int Py_TPFLAGS_TUPLE_SUBCLASS = 67108864; - -const int Py_TPFLAGS_BYTES_SUBCLASS = 134217728; - -const int Py_TPFLAGS_UNICODE_SUBCLASS = 268435456; - -const int Py_TPFLAGS_DICT_SUBCLASS = 536870912; - -const int Py_TPFLAGS_BASE_EXC_SUBCLASS = 1073741824; - -const int Py_TPFLAGS_TYPE_SUBCLASS = 2147483648; - -const int Py_TPFLAGS_DEFAULT = 0; - -const int Py_TPFLAGS_HAVE_FINALIZE = 1; - -const int Py_TPFLAGS_HAVE_VERSION_TAG = 262144; - -const int Py_LT = 0; - -const int Py_LE = 1; - -const int Py_EQ = 2; - -const int Py_NE = 3; - -const int Py_GT = 4; - -const int Py_GE = 5; - -const int TYPE_MAX_WATCHERS = 8; - -const int Py_bf_getbuffer = 1; - -const int Py_bf_releasebuffer = 2; - -const int Py_mp_ass_subscript = 3; - -const int Py_mp_length = 4; - -const int Py_mp_subscript = 5; - -const int Py_nb_absolute = 6; - -const int Py_nb_add = 7; - -const int Py_nb_and = 8; - -const int Py_nb_bool = 9; - -const int Py_nb_divmod = 10; - -const int Py_nb_float = 11; - -const int Py_nb_floor_divide = 12; - -const int Py_nb_index = 13; - -const int Py_nb_inplace_add = 14; - -const int Py_nb_inplace_and = 15; - -const int Py_nb_inplace_floor_divide = 16; - -const int Py_nb_inplace_lshift = 17; - -const int Py_nb_inplace_multiply = 18; - -const int Py_nb_inplace_or = 19; - -const int Py_nb_inplace_power = 20; - -const int Py_nb_inplace_remainder = 21; - -const int Py_nb_inplace_rshift = 22; - -const int Py_nb_inplace_subtract = 23; - -const int Py_nb_inplace_true_divide = 24; - -const int Py_nb_inplace_xor = 25; - -const int Py_nb_int = 26; - -const int Py_nb_invert = 27; - -const int Py_nb_lshift = 28; - -const int Py_nb_multiply = 29; - -const int Py_nb_negative = 30; - -const int Py_nb_or = 31; - -const int Py_nb_positive = 32; - -const int Py_nb_power = 33; - -const int Py_nb_remainder = 34; - -const int Py_nb_rshift = 35; - -const int Py_nb_subtract = 36; - -const int Py_nb_true_divide = 37; - -const int Py_nb_xor = 38; - -const int Py_sq_ass_item = 39; - -const int Py_sq_concat = 40; - -const int Py_sq_contains = 41; - -const int Py_sq_inplace_concat = 42; - -const int Py_sq_inplace_repeat = 43; - -const int Py_sq_item = 44; - -const int Py_sq_length = 45; - -const int Py_sq_repeat = 46; - -const int Py_tp_alloc = 47; - -const int Py_tp_base = 48; - -const int Py_tp_bases = 49; - -const int Py_tp_call = 50; - -const int Py_tp_clear = 51; - -const int Py_tp_dealloc = 52; - -const int Py_tp_del = 53; - -const int Py_tp_descr_get = 54; - -const int Py_tp_descr_set = 55; - -const int Py_tp_doc = 56; - -const int Py_tp_getattr = 57; - -const int Py_tp_getattro = 58; - -const int Py_tp_hash = 59; - -const int Py_tp_init = 60; - -const int Py_tp_is_gc = 61; - -const int Py_tp_iter = 62; - -const int Py_tp_iternext = 63; - -const int Py_tp_methods = 64; - -const int Py_tp_new = 65; - -const int Py_tp_repr = 66; - -const int Py_tp_richcompare = 67; - -const int Py_tp_setattr = 68; - -const int Py_tp_setattro = 69; - -const int Py_tp_str = 70; - -const int Py_tp_traverse = 71; - -const int Py_tp_members = 72; - -const int Py_tp_getset = 73; - -const int Py_tp_free = 74; - -const int Py_nb_matrix_multiply = 75; - -const int Py_nb_inplace_matrix_multiply = 76; - -const int Py_am_await = 77; - -const int Py_am_aiter = 78; - -const int Py_am_anext = 79; - -const int Py_tp_finalize = 80; - -const int Py_am_send = 81; - -const int _PyHASH_MULTIPLIER = 1000003; - -const int _PyHASH_BITS = 61; - -const int _PyHASH_MODULUS = 2305843009213693951; - -const int _PyHASH_INF = 314159; - -const int _PyHASH_IMAG = 1000003; - -const int Py_HASH_CUTOFF = 0; - -const int Py_HASH_EXTERNAL = 0; - -const int Py_HASH_SIPHASH24 = 1; - -const int Py_HASH_FNV = 2; - -const int Py_HASH_SIPHASH13 = 3; - -const int Py_HASH_ALGORITHM = 3; - -const int Py_UNICODE_SIZE = 4; - -const int Py_UNICODE_REPLACEMENT_CHARACTER = 65533; - -const int SSTATE_NOT_INTERNED = 0; - -const int SSTATE_INTERNED_MORTAL = 1; - -const int SSTATE_INTERNED_IMMORTAL = 2; - -const int SSTATE_INTERNED_IMMORTAL_STATIC = 3; - -const int MAX_CO_EXTRA_USERS = 255; - -const int Py_RTFLAGS_USE_MAIN_OBMALLOC = 32; - -const int Py_RTFLAGS_MULTI_INTERP_EXTENSIONS = 256; - -const int Py_RTFLAGS_THREADS = 1024; - -const int Py_RTFLAGS_DAEMON_THREADS = 2048; - -const int Py_RTFLAGS_FORK = 32768; - -const int Py_RTFLAGS_EXEC = 65536; - -const int PyTrace_CALL = 0; - -const int PyTrace_EXCEPTION = 1; - -const int PyTrace_LINE = 2; - -const int PyTrace_RETURN = 3; - -const int PyTrace_C_CALL = 4; - -const int PyTrace_C_EXCEPTION = 5; - -const int PyTrace_C_RETURN = 6; - -const int PyTrace_OPCODE = 7; - -const int C_RECURSION_LIMIT = 10000; - -const String _Py_PARSE_PID = 'i'; - -const String _Py_PARSE_INTPTR = 'l'; - -const String _Py_PARSE_UINTPTR = 'k'; - -const int PyLong_SHIFT = 30; - -const int _PyLong_DECIMAL_SHIFT = 9; - -const int _PyLong_DECIMAL_BASE = 1000000000; - -const int PyLong_BASE = 1073741824; - -const int PyLong_MASK = 1073741823; - -const int _PyLong_SIGN_MASK = 3; - -const int _PyLong_NON_SIZE_BITS = 3; - -const int _Py_MANAGED_BUFFER_RELEASED = 1; - -const int _Py_MANAGED_BUFFER_FREE_FORMAT = 2; - -const int _Py_MEMORYVIEW_RELEASED = 1; - -const int _Py_MEMORYVIEW_C = 2; - -const int _Py_MEMORYVIEW_FORTRAN = 4; - -const int _Py_MEMORYVIEW_SCALAR = 8; - -const int _Py_MEMORYVIEW_PIL = 16; - -const int _Py_MEMORYVIEW_RESTRICTED = 32; - -const int PySet_MINSIZE = 8; - -const int METH_VARARGS = 1; - -const int METH_KEYWORDS = 2; - -const int METH_NOARGS = 4; - -const int METH_O = 8; - -const int METH_CLASS = 16; - -const int METH_STATIC = 32; - -const int METH_COEXIST = 64; - -const int METH_FASTCALL = 128; - -const int METH_STACKLESS = 0; - -const int METH_METHOD = 512; - -const int Py_mod_create = 1; - -const int Py_mod_exec = 2; - -const int Py_mod_multiple_interpreters = 3; - -const int _Py_mod_LAST_SLOT = 3; - -const String PY_STDIOTEXTMODE = 'b'; - -const int _PY_MONITORING_LOCAL_EVENTS = 10; - -const int _PY_MONITORING_UNGROUPED_EVENTS = 15; - -const int _PY_MONITORING_EVENTS = 17; - -const int CO_OPTIMIZED = 1; - -const int CO_NEWLOCALS = 2; - -const int CO_VARARGS = 4; - -const int CO_VARKEYWORDS = 8; - -const int CO_NESTED = 16; - -const int CO_GENERATOR = 32; - -const int CO_COROUTINE = 128; - -const int CO_ITERABLE_COROUTINE = 256; - -const int CO_ASYNC_GENERATOR = 512; - -const int CO_FUTURE_DIVISION = 131072; - -const int CO_FUTURE_ABSOLUTE_IMPORT = 262144; - -const int CO_FUTURE_WITH_STATEMENT = 524288; - -const int CO_FUTURE_PRINT_FUNCTION = 1048576; - -const int CO_FUTURE_UNICODE_LITERALS = 2097152; - -const int CO_FUTURE_BARRY_AS_BDFL = 4194304; - -const int CO_FUTURE_GENERATOR_STOP = 8388608; - -const int CO_FUTURE_ANNOTATIONS = 16777216; - -const int CO_MAXBLOCKS = 20; - -const int Py_T_SHORT = 0; - -const int Py_T_INT = 1; - -const int Py_T_LONG = 2; - -const int Py_T_FLOAT = 3; - -const int Py_T_DOUBLE = 4; - -const int Py_T_STRING = 5; - -const int _Py_T_OBJECT = 6; - -const int Py_T_CHAR = 7; - -const int Py_T_BYTE = 8; - -const int Py_T_UBYTE = 9; - -const int Py_T_USHORT = 10; - -const int Py_T_UINT = 11; - -const int Py_T_ULONG = 12; - -const int Py_T_STRING_INPLACE = 13; - -const int Py_T_BOOL = 14; - -const int Py_T_OBJECT_EX = 16; - -const int Py_T_LONGLONG = 17; - -const int Py_T_ULONGLONG = 18; - -const int Py_T_PYSSIZET = 19; - -const int _Py_T_NONE = 20; - -const int Py_READONLY = 1; - -const int Py_AUDIT_READ = 2; - -const int _Py_WRITE_RESTRICTED = 4; - -const int Py_RELATIVE_OFFSET = 8; - -const int PyWrapperFlag_KEYWORDS = 1; - -const int _PyTime_MIN = -9223372036854775808; - -const int _PyTime_MAX = 9223372036854775807; - -const int _SIZEOF_PYTIME_T = 8; - -const int WAIT_LOCK = 1; - -const int NOWAIT_LOCK = 0; - -const int PY_TIMEOUT_MAX = 9223372036854775; - -const int PYTHREAD_INVALID_THREAD_ID = -1; - -const int Py_CLEANUP_SUPPORTED = 131072; - -const int PYTHON_API_VERSION = 1013; - -const String PYTHON_API_STRING = '1013'; - -const int PYTHON_ABI_VERSION = 3; - -const String PYTHON_ABI_STRING = '3'; - -const int Py_single_input = 256; - -const int Py_file_input = 257; - -const int Py_eval_input = 258; - -const int Py_func_type_input = 345; - -const int PyCF_MASK = 33423360; - -const int PyCF_MASK_OBSOLETE = 16; - -const int PyCF_SOURCE_IS_UTF8 = 256; - -const int PyCF_DONT_IMPLY_DEDENT = 512; - -const int PyCF_ONLY_AST = 1024; - -const int PyCF_IGNORE_COOKIE = 2048; - -const int PyCF_TYPE_COMMENTS = 4096; - -const int PyCF_ALLOW_TOP_LEVEL_AWAIT = 8192; - -const int PyCF_ALLOW_INCOMPLETE_INPUT = 16384; - -const int PyCF_COMPILE_MASK = 30208; - -const String FUTURE_NESTED_SCOPES = 'nested_scopes'; - -const String FUTURE_GENERATORS = 'generators'; - -const String FUTURE_DIVISION = 'division'; - -const String FUTURE_ABSOLUTE_IMPORT = 'absolute_import'; - -const String FUTURE_WITH_STATEMENT = 'with_statement'; - -const String FUTURE_PRINT_FUNCTION = 'print_function'; - -const String FUTURE_UNICODE_LITERALS = 'unicode_literals'; - -const String FUTURE_BARRY_AS_BDFL = 'barry_as_FLUFL'; - -const String FUTURE_GENERATOR_STOP = 'generator_stop'; - -const String FUTURE_ANNOTATIONS = 'annotations'; - -const int PY_INVALID_STACK_EFFECT = 2147483647; - -const int PYOS_STACK_MARGIN = 2048; - -const int PyInterpreterConfig_DEFAULT_GIL = 0; - -const int PyInterpreterConfig_SHARED_GIL = 1; - -const int PyInterpreterConfig_OWN_GIL = 2; - -const int FVC_MASK = 3; - -const int FVC_NONE = 0; - -const int FVC_STR = 1; - -const int FVC_REPR = 2; - -const int FVC_ASCII = 3; - -const int FVS_MASK = 4; - -const int FVS_HAVE_SPEC = 4; - -const int PY_VECTORCALL_ARGUMENTS_OFFSET = -9223372036854775808; - -const int _PY_FASTCALL_SMALL_STACK = 5; - -const int PY_ITERSEARCH_COUNT = 1; - -const int PY_ITERSEARCH_INDEX = 2; - -const int PY_ITERSEARCH_CONTAINS = 3; - -const int PY_CTF_LOWER = 1; - -const int PY_CTF_UPPER = 2; - -const int PY_CTF_ALPHA = 3; - -const int PY_CTF_DIGIT = 4; - -const int PY_CTF_ALNUM = 7; - -const int PY_CTF_SPACE = 8; - -const int PY_CTF_XDIGIT = 16; - -const int Py_DTSF_SIGN = 1; - -const int Py_DTSF_ADD_DOT_0 = 2; - -const int Py_DTSF_ALT = 4; - -const int Py_DTSF_NO_NEG_0 = 8; - -const int Py_DTST_FINITE = 0; - -const int Py_DTST_INFINITE = 1; - -const int Py_DTST_NAN = 2; diff --git a/src/serious_python_android/lib/src/log.dart b/src/serious_python_android/lib/src/log.dart deleted file mode 100644 index 2cfa01ec..00000000 --- a/src/serious_python_android/lib/src/log.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/foundation.dart'; - -void spDebug(String message) { - if (message.startsWith('[serious_python]')) { - debugPrint(message); - } else { - debugPrint('[serious_python] $message'); - } -} - diff --git a/src/serious_python_android/pubspec.yaml b/src/serious_python_android/pubspec.yaml index 81be5f4d..e17a7902 100644 --- a/src/serious_python_android/pubspec.yaml +++ b/src/serious_python_android/pubspec.yaml @@ -15,14 +15,12 @@ dependencies: serious_python_platform_interface: path: ../serious_python_platform_interface path: ^1.9.0 - ffi: ^2.1.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - ffigen: ^9.0.0 - + flutter: plugin: implements: serious_python diff --git a/src/serious_python_android/python_ffigen.yaml b/src/serious_python_android/python_ffigen.yaml deleted file mode 100644 index af1efb05..00000000 --- a/src/serious_python_android/python_ffigen.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Run with `dart run ffigen --config python_ffigen.yaml`. - -output: "lib/src/gen.dart" -# enums: -# rename: -# "_(.*)": "$1" -# member-rename: -# "_(.*)": -# "_(.*)": "$1" -globals: - rename: - "^class (\\w+) extends ffi.Struct": "final class $1 extends ffi.Struct" - "^class (\\w+) extends ffi.Opaque": "final class $1 extends ffi.Opaque" - "^class (\\w+) extends ffi.Union": "final class $1 extends ffi.Union" -headers: - entry-points: - - "/Users/feodor/projects/flet-dev/python-mobile/install/android/arm64-v8a/python-3.12/include/python3.12/Python.h" - include-directives: - - "/Users/feodor/projects/flet-dev/python-mobile/install/android/arm64-v8a/python-3.12/include/python3.12/*" - - "/Users/feodor/projects/flet-dev/python-mobile/install/android/arm64-v8a/python-3.12/include/python3.12/internal/*" - - "/Users/feodor/projects/flet-dev/python-mobile/install/android/arm64-v8a/python-3.12/include/python3.12/cpython/*" -name: "CPython" -llvm-path: - - /opt/homebrew/opt/llvm -#compiler-opts: "-I/usr/local/opt/llvm/lib/clang/10.0.0/include/ -I/usr/local/Frameworks/Python.framework/Versions/3.8/include/python3.8/" -description: "Bindings to Python C interface\nignore_for_file: unused_field, unused_element\n" -#array-workaround: true \ No newline at end of file diff --git a/src/serious_python_android/src/CMakeLists.txt b/src/serious_python_android/src/CMakeLists.txt deleted file mode 100644 index c2800814..00000000 --- a/src/serious_python_android/src/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# The Flutter tooling requires that developers have CMake 3.10 or later -# installed. You should not increase this version, as doing so will cause -# the plugin to fail to compile for some customers of the plugin. -cmake_minimum_required(VERSION 3.10) - -project(serious_python_library VERSION 0.0.1 LANGUAGES C) - -add_library(serious_python SHARED - "serious_python.c" -) - -set_target_properties(serious_python PROPERTIES - PUBLIC_HEADER serious_python.h - OUTPUT_NAME "serious_python" -) - -# Add 16 KB page size support for Android 15 -if(ANDROID) - set_target_properties(serious_python PROPERTIES - LINK_FLAGS "-Wl,-z,max-page-size=16384" - ) -endif() - -target_compile_definitions(serious_python PUBLIC DART_SHARED_LIB) diff --git a/src/serious_python_android/src/serious_python.c b/src/serious_python_android/src/serious_python.c deleted file mode 100644 index e952f9f7..00000000 --- a/src/serious_python_android/src/serious_python.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "serious_python.h" - -// A very short-lived native function. -// -// For very short-lived functions, it is fine to call them on the main isolate. -// They will block the Dart execution while running the native function, so -// only do this for native functions which are guaranteed to be short-lived. -FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b) { return a + b; } - -// A longer-lived native function, which occupies the thread calling it. -// -// Do not call these kind of native functions in the main isolate. They will -// block Dart execution. This will cause dropped frames in Flutter applications. -// Instead, call these native functions on a separate isolate. -FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b) { - // Simulate work. -#if _WIN32 - Sleep(5000); -#else - usleep(5000 * 1000); -#endif - return a + b; -} diff --git a/src/serious_python_android/src/serious_python.h b/src/serious_python_android/src/serious_python.h deleted file mode 100644 index 084c6422..00000000 --- a/src/serious_python_android/src/serious_python.h +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -#if _WIN32 -#include -#else -#include -#include -#endif - -#if _WIN32 -#define FFI_PLUGIN_EXPORT __declspec(dllexport) -#else -#define FFI_PLUGIN_EXPORT -#endif - -// A very short-lived native function. -// -// For very short-lived functions, it is fine to call them on the main isolate. -// They will block the Dart execution while running the native function, so -// only do this for native functions which are guaranteed to be short-lived. -FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b); - -// A longer lived native function, which occupies the thread calling it. -// -// Do not call these kind of native functions in the main isolate. They will -// block Dart execution. This will cause dropped frames in Flutter applications. -// Instead, call these native functions on a separate isolate. -FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b); From c28bec37a28705693cd2e2208b3d19aea9f28ead Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 12:00:30 -0700 Subject: [PATCH 048/114] Windows: absorb Python lifecycle into dart_bridge[_d].dll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the darwin + android absorption. Python lifecycle code that used to live in serious_python_windows_plugin.cpp (Py_Initialize, PyRun_SimpleFile, std::thread worker) moves into dart_bridge.dll, downloaded as a prebuilt artifact from flet-dev/dart-bridge at CMake configure time. What moved: - CMakeLists.txt drops Python.h include + python.lib linking (no Python C API call sites left in this plugin). Adds file(DOWNLOAD)s for dart_bridge-windows-x86_64.dll (Release CRT) and dart_bridge_d-windows-x86_64.dll (Debug CRT). The right one for the current $ is added to serious_python_windows_bundled_libraries so Flutter's CONFIG-aware copy machinery picks it for each build mode. - serious_python_windows_plugin.{cpp,h} shrink to a getPlatformVersion method-channel handler. RunPythonProgram*/RunPythonScript* and the std::thread worker are gone. - serious_python_windows.dart's run() becomes one FFI call to serious_python_run via DartBridge.instance (which picks the Debug or Release DLL based on kDebugMode). path: ^1.9.0 added. Note: python3X.dll + python3.dll + Lib/ + DLLs/ + site-packages still get bundled — libdart_bridge.dll's import table references python3.dll (abi3 stub) which forwards to python3X.dll, and Python's import system needs Lib/site-packages on disk at runtime. CI: test-bridge-build.yml gains a test_bridge_example_windows job for all three Python versions. --- .github/workflows/test-bridge-build.yml | 44 ++++ .../lib/serious_python_windows.dart | 59 ++++- src/serious_python_windows/pubspec.yaml | 1 + .../windows/CMakeLists.txt | 43 +++- .../windows/serious_python_windows_plugin.cpp | 209 +----------------- .../windows/serious_python_windows_plugin.h | 6 - 6 files changed, 128 insertions(+), 234 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 6f62b22a..868f3b00 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -175,3 +175,47 @@ jobs: echo "Native libs inside APK:" unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" fi + + test_bridge_example_windows: + name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Package + run integration test + working-directory: "src/serious_python/example/bridge_example" + run: | + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} + flutter test integration_test -d windows + + - name: Diagnostics on failure + if: failure() + shell: bash + working-directory: "src/serious_python/example/bridge_example" + run: | + set +e + DBG_DIR=build/windows/x64/runner/Debug + echo "=== runner/Debug dir ===" + ls -la $DBG_DIR/ || true + echo + echo "=== dart_bridge*.dll bundled? ===" + ls -la $DBG_DIR/dart_bridge*.dll || echo "(no dart_bridge dll bundled)" + echo + echo "=== runner/Debug/Lib (Python stdlib) ===" + ls $DBG_DIR/Lib | head -20 || true + echo + echo "=== runner/Debug/site-packages ===" + ls -la $DBG_DIR/site-packages/ || true diff --git a/src/serious_python_windows/lib/serious_python_windows.dart b/src/serious_python_windows/lib/serious_python_windows.dart index c0f48cf7..b6890224 100644 --- a/src/serious_python_windows/lib/serious_python_windows.dart +++ b/src/serious_python_windows/lib/serious_python_windows.dart @@ -2,14 +2,24 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:path/path.dart' as p; import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; +/// Windows implementation of [SeriousPythonPlatform]. +/// +/// Python lifecycle (env, sys.path, Py_Initialize, run, finalize, sync/async) +/// lives in `serious_python_run`, packaged as `dart_bridge.dll` (Release CRT) +/// or `dart_bridge_d.dll` (Debug CRT) and bundled next to the .exe by this +/// plugin's CMakeLists.txt. The correct DLL is picked at runtime based on +/// [kDebugMode]. +/// +/// This class derives PYTHONHOME from `Platform.resolvedExecutable` (the +/// runner .exe directory, where the bundled CPython lives) and dispatches a +/// single FFI call to `serious_python_run`. class SeriousPythonWindows extends SeriousPythonPlatform { - /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('serious_python_windows'); - /// Registers this class as the default instance of [SeriousPythonPlatform] static void registerWith() { SeriousPythonPlatform.instance = SeriousPythonWindows(); } @@ -18,7 +28,7 @@ class SeriousPythonWindows extends SeriousPythonPlatform { Future getPlatformVersion() async { final version = await methodChannel.invokeMethod('getPlatformVersion'); - return "$version ${Platform.resolvedExecutable}"; + return '$version ${Platform.resolvedExecutable}'; } @override @@ -27,14 +37,41 @@ class SeriousPythonWindows extends SeriousPythonPlatform { List? modulePaths, Map? environmentVariables, bool? sync}) async { - final Map arguments = { - 'exePath': Platform.resolvedExecutable, - 'appPath': appPath, - 'script': script, - 'modulePaths': modulePaths, - 'environmentVariables': environmentVariables, - 'sync': sync + final exeDir = p.dirname(Platform.resolvedExecutable); + final appDir = p.dirname(appPath); + + final pythonPaths = [ + ...?modulePaths, + appDir, + p.join(appDir, '__pypackages__'), + p.join(exeDir, 'site-packages'), + p.join(exeDir, 'DLLs'), + p.join(exeDir, 'Lib'), + p.join(exeDir, 'Lib', 'site-packages'), + ]; + + final env = { + 'PYTHONINSPECT': '1', + 'PYTHONDONTWRITEBYTECODE': '1', + 'PYTHONNOUSERSITE': '1', + 'PYTHONUNBUFFERED': '1', + 'LC_CTYPE': 'UTF-8', + 'PYTHONHOME': exeDir, + 'PYTHONPATH': pythonPaths.join(';'), + ...?environmentVariables, }; - return await methodChannel.invokeMethod('runPython', arguments); + + final rc = runPython( + bridge: DartBridge.instance, + appPath: script == null ? appPath : null, + script: script, + modulePaths: pythonPaths, + environmentVariables: env, + sync: sync ?? false, + ); + + // sync=true: rc is the Python exit code. sync=false: rc is the spawn + // result (0 = worker thread started successfully). + return rc != 0 ? 'Python exited with code $rc' : null; } } diff --git a/src/serious_python_windows/pubspec.yaml b/src/serious_python_windows/pubspec.yaml index f41422dd..c71248af 100644 --- a/src/serious_python_windows/pubspec.yaml +++ b/src/serious_python_windows/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: plugin_platform_interface: ^2.1.8 serious_python_platform_interface: path: ../serious_python_platform_interface + path: ^1.9.0 dev_dependencies: flutter_test: diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index 53910244..4df1afe4 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -12,6 +12,11 @@ else() set(PYTHON_VERSION "3.14") endif() string(REPLACE "." "" PYTHON_VERSION_NODOT "${PYTHON_VERSION}") +if(DEFINED ENV{DART_BRIDGE_VERSION}) + set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") +else() + set(DART_BRIDGE_VERSION "1.2.1") +endif() project(${PROJECT_NAME} LANGUAGES CXX) # Explicitly opt in to modern CMake behaviors to avoid warnings with recent @@ -22,6 +27,11 @@ cmake_policy(VERSION 3.14...3.25) # not be changed set(PLUGIN_NAME "serious_python_windows_plugin") +# ---- python-windows-for-dart (runtime DLLs + stdlib) ---------------------- +# python3X.dll, python3.dll, Lib/, DLLs/ — required at runtime so the embedded +# CPython (driven by libdart_bridge.dll) can find its stdlib and the abi3 stub +# python3.dll can forward to python3X.dll. We no longer need the .lib / headers +# here because no Python C API call sites live in this plugin anymore. set(PYTHON_PACKAGE ${CMAKE_BINARY_DIR}/python) set(PYTHON_URL "https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-windows-for-dart-${PYTHON_VERSION}.zip") set(PYTHON_FILE ${CMAKE_BINARY_DIR}/python-windows-for-dart.zip) @@ -30,6 +40,26 @@ if (NOT EXISTS ${PYTHON_FILE}) file(ARCHIVE_EXTRACT INPUT ${PYTHON_FILE} DESTINATION ${PYTHON_PACKAGE}) endif() +# ---- dart_bridge prebuilt DLLs -------------------------------------------- +# Release CRT (.dll) is what Release Flutter builds consume; Debug CRT +# (_d.dll) is what `fvm flutter run` / Debug builds consume. Both ship in +# every release of flet-dev/dart-bridge; we bundle both and let Flutter's +# CONFIG-aware copy machinery pick the right one at app launch time. +set(DART_BRIDGE_DIR ${CMAKE_BINARY_DIR}/dart_bridge) +set(DART_BRIDGE_RELEASE_DLL "${DART_BRIDGE_DIR}/dart_bridge.dll") +set(DART_BRIDGE_DEBUG_DLL "${DART_BRIDGE_DIR}/dart_bridge_d.dll") +file(MAKE_DIRECTORY ${DART_BRIDGE_DIR}) +if(NOT EXISTS "${DART_BRIDGE_RELEASE_DLL}") + file(DOWNLOAD + "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge-windows-x86_64.dll" + "${DART_BRIDGE_RELEASE_DLL}") +endif() +if(NOT EXISTS "${DART_BRIDGE_DEBUG_DLL}") + file(DOWNLOAD + "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge_d-windows-x86_64.dll" + "${DART_BRIDGE_DEBUG_DLL}") +endif() + # Any new source files that you add to the plugin should be added here. list(APPEND PLUGIN_SOURCES "serious_python_windows_plugin.cpp" @@ -62,16 +92,8 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") -include_directories( - "${PYTHON_PACKAGE}/include" -) - target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) -target_link_libraries(${PLUGIN_NAME} PRIVATE - "${PYTHON_PACKAGE}/libs/python${PYTHON_VERSION_NODOT}$<$:_d>.lib" -) - # List of absolute paths to libraries that should be bundled with the plugin. # This list could contain prebuilt libraries, or libraries created by an # external build triggered from this build file. @@ -79,6 +101,7 @@ string(REPLACE "\\" "/" SERIOUS_PYTHON_WINDIR "$ENV{WINDIR}") set(serious_python_windows_bundled_libraries "${PYTHON_PACKAGE}/python${PYTHON_VERSION_NODOT}$<$:_d>.dll" "${PYTHON_PACKAGE}/python3$<$:_d>.dll" + "$,${DART_BRIDGE_DEBUG_DLL},${DART_BRIDGE_RELEASE_DLL}>" "${SERIOUS_PYTHON_WINDIR}/System32/msvcp140.dll" "${SERIOUS_PYTHON_WINDIR}/System32/vcruntime140.dll" "${SERIOUS_PYTHON_WINDIR}/System32/vcruntime140_1.dll" @@ -90,10 +113,10 @@ add_custom_target(CopyPythonDLLs ALL DEPENDS PYTHON_PACKAGE_DOWNLOAD) add_custom_command(TARGET CopyPythonDLLs POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>" - COMMAND ${CMAKE_COMMAND} -E copy_directory + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYTHON_PACKAGE}/Lib" "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/Lib" - COMMAND ${CMAKE_COMMAND} -E copy_directory + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYTHON_PACKAGE}/DLLs" "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs" COMMAND IF \"$<$:release>\" == \"release\" DEL \"${CMAKE_BINARY_DIR}/runner/Release/DLLs\\*_d.*\" /S /Q diff --git a/src/serious_python_windows/windows/serious_python_windows_plugin.cpp b/src/serious_python_windows/windows/serious_python_windows_plugin.cpp index 2b7ec85c..4f88ae68 100644 --- a/src/serious_python_windows/windows/serious_python_windows_plugin.cpp +++ b/src/serious_python_windows/windows/serious_python_windows_plugin.cpp @@ -3,7 +3,6 @@ // This must be included before many other Windows headers. #include -// For getPlatformVersion; remove unless needed for your plugin implementation. #include #include @@ -13,25 +12,9 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - namespace serious_python_windows { - using flutter::EncodableList; - using flutter::EncodableMap; - using flutter::EncodableValue; - // static void SeriousPythonWindowsPlugin::RegisterWithRegistrar( flutter::PluginRegistrarWindows *registrar) @@ -56,12 +39,12 @@ namespace serious_python_windows SeriousPythonWindowsPlugin::~SeriousPythonWindowsPlugin() {} + // Thin Flutter plugin: only surfaces the OS version. Python lifecycle now + // lives in dart_bridge[_d].dll, invoked from Dart via FFI. void SeriousPythonWindowsPlugin::HandleMethodCall( const flutter::MethodCall &method_call, std::unique_ptr> result) { - const auto *arguments = std::get_if(method_call.arguments()); - if (method_call.method_name().compare("getPlatformVersion") == 0) { std::ostringstream version_stream; @@ -81,198 +64,10 @@ namespace serious_python_windows result->Success(flutter::EncodableValue(version_stream.str())); } - else if (method_call.method_name().compare("runPython") == 0) - { - std::string exe_path; - std::string app_path; - std::string script; - flutter::EncodableList module_paths; - flutter::EncodableMap env_vars; - bool sync = false; - - if (arguments) - { - auto exe_path_it = arguments->find(EncodableValue("exePath")); - if (exe_path_it != arguments->end()) - { - exe_path = std::get(exe_path_it->second); - } - - auto app_path_it = arguments->find(EncodableValue("appPath")); - if (app_path_it != arguments->end()) - { - app_path = std::get(app_path_it->second); - } - - auto script_it = arguments->find(EncodableValue("script")); - if (script_it != arguments->end()) - { - script = std::get(script_it->second); - } - - auto module_paths_it = arguments->find(EncodableValue("modulePaths")); - if (module_paths_it != arguments->end() && !module_paths_it->second.IsNull()) - { - module_paths = std::get(module_paths_it->second); - } - - auto env_vars_it = arguments->find(EncodableValue("environmentVariables")); - if (env_vars_it != arguments->end() && !env_vars_it->second.IsNull()) - { - env_vars = std::get(env_vars_it->second); - } - - auto sync_it = arguments->find(EncodableValue("sync")); - if (sync_it != arguments->end() && !sync_it->second.IsNull()) - { - sync = std::get(sync_it->second); - } - } - else - { - result->Error("ARGUMENT_ERROR", "arguments is missing."); - return; - } - - std::string exe_dir = std::filesystem::path(exe_path).parent_path().string(); - std::string app_dir = std::filesystem::path(app_path).parent_path().string(); - - printf("exePath: %s\n", exe_path.c_str()); - printf("exeDir: %s\n", exe_dir.c_str()); - printf("appPath: %s\n", app_path.c_str()); - - std::vector python_paths; - - // add user module paths to the top - for (const auto &item : module_paths) - { - if (auto str_value = std::get_if(&item)) - { - printf("module_path: %s\n", str_value->c_str()); - python_paths.push_back(*str_value); - } - } - - // add system paths - python_paths.push_back(app_dir); - python_paths.push_back(app_dir + "\\__pypackages__"); - python_paths.push_back(exe_dir + "\\site-packages"); - python_paths.push_back(exe_dir + "\\DLLs"); - python_paths.push_back(exe_dir + "\\Lib"); - python_paths.push_back(exe_dir + "\\Lib\\site-packages"); - - std::string python_path; - for (int i = 0; i < python_paths.size(); i++) - { - python_path += python_paths[i]; - if (i < python_paths.size() - 1) - { // Don't add separator after the last element - python_path += ";"; - } - } - - printf("PYTHONPATH: %s\n", python_path.c_str()); - - // set python-related env vars - _putenv_s("PYTHONINSPECT", "1"); - _putenv_s("PYTHONDONTWRITEBYTECODE", "1"); - _putenv_s("PYTHONNOUSERSITE", "1"); - _putenv_s("PYTHONUNBUFFERED", "1"); - _putenv_s("LC_CTYPE", "UTF-8"); - _putenv_s("PYTHONHOME", exe_dir.c_str()); - _putenv_s("PYTHONPATH", python_path.c_str()); - - // set user environment variables - for (const auto &kv : env_vars) - { - auto key = kv.first; - auto value = kv.second; - if (auto str_key = std::get_if(&key); - auto str_value = std::get_if(&value)) - { - printf("env_var: %s=%s\n", str_key->c_str(), str_value->c_str()); - _putenv_s(str_key->c_str(), str_value->c_str()); - } - } - - printf("sync: %s\n", sync ? "true" : "false"); - - // run program - if (sync) - { - if (script.empty()) - { - printf("Running Python program synchronously..."); - RunPythonProgram(app_path); - } - else - { - printf("Running Python script synchronously..."); - RunPythonScript(script); - } - } - else - { - if (script.empty()) - { - printf("Running Python program asynchronously..."); - RunPythonProgramAsync(app_path); - } - else - { - printf("Running Python script asynchronously..."); - RunPythonScriptAsync(script); - } - } - - result->Success(flutter::EncodableValue(app_path)); - } else { result->NotImplemented(); } } - void SeriousPythonWindowsPlugin::RunPythonProgramAsync(std::string appPath) - { - // Create a new thread that runs the program - std::thread pyThread(&SeriousPythonWindowsPlugin::RunPythonProgram, this, appPath); - - // Detach the thread so it runs independently - pyThread.detach(); - } - - void SeriousPythonWindowsPlugin::RunPythonScriptAsync(std::string script) - { - // Create a new thread that runs the script - std::thread pyThread(&SeriousPythonWindowsPlugin::RunPythonScript, this, script); - - // Detach the thread so it runs independently - pyThread.detach(); - } - - void SeriousPythonWindowsPlugin::RunPythonProgram(std::string appPath) - { - Py_Initialize(); - - FILE *file; - errno_t err = fopen_s(&file, appPath.c_str(), "r"); - if (err == 0 && file != NULL) - { - PyRun_SimpleFileEx(file, appPath.c_str(), 1); - fclose(file); - } - - Py_Finalize(); - } - - void SeriousPythonWindowsPlugin::RunPythonScript(std::string script) - { - Py_Initialize(); - - PyRun_SimpleString(script.c_str()); - - Py_Finalize(); - } - } // namespace serious_python_windows diff --git a/src/serious_python_windows/windows/serious_python_windows_plugin.h b/src/serious_python_windows/windows/serious_python_windows_plugin.h index dca611d7..52c1893b 100644 --- a/src/serious_python_windows/windows/serious_python_windows_plugin.h +++ b/src/serious_python_windows/windows/serious_python_windows_plugin.h @@ -26,12 +26,6 @@ namespace serious_python_windows void HandleMethodCall( const flutter::MethodCall &method_call, std::unique_ptr> result); - - void RunPythonProgram(std::string appPath); - void RunPythonProgramAsync(std::string appPath); - - void RunPythonScript(std::string script); - void RunPythonScriptAsync(std::string script); }; } // namespace serious_python_windows From 195b604809a5f925f11f40c6545dd44f71e19210 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 12:16:37 -0700 Subject: [PATCH 049/114] Windows: robustify CopyPythonDLLs target + verbose flutter test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CopyPythonDLLs custom target was failing in CI with MSBuild dumping the whole batch on a non-zero exit code from one of the cmd.exe DEL invocations (typical cause: DEL on a missing pattern returns 1, which MSBuild treats as fatal). Replace the fragile DELs with `cmake -E rm -f` (forgiving about missing files) and a small rm_globs.cmake helper for the *.ico / *.cat globs. Both are platform-native to CMake and don't depend on cmd.exe semantics. Also tighten dart_bridge DLL downloads with a STATUS check + FATAL_ERROR on failure — so a flaky GitHub Releases fetch surfaces immediately instead of silently producing an empty file. Pass `-v` to `flutter test` (and tail the last 200 lines) so the next CI run actually shows the underlying MSBuild output if anything still fails. --- .github/workflows/test-bridge-build.yml | 2 +- .../windows/CMakeLists.txt | 63 +++++++++++-------- .../windows/rm_globs.cmake | 14 +++++ 3 files changed, 53 insertions(+), 26 deletions(-) create mode 100644 src/serious_python_windows/windows/rm_globs.cmake diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 868f3b00..0cd5a5d9 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -199,7 +199,7 @@ jobs: working-directory: "src/serious_python/example/bridge_example" run: | dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} - flutter test integration_test -d windows + flutter test integration_test -d windows -v 2>&1 | tail -200 - name: Diagnostics on failure if: failure() diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index 4df1afe4..d16e0b8c 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -49,16 +49,27 @@ set(DART_BRIDGE_DIR ${CMAKE_BINARY_DIR}/dart_bridge) set(DART_BRIDGE_RELEASE_DLL "${DART_BRIDGE_DIR}/dart_bridge.dll") set(DART_BRIDGE_DEBUG_DLL "${DART_BRIDGE_DIR}/dart_bridge_d.dll") file(MAKE_DIRECTORY ${DART_BRIDGE_DIR}) -if(NOT EXISTS "${DART_BRIDGE_RELEASE_DLL}") - file(DOWNLOAD - "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge-windows-x86_64.dll" - "${DART_BRIDGE_RELEASE_DLL}") -endif() -if(NOT EXISTS "${DART_BRIDGE_DEBUG_DLL}") - file(DOWNLOAD - "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge_d-windows-x86_64.dll" - "${DART_BRIDGE_DEBUG_DLL}") -endif() + +function(_sp_download url dest) + if(EXISTS "${dest}") + return() + endif() + message(STATUS "Downloading dart_bridge: ${url}") + file(DOWNLOAD "${url}" "${dest}" STATUS _dl_status SHOW_PROGRESS) + list(GET _dl_status 0 _dl_code) + list(GET _dl_status 1 _dl_message) + if(NOT _dl_code EQUAL 0) + file(REMOVE "${dest}") + message(FATAL_ERROR "Failed to download ${url}: ${_dl_message}") + endif() +endfunction() + +_sp_download( + "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge-windows-x86_64.dll" + "${DART_BRIDGE_RELEASE_DLL}") +_sp_download( + "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge_d-windows-x86_64.dll" + "${DART_BRIDGE_DEBUG_DLL}") # Any new source files that you add to the plugin should be added here. list(APPEND PLUGIN_SOURCES @@ -108,22 +119,24 @@ set(serious_python_windows_bundled_libraries PARENT_SCOPE ) -# Copy Python libraries -add_custom_target(CopyPythonDLLs ALL DEPENDS PYTHON_PACKAGE_DOWNLOAD) +# Copy Python libraries. +# +# Replaced the prior cmd.exe `DEL` invocations with `cmake -E rm -f --` which +# is forgiving about missing globs / missing files. MSBuild's CustomBuild +# wrapper treats any non-zero exit code as a hard failure, and `DEL ` +# returns 1, which made the whole CopyPythonDLLs target fragile. +set(SP_RUNNER_OUT "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>") +add_custom_target(CopyPythonDLLs ALL) add_custom_command(TARGET CopyPythonDLLs POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>" - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${PYTHON_PACKAGE}/Lib" - "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/Lib" - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${PYTHON_PACKAGE}/DLLs" - "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs" - COMMAND IF \"$<$:release>\" == \"release\" DEL \"${CMAKE_BINARY_DIR}/runner/Release/DLLs\\*_d.*\" /S /Q - COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*.ico\" /S /Q - COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\*.cat\" /S /Q - COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\tcl86t.dll\" /Q - COMMAND DEL \"${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/DLLs\\tk86t.dll\" /Q + COMMAND ${CMAKE_COMMAND} -E make_directory "${SP_RUNNER_OUT}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYTHON_PACKAGE}/Lib" "${SP_RUNNER_OUT}/Lib" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYTHON_PACKAGE}/DLLs" "${SP_RUNNER_OUT}/DLLs" + # Strip Debug-only PYDs from Release builds (best effort — missing files OK). + COMMAND ${CMAKE_COMMAND} -E rm -f -- + "${SP_RUNNER_OUT}/DLLs/tcl86t.dll" + "${SP_RUNNER_OUT}/DLLs/tk86t.dll" + COMMAND ${CMAKE_COMMAND} -DDIR=${SP_RUNNER_OUT}/DLLs -DGLOBS=*.ico\;*.cat + -P "${CMAKE_CURRENT_SOURCE_DIR}/rm_globs.cmake" ) if(DEFINED ENV{SERIOUS_PYTHON_SITE_PACKAGES}) diff --git a/src/serious_python_windows/windows/rm_globs.cmake b/src/serious_python_windows/windows/rm_globs.cmake new file mode 100644 index 00000000..a52ca142 --- /dev/null +++ b/src/serious_python_windows/windows/rm_globs.cmake @@ -0,0 +1,14 @@ +# Helper invoked by CMakeLists.txt's CopyPythonDLLs target. +# Removes files matching semicolon-separated -DGLOBS=... under -DDIR=... +# without failing if the glob has no matches. + +if(NOT DEFINED DIR OR NOT DEFINED GLOBS) + message(FATAL_ERROR "rm_globs.cmake requires -DDIR and -DGLOBS") +endif() + +foreach(_pattern IN LISTS GLOBS) + file(GLOB _matches "${DIR}/${_pattern}") + if(_matches) + file(REMOVE ${_matches}) + endif() +endforeach() From 07dea03e7befb7d15fc1d8146c9cd515ceef5287 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 12:24:04 -0700 Subject: [PATCH 050/114] Windows: skip site-packages copy when source dir is missing + propagate flutter test failure on Windows runner. Two bugs surfaced in the previous Windows CI run: 1. The workflow-level env var SERIOUS_PYTHON_SITE_PACKAGES is set, but the directory it points at only exists when an outer step (the old cibuildwheel-based workflow) populated it. With the new pre-built-binary pipeline that step is gone, so cmake -E copy_directory ran against a missing source and CopyPythonDLLs.vcxproj exited 1. Guard with `if(DEFINED ENV{...} AND EXISTS "$ENV{...}")`. 2. The Windows job's GitHub Actions step used the default PowerShell shell, where `flutter test ... | tail -200` swallows flutter's non-zero exit (PowerShell pipelines don't honor pipefail). Tests reported "0 tests passed, 1 failed" yet the step reported success. Switch to `shell: bash` + explicit `set -o pipefail` so failures surface. --- .github/workflows/test-bridge-build.yml | 7 ++++++- src/serious_python_windows/windows/CMakeLists.txt | 15 +++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 0cd5a5d9..7bae887f 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -197,9 +197,14 @@ jobs: - name: Package + run integration test working-directory: "src/serious_python/example/bridge_example" + shell: bash run: | dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} - flutter test integration_test -d windows -v 2>&1 | tail -200 + # bash + pipefail so the test step actually fails when flutter fails + # (default PowerShell shell on windows runners eats the failure when + # piping into tail). + set -o pipefail + flutter test integration_test -d windows -v 2>&1 | tail -300 - name: Diagnostics on failure if: failure() diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index d16e0b8c..f287ec91 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -139,14 +139,17 @@ add_custom_command(TARGET CopyPythonDLLs POST_BUILD -P "${CMAKE_CURRENT_SOURCE_DIR}/rm_globs.cmake" ) -if(DEFINED ENV{SERIOUS_PYTHON_SITE_PACKAGES}) +# Mirror the user's external site-packages dir into runner/site-packages if +# the env var is set AND points at an existing directory. (The CI env var +# may be set workflow-wide while specific jobs don't actually create the +# directory — `cmake -E copy_directory` against a missing source fails, +# which used to wedge CopyPythonDLLs.) +if(DEFINED ENV{SERIOUS_PYTHON_SITE_PACKAGES} AND EXISTS "$ENV{SERIOUS_PYTHON_SITE_PACKAGES}") add_custom_command(TARGET CopyPythonDLLs POST_BUILD - COMMAND ${CMAKE_COMMAND} -E remove_directory - "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/site-packages" - COMMAND ${CMAKE_COMMAND} -E make_directory - "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/site-packages" + COMMAND ${CMAKE_COMMAND} -E rm -rf "${SP_RUNNER_OUT}/site-packages" + COMMAND ${CMAKE_COMMAND} -E make_directory "${SP_RUNNER_OUT}/site-packages" COMMAND ${CMAKE_COMMAND} -E copy_directory "$ENV{SERIOUS_PYTHON_SITE_PACKAGES}" - "${CMAKE_BINARY_DIR}/runner/$<$:Release>$<$:Debug>/site-packages" + "${SP_RUNNER_OUT}/site-packages" ) endif() From 5410eb6ee4bdf18e73ef11c38c0c62f53ea731f3 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 12:33:51 -0700 Subject: [PATCH 051/114] Drop Windows-specific script:\"\" hack from SeriousPython.run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serious_python.dart was passing `script: Platform.isWindows ? \"\" : null` to runProgram() — a workaround for the old C++ Windows plugin's HandleMethodCall which treated an empty script string as a sentinel for \"use appPath\". With the new unified `serious_python_run`, mode=SCRIPT with an empty source string runs nothing — so on Windows the embedded Python interpreter started, did nothing, and the bridge_example's retry loop timed out with 'Python did not register a handler within 30s'. Pass `script: null` on all platforms; let the platform impls' `script == null ? appPath : null` branch route to PATH mode uniformly. Also gate the macOS / iOS / Android jobs in test-bridge-build.yml with `if: false` for faster Windows iteration. Re-enable when Windows is green. --- .github/workflows/test-bridge-build.yml | 5 +++++ src/serious_python/lib/serious_python.dart | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 7bae887f..c4912610 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -19,6 +19,9 @@ env: jobs: test_bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) + # Temporarily gated off while iterating on Windows. Re-enable by removing + # this `if: false`. + if: false runs-on: macos-latest strategy: fail-fast: false @@ -44,6 +47,7 @@ jobs: test_bridge_example_ios: name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) + if: false # Temporarily gated off while iterating on Windows. runs-on: macos-latest timeout-minutes: 25 strategy: @@ -99,6 +103,7 @@ jobs: test_bridge_example_android: name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) + if: false # Temporarily gated off while iterating on Windows. runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/src/serious_python/lib/serious_python.dart b/src/serious_python/lib/serious_python.dart index 968d35f3..722d87fa 100644 --- a/src/serious_python/lib/serious_python.dart +++ b/src/serious_python/lib/serious_python.dart @@ -64,7 +64,6 @@ class SeriousPython { return runProgram(appPath, modulePaths: modulePaths, environmentVariables: environmentVariables, - script: Platform.isWindows ? "" : null, sync: sync); } From cea8ffb08227c1d1a37287a596d1de044941e277 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 12:39:48 -0700 Subject: [PATCH 052/114] Re-enable macOS/iOS/Android jobs in test-bridge-build (Windows is green now) --- .github/workflows/test-bridge-build.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index c4912610..7bae887f 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -19,9 +19,6 @@ env: jobs: test_bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) - # Temporarily gated off while iterating on Windows. Re-enable by removing - # this `if: false`. - if: false runs-on: macos-latest strategy: fail-fast: false @@ -47,7 +44,6 @@ jobs: test_bridge_example_ios: name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) - if: false # Temporarily gated off while iterating on Windows. runs-on: macos-latest timeout-minutes: 25 strategy: @@ -103,7 +99,6 @@ jobs: test_bridge_example_android: name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) - if: false # Temporarily gated off while iterating on Windows. runs-on: ubuntu-latest strategy: fail-fast: false From 41751be493e288b17bad7b784f10e4f430fc7524 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 13:08:33 -0700 Subject: [PATCH 053/114] Linux: absorb Python lifecycle into libdart_bridge.so MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the darwin / android / windows absorption. Python lifecycle code that used to live in serious_python_linux_plugin.cc (Py_Initialize, PyRun_SimpleFileEx, g_thread spawn) moves into libdart_bridge.so, downloaded as a prebuilt artifact from flet-dev/dart-bridge at CMake configure time. What moved: - CMakeLists.txt downloads libdart_bridge-linux-.so (pinned to DART_BRIDGE_VERSION=1.2.2 — earlier 1.2.x had no libpython in DT_NEEDED). Both libdart_bridge.so AND the existing libpython3.so / libpython.so.1.0 stay in serious_python_linux_bundled_libraries so Flutter copies them to the runner's lib/ dir; the runtime linker then finds libpython3.so next to the exe and chains through to the version-specific lib. - serious_python_linux_plugin.cc shrinks to a getPlatformVersion method-channel handler. - serious_python_linux_plugin_private.h drops the run_python_* declarations. - serious_python_linux.dart's run() becomes one FFI call to serious_python_run via DartBridge.instance. The Python stdlib path is resolved by scanning for the python3./ subdir installed by CMake. - path: ^1.9.0 added. CI: gates the other platforms in test-bridge-build.yml with `if: false` for fast Linux iteration; adds a test_bridge_example_linux job (matrix amd64 + arm64 × Python 3.12/3.13/3.14). --- .github/workflows/test-bridge-build.yml | 83 ++++++++ .../lib/serious_python_linux.dart | 75 ++++++-- src/serious_python_linux/linux/CMakeLists.txt | 55 ++++-- .../linux/serious_python_linux_plugin.cc | 182 +----------------- .../serious_python_linux_plugin_private.h | 6 - src/serious_python_linux/pubspec.yaml | 1 + 6 files changed, 188 insertions(+), 214 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index 7bae887f..b911c25b 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -19,6 +19,7 @@ env: jobs: test_bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) + if: false # Temporarily gated off while iterating on Linux. runs-on: macos-latest strategy: fail-fast: false @@ -44,6 +45,7 @@ jobs: test_bridge_example_ios: name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) + if: false # Temporarily gated off while iterating on Linux. runs-on: macos-latest timeout-minutes: 25 strategy: @@ -99,6 +101,7 @@ jobs: test_bridge_example_android: name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) + if: false # Temporarily gated off while iterating on Linux. runs-on: ubuntu-latest strategy: fail-fast: false @@ -178,6 +181,7 @@ jobs: test_bridge_example_windows: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) + if: false # Temporarily gated off while iterating on Linux. runs-on: windows-latest strategy: fail-fast: false @@ -224,3 +228,82 @@ jobs: echo echo "=== runner/Debug/site-packages ===" ls -la $DBG_DIR/site-packages/ || true + + test_bridge_example_linux: + name: Bridge example Linux round-trip (Python ${{ matrix.python_version }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + arch: [amd64, arm64] + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Get Flutter version from .fvmrc + uses: kuhnroyal/flutter-fvm-config-action/config@v3 + id: fvm-config-action + with: + path: '.fvmrc' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} + cache: true + + - name: Install Linux desktop build deps + run: | + sudo apt-get update --allow-releaseinfo-change + sudo apt-get install -y xvfb libgtk-3-dev + if [ "${{ matrix.arch }}" = "amd64" ]; then + sudo apt-get install -y \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + else + sudo apt-get install -y \ + clang ninja-build gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + fi + + - name: Package + run integration test + working-directory: src/serious_python/example/bridge_example + run: | + flutter pub get + dart run serious_python:main package app/src \ + --platform Linux \ + --python-version ${{ matrix.python_version }} + set -o pipefail + xvfb-run flutter test integration_test -d linux -v 2>&1 | tail -300 + + - name: Diagnostics on failure + if: failure() + working-directory: src/serious_python/example/bridge_example + run: | + set +e + DBG_DIR=build/linux/${{ matrix.arch == 'arm64' && 'arm64' || 'x64' }}/debug/bundle + echo "=== bundle dir ===" + ls -la $DBG_DIR/ 2>/dev/null + echo + echo "=== bundle/lib (bundled shared libs) ===" + ls -la $DBG_DIR/lib/ 2>/dev/null + echo + echo "=== readelf -d on libdart_bridge.so ===" + readelf -d $DBG_DIR/lib/libdart_bridge.so 2>/dev/null | grep -E "NEEDED|libpython" || echo "(libdart_bridge.so not found)" + echo + echo "=== bundle data/flutter_assets/native_assets/linux/ ===" + ls -la $DBG_DIR/data/flutter_assets/native_assets/linux/ 2>/dev/null + echo + echo "=== Python stdlib dir ===" + ls -d $DBG_DIR/python3.* 2>/dev/null | head -5 diff --git a/src/serious_python_linux/lib/serious_python_linux.dart b/src/serious_python_linux/lib/serious_python_linux.dart index c76ab176..361ccc08 100644 --- a/src/serious_python_linux/lib/serious_python_linux.dart +++ b/src/serious_python_linux/lib/serious_python_linux.dart @@ -2,14 +2,27 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:path/path.dart' as p; import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; +/// Linux implementation of [SeriousPythonPlatform]. +/// +/// Python lifecycle (env, sys.path, Py_Initialize, run, finalize, sync/async) +/// lives in `serious_python_run`, packaged as `libdart_bridge.so` and +/// downloaded by the plugin's CMakeLists.txt from +/// flet-dev/dart-bridge's GitHub Releases. +/// +/// At runtime this class: +/// 1. Derives PYTHONHOME from `Platform.resolvedExecutable` (where the +/// bundled CPython stdlib lives, alongside the runner .exe). +/// 2. Locates the `python3.` stdlib subdir by scanning the exe dir +/// (the actual minor version is fixed at build time but the Dart side +/// doesn't have a compile-time constant for it). +/// 3. Hands env + sys.path to `serious_python_run` in a single FFI call. class SeriousPythonLinux extends SeriousPythonPlatform { - /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('serious_python_linux'); - /// Registers this class as the default instance of [SeriousPythonPlatform] static void registerWith() { SeriousPythonPlatform.instance = SeriousPythonLinux(); } @@ -18,7 +31,7 @@ class SeriousPythonLinux extends SeriousPythonPlatform { Future getPlatformVersion() async { final version = await methodChannel.invokeMethod('getPlatformVersion'); - return "$version ${Platform.resolvedExecutable}"; + return '$version ${Platform.resolvedExecutable}'; } @override @@ -27,16 +40,52 @@ class SeriousPythonLinux extends SeriousPythonPlatform { List? modulePaths, Map? environmentVariables, bool? sync}) async { - final Map arguments = { - 'exePath': Platform.resolvedExecutable, - 'appPath': appPath, - 'modulePaths': modulePaths, - 'environmentVariables': environmentVariables, - 'sync': sync + final exeDir = p.dirname(Platform.resolvedExecutable); + final appDir = p.dirname(appPath); + final stdlibDir = _resolvePythonStdlibDir(exeDir); + + final pythonPaths = [ + ...?modulePaths, + appDir, + p.join(appDir, '__pypackages__'), + p.join(exeDir, 'site-packages'), + stdlibDir, + ]; + + final env = { + 'PYTHONINSPECT': '1', + 'PYTHONDONTWRITEBYTECODE': '1', + 'PYTHONNOUSERSITE': '1', + 'PYTHONUNBUFFERED': '1', + 'LC_CTYPE': 'UTF-8', + 'PYTHONHOME': exeDir, + 'PYTHONPATH': pythonPaths.join(':'), + ...?environmentVariables, }; - if (script != null) { - arguments['script'] = script; - } - return await methodChannel.invokeMethod('runPython', arguments); + + final rc = runPython( + bridge: DartBridge.instance, + appPath: script == null ? appPath : null, + script: script, + modulePaths: pythonPaths, + environmentVariables: env, + sync: sync ?? false, + ); + + // sync=true: rc is the Python exit code. sync=false: rc is the spawn + // result (0 = worker thread started successfully). + return rc != 0 ? 'Python exited with code $rc' : null; + } + + /// The Linux CMakeLists installs the python stdlib at + /// `/python`. Find the right subdir by name pattern. + static String _resolvePythonStdlibDir(String exeDir) { + final pattern = RegExp(r'^python3\.\d+$'); + final match = Directory(exeDir).listSync().whereType().firstWhere( + (d) => pattern.hasMatch(p.basename(d.path)), + orElse: () => throw StateError( + 'serious_python: no python3. stdlib dir found under $exeDir'), + ); + return match.path; } } diff --git a/src/serious_python_linux/linux/CMakeLists.txt b/src/serious_python_linux/linux/CMakeLists.txt index 89f6eb65..edc6b1f9 100644 --- a/src/serious_python_linux/linux/CMakeLists.txt +++ b/src/serious_python_linux/linux/CMakeLists.txt @@ -14,12 +14,18 @@ else() set(PYTHON_VERSION "3.14") endif() set(PYTHON_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) +if(DEFINED ENV{DART_BRIDGE_VERSION}) + set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") +else() + set(DART_BRIDGE_VERSION "1.2.2") +endif() project(${PROJECT_NAME} LANGUAGES CXX) # This value is used when generating builds using this plugin, so it must # not be changed. set(PLUGIN_NAME "serious_python_linux_plugin") +# ---- python-linux-dart tarball (libpython + stdlib) ----------------------- set(PYTHON_PACKAGE ${CMAKE_BINARY_DIR}/python) set(PYTHON_URL https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz) set(PYTHON_FILE ${CMAKE_BINARY_DIR}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz) @@ -28,6 +34,25 @@ if (NOT EXISTS ${PYTHON_FILE}) file(ARCHIVE_EXTRACT INPUT ${PYTHON_FILE} DESTINATION ${CMAKE_BINARY_DIR}/python) endif() +# ---- dart_bridge prebuilt .so --------------------------------------------- +# abi3-linked against libpython3.so (the runtime linker finds libpython3.so +# next to the consuming app's exe; the python-linux-dart tarball above +# provides it). +set(DART_BRIDGE_SO ${CMAKE_BINARY_DIR}/dart_bridge/libdart_bridge.so) +if(NOT EXISTS "${DART_BRIDGE_SO}") + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dart_bridge) + file(DOWNLOAD + "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/libdart_bridge-linux-${PYTHON_ARCH}.so" + "${DART_BRIDGE_SO}" + STATUS _dl_status SHOW_PROGRESS) + list(GET _dl_status 0 _dl_code) + list(GET _dl_status 1 _dl_message) + if(NOT _dl_code EQUAL 0) + file(REMOVE "${DART_BRIDGE_SO}") + message(FATAL_ERROR "Failed to download libdart_bridge: ${_dl_message}") + endif() +endif() + # Any new source files that you add to the plugin should be added here. list(APPEND PLUGIN_SOURCES "serious_python_linux_plugin.cc" @@ -50,28 +75,23 @@ apply_standard_settings(${PLUGIN_NAME}) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) -target_compile_definitions(${PLUGIN_NAME} PRIVATE - SERIOUS_PYTHON_VERSION="${PYTHON_VERSION}") # Source include directories and library dependencies. Add any plugin-specific # dependencies here. target_include_directories(${PLUGIN_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include" ) -include_directories( - "${PYTHON_PACKAGE}/include/python${PYTHON_VERSION}" -) target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) -target_link_libraries(${PLUGIN_NAME} PRIVATE - "${PYTHON_PACKAGE}/lib/libpython3.so" -) # List of absolute paths to libraries that should be bundled with the plugin. -# This list could contain prebuilt libraries, or libraries created by an -# external build triggered from this build file. +# Includes libdart_bridge.so (downloaded above) so Flutter copies it into the +# runner's lib/ dir; libpython3.so + libpython.so.1.0 from the python- +# linux-dart tarball so dart_bridge's DT_NEEDED libpython3.so resolves at +# runtime to the abi3 stub which forwards to the version-specific lib. set(serious_python_linux_bundled_libraries + "${DART_BRIDGE_SO}" "${PYTHON_PACKAGE}/lib/libpython3.so" "${PYTHON_PACKAGE}/lib/libpython${PYTHON_VERSION}.so.1.0" PARENT_SCOPE @@ -80,8 +100,13 @@ set(serious_python_linux_bundled_libraries install(DIRECTORY "${PYTHON_PACKAGE}/lib/python${PYTHON_VERSION}" DESTINATION "${CMAKE_BINARY_DIR}/bundle") -install(CODE " - file(REMOVE_RECURSE \"${CMAKE_BINARY_DIR}/bundle/site-packages\") - file(MAKE_DIRECTORY \"${CMAKE_BINARY_DIR}/bundle/site-packages\") - file(COPY \"$ENV{SERIOUS_PYTHON_SITE_PACKAGES}/\" DESTINATION \"${CMAKE_BINARY_DIR}/bundle/site-packages\") -") \ No newline at end of file +# Mirror an external site-packages dir into the bundle if the env var is set +# AND points at an existing directory. The env var may be set workflow-wide +# while specific jobs don't actually create the directory. +if(DEFINED ENV{SERIOUS_PYTHON_SITE_PACKAGES} AND EXISTS "$ENV{SERIOUS_PYTHON_SITE_PACKAGES}") + install(CODE " + file(REMOVE_RECURSE \"${CMAKE_BINARY_DIR}/bundle/site-packages\") + file(MAKE_DIRECTORY \"${CMAKE_BINARY_DIR}/bundle/site-packages\") + file(COPY \"$ENV{SERIOUS_PYTHON_SITE_PACKAGES}/\" DESTINATION \"${CMAKE_BINARY_DIR}/bundle/site-packages\") + ") +endif() diff --git a/src/serious_python_linux/linux/serious_python_linux_plugin.cc b/src/serious_python_linux/linux/serious_python_linux_plugin.cc index 33d4970d..4c1c75c7 100644 --- a/src/serious_python_linux/linux/serious_python_linux_plugin.cc +++ b/src/serious_python_linux/linux/serious_python_linux_plugin.cc @@ -5,19 +5,11 @@ #include #include -#include #include "serious_python_linux_plugin_private.h" -#include - -// Defined by linux/CMakeLists.txt to match the bundled libpython -// (e.g. "3.13"). The fallback only matters if this file is ever compiled -// outside the plugin's own CMake — defaults to the same version CMakeLists -// falls back to when SERIOUS_PYTHON_VERSION env var is unset. -#ifndef SERIOUS_PYTHON_VERSION -#define SERIOUS_PYTHON_VERSION "3.14" -#endif +// Thin Flutter plugin: only surfaces the OS version. Python lifecycle now +// lives in libdart_bridge.so, invoked from Dart via FFI. #define SERIOUS_PYTHON_LINUX_PLUGIN(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), serious_python_linux_plugin_get_type(), \ @@ -30,149 +22,17 @@ struct _SeriousPythonLinuxPlugin G_DEFINE_TYPE(SeriousPythonLinuxPlugin, serious_python_linux_plugin, g_object_get_type()) -// Called when a method call is received from Flutter. static void serious_python_linux_plugin_handle_method_call( SeriousPythonLinuxPlugin *self, FlMethodCall *method_call) { g_autoptr(FlMethodResponse) response = nullptr; - const gchar *method = fl_method_call_get_name(method_call); - FlValue *args = fl_method_call_get_args(method_call); if (strcmp(method, "getPlatformVersion") == 0) { response = get_platform_version(); } - else if (strcmp(method, "runPython") == 0) - { - if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) - { - return; - } - - // exePath - FlValue *exe_path = fl_value_lookup_string(args, "exePath"); - if (exe_path == nullptr) - { - return; - } - - gchar *exe_dir = g_path_get_dirname(fl_value_to_string(exe_path)); - - // appPath - FlValue *app_path = fl_value_lookup_string(args, "appPath"); - if (app_path == nullptr) - { - return; - } - - gchar *app_dir = g_path_get_dirname(fl_value_to_string(app_path)); - - // script - FlValue *script = fl_value_lookup_string(args, "script"); - - // sync - bool sync = false; - g_autoptr(FlValue) sync_key = fl_value_new_string("sync"); - FlValue *sync_value = fl_value_lookup(args, sync_key); - if (sync_value != nullptr && fl_value_get_type(sync_value) == FL_VALUE_TYPE_BOOL) - { - sync = fl_value_get_bool(sync_value); - } - - // modulePaths - size_t module_paths_size = 0; - - g_autoptr(FlValue) module_paths_key = fl_value_new_string("modulePaths"); - FlValue *module_paths = fl_value_lookup(args, module_paths_key); - if (module_paths != nullptr && fl_value_get_type(module_paths) == FL_VALUE_TYPE_LIST) - { - module_paths_size = fl_value_get_length(module_paths); - printf("modulePaths is a LIST: %zu\n", module_paths_size); - } - - gchar **module_paths_str_array = g_new(gchar *, module_paths_size + 4 /* standard modules */ + 1 /* for the NULL at the end */); - - // user module paths - size_t i = 0; - if (module_paths_size > 0) - { - for (; i < module_paths_size; i++) - { - FlValue *v = fl_value_get_list_value(module_paths, i); - printf("modulePath: %s\n", fl_value_to_string(v)); - module_paths_str_array[i] = g_strdup(fl_value_to_string(v)); - } - } - - // system module paths - module_paths_str_array[i++] = g_strdup_printf("%s", app_dir); - module_paths_str_array[i++] = g_strdup_printf("%s/__pypackages__", app_dir); - module_paths_str_array[i++] = g_strdup_printf("%s/site-packages", exe_dir); - module_paths_str_array[i++] = - g_strdup_printf("%s/python" SERIOUS_PYTHON_VERSION, exe_dir); - module_paths_str_array[i++] = NULL; - - gchar *module_paths_str = g_strjoinv(":", module_paths_str_array); // join with comma and space as separators - printf("modulePaths joined string: %s\n", module_paths_str); - - // environmentVariables - g_setenv("PYTHONINSPECT", "1", TRUE); - g_setenv("PYTHONDONTWRITEBYTECODE", "1", TRUE); - g_setenv("PYTHONNOUSERSITE", "1", TRUE); - g_setenv("PYTHONUNBUFFERED", "1", TRUE); - g_setenv("LC_CTYPE", "UTF-8", TRUE); - g_setenv("PYTHONHOME", exe_dir, TRUE); - g_setenv("PYTHONPATH", module_paths_str, TRUE); - - g_autoptr(FlValue) env_vars_key = fl_value_new_string("environmentVariables"); - FlValue *env_vars_map = fl_value_lookup(args, env_vars_key); - if (env_vars_map != nullptr && fl_value_get_type(env_vars_map) == FL_VALUE_TYPE_MAP) - { - size_t size = fl_value_get_length(env_vars_map); - printf("environmentVariables is a MAP: %zu\n", size); - for (size_t i = 0; i < size; i++) - { - FlValue *key = fl_value_get_map_key(env_vars_map, i); - FlValue *val = fl_value_lookup(env_vars_map, key); - printf("env var %s=%s\n", fl_value_to_string(key), fl_value_to_string(val)); - g_setenv(fl_value_to_string(key), fl_value_to_string(val), TRUE); - } - } - - printf("exe_dir: %s\n", exe_dir); - printf("app_dir: %s\n", app_dir); - printf("sync: %s\n", sync ? "true" : "false"); - - g_strfreev(module_paths_str_array); // free the array and its elements - g_free(module_paths_str); // free the joined string - - if (sync) - { - if (script != nullptr) - { - run_python_script(fl_value_to_string(script)); - } - else - { - run_python_program(fl_value_to_string(app_path)); - } - } - else - { - if (script != nullptr) - { - g_thread_new(NULL, run_python_script_async, g_strdup(fl_value_to_string(script))); - } - else - { - g_thread_new(NULL, run_python_program_async, g_strdup(fl_value_to_string(app_path))); - } - } - - response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_string(""))); - } else { response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); @@ -181,44 +41,6 @@ static void serious_python_linux_plugin_handle_method_call( fl_method_call_respond(method_call, response, nullptr); } -void run_python_program(gchar *appPath) -{ - Py_Initialize(); - - FILE *file = fopen(appPath, "r"); - if (file != NULL) - { - PyRun_SimpleFileEx(file, appPath, 1); - } - else - { - printf("Failed to open Python app file: %s\n", appPath); - } - - Py_Finalize(); -} - -void run_python_script(gchar *script) -{ - Py_Initialize(); - - PyRun_SimpleString(script); - - Py_Finalize(); -} - -gpointer run_python_program_async(gpointer data) -{ - run_python_program((gchar *)data); - return NULL; -} - -gpointer run_python_script_async(gpointer data) -{ - run_python_script((gchar *)data); - return NULL; -} - FlMethodResponse *get_platform_version() { struct utsname uname_data = {}; diff --git a/src/serious_python_linux/linux/serious_python_linux_plugin_private.h b/src/serious_python_linux/linux/serious_python_linux_plugin_private.h index 3874fd2a..8bbd6ab9 100644 --- a/src/serious_python_linux/linux/serious_python_linux_plugin_private.h +++ b/src/serious_python_linux/linux/serious_python_linux_plugin_private.h @@ -8,9 +8,3 @@ // Handles the getPlatformVersion method call. FlMethodResponse *get_platform_version(); - -void run_python_program(gchar *appPath); -gpointer run_python_program_async(gpointer data); - -void run_python_script(gchar *script); -gpointer run_python_script_async(gpointer data); \ No newline at end of file diff --git a/src/serious_python_linux/pubspec.yaml b/src/serious_python_linux/pubspec.yaml index 9a834cb7..c1d5ae83 100644 --- a/src/serious_python_linux/pubspec.yaml +++ b/src/serious_python_linux/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: plugin_platform_interface: ^2.1.8 serious_python_platform_interface: path: ../serious_python_platform_interface + path: ^1.9.0 dev_dependencies: flutter_test: From 398140bb200ee2d1b844638837f221e2aa39af9b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 13:19:42 -0700 Subject: [PATCH 054/114] Pin DART_BRIDGE_VERSION to 1.2.3 for Linux (DT_RPATH $ORIGIN) --- src/serious_python_linux/linux/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serious_python_linux/linux/CMakeLists.txt b/src/serious_python_linux/linux/CMakeLists.txt index edc6b1f9..46c9ae6e 100644 --- a/src/serious_python_linux/linux/CMakeLists.txt +++ b/src/serious_python_linux/linux/CMakeLists.txt @@ -17,7 +17,7 @@ set(PYTHON_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) if(DEFINED ENV{DART_BRIDGE_VERSION}) set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") else() - set(DART_BRIDGE_VERSION "1.2.2") + set(DART_BRIDGE_VERSION "1.2.3") endif() project(${PROJECT_NAME} LANGUAGES CXX) From b9245271d33853a2844ac76acea8e7c358ce54d9 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 13:28:07 -0700 Subject: [PATCH 055/114] Re-enable all platforms in test-bridge-build (Linux is green now) --- .github/workflows/test-bridge-build.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml index b911c25b..f0e30c5c 100644 --- a/.github/workflows/test-bridge-build.yml +++ b/.github/workflows/test-bridge-build.yml @@ -19,7 +19,6 @@ env: jobs: test_bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) - if: false # Temporarily gated off while iterating on Linux. runs-on: macos-latest strategy: fail-fast: false @@ -45,7 +44,6 @@ jobs: test_bridge_example_ios: name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) - if: false # Temporarily gated off while iterating on Linux. runs-on: macos-latest timeout-minutes: 25 strategy: @@ -101,7 +99,6 @@ jobs: test_bridge_example_android: name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) - if: false # Temporarily gated off while iterating on Linux. runs-on: ubuntu-latest strategy: fail-fast: false @@ -181,7 +178,6 @@ jobs: test_bridge_example_windows: name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) - if: false # Temporarily gated off while iterating on Linux. runs-on: windows-latest strategy: fail-fast: false From 992ffab80342395927c3acf03325e31b44c6821e Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:00:35 -0700 Subject: [PATCH 056/114] Phase 2: delete serious_python_bridge plugin, fold bridge_example into ci.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 absorbed the bridge's Python lifecycle + transport into prebuilt libdart_bridge artifacts consumed by serious_python_{darwin,android, windows,linux}, so the separate serious_python_bridge Flutter plugin is no longer reachable from any in-repo code path. Deletes: - `src/serious_python_bridge/` (entire plugin tree, ~7k lines: python wheel + native C + darwin static-link + linux/android/windows CMake + Swift/C++ plugin entry points + the old bridge_example). - `.github/workflows/test-bridge-build.yml` — throwaway workflow used for fast iteration of the absorption work; its 5 bridge_example jobs (one per platform, all green at end of Phase 1) move into ci.yml. ci.yml changes: - Drops the TEMPORARY iteration scoping; restores `branches: '**'` push triggers so PR branches get the full matrix again. - bridge_example_{macos,ios,android,windows,linux} replace the previous bridge_example jobs that pointed at the old example location and depended on cibuildwheel-built dart_bridge wheels. - Drops the entire `release_build` / `release_build_android` / `collect_release` cibuildwheel + NDK + GitHub-Release pipeline (the dart-bridge repo replaces all of it). - Drops `serious_python_bridge` from the publish pipeline (both the needs: list and the patch_pubspec/publish_pkg loop). The publish loop is now: platform_interface → 4 platform plugins → top- level serious_python. No bridge to publish last. Cross-repo follow-up (NOT in this commit, requires Flet repo access): migrate flet's `flet_backend_channel_ffi.dart` to import from `package:serious_python/bridge.dart` instead of `package:serious_python_bridge/serious_python_bridge.dart`, and update flet's Python imports to the v1.2.x keyed `set_enqueue_handler_func( port, handler)` signature. --- .github/workflows/ci.yml | 430 +- .github/workflows/test-bridge-build.yml | 305 -- src/serious_python_bridge/CHANGELOG.md | 5 - src/serious_python_bridge/LICENSE | 201 - src/serious_python_bridge/README.md | 53 - .../analysis_options.yaml | 4 - .../android/CMakeLists.txt | 31 - .../android/build.gradle | 146 - .../android/src/main/AndroidManifest.xml | 3 - .../Classes/SeriousPythonBridgePlugin.swift | 34 - .../darwin/Classes/dart_api/dart_api.h | 1 - .../darwin/Classes/dart_api/dart_api_dl.c | 1 - .../darwin/Classes/dart_api/dart_api_dl.h | 1 - .../darwin/Classes/dart_api/dart_native_api.h | 1 - .../darwin/Classes/dart_api/dart_tools_api.h | 1 - .../darwin/Classes/dart_api/dart_version.h | 1 - .../dart_api/internal/dart_api_dl_impl.h | 1 - .../darwin/Classes/dart_bridge.c | 1 - .../darwin/Classes/dart_bridge_shim.c | 1 - .../darwin/serious_python_bridge.podspec | 53 - .../lib/serious_python_bridge.dart | 126 - .../linux/CMakeLists.txt | 13 - .../native/CMakeLists.txt | 67 - .../native/dart_api/dart_api.h | 4186 ----------------- .../native/dart_api/dart_api_dl.c | 79 - .../native/dart_api/dart_api_dl.h | 172 - .../native/dart_api/dart_native_api.h | 224 - .../native/dart_api/dart_tools_api.h | 627 --- .../native/dart_api/dart_version.h | 16 - .../dart_api/internal/dart_api_dl_impl.h | 21 - .../native/dart_bridge.c | 102 - .../native/dart_bridge_shim.c | 240 - src/serious_python_bridge/pubspec.yaml | 41 - src/serious_python_bridge/python/MANIFEST.in | 4 - .../python/pyproject.toml | 36 - src/serious_python_bridge/python/setup.cfg | 5 - src/serious_python_bridge/python/setup.py | 28 - .../windows/CMakeLists.txt | 63 - 38 files changed, 179 insertions(+), 7145 deletions(-) delete mode 100644 .github/workflows/test-bridge-build.yml delete mode 100644 src/serious_python_bridge/CHANGELOG.md delete mode 100644 src/serious_python_bridge/LICENSE delete mode 100644 src/serious_python_bridge/README.md delete mode 100644 src/serious_python_bridge/analysis_options.yaml delete mode 100644 src/serious_python_bridge/android/CMakeLists.txt delete mode 100644 src/serious_python_bridge/android/build.gradle delete mode 100644 src/serious_python_bridge/android/src/main/AndroidManifest.xml delete mode 100644 src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_bridge.c delete mode 120000 src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c delete mode 100644 src/serious_python_bridge/darwin/serious_python_bridge.podspec delete mode 100644 src/serious_python_bridge/lib/serious_python_bridge.dart delete mode 100644 src/serious_python_bridge/linux/CMakeLists.txt delete mode 100644 src/serious_python_bridge/native/CMakeLists.txt delete mode 100644 src/serious_python_bridge/native/dart_api/dart_api.h delete mode 100644 src/serious_python_bridge/native/dart_api/dart_api_dl.c delete mode 100644 src/serious_python_bridge/native/dart_api/dart_api_dl.h delete mode 100644 src/serious_python_bridge/native/dart_api/dart_native_api.h delete mode 100644 src/serious_python_bridge/native/dart_api/dart_tools_api.h delete mode 100644 src/serious_python_bridge/native/dart_api/dart_version.h delete mode 100644 src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h delete mode 100644 src/serious_python_bridge/native/dart_bridge.c delete mode 100644 src/serious_python_bridge/native/dart_bridge_shim.c delete mode 100644 src/serious_python_bridge/pubspec.yaml delete mode 100644 src/serious_python_bridge/python/MANIFEST.in delete mode 100644 src/serious_python_bridge/python/pyproject.toml delete mode 100644 src/serious_python_bridge/python/setup.cfg delete mode 100644 src/serious_python_bridge/python/setup.py delete mode 100644 src/serious_python_bridge/windows/CMakeLists.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 307b6001..ad53f10e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,9 @@ name: CI -# TEMPORARY (dart-bridge branch only): scoped to main + tags + dispatch so -# iteration pushes to dart-bridge don't fire the slow flet_example platform -# matrix (~20-30 min per run). The throwaway test-bridge-build.yml covers -# the new bridge work fast. REVERT to `branches: '**'` before merging. on: push: - branches: - - main - - master - tags: - - '*' + branches: ['**'] + tags: ['*'] pull_request: workflow_dispatch: @@ -242,7 +235,7 @@ jobs: xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: - name: Test bridge example on macOS (Python ${{ matrix.python_version }}) + name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) runs-on: macos-latest strategy: fail-fast: false @@ -260,14 +253,14 @@ jobs: path: '.fvmrc' cache: true - - name: Run integration test - working-directory: "src/serious_python_bridge/example" + - name: Package + run integration test + working-directory: "src/serious_python/example/bridge_example" run: | dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} flutter test integration_test -d macos bridge_example_ios: - name: Test bridge example on iOS (Python ${{ matrix.python_version }}) + name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) runs-on: macos-latest timeout-minutes: 25 strategy: @@ -286,6 +279,16 @@ jobs: path: '.fvmrc' cache: true + # serious_python_darwin's prepare_ios.sh downloads python-ios-dart-.tar.gz + # (~100MB) into src/serious_python_darwin/darwin/dist_ios/ and skips the + # download if the directory already exists. Cache it so reruns and + # subsequent matrix jobs don't re-fetch from GitHub Releases. + - name: Cache iOS Python framework + uses: actions/cache@v4 + with: + path: src/serious_python_darwin/darwin/dist_ios + key: ios-python-dist-${{ matrix.python_version }}-v2 + - name: Setup iOS Simulator id: simulator uses: futureware-tech/simulator-action@v4 @@ -296,109 +299,103 @@ jobs: shutdown_after_job: true wait_for_boot: true - - name: Run integration test - working-directory: "src/serious_python_bridge/example" + - name: Package + run integration test + working-directory: "src/serious_python/example/bridge_example" run: | - # certifi placeholder: serious_python_darwin's sync_site_packages.sh - # only populates dist_ios/site-xcframeworks when iOS-specific - # site-packages subdirs exist (i.e., requirements installed for - # iphoneos.arm64 + iphonesimulator.arm64 + iphonesimulator.x86_64). - # An empty --requirements skips that branch and bundle-python- - # frameworks-ios.sh later fails finding site-xcframeworks. + ts() { date '+%H:%M:%S'; } + echo "[$(ts)] >>> dart run serious_python:main package" + # certifi is a placeholder requirement: serious_python_darwin's + # sync_site_packages.sh only populates dist_ios/site-xcframeworks + # (which bundle-python-frameworks-ios.sh then requires at build + # time) when iOS-specific site-packages subdirs exist. Empty + # --requirements skips that branch and the build fails. dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi + echo "[$(ts)] >>> flutter test integration_test" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} + echo "[$(ts)] >>> done" - bridge_example_linux: - name: Test bridge example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) - runs-on: ${{ matrix.runner }} - # Linux desktop needs the dart_bridge abi3 wheel installed into the bundled - # Python (no static-link path like on Apple); pull it from the wheel build. - needs: release_build - if: startsWith(github.ref, 'refs/tags/v') + bridge_example_android: + name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) + runs-on: ubuntu-latest strategy: fail-fast: false matrix: + # x86_64 matches the emulator architecture; only build/install for + # that ABI to keep CI fast. python_version: ['3.12', '3.13', '3.14'] - arch: [arm64, amd64] - include: - - arch: arm64 - runner: ubuntu-24.04-arm - title: ARM64 - wheel_artifact: bridge-wheels-ubuntu-24.04-arm - - arch: amd64 - runner: ubuntu-24.04 - title: AMD64 - wheel_artifact: bridge-wheels-ubuntu-24.04 env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup uv - uses: astral-sh/setup-uv@v6 - - - name: Get Flutter version from .fvmrc - uses: kuhnroyal/flutter-fvm-config-action/config@v3 - id: fvm-config-action - with: - path: '.fvmrc' - - name: Setup Flutter - uses: subosito/flutter-action@v2 + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 with: - flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} - channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} + path: '.fvmrc' cache: true - - name: Install Linux desktop build deps + - name: Enable KVM run: | - sudo apt-get update --allow-releaseinfo-change - sudo apt-get install -y xvfb libgtk-3-dev - if [ "${{ matrix.arch }}" = "amd64" ]; then - sudo apt-get install -y \ - libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav - else - sudo apt-get install -y \ - clang ninja-build gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav - fi + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm - - name: Download dart_bridge wheel artifact - uses: actions/download-artifact@v4 + - name: Gradle cache + uses: gradle/actions/setup-gradle@v3 + + - name: AVD cache + uses: actions/cache@v4 + id: avd-cache with: - name: ${{ matrix.wheel_artifact }} - path: ${{ runner.temp }}/dart_bridge_wheels + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-bridge - - name: Pick matching wheel for this arch - id: wheel - run: | - set -euo pipefail - # cibuildwheel produces one wheel per arch in this artifact; the - # repaired manylinux wheel is the one we want. - WHL=$(ls "${{ runner.temp }}/dart_bridge_wheels"/dart_bridge-*manylinux*.whl | head -n1) - test -n "$WHL" - echo "path=$WHL" >> "$GITHUB_OUTPUT" - echo "Picked: $WHL" - - - name: Run integration test - working-directory: src/serious_python_bridge/example + - name: Setup Android Emulator + Run tests + uses: reactivecircus/android-emulator-runner@v2 + env: + EMULATOR_PORT: 5554 + with: + avd-name: android_emulator + api-level: 33 + target: google_atd + arch: x86_64 + profile: pixel_5 + sdcard-path-or-size: 128M + ram-size: 2048M + disk-size: 4096M + emulator-port: ${{ env.EMULATOR_PORT }} + disable-animations: true + emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 + pre-emulator-launch-script: | + sdkmanager --list_installed + script: | + cd src/serious_python/example/bridge_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} + cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} + + - name: Diagnostics on failure + if: failure() + shell: bash run: | - flutter pub get - dart run serious_python:main package app/src \ - --platform Linux \ - --python-version ${{ matrix.python_version }} \ - --requirements ${{ steps.wheel.outputs.path }} - xvfb-run flutter test integration_test -d linux + set +e + REPO="$GITHUB_WORKSPACE" + ABI=x86_64 + echo "=== serious_python_android/android/src/main/jniLibs/$ABI/ ===" + ls -la "$REPO/src/serious_python_android/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" + echo + echo "=== example/build/app/outputs/apk/debug/*.apk ===" + APK=$(find "$REPO/src/serious_python/example/bridge_example/build" -name "*-debug.apk" 2>/dev/null | head -n1) + echo "APK: $APK" + if [ -n "$APK" ]; then + echo "Native libs inside APK:" + unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" + fi bridge_example_windows: - name: Test bridge example on Windows (Python ${{ matrix.python_version }}) + name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) runs-on: windows-latest - needs: release_build - if: startsWith(github.ref, 'refs/tags/v') strategy: fail-fast: false matrix: @@ -415,178 +412,114 @@ jobs: path: '.fvmrc' cache: true - - name: Download dart_bridge wheel artifact - uses: actions/download-artifact@v4 - with: - name: bridge-wheels-windows-latest - path: ${{ runner.temp }}\dart_bridge_wheels - - - name: Pick matching wheel - id: wheel + - name: Package + run integration test + working-directory: "src/serious_python/example/bridge_example" shell: bash run: | - set -euo pipefail - WHL=$(ls "$RUNNER_TEMP/dart_bridge_wheels"/dart_bridge-*-win_amd64.whl | head -n1) - test -n "$WHL" - echo "path=$WHL" >> "$GITHUB_OUTPUT" - echo "Picked: $WHL" - - - name: Run integration test - working-directory: "src/serious_python_bridge/example" + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} + # bash + pipefail so the test step actually fails when flutter fails + # (default PowerShell shell on windows runners eats the failure when + # piping into tail). + set -o pipefail + flutter test integration_test -d windows -v 2>&1 | tail -300 + + - name: Diagnostics on failure + if: failure() + shell: bash + working-directory: "src/serious_python/example/bridge_example" run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements ${{ steps.wheel.outputs.path }} - flutter test integration_test -d windows + set +e + DBG_DIR=build/windows/x64/runner/Debug + echo "=== runner/Debug dir ===" + ls -la $DBG_DIR/ || true + echo + echo "=== dart_bridge*.dll bundled? ===" + ls -la $DBG_DIR/dart_bridge*.dll || echo "(no dart_bridge dll bundled)" + echo + echo "=== runner/Debug/Lib (Python stdlib) ===" + ls $DBG_DIR/Lib | head -20 || true + echo + echo "=== runner/Debug/site-packages ===" + ls -la $DBG_DIR/site-packages/ || true - release_build: - name: Build dart_bridge wheel (${{ matrix.os }}) - if: startsWith(github.ref, 'refs/tags/v') - strategy: - fail-fast: false - matrix: - # Apple platforms use static-link + inittab (see serious_python_bridge/ - # darwin/), so no macOS/iOS wheel. Android needs an NDK cross-build - # that's deferred to a follow-up CI change. - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 - with: - package-dir: src/serious_python_bridge/python - - - name: Upload wheel artifacts - uses: actions/upload-artifact@v4 - with: - name: bridge-wheels-${{ matrix.os }} - path: wheelhouse/*.whl - if-no-files-found: error - - release_build_android: - name: Build dart_bridge.abi3.so (Android ${{ matrix.abi }}) - if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-24.04 + bridge_example_linux: + name: Bridge example Linux round-trip (Python ${{ matrix.python_version }}) + runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: - # Single abi3 binary per ABI works across all Python 3.12+ versions; - # we only need to pin a Python version for the headers + libpython to - # link against, not for the matrix dimension. 3.12 chosen for header - # parity with the abi3 floor in pyproject.toml. armeabi-v7a is still - # included because PEP 738 dropped it in 3.13, so 3.12 headers are - # the only ones with that ABI tarball. - abi: [arm64-v8a, armeabi-v7a, x86_64] + python_version: ['3.12', '3.13', '3.14'] + arch: [amd64, arm64] + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm env: - PYTHON_VERSION: "3.12" + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Download python-android-mobile-forge tarball (one tarball, all ABIs) - run: | - set -euo pipefail - VER="$PYTHON_VERSION" - ABI="${{ matrix.abi }}" - ARCHIVE="python-android-mobile-forge-${VER}.tar.gz" - curl -fL -o "$ARCHIVE" \ - "https://github.com/flet-dev/python-build/releases/download/v${VER}/${ARCHIVE}" - # Extract only the python-*/include and python-*/lib subtrees for our - # target ABI — the full archive is ~314MB and includes openssl/sqlite - # builds we don't need. - mkdir -p pydist - tar -xzf "$ARCHIVE" -C pydist \ - "install/android/${ABI}/python-${VER}.13/include/" \ - "install/android/${ABI}/python-${VER}.13/lib/" - find pydist -name "Python.h" - find pydist -name "libpython*.so" | head -5 - - - name: Cross-compile dart_bridge.abi3.so - run: | - set -euxo pipefail - VER="$PYTHON_VERSION" - ABI="${{ matrix.abi }}" - - case "$ABI" in - arm64-v8a) TARGET=aarch64-linux-android ;; - armeabi-v7a) TARGET=armv7a-linux-androideabi ;; - x86_64) TARGET=x86_64-linux-android ;; - *) echo "unsupported ABI: $ABI" >&2 ; exit 1 ;; - esac - - # Android API 21 matches serious_python_android's minSdkVersion. - API=21 - NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK_LATEST_HOME}}" - TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64" - CC="$TOOLCHAIN/bin/${TARGET}${API}-clang" - test -x "$CC" - - INCLUDE_DIR=$(find pydist -path "*/python-${VER}.13/include/python${VER}" | head -n1) - LIBPYTHON=$(find pydist -path "*/python-${VER}.13/lib/libpython${VER}.so" | head -n1) - test -n "$INCLUDE_DIR" -a -n "$LIBPYTHON" - - # ABI in the filename so all three coexist as Release assets without - # collision. package_command.dart renames back to dart_bridge.abi3.so - # when placing into the bundled site-packages (CPython's import - # mechanism requires the canonical name). - OUT="dart_bridge.abi3-android-${ABI}.so" - - $CC -shared -fPIC -fvisibility=hidden \ - -DPy_LIMITED_API=0x030c0000 \ - -I"$INCLUDE_DIR" \ - -I"src/serious_python_bridge/native" \ - src/serious_python_bridge/native/dart_bridge.c \ - src/serious_python_bridge/native/dart_api/dart_api_dl.c \ - "$LIBPYTHON" \ - -Wl,-z,max-page-size=16384 \ - -o "$OUT" - - file "$OUT" - ls -lh "$OUT" - - - name: Upload .so artifact - uses: actions/upload-artifact@v4 - with: - name: bridge-android-${{ matrix.abi }} - path: dart_bridge.abi3-android-*.so - if-no-files-found: error - - collect_release: - name: Attach bridge binaries to GitHub Release - needs: - - release_build - - release_build_android - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/v') - permissions: - contents: write - steps: - - name: Download wheel artifacts (Linux / Windows) - uses: actions/download-artifact@v4 + - name: Get Flutter version from .fvmrc + uses: kuhnroyal/flutter-fvm-config-action/config@v3 + id: fvm-config-action with: - pattern: bridge-wheels-* - merge-multiple: true - path: release-assets + path: '.fvmrc' - - name: Download Android .so artifacts - uses: actions/download-artifact@v4 + - name: Setup Flutter + uses: subosito/flutter-action@v2 with: - pattern: bridge-android-* - merge-multiple: true - path: release-assets + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} + cache: true - - name: List collected assets - run: ls -la release-assets/ + - name: Install Linux desktop build deps + run: | + sudo apt-get update --allow-releaseinfo-change + sudo apt-get install -y xvfb libgtk-3-dev + if [ "${{ matrix.arch }}" = "amd64" ]; then + sudo apt-get install -y \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + else + sudo apt-get install -y \ + clang ninja-build gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav + fi - - name: Create or update GitHub Release with bridge binaries - uses: softprops/action-gh-release@v2 - with: - files: | - release-assets/*.whl - release-assets/dart_bridge.abi3-android-*.so - fail_on_unmatched_files: true + - name: Package + run integration test + working-directory: src/serious_python/example/bridge_example + run: | + flutter pub get + dart run serious_python:main package app/src \ + --platform Linux \ + --python-version ${{ matrix.python_version }} + set -o pipefail + xvfb-run flutter test integration_test -d linux -v 2>&1 | tail -300 + - name: Diagnostics on failure + if: failure() + working-directory: src/serious_python/example/bridge_example + run: | + set +e + DBG_DIR=build/linux/${{ matrix.arch == 'arm64' && 'arm64' || 'x64' }}/debug/bundle + echo "=== bundle dir ===" + ls -la $DBG_DIR/ 2>/dev/null + echo + echo "=== bundle/lib (bundled shared libs) ===" + ls -la $DBG_DIR/lib/ 2>/dev/null + echo + echo "=== readelf -d on libdart_bridge.so ===" + readelf -d $DBG_DIR/lib/libdart_bridge.so 2>/dev/null | grep -E "NEEDED|libpython" || echo "(libdart_bridge.so not found)" + echo + echo "=== bundle data/flutter_assets/native_assets/linux/ ===" + ls -la $DBG_DIR/data/flutter_assets/native_assets/linux/ 2>/dev/null + echo + echo "=== Python stdlib dir ===" + ls -d $DBG_DIR/python3.* 2>/dev/null | head -5 publish: name: Publish to pub.dev needs: @@ -597,9 +530,9 @@ jobs: - linux - bridge_example_macos - bridge_example_ios + - bridge_example_android - bridge_example_linux - bridge_example_windows - - collect_release runs-on: ubuntu-22.04 if: startsWith(github.ref, 'refs/tags/v') steps: @@ -657,8 +590,7 @@ jobs: "serious_python_android" \ "serious_python_darwin" \ "serious_python_windows" \ - "serious_python_linux" \ - "serious_python_bridge"; do + "serious_python_linux"; do uv run "$SCRIPTS/patch_pubspec.py" "$pkg/pubspec.yaml" "$PKG_VER" done @@ -679,7 +611,3 @@ jobs: publish_pkg src/serious_python_linux sleep 600 publish_pkg src/serious_python - sleep 600 - # Bridge depends on serious_python + serious_python_darwin; publish - # last so all its path-deps already resolve on pub.dev. - publish_pkg src/serious_python_bridge \ No newline at end of file diff --git a/.github/workflows/test-bridge-build.yml b/.github/workflows/test-bridge-build.yml deleted file mode 100644 index f0e30c5c..00000000 --- a/.github/workflows/test-bridge-build.yml +++ /dev/null @@ -1,305 +0,0 @@ -name: Test bridge (no publish, no slow platform tests) - -# Throwaway workflow that exercises just the new bridge_example end-to-end -# on Darwin (macOS + iOS) — the platforms ported so far in the dart-bridge -# branch's consolidation work. Other platforms (Linux/Windows/Android) will -# return as each `serious_python_*` plugin gets wired up to download -# pre-built libdart_bridge binaries from flet-dev/dart-bridge releases. -# -# Delete before merging to main. - -on: - push: - branches: [dart-bridge] - workflow_dispatch: - -env: - SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" - -jobs: - test_bridge_example_macos: - name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) - runs-on: macos-latest - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Package + run integration test - working-directory: "src/serious_python/example/bridge_example" - run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} - flutter test integration_test -d macos - - test_bridge_example_ios: - name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) - runs-on: macos-latest - timeout-minutes: 25 - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - # serious_python_darwin's prepare_ios.sh downloads python-ios-dart-.tar.gz - # (~100MB) into src/serious_python_darwin/darwin/dist_ios/ and skips the - # download if the directory already exists. Cache it so reruns and - # subsequent matrix jobs don't re-fetch from GitHub Releases. - - name: Cache iOS Python framework - uses: actions/cache@v4 - with: - path: src/serious_python_darwin/darwin/dist_ios - key: ios-python-dist-${{ matrix.python_version }}-v2 - - - name: Setup iOS Simulator - id: simulator - uses: futureware-tech/simulator-action@v4 - with: - model: 'iPhone 16 Pro Max' - os: "iOS" - os_version: "^18.6" - shutdown_after_job: true - wait_for_boot: true - - - name: Package + run integration test - working-directory: "src/serious_python/example/bridge_example" - run: | - ts() { date '+%H:%M:%S'; } - echo "[$(ts)] >>> dart run serious_python:main package" - # certifi is a placeholder requirement: serious_python_darwin's - # sync_site_packages.sh only populates dist_ios/site-xcframeworks - # (which bundle-python-frameworks-ios.sh then requires at build - # time) when iOS-specific site-packages subdirs exist. Empty - # --requirements skips that branch and the build fails. - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi - echo "[$(ts)] >>> flutter test integration_test" - flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} - echo "[$(ts)] >>> done" - - test_bridge_example_android: - name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - # x86_64 matches the emulator architecture; only build/install for - # that ABI to keep CI fast. - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 - - - name: AVD cache - uses: actions/cache@v4 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-bridge - - - name: Setup Android Emulator + Run tests - uses: reactivecircus/android-emulator-runner@v2 - env: - EMULATOR_PORT: 5554 - with: - avd-name: android_emulator - api-level: 33 - target: google_atd - arch: x86_64 - profile: pixel_5 - sdcard-path-or-size: 128M - ram-size: 2048M - disk-size: 4096M - emulator-port: ${{ env.EMULATOR_PORT }} - disable-animations: true - emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 - pre-emulator-launch-script: | - sdkmanager --list_installed - script: | - cd src/serious_python/example/bridge_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} - cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} - - - name: Diagnostics on failure - if: failure() - shell: bash - run: | - set +e - REPO="$GITHUB_WORKSPACE" - ABI=x86_64 - echo "=== serious_python_android/android/src/main/jniLibs/$ABI/ ===" - ls -la "$REPO/src/serious_python_android/android/src/main/jniLibs/$ABI/" 2>/dev/null || echo "(not found)" - echo - echo "=== example/build/app/outputs/apk/debug/*.apk ===" - APK=$(find "$REPO/src/serious_python/example/bridge_example/build" -name "*-debug.apk" 2>/dev/null | head -n1) - echo "APK: $APK" - if [ -n "$APK" ]; then - echo "Native libs inside APK:" - unzip -l "$APK" | grep -E "lib/$ABI/" || echo "(no lib/$ABI/ entries)" - fi - - test_bridge_example_windows: - name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Package + run integration test - working-directory: "src/serious_python/example/bridge_example" - shell: bash - run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} - # bash + pipefail so the test step actually fails when flutter fails - # (default PowerShell shell on windows runners eats the failure when - # piping into tail). - set -o pipefail - flutter test integration_test -d windows -v 2>&1 | tail -300 - - - name: Diagnostics on failure - if: failure() - shell: bash - working-directory: "src/serious_python/example/bridge_example" - run: | - set +e - DBG_DIR=build/windows/x64/runner/Debug - echo "=== runner/Debug dir ===" - ls -la $DBG_DIR/ || true - echo - echo "=== dart_bridge*.dll bundled? ===" - ls -la $DBG_DIR/dart_bridge*.dll || echo "(no dart_bridge dll bundled)" - echo - echo "=== runner/Debug/Lib (Python stdlib) ===" - ls $DBG_DIR/Lib | head -20 || true - echo - echo "=== runner/Debug/site-packages ===" - ls -la $DBG_DIR/site-packages/ || true - - test_bridge_example_linux: - name: Bridge example Linux round-trip (Python ${{ matrix.python_version }}) - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - arch: [amd64, arm64] - include: - - arch: amd64 - runner: ubuntu-24.04 - - arch: arm64 - runner: ubuntu-24.04-arm - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Get Flutter version from .fvmrc - uses: kuhnroyal/flutter-fvm-config-action/config@v3 - id: fvm-config-action - with: - path: '.fvmrc' - - - name: Setup Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} - channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} - cache: true - - - name: Install Linux desktop build deps - run: | - sudo apt-get update --allow-releaseinfo-change - sudo apt-get install -y xvfb libgtk-3-dev - if [ "${{ matrix.arch }}" = "amd64" ]; then - sudo apt-get install -y \ - libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav - else - sudo apt-get install -y \ - clang ninja-build gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly gstreamer1.0-libav - fi - - - name: Package + run integration test - working-directory: src/serious_python/example/bridge_example - run: | - flutter pub get - dart run serious_python:main package app/src \ - --platform Linux \ - --python-version ${{ matrix.python_version }} - set -o pipefail - xvfb-run flutter test integration_test -d linux -v 2>&1 | tail -300 - - - name: Diagnostics on failure - if: failure() - working-directory: src/serious_python/example/bridge_example - run: | - set +e - DBG_DIR=build/linux/${{ matrix.arch == 'arm64' && 'arm64' || 'x64' }}/debug/bundle - echo "=== bundle dir ===" - ls -la $DBG_DIR/ 2>/dev/null - echo - echo "=== bundle/lib (bundled shared libs) ===" - ls -la $DBG_DIR/lib/ 2>/dev/null - echo - echo "=== readelf -d on libdart_bridge.so ===" - readelf -d $DBG_DIR/lib/libdart_bridge.so 2>/dev/null | grep -E "NEEDED|libpython" || echo "(libdart_bridge.so not found)" - echo - echo "=== bundle data/flutter_assets/native_assets/linux/ ===" - ls -la $DBG_DIR/data/flutter_assets/native_assets/linux/ 2>/dev/null - echo - echo "=== Python stdlib dir ===" - ls -d $DBG_DIR/python3.* 2>/dev/null | head -5 diff --git a/src/serious_python_bridge/CHANGELOG.md b/src/serious_python_bridge/CHANGELOG.md deleted file mode 100644 index ddf41ee3..00000000 --- a/src/serious_python_bridge/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -## 2.0.0 - -* Initial release. Generic in-process Dart ↔ Python byte transport built on - Dart's native API DL (`Dart_PostCObject_DL`) and the embedded Python runtime - provided by `serious_python`. diff --git a/src/serious_python_bridge/LICENSE b/src/serious_python_bridge/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/src/serious_python_bridge/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/src/serious_python_bridge/README.md b/src/serious_python_bridge/README.md deleted file mode 100644 index 953cefa4..00000000 --- a/src/serious_python_bridge/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# serious_python_bridge - -A generic in-process Dart ↔ Python byte transport for the embedded Python -runtime provided by [`serious_python`](../serious_python). Eliminates the -socket/TCP/WebSocket overhead of out-of-process IPC by exchanging bytes -directly across the Dart FFI / CPython C API boundary. - -This package is **independent of any specific protocol** — it exchanges -opaque byte buffers. Higher-level frameworks (e.g. Flet) layer their own -serialization (msgpack, JSON, etc.) on top. - -## Usage - -Dart side: - -```dart -import 'package:serious_python_bridge/serious_python_bridge.dart'; - -final bridge = PythonBridge.init(); - -bridge.messages.listen((bytes) { - // bytes posted by Python via dart_bridge.send_bytes(port, payload) -}); - -// Hand off the native port id to Python (typically as the first frame). -bridge.send(_encodeNativePort(bridge.nativePort)); - -// Send arbitrary bytes to Python. -bridge.send(Uint8List.fromList([0x01, 0x02, 0x03])); -``` - -Python side (executed inside the embedded interpreter started by -`serious_python`): - -```python -import dart_bridge - -def on_message(data: bytes) -> None: - ... - -dart_bridge.set_enqueue_handler_func(on_message) -dart_bridge.send_bytes(native_port, b"reply") -``` - -## Threading - -`PythonBridge.send()` is synchronous and acquires the Python GIL for the -duration of the dispatch. Call it from a dedicated isolate rather than the -root isolate to avoid stalling Flutter UI frames. - -## License - -See [LICENSE](LICENSE). diff --git a/src/serious_python_bridge/analysis_options.yaml b/src/serious_python_bridge/analysis_options.yaml deleted file mode 100644 index a5744c1c..00000000 --- a/src/serious_python_bridge/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/src/serious_python_bridge/android/CMakeLists.txt b/src/serious_python_bridge/android/CMakeLists.txt deleted file mode 100644 index 682fdc83..00000000 --- a/src/serious_python_bridge/android/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -set(PROJECT_NAME "serious_python_bridge") -project(${PROJECT_NAME} LANGUAGES C) - -# Python headers + libpython3.so come from the python-android-mobile-forge -# tarball that build.gradle's preparePythonDist task extracts. The gradle -# script passes the staging root via -DPYTHON_DIST_DIR (set to the gradle -# module's buildDir/python-dist — which lives under the *consumer's* build -# tree, NOT the bridge plugin's source dir). We link against libpython at -# build time so Android's strict dynamic linker accepts the .so on load; at -# runtime the linker resolves libpython3.so against the copy -# serious_python_android already shipped in the same jniLibs/${ANDROID_ABI}/. -if(NOT DEFINED PYTHON_DIST_DIR) - message(FATAL_ERROR "PYTHON_DIST_DIR not set — build.gradle must pass it via -DPYTHON_DIST_DIR=") -endif() -set(PYTHON_ABI_DIR "${PYTHON_DIST_DIR}/${ANDROID_ABI}") -set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS "${PYTHON_ABI_DIR}/include/python${PYTHON_VERSION}") -set(FLET_BRIDGE_PYTHON_LIBRARIES "${PYTHON_ABI_DIR}/lib/libpython3.so") - -add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") - -# Android 15: 16 KB page size support. -set_target_properties(flet_bridge PROPERTIES - LINK_FLAGS "-Wl,-z,max-page-size=16384" -) - -set(serious_python_bridge_bundled_libraries - $ - PARENT_SCOPE -) diff --git a/src/serious_python_bridge/android/build.gradle b/src/serious_python_bridge/android/build.gradle deleted file mode 100644 index 3dcebc51..00000000 --- a/src/serious_python_bridge/android/build.gradle +++ /dev/null @@ -1,146 +0,0 @@ -group 'com.flet.serious_python_bridge' -version '2.0.0' - -def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: '3.14' - -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' - classpath 'de.undercouch:gradle-download-task:4.1.2' - } -} - -rootProject.allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' -apply plugin: 'de.undercouch.download' - -// Hoisted before `android { ... }` so the cmake.arguments block below can -// reference it. Mirrors the same expression used later for the extract task. -def pythonStagingRoot = new File(buildDir, 'python-dist') - -android { - namespace "com.flet.serious_python_bridge" - - compileSdkVersion 31 - - externalNativeBuild { - cmake { - path "CMakeLists.txt" - // CMake 3.10.2 is the AGP default; do not raise (Flutter docs). - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdkVersion 21 - - ndk { - // Match the ABI set serious_python_android supports for the same - // python_version (32-bit dropped for 3.13+ per PEP 738). - if (python_version == '3.12') { - abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64' - } else { - abiFilters 'arm64-v8a', 'x86_64' - } - } - - externalNativeBuild { - cmake { - // PYTHON_DIST_DIR is read by android/CMakeLists.txt — must - // match the pythonStagingRoot the extract task writes to - // (which is `buildDir/python-dist`, where buildDir is the - // consumer module's gradle build dir — NOT plugin source). - arguments "-DPYTHON_VERSION=${python_version}", - "-DPYTHON_DIST_DIR=${pythonStagingRoot}" - } - } - } -} - -import de.undercouch.gradle.tasks.download.Download - -def fletCacheRoot = System.getenv('FLET_CACHE_DIR') -def pythonCacheDir = new File( - fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), - "python-build/v${python_version}" -) - -// Headers and libpython3.so are extracted from the same python-android-dart -// tarball that serious_python_android uses. We extract into a build-time -// scratch dir (not jniLibs/) because we do NOT want to ship libpython -// ourselves — serious_python_android ships it; we just link against it at -// build time. (`pythonStagingRoot` is defined above the android{} block so -// it can be passed into the cmake arguments.) - -// Single tarball contains all 4 Android ABIs' Python installs WITH headers -// and the libpython3.so abi3 stub. The python-android-dart variant is just -// runtime libs (no headers), which can't satisfy dart_bridge.c's -// `#include ` at build time. -def archiveName = "python-android-mobile-forge-${python_version}.tar.gz" -def archiveCachePath = new File(pythonCacheDir, archiveName) - -tasks.register("downloadPythonDist", Download) { - src "https://github.com/flet-dev/python-build/releases/download/v${python_version}/${archiveName}" - dest archiveCachePath - onlyIfModified true - useETag "all" - tempAndMove true - doFirst { dest.parentFile.mkdirs() } -} - -def prepareTasks = [] -android.defaultConfig.ndk.abiFilters.each { abi -> - def stagingDir = new File(pythonStagingRoot, abi) - - tasks.register("extractPythonDist_${abi}", Copy) { - dependsOn "downloadPythonDist" - from tarTree(archiveCachePath) - into stagingDir - // mobile-forge layout: install/android//python-/... - include "install/android/${abi}/python-${python_version}.*/include/**" - include "install/android/${abi}/python-${python_version}.*/lib/libpython*.so" - // Flatten the install/android//python-/ prefix so the - // result is python-dist//{include,lib}/... — matches what - // android/CMakeLists.txt expects. - eachFile { fcd -> - fcd.path = fcd.path.replaceAll("^install/android/[^/]+/python-[^/]+/", "") - } - includeEmptyDirs = false - - doFirst { - println "[serious_python_bridge] extractPythonDist_${abi}: staging to ${stagingDir}" - println "[serious_python_bridge] tar: ${archiveCachePath} (exists=${archiveCachePath.exists()})" - } - doLast { - def libpython = new File(stagingDir, "lib/libpython3.so") - def header = new File(stagingDir, "include/python${python_version}/Python.h") - println "[serious_python_bridge] extractPythonDist_${abi} done" - println "[serious_python_bridge] ${libpython}: exists=${libpython.exists()}" - println "[serious_python_bridge] ${header}: exists=${header.exists()}" - if (!libpython.exists() || !header.exists()) { - println "[serious_python_bridge] STAGED CONTENTS:" - stagingDir.eachFileRecurse { f -> println " ${f}" } - } - } - } - - prepareTasks.add("extractPythonDist_${abi}") -} - -task preparePythonDist { dependsOn prepareTasks } -preBuild.dependsOn preparePythonDist diff --git a/src/serious_python_bridge/android/src/main/AndroidManifest.xml b/src/serious_python_bridge/android/src/main/AndroidManifest.xml deleted file mode 100644 index 080338e5..00000000 --- a/src/serious_python_bridge/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift b/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift deleted file mode 100644 index 01d4dd7d..00000000 --- a/src/serious_python_bridge/darwin/Classes/SeriousPythonBridgePlugin.swift +++ /dev/null @@ -1,34 +0,0 @@ -#if os(iOS) -import Flutter -import UIKit -#elseif os(macOS) -import FlutterMacOS -#endif - -import Darwin -import serious_python_darwin - -public class SeriousPythonBridgePlugin: NSObject, FlutterPlugin { - - public static func register(with registrar: FlutterPluginRegistrar) { - // Register dart_bridge as a built-in CPython module so `import - // dart_bridge` resolves against the statically linked symbols in - // ../native/dart_bridge.c instead of looking for a filesystem .so. - // Required on iOS (no late-loaded dylibs allowed). Used on macOS too - // for symbol-visibility consistency: Dart's DynamicLibrary.process() - // and Python's `import dart_bridge` share the same - // global_enqueue_handler_func state. - // - // dlsym(RTLD_DEFAULT) finds PyInit_dart_bridge in the process's global - // symbol table — populated by linking dart_bridge.c into this pod. We - // avoid declaring the symbol in a header because doing so pulls - // into the umbrella module map, which CocoaPods scans - // without the Python.framework search path. - guard let symbol = dlsym(UnsafeMutableRawPointer(bitPattern: -2), "PyInit_dart_bridge") else { - NSLog("[SeriousPythonBridgePlugin] PyInit_dart_bridge symbol not found in process") - return - } - let initFn = unsafeBitCast(symbol, to: SeriousPythonPlugin.PyInitFunction.self) - SeriousPythonPlugin.registerPythonExtension(name: "dart_bridge", initFn: initFn) - } -} diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h deleted file mode 120000 index 8779aae9..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api.h +++ /dev/null @@ -1 +0,0 @@ -../../../native/dart_api/dart_api.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c deleted file mode 120000 index 436f0e2d..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.c +++ /dev/null @@ -1 +0,0 @@ -../../../native/dart_api/dart_api_dl.c \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h deleted file mode 120000 index 5e1f970b..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/dart_api_dl.h +++ /dev/null @@ -1 +0,0 @@ -../../../native/dart_api/dart_api_dl.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h deleted file mode 120000 index e9be7b9e..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/dart_native_api.h +++ /dev/null @@ -1 +0,0 @@ -../../../native/dart_api/dart_native_api.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h deleted file mode 120000 index f8b2a698..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/dart_tools_api.h +++ /dev/null @@ -1 +0,0 @@ -../../../native/dart_api/dart_tools_api.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h b/src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h deleted file mode 120000 index 58d7bc46..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/dart_version.h +++ /dev/null @@ -1 +0,0 @@ -../../../native/dart_api/dart_version.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h b/src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h deleted file mode 120000 index 5e5068b9..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_api/internal/dart_api_dl_impl.h +++ /dev/null @@ -1 +0,0 @@ -../../../../native/dart_api/internal/dart_api_dl_impl.h \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_bridge.c b/src/serious_python_bridge/darwin/Classes/dart_bridge.c deleted file mode 120000 index b3c323a8..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_bridge.c +++ /dev/null @@ -1 +0,0 @@ -../../native/dart_bridge.c \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c b/src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c deleted file mode 120000 index 0d896916..00000000 --- a/src/serious_python_bridge/darwin/Classes/dart_bridge_shim.c +++ /dev/null @@ -1 +0,0 @@ -../../native/dart_bridge_shim.c \ No newline at end of file diff --git a/src/serious_python_bridge/darwin/serious_python_bridge.podspec b/src/serious_python_bridge/darwin/serious_python_bridge.podspec deleted file mode 100644 index 41ee8cc0..00000000 --- a/src/serious_python_bridge/darwin/serious_python_bridge.podspec +++ /dev/null @@ -1,53 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint serious_python_bridge.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'serious_python_bridge' - s.version = '2.0.0' - s.summary = 'Generic in-process Dart ↔ Python byte transport for serious_python.' - s.description = <<-DESC - Pure-FFI Flutter plugin that exposes the dart_bridge C primitives - (DartBridge_InitDartApiDL, DartBridge_EnqueueMessage) and the matching - Python module (send_bytes, set_enqueue_handler_func). On Apple platforms - the bridge is statically linked into the app process and registered with - CPython via serious_python_darwin's registerPythonExtension hook. - DESC - s.homepage = 'https://flet.dev' - s.license = { :file => '../LICENSE' } - s.author = { 'Appveyor Systems Inc.' => 'hello@flet.dev' } - s.source = { :path => '.' } - - # CocoaPods silently drops `s.source_files` entries that traverse outside - # the podspec's directory (`../native/*.c`), so Classes/ contains committed - # symlinks to the canonical native/ sources. Symlinks (rather than copies) - # keep native/ as the single source of truth shared with linux/, windows/, - # android/ CMakeLists builds. The darwin/ pod is only built on Apple - # platforms where symlinks-in-git work fine. - # - # No public headers exposed — Swift accesses PyInit_dart_bridge via - # dlsym(RTLD_DEFAULT, ...), keeping out of the umbrella modulemap. - s.source_files = 'Classes/**/*.{swift,c,h}' - - s.ios.dependency 'Flutter' - s.osx.dependency 'FlutterMacOS' - s.dependency 'serious_python_darwin' - - s.ios.deployment_target = '13.0' - s.osx.deployment_target = '10.15' - - s.pod_target_xcconfig = { - 'DEFINES_MODULE' => 'YES', - # First entry: dart_bridge.c does `#include "dart_api/dart_api_dl.h"`. - # Second entry: dart_bridge.c does `#include ` (standard, - # non-framework form). The Python xcframework's slice is extracted by - # CocoaPods into PODS_XCFRAMEWORKS_BUILD_DIR/serious_python_darwin/ - # Python.framework, so pointing at its Headers/ subdirectory lets the - # unprefixed include resolve without changing the .c source. - 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}/../native" "${PODS_XCFRAMEWORKS_BUILD_DIR}/serious_python_darwin/Python.framework/Headers"', - # Py* symbols are resolved at the final app link against the Python - # framework provided by serious_python_darwin's vendored xcframework. - 'OTHER_LDFLAGS' => '$(inherited) -undefined dynamic_lookup', - } - s.swift_version = '5.0' -end diff --git a/src/serious_python_bridge/lib/serious_python_bridge.dart b/src/serious_python_bridge/lib/serious_python_bridge.dart deleted file mode 100644 index 06ca98b8..00000000 --- a/src/serious_python_bridge/lib/serious_python_bridge.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'dart:async'; -import 'dart:ffi'; -import 'dart:io'; -import 'dart:isolate'; -import 'dart:typed_data'; - -import 'package:ffi/ffi.dart'; - -typedef _DartBridgeInitNative = IntPtr Function(Pointer); -typedef _DartBridgeInit = int Function(Pointer); - -typedef _DartBridgeEnqueueNative = Void Function(Pointer, IntPtr); -typedef _DartBridgeEnqueue = void Function(Pointer, int); - -/// Generic in-process Dart ↔ Python byte transport. -/// -/// Wraps the native `dart_bridge` C symbols (`DartBridge_InitDartApiDL`, -/// `DartBridge_EnqueueMessage`, and the corresponding Python-side -/// `dart_bridge.send_bytes`) into an idiomatic Dart API: -/// -/// * `messages` — broadcast stream of byte buffers posted from Python. -/// * `send(bytes)` — push bytes to Python (synchronous; acquires the GIL). -/// * `nativePort` — the Dart native port id Python uses to post back; the -/// caller is responsible for handing this id to Python in whatever way its -/// protocol requires (typically as the first frame). -/// -/// The bridge is process-global state (Python's `global_enqueue_handler_func` -/// and Dart's API-DL initialization are both singletons), so this class is -/// implemented as a singleton. `PythonBridge.init()` is idempotent. -/// -/// Threading: `send()` blocks the calling thread for the duration of the -/// Python handler dispatch (which runs synchronously under `PyGILState_Ensure`). -/// To avoid stalling Flutter UI frames, call `send()` from a dedicated isolate -/// rather than the root isolate. -class PythonBridge { - PythonBridge._(); - - static PythonBridge? _instance; - - late final DynamicLibrary _lib; - late final _DartBridgeInit _initDartApiDL; - late final _DartBridgeEnqueue _enqueueMessage; - - late final ReceivePort _receivePort; - final StreamController _messages = - StreamController.broadcast(); - - /// Returns the singleton bridge instance, initializing it on first call. - factory PythonBridge.init() { - final existing = _instance; - if (existing != null) return existing; - final bridge = PythonBridge._().._initialize(); - _instance = bridge; - return bridge; - } - - /// The currently initialized bridge, or `null` if `init()` hasn't been called. - static PythonBridge? get instance => _instance; - - void _initialize() { - _lib = _openNativeLibrary(); - - _initDartApiDL = _lib - .lookup>('DartBridge_InitDartApiDL') - .asFunction(); - _enqueueMessage = _lib - .lookup>('DartBridge_EnqueueMessage') - .asFunction(); - - if (_initDartApiDL(NativeApi.initializeApiDLData) != 0) { - throw StateError( - 'DartBridge_InitDartApiDL failed: Dart VM API version mismatch'); - } - - _receivePort = ReceivePort(); - _receivePort.listen((message) { - if (message is Uint8List) { - _messages.add(message); - } else if (message is TransferableTypedData) { - _messages.add(message.materialize().asUint8List()); - } - }); - } - - static DynamicLibrary _openNativeLibrary() { - // Apple platforms (iOS + macOS desktop): the bridge is linked into the - // app process by the serious_python_bridge pod and registered with CPython - // via inittab. DynamicLibrary.process() resolves DartBridge_* via dlsym - // on the host process; no separate dylib open is needed. - if (Platform.isIOS || Platform.isMacOS) return DynamicLibrary.process(); - if (Platform.isWindows) return DynamicLibrary.open('flet_bridge.dll'); - if (Platform.isLinux || Platform.isAndroid) { - return DynamicLibrary.open('libflet_bridge.so'); - } - throw UnsupportedError( - 'serious_python_bridge does not support ${Platform.operatingSystem}'); - } - - /// Bytes posted from Python via `dart_bridge.send_bytes(port, payload)`. - Stream get messages => _messages.stream; - - /// Native port id to hand to Python so it can post back to this bridge. - int get nativePort => _receivePort.sendPort.nativePort; - - /// Send a buffer to the Python handler registered via - /// `dart_bridge.set_enqueue_handler_func`. - /// - /// The call is synchronous and acquires the Python GIL for the duration of - /// the dispatch. Callers should run this off the root isolate to avoid - /// stalling Flutter UI frames. - void send(Uint8List bytes) { - using((arena) { - final ptr = arena(bytes.length); - ptr.asTypedList(bytes.length).setAll(0, bytes); - _enqueueMessage(ptr, bytes.length); - }); - } - - /// Release resources and tear down the singleton. After dispose, callers - /// must invoke `PythonBridge.init()` again before further use. - void dispose() { - _receivePort.close(); - _messages.close(); - _instance = null; - } -} diff --git a/src/serious_python_bridge/linux/CMakeLists.txt b/src/serious_python_bridge/linux/CMakeLists.txt deleted file mode 100644 index be9816ce..00000000 --- a/src/serious_python_bridge/linux/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -set(PROJECT_NAME "serious_python_bridge") -project(${PROJECT_NAME} LANGUAGES C) - -add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") - -# Flutter picks up bundled libraries via this variable and copies the file -# alongside the app binary; Dart resolves it via DynamicLibrary.open. -set(serious_python_bridge_bundled_libraries - $ - PARENT_SCOPE -) diff --git a/src/serious_python_bridge/native/CMakeLists.txt b/src/serious_python_bridge/native/CMakeLists.txt deleted file mode 100644 index 5c3dea02..00000000 --- a/src/serious_python_bridge/native/CMakeLists.txt +++ /dev/null @@ -1,67 +0,0 @@ -# Cross-platform CMake target for libflet_bridge. -# -# Built from the same dart_bridge.c source used by the Python shim. Per-platform -# wrappers under linux/, windows/, android/ include this file via add_subdirectory. -# -# Python integration: -# - If FLET_BRIDGE_PYTHON_INCLUDE_DIRS + FLET_BRIDGE_PYTHON_LIBRARIES are set -# before add_subdirectory, those are used (Android uses this path to point -# at the python-android-dart tarball it downloads). -# - Otherwise we use find_package(Python3 ... Development.Module) + the -# Python3::Module imported target, which handles Linux/macOS/Windows link -# conventions automatically. - -cmake_minimum_required(VERSION 3.15) - -project(flet_bridge VERSION 0.0.1 LANGUAGES C) - -if(NOT DEFINED FLET_BRIDGE_PYTHON_INCLUDE_DIRS) - find_package(Python3 REQUIRED COMPONENTS Development.Module) - set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS ${Python3_INCLUDE_DIRS}) - if(WIN32) - # Python3::Module picks pythonXY.lib (or pythonXY_d.lib in Debug builds), - # but python-build-standalone for Windows doesn't ship a Debug variant - # so Flutter's debug builds fail with LNK1104. Link the abi3 stable-ABI - # stub python3.lib instead — it's version-agnostic AND has no debug - # variant requirement (matches our Py_LIMITED_API choice). - get_filename_component(_flet_bridge_python_root "${Python3_INCLUDE_DIRS}" DIRECTORY) - set(FLET_BRIDGE_PYTHON_LIBRARIES "${_flet_bridge_python_root}/libs/python3.lib") - else() - set(FLET_BRIDGE_PYTHON_LIBRARIES Python3::Module) - endif() -endif() - -add_library(flet_bridge SHARED - "dart_bridge.c" - "dart_api/dart_api_dl.c" -) - -target_include_directories(flet_bridge PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}" - ${FLET_BRIDGE_PYTHON_INCLUDE_DIRS} -) - -target_link_libraries(flet_bridge PRIVATE ${FLET_BRIDGE_PYTHON_LIBRARIES}) - -set_target_properties(flet_bridge PROPERTIES - C_VISIBILITY_PRESET hidden - OUTPUT_NAME "flet_bridge" -) - -target_compile_definitions(flet_bridge PRIVATE DART_SHARED_LIB) - -if(WIN32) - # Python's pyconfig.h emits `#pragma comment(lib, "pythonXY_d.lib")` in - # Debug builds, which makes MSVC auto-link the Debug variant of libpython - # even though we explicitly linked python3.lib above. python-build-standalone - # doesn't ship a Debug lib, so the link fails (LNK1104). Py_NO_LINK_LIB - # suppresses the pragma in Python 3.14+, but 3.12 and 3.13 pyconfig.h don't - # honor it — use /NODEFAULTLIB:pythonXY_d.lib to explicitly exclude the - # Debug lib at link time. Works on every supported version. - target_compile_definitions(flet_bridge PRIVATE Py_NO_LINK_LIB) - if(Python3_VERSION_MAJOR AND Python3_VERSION_MINOR) - target_link_options(flet_bridge PRIVATE - "/NODEFAULTLIB:python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}_d.lib" - ) - endif() -endif() diff --git a/src/serious_python_bridge/native/dart_api/dart_api.h b/src/serious_python_bridge/native/dart_api/dart_api.h deleted file mode 100644 index 1d83c903..00000000 --- a/src/serious_python_bridge/native/dart_api/dart_api.h +++ /dev/null @@ -1,4186 +0,0 @@ -/* - * Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#ifndef RUNTIME_INCLUDE_DART_API_H_ -#define RUNTIME_INCLUDE_DART_API_H_ - -/** \mainpage Dart Embedding API Reference - * - * This reference describes the Dart Embedding API, which is used to embed the - * Dart Virtual Machine within C/C++ applications. - * - * This reference is generated from the header include/dart_api.h. - */ - -/* __STDC_FORMAT_MACROS has to be defined before including to - * enable platform independent printf format specifiers. */ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif - -#include -#include -#include - -#if defined(__Fuchsia__) -#include -#endif - -#ifdef __cplusplus -#define DART_EXTERN_C extern "C" -#else -#define DART_EXTERN_C extern -#endif - -#if defined(__CYGWIN__) -#error Tool chain and platform not supported. -#elif defined(_WIN32) -#if defined(DART_SHARED_LIB) -#define DART_EXPORT DART_EXTERN_C __declspec(dllexport) -#else -#define DART_EXPORT DART_EXTERN_C -#endif -#else -#if __GNUC__ >= 4 -#if defined(DART_SHARED_LIB) -#define DART_EXPORT \ - DART_EXTERN_C __attribute__((visibility("default"))) __attribute((used)) -#else -#define DART_EXPORT DART_EXTERN_C -#endif -#else -#error Tool chain not supported. -#endif -#endif - -#if __GNUC__ -#define DART_API_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#define DART_API_DEPRECATED(msg) __attribute__((deprecated(msg))) -#elif _MSC_VER -#define DART_API_WARN_UNUSED_RESULT _Check_return_ -#define DART_API_DEPRECATED(msg) __declspec(deprecated(msg)) -#else -#define DART_API_WARN_UNUSED_RESULT -#define DART_API_DEPRECATED(msg) -#endif - -/* - * ======= - * Handles - * ======= - */ - -/** - * An isolate is the unit of concurrency in Dart. Each isolate has - * its own memory and thread of control. No state is shared between - * isolates. Instead, isolates communicate by message passing. - * - * Each thread keeps track of its current isolate, which is the - * isolate which is ready to execute on the current thread. The - * current isolate may be NULL, in which case no isolate is ready to - * execute. Most of the Dart apis require there to be a current - * isolate in order to function without error. The current isolate is - * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate. - */ -typedef struct _Dart_Isolate* Dart_Isolate; -typedef struct _Dart_IsolateGroup* Dart_IsolateGroup; - -/** - * An object reference managed by the Dart VM garbage collector. - * - * Because the garbage collector may move objects, it is unsafe to - * refer to objects directly. Instead, we refer to objects through - * handles, which are known to the garbage collector and updated - * automatically when the object is moved. Handles should be passed - * by value (except in cases like out-parameters) and should never be - * allocated on the heap. - * - * Most functions in the Dart Embedding API return a handle. When a - * function completes normally, this will be a valid handle to an - * object in the Dart VM heap. This handle may represent the result of - * the operation or it may be a special valid handle used merely to - * indicate successful completion. Note that a valid handle may in - * some cases refer to the null object. - * - * --- Error handles --- - * - * When a function encounters a problem that prevents it from - * completing normally, it returns an error handle (See Dart_IsError). - * An error handle has an associated error message that gives more - * details about the problem (See Dart_GetError). - * - * There are four kinds of error handles that can be produced, - * depending on what goes wrong: - * - * - Api error handles are produced when an api function is misused. - * This happens when a Dart embedding api function is called with - * invalid arguments or in an invalid context. - * - * - Unhandled exception error handles are produced when, during the - * execution of Dart code, an exception is thrown but not caught. - * Prototypically this would occur during a call to Dart_Invoke, but - * it can occur in any function which triggers the execution of Dart - * code (for example, Dart_ToString). - * - * An unhandled exception error provides access to an exception and - * stacktrace via the functions Dart_ErrorGetException and - * Dart_ErrorGetStackTrace. - * - * - Compilation error handles are produced when, during the execution - * of Dart code, a compile-time error occurs. As above, this can - * occur in any function which triggers the execution of Dart code. - * - * - Fatal error handles are produced when the system wants to shut - * down the current isolate. - * - * --- Propagating errors --- - * - * When an error handle is returned from the top level invocation of - * Dart code in a program, the embedder must handle the error as they - * see fit. Often, the embedder will print the error message produced - * by Dart_Error and exit the program. - * - * When an error is returned while in the body of a native function, - * it can be propagated up the call stack by calling - * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException. - * Errors should be propagated unless there is a specific reason not - * to. If an error is not propagated then it is ignored. For - * example, if an unhandled exception error is ignored, that - * effectively "catches" the unhandled exception. Fatal errors must - * always be propagated. - * - * When an error is propagated, any current scopes created by - * Dart_EnterScope will be exited. - * - * Using Dart_SetReturnValue to propagate an exception is somewhat - * more convenient than using Dart_PropagateError, and should be - * preferred for reasons discussed below. - * - * Dart_PropagateError and Dart_ThrowException do not return. Instead - * they transfer control non-locally using a setjmp-like mechanism. - * This can be inconvenient if you have resources that you need to - * clean up before propagating the error. - * - * When relying on Dart_PropagateError, we often return error handles - * rather than propagating them from helper functions. Consider the - * following contrived example: - * - * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) { - * 2 intptr_t* length = 0; - * 3 result = Dart_StringLength(arg, &length); - * 4 if (Dart_IsError(result)) { - * 5 return result; - * 6 } - * 7 return Dart_NewBoolean(length > 100); - * 8 } - * 9 - * 10 void NativeFunction_isLongString(Dart_NativeArguments args) { - * 11 Dart_EnterScope(); - * 12 AllocateMyResource(); - * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); - * 14 Dart_Handle result = isLongStringHelper(arg); - * 15 if (Dart_IsError(result)) { - * 16 FreeMyResource(); - * 17 Dart_PropagateError(result); - * 18 abort(); // will not reach here - * 19 } - * 20 Dart_SetReturnValue(result); - * 21 FreeMyResource(); - * 22 Dart_ExitScope(); - * 23 } - * - * In this example, we have a native function which calls a helper - * function to do its work. On line 5, the helper function could call - * Dart_PropagateError, but that would not give the native function a - * chance to call FreeMyResource(), causing a leak. Instead, the - * helper function returns the error handle to the caller, giving the - * caller a chance to clean up before propagating the error handle. - * - * When an error is propagated by calling Dart_SetReturnValue, the - * native function will be allowed to complete normally and then the - * exception will be propagated only once the native call - * returns. This can be convenient, as it allows the C code to clean - * up normally. - * - * The example can be written more simply using Dart_SetReturnValue to - * propagate the error. - * - * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) { - * 2 intptr_t* length = 0; - * 3 result = Dart_StringLength(arg, &length); - * 4 if (Dart_IsError(result)) { - * 5 return result - * 6 } - * 7 return Dart_NewBoolean(length > 100); - * 8 } - * 9 - * 10 void NativeFunction_isLongString(Dart_NativeArguments args) { - * 11 Dart_EnterScope(); - * 12 AllocateMyResource(); - * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); - * 14 Dart_SetReturnValue(isLongStringHelper(arg)); - * 15 FreeMyResource(); - * 16 Dart_ExitScope(); - * 17 } - * - * In this example, the call to Dart_SetReturnValue on line 14 will - * either return the normal return value or the error (potentially - * generated on line 3). The call to FreeMyResource on line 15 will - * execute in either case. - * - * --- Local and persistent handles --- - * - * Local handles are allocated within the current scope (see - * Dart_EnterScope) and go away when the current scope exits. Unless - * otherwise indicated, callers should assume that all functions in - * the Dart embedding api return local handles. - * - * Persistent handles are allocated within the current isolate. They - * can be used to store objects across scopes. Persistent handles have - * the lifetime of the current isolate unless they are explicitly - * deallocated (see Dart_DeletePersistentHandle). - * The type Dart_Handle represents a handle (both local and persistent). - * The type Dart_PersistentHandle is a Dart_Handle and it is used to - * document that a persistent handle is expected as a parameter to a call - * or the return value from a call is a persistent handle. - * - * FinalizableHandles are persistent handles which are auto deleted when - * the object is garbage collected. It is never safe to use these handles - * unless you know the object is still reachable. - * - * WeakPersistentHandles are persistent handles which are automatically set - * to point Dart_Null when the object is garbage collected. They are not auto - * deleted, so it is safe to use them after the object has become unreachable. - */ -typedef struct _Dart_Handle* Dart_Handle; -typedef Dart_Handle Dart_PersistentHandle; -typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle; -typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle; -// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the -// version when changing this struct. - -typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer); - -/** - * Is this an error handle? - * - * Requires there to be a current isolate. - */ -DART_EXPORT bool Dart_IsError(Dart_Handle handle); - -/** - * Is this an api error handle? - * - * Api error handles are produced when an api function is misused. - * This happens when a Dart embedding api function is called with - * invalid arguments or in an invalid context. - * - * Requires there to be a current isolate. - */ -DART_EXPORT bool Dart_IsApiError(Dart_Handle handle); - -/** - * Is this an unhandled exception error handle? - * - * Unhandled exception error handles are produced when, during the - * execution of Dart code, an exception is thrown but not caught. - * This can occur in any function which triggers the execution of Dart - * code. - * - * See Dart_ErrorGetException and Dart_ErrorGetStackTrace. - * - * Requires there to be a current isolate. - */ -DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle handle); - -/** - * Is this a compilation error handle? - * - * Compilation error handles are produced when, during the execution - * of Dart code, a compile-time error occurs. This can occur in any - * function which triggers the execution of Dart code. - * - * Requires there to be a current isolate. - */ -DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle); - -/** - * Is this a fatal error handle? - * - * Fatal error handles are produced when the system wants to shut down - * the current isolate. - * - * Requires there to be a current isolate. - */ -DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle); - -/** - * Gets the error message from an error handle. - * - * Requires there to be a current isolate. - * - * \return A C string containing an error message if the handle is - * error. An empty C string ("") if the handle is valid. This C - * String is scope allocated and is only valid until the next call - * to Dart_ExitScope. -*/ -DART_EXPORT const char* Dart_GetError(Dart_Handle handle); - -/** - * Is this an error handle for an unhandled exception? - */ -DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle); - -/** - * Gets the exception Object from an unhandled exception error handle. - */ -DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle); - -/** - * Gets the stack trace Object from an unhandled exception error handle. - */ -DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle); - -/** - * Produces an api error handle with the provided error message. - * - * Requires there to be a current isolate. - * - * \param error the error message. - */ -DART_EXPORT Dart_Handle Dart_NewApiError(const char* error); -DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error); - -/** - * Produces a new unhandled exception error handle. - * - * Requires there to be a current isolate. - * - * \param exception An instance of a Dart object to be thrown or - * an ApiError or CompilationError handle. - * When an ApiError or CompilationError handle is passed in - * a string object of the error message is created and it becomes - * the Dart object to be thrown. - */ -DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception); - -/** - * Propagates an error. - * - * If the provided handle is an unhandled exception error, this - * function will cause the unhandled exception to be rethrown. This - * will proceed in the standard way, walking up Dart frames until an - * appropriate 'catch' block is found, executing 'finally' blocks, - * etc. - * - * If the error is not an unhandled exception error, we will unwind - * the stack to the next C frame. Intervening Dart frames will be - * discarded; specifically, 'finally' blocks will not execute. This - * is the standard way that compilation errors (and the like) are - * handled by the Dart runtime. - * - * In either case, when an error is propagated any current scopes - * created by Dart_EnterScope will be exited. - * - * See the additional discussion under "Propagating Errors" at the - * beginning of this file. - * - * \param handle An error handle (See Dart_IsError) - * - * On success, this function does not return. On failure, the - * process is terminated. - */ -DART_EXPORT void Dart_PropagateError(Dart_Handle handle); - -/** - * Converts an object to a string. - * - * May generate an unhandled exception error. - * - * \return The converted string if no error occurs during - * the conversion. If an error does occur, an error handle is - * returned. - */ -DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object); - -/** - * Checks to see if two handles refer to identically equal objects. - * - * If both handles refer to instances, this is equivalent to using the top-level - * function identical() from dart:core. Otherwise, returns whether the two - * argument handles refer to the same object. - * - * \param obj1 An object to be compared. - * \param obj2 An object to be compared. - * - * \return True if the objects are identically equal. False otherwise. - */ -DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2); - -/** - * Allocates a handle in the current scope from a persistent handle. - */ -DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object); - -/** - * Allocates a handle in the current scope from a weak persistent handle. - * - * This will be a handle to Dart_Null if the object has been garbage collected. - */ -DART_EXPORT Dart_Handle -Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object); - -/** - * Allocates a persistent handle for an object. - * - * This handle has the lifetime of the current isolate unless it is - * explicitly deallocated by calling Dart_DeletePersistentHandle. - * - * Requires there to be a current isolate. - */ -DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object); - -/** - * Assign value of local handle to a persistent handle. - * - * Requires there to be a current isolate. - * - * \param obj1 A persistent handle whose value needs to be set. - * \param obj2 An object whose value needs to be set to the persistent handle. - */ -DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1, - Dart_Handle obj2); - -/** - * Deallocates a persistent handle. - * - * Requires there to be a current isolate group. - */ -DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object); - -/** - * Allocates a weak persistent handle for an object. - * - * This handle has the lifetime of the current isolate. The handle can also be - * explicitly deallocated by calling Dart_DeleteWeakPersistentHandle. - * - * If the object becomes unreachable the callback is invoked with the peer as - * argument. The callback can be executed on any thread, will have a current - * isolate group, but will not have a current isolate. The callback can only - * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This - * gives the embedder the ability to cleanup data associated with the object. - * The handle will point to the Dart_Null object after the finalizer has been - * run. It is illegal to call into the VM with any other Dart_* functions from - * the callback. If the handle is deleted before the object becomes - * unreachable, the callback is never invoked. - * - * Requires there to be a current isolate. - * - * \param object An object with identity. - * \param peer A pointer to a native object or NULL. This value is - * provided to callback when it is invoked. - * \param external_allocation_size The number of externally allocated - * bytes for peer. Used to inform the garbage collector. - * \param callback A function pointer that will be invoked sometime - * after the object is garbage collected, unless the handle has been deleted. - * A valid callback needs to be specified it cannot be NULL. - * - * \return The weak persistent handle or NULL. NULL is returned in case of bad - * parameters. - */ -DART_EXPORT Dart_WeakPersistentHandle -Dart_NewWeakPersistentHandle(Dart_Handle object, - void* peer, - intptr_t external_allocation_size, - Dart_HandleFinalizer callback); - -/** - * Deletes the given weak persistent [object] handle. - * - * Requires there to be a current isolate group. - */ -DART_EXPORT void Dart_DeleteWeakPersistentHandle( - Dart_WeakPersistentHandle object); - -/** - * Allocates a finalizable handle for an object. - * - * This handle has the lifetime of the current isolate group unless the object - * pointed to by the handle is garbage collected, in this case the VM - * automatically deletes the handle after invoking the callback associated - * with the handle. The handle can also be explicitly deallocated by - * calling Dart_DeleteFinalizableHandle. - * - * If the object becomes unreachable the callback is invoked with the - * the peer as argument. The callback can be executed on any thread, will have - * an isolate group, but will not have a current isolate. The callback can only - * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. - * This gives the embedder the ability to cleanup data associated with the - * object and clear out any cached references to the handle. All references to - * this handle after the callback will be invalid. It is illegal to call into - * the VM with any other Dart_* functions from the callback. If the handle is - * deleted before the object becomes unreachable, the callback is never - * invoked. - * - * Requires there to be a current isolate. - * - * \param object An object with identity. - * \param peer A pointer to a native object or NULL. This value is - * provided to callback when it is invoked. - * \param external_allocation_size The number of externally allocated - * bytes for peer. Used to inform the garbage collector. - * \param callback A function pointer that will be invoked sometime - * after the object is garbage collected, unless the handle has been deleted. - * A valid callback needs to be specified it cannot be NULL. - * - * \return The finalizable handle or NULL. NULL is returned in case of bad - * parameters. - */ -DART_EXPORT Dart_FinalizableHandle -Dart_NewFinalizableHandle(Dart_Handle object, - void* peer, - intptr_t external_allocation_size, - Dart_HandleFinalizer callback); - -/** - * Deletes the given finalizable [object] handle. - * - * The caller has to provide the actual Dart object the handle was created from - * to prove the object (and therefore the finalizable handle) is still alive. - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_DeleteFinalizableHandle(Dart_FinalizableHandle object, - Dart_Handle strong_ref_to_object); - -/* - * ========================== - * Initialization and Globals - * ========================== - */ - -/** - * Gets the version string for the Dart VM. - * - * The version of the Dart VM can be accessed without initializing the VM. - * - * \return The version string for the embedded Dart VM. - */ -DART_EXPORT const char* Dart_VersionString(void); - -/** - * Isolate specific flags are set when creating a new isolate using the - * Dart_IsolateFlags structure. - * - * Current version of flags is encoded in a 32-bit integer with 16 bits used - * for each part. - */ - -#define DART_FLAGS_CURRENT_VERSION (0x0000000d) - -typedef struct { - int32_t version; - bool enable_asserts; - bool use_field_guards; - bool use_osr; - bool obfuscate; - bool load_vmservice_library; - bool null_safety; - bool is_system_isolate; - bool is_service_isolate; - bool is_kernel_isolate; - bool snapshot_is_dontneed_safe; - bool branch_coverage; - bool coverage; -} Dart_IsolateFlags; - -/** - * Initialize Dart_IsolateFlags with correct version and default values. - */ -DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); - -/** - * An isolate creation and initialization callback function. - * - * This callback, provided by the embedder, is called when the VM - * needs to create an isolate. The callback should create an isolate - * by calling Dart_CreateIsolateGroup and load any scripts required for - * execution. - * - * This callback may be called on a different thread than the one - * running the parent isolate. - * - * When the function returns NULL, it is the responsibility of this - * function to ensure that Dart_ShutdownIsolate has been called if - * required (for example, if the isolate was created successfully by - * Dart_CreateIsolateGroup() but the root library fails to load - * successfully, then the function should call Dart_ShutdownIsolate - * before returning). - * - * When the function returns NULL, the function should set *error to - * a malloc-allocated buffer containing a useful error message. The - * caller of this function (the VM) will make sure that the buffer is - * freed. - * - * \param script_uri The uri of the main source file or snapshot to load. - * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for - * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the - * library tag handler of the parent isolate. - * The callback is responsible for loading the program by a call to - * Dart_LoadScriptFromKernel. - * \param main The name of the main entry point this isolate will - * eventually run. This is provided for advisory purposes only to - * improve debugging messages. The main function is not invoked by - * this function. - * \param package_root Ignored. - * \param package_config Uri of the package configuration file (either in format - * of .packages or .dart_tool/package_config.json) for this isolate - * to resolve package imports against. If this parameter is not passed the - * package resolution of the parent isolate should be used. - * \param flags Default flags for this isolate being spawned. Either inherited - * from the spawning isolate or passed as parameters when spawning the - * isolate from Dart code. - * \param isolate_data The isolate data which was passed to the - * parent isolate when it was created by calling Dart_CreateIsolateGroup(). - * \param error A structure into which the embedder can place a - * C string containing an error message in the case of failures. - * - * \return The embedder returns NULL if the creation and - * initialization was not successful and the isolate if successful. - */ -typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)( - const char* script_uri, - const char* main, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - void* isolate_data, - char** error); - -/** - * An isolate initialization callback function. - * - * This callback, provided by the embedder, is called when the VM has created an - * isolate within an existing isolate group (i.e. from the same source as an - * existing isolate). - * - * The callback should setup native resolvers and might want to set a custom - * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as - * runnable. - * - * This callback may be called on a different thread than the one - * running the parent isolate. - * - * When the function returns `false`, it is the responsibility of this - * function to ensure that `Dart_ShutdownIsolate` has been called. - * - * When the function returns `false`, the function should set *error to - * a malloc-allocated buffer containing a useful error message. The - * caller of this function (the VM) will make sure that the buffer is - * freed. - * - * \param child_isolate_data The callback data to associate with the new - * child isolate. - * \param error A structure into which the embedder can place a - * C string containing an error message in the case the initialization fails. - * - * \return The embedder returns true if the initialization was successful and - * false otherwise (in which case the VM will terminate the isolate). - */ -typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data, - char** error); - -/** - * An isolate shutdown callback function. - * - * This callback, provided by the embedder, is called before the vm - * shuts down an isolate. The isolate being shutdown will be the current - * isolate. It is safe to run Dart code. - * - * This function should be used to dispose of native resources that - * are allocated to an isolate in order to avoid leaks. - * - * \param isolate_group_data The same callback data which was passed to the - * isolate group when it was created. - * \param isolate_data The same callback data which was passed to the isolate - * when it was created. - */ -typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data, - void* isolate_data); - -/** - * An isolate cleanup callback function. - * - * This callback, provided by the embedder, is called after the vm - * shuts down an isolate. There will be no current isolate and it is *not* - * safe to run Dart code. - * - * This function should be used to dispose of native resources that - * are allocated to an isolate in order to avoid leaks. - * - * \param isolate_group_data The same callback data which was passed to the - * isolate group when it was created. - * \param isolate_data The same callback data which was passed to the isolate - * when it was created. - */ -typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data, - void* isolate_data); - -/** - * An isolate group cleanup callback function. - * - * This callback, provided by the embedder, is called after the vm - * shuts down an isolate group. - * - * This function should be used to dispose of native resources that - * are allocated to an isolate in order to avoid leaks. - * - * \param isolate_group_data The same callback data which was passed to the - * isolate group when it was created. - * - */ -typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data); - -/** - * A thread start callback function. - * This callback, provided by the embedder, is called after a thread in the - * vm thread pool starts. - * This function could be used to adjust thread priority or attach native - * resources to the thread. - */ -typedef void (*Dart_ThreadStartCallback)(void); - -/** - * A thread death callback function. - * This callback, provided by the embedder, is called before a thread in the - * vm thread pool exits. - * This function could be used to dispose of native resources that - * are associated and attached to the thread, in order to avoid leaks. - */ -typedef void (*Dart_ThreadExitCallback)(void); - -/** - * Opens a file for reading or writing. - * - * Callback provided by the embedder for file operations. If the - * embedder does not allow file operations this callback can be - * NULL. - * - * \param name The name of the file to open. - * \param write A boolean variable which indicates if the file is to - * opened for writing. If there is an existing file it needs to truncated. - */ -typedef void* (*Dart_FileOpenCallback)(const char* name, bool write); - -/** - * Read contents of file. - * - * Callback provided by the embedder for file operations. If the - * embedder does not allow file operations this callback can be - * NULL. - * - * \param data Buffer allocated in the callback into which the contents - * of the file are read into. It is the responsibility of the caller to - * free this buffer. - * \param file_length A variable into which the length of the file is returned. - * In the case of an error this value would be -1. - * \param stream Handle to the opened file. - */ -typedef void (*Dart_FileReadCallback)(uint8_t** data, - intptr_t* file_length, - void* stream); - -/** - * Write data into file. - * - * Callback provided by the embedder for file operations. If the - * embedder does not allow file operations this callback can be - * NULL. - * - * \param data Buffer which needs to be written into the file. - * \param length Length of the buffer. - * \param stream Handle to the opened file. - */ -typedef void (*Dart_FileWriteCallback)(const void* data, - intptr_t length, - void* stream); - -/** - * Closes the opened file. - * - * Callback provided by the embedder for file operations. If the - * embedder does not allow file operations this callback can be - * NULL. - * - * \param stream Handle to the opened file. - */ -typedef void (*Dart_FileCloseCallback)(void* stream); - -typedef bool (*Dart_EntropySource)(uint8_t* buffer, intptr_t length); - -/** - * Callback provided by the embedder that is used by the vmservice isolate - * to request the asset archive. The asset archive must be an uncompressed tar - * archive that is stored in a Uint8List. - * - * If the embedder has no vmservice isolate assets, the callback can be NULL. - * - * \return The embedder must return a handle to a Uint8List containing an - * uncompressed tar archive or null. - */ -typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(void); - -/** - * The current version of the Dart_InitializeFlags. Should be incremented every - * time Dart_InitializeFlags changes in a binary incompatible way. - */ -#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000008) - -/** Forward declaration */ -struct Dart_CodeObserver; - -/** - * Callback provided by the embedder that is used by the VM to notify on code - * object creation, *before* it is invoked the first time. - * This is useful for embedders wanting to e.g. keep track of PCs beyond - * the lifetime of the garbage collected code objects. - * Note that an address range may be used by more than one code object over the - * lifecycle of a process. Clients of this function should record timestamps for - * these compilation events and when collecting PCs to disambiguate reused - * address ranges. - */ -typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer, - const char* name, - uintptr_t base, - uintptr_t size); - -typedef struct Dart_CodeObserver { - void* data; - - Dart_OnNewCodeCallback on_new_code; -} Dart_CodeObserver; - -/** - * Optional callback provided by the embedder that is used by the VM to - * implement registration of kernel blobs for the subsequent Isolate.spawnUri - * If no callback is provided, the registration of kernel blobs will throw - * an error. - * - * \param kernel_buffer A buffer which contains a kernel program. Callback - * should copy the contents of `kernel_buffer` as - * it may be freed immediately after registration. - * \param kernel_buffer_size The size of `kernel_buffer`. - * - * \return A C string representing URI which can be later used - * to spawn a new isolate. This C String should be scope allocated - * or owned by the embedder. - * Returns NULL if embedder runs out of memory. - */ -typedef const char* (*Dart_RegisterKernelBlobCallback)( - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size); - -/** - * Optional callback provided by the embedder that is used by the VM to - * unregister kernel blobs. - * If no callback is provided, the unregistration of kernel blobs will throw - * an error. - * - * \param kernel_blob_uri URI of the kernel blob to unregister. - */ -typedef void (*Dart_UnregisterKernelBlobCallback)(const char* kernel_blob_uri); - -/** - * Describes how to initialize the VM. Used with Dart_Initialize. - */ -typedef struct { - /** - * Identifies the version of the struct used by the client. - * should be initialized to DART_INITIALIZE_PARAMS_CURRENT_VERSION. - */ - int32_t version; - - /** - * A buffer containing snapshot data, or NULL if no snapshot is provided. - * - * If provided, the buffer must remain valid until Dart_Cleanup returns. - */ - const uint8_t* vm_snapshot_data; - - /** - * A buffer containing a snapshot of precompiled instructions, or NULL if - * no snapshot is provided. - * - * If provided, the buffer must remain valid until Dart_Cleanup returns. - */ - const uint8_t* vm_snapshot_instructions; - - /** - * A function to be called during isolate group creation. - * See Dart_IsolateGroupCreateCallback. - */ - Dart_IsolateGroupCreateCallback create_group; - - /** - * A function to be called during isolate - * initialization inside an existing isolate group. - * See Dart_InitializeIsolateCallback. - */ - Dart_InitializeIsolateCallback initialize_isolate; - - /** - * A function to be called right before an isolate is shutdown. - * See Dart_IsolateShutdownCallback. - */ - Dart_IsolateShutdownCallback shutdown_isolate; - - /** - * A function to be called after an isolate was shutdown. - * See Dart_IsolateCleanupCallback. - */ - Dart_IsolateCleanupCallback cleanup_isolate; - - /** - * A function to be called after an isolate group is - * shutdown. See Dart_IsolateGroupCleanupCallback. - */ - Dart_IsolateGroupCleanupCallback cleanup_group; - - Dart_ThreadStartCallback thread_start; - Dart_ThreadExitCallback thread_exit; - Dart_FileOpenCallback file_open; - Dart_FileReadCallback file_read; - Dart_FileWriteCallback file_write; - Dart_FileCloseCallback file_close; - Dart_EntropySource entropy_source; - - /** - * A function to be called by the service isolate when it requires the - * vmservice assets archive. See Dart_GetVMServiceAssetsArchive. - */ - Dart_GetVMServiceAssetsArchive get_service_assets; - - bool start_kernel_isolate; - - /** - * An external code observer callback function. The observer can be invoked - * as early as during the Dart_Initialize() call. - */ - Dart_CodeObserver* code_observer; - - /** - * Kernel blob registration callback function. See Dart_RegisterKernelBlobCallback. - */ - Dart_RegisterKernelBlobCallback register_kernel_blob; - - /** - * Kernel blob unregistration callback function. See Dart_UnregisterKernelBlobCallback. - */ - Dart_UnregisterKernelBlobCallback unregister_kernel_blob; - -#if defined(__Fuchsia__) - /** - * The resource needed to use zx_vmo_replace_as_executable. Can be - * ZX_HANDLE_INVALID if the process has ambient-replace-as-executable or if - * executable memory is not needed (e.g., this is an AOT runtime). - */ - zx_handle_t vmex_resource; -#endif -} Dart_InitializeParams; - -/** - * Initializes the VM. - * - * \param params A struct containing initialization information. The version - * field of the struct must be DART_INITIALIZE_PARAMS_CURRENT_VERSION. - * - * \return NULL if initialization is successful. Returns an error message - * otherwise. The caller is responsible for freeing the error message. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_Initialize( - Dart_InitializeParams* params); - -/** - * Cleanup state in the VM before process termination. - * - * \return NULL if cleanup is successful. Returns an error message otherwise. - * The caller is responsible for freeing the error message. - * - * NOTE: This function must not be called on a thread that was created by the VM - * itself. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_Cleanup(void); - -/** - * Sets command line flags. Should be called before Dart_Initialize. - * - * \param argc The length of the arguments array. - * \param argv An array of arguments. - * - * \return NULL if successful. Returns an error message otherwise. - * The caller is responsible for freeing the error message. - * - * NOTE: This call does not store references to the passed in c-strings. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_SetVMFlags( - int argc, - const char** argv); - -/** - * Returns true if the named VM flag is of boolean type, specified, and set to - * true. - * - * \param flag_name The name of the flag without leading punctuation - * (example: "enable_asserts"). - */ -DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); - -/* - * ======== - * Isolates - * ======== - */ - -/** - * Creates a new isolate. The new isolate becomes the current isolate. - * - * A snapshot can be used to restore the VM quickly to a saved state - * and is useful for fast startup. If snapshot data is provided, the - * isolate will be started using that snapshot data. Requires a core snapshot or - * an app snapshot created by Dart_CreateSnapshot or - * Dart_CreatePrecompiledSnapshot* from a VM with the same version. - * - * Requires there to be no current isolate. - * - * \param script_uri The main source file or snapshot this isolate will load. - * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a - * child isolate is created by Isolate.spawn. The embedder should use a URI - * that allows it to load the same program into such a child isolate. - * \param name A short name for the isolate to improve debugging messages. - * Typically of the format 'foo.dart:main()'. - * \param isolate_snapshot_data Buffer containing the snapshot data of the - * isolate or NULL if no snapshot is provided. If provided, the buffer must - * remain valid until the isolate shuts down. - * \param isolate_snapshot_instructions Buffer containing the snapshot - * instructions of the isolate or NULL if no snapshot is provided. If - * provided, the buffer must remain valid until the isolate shuts down. - * \param flags Pointer to VM specific flags or NULL for default flags. - * \param isolate_group_data Embedder group data. This data can be obtained - * by calling Dart_IsolateGroupData and will be passed to the - * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and - * Dart_IsolateGroupCleanupCallback. - * \param isolate_data Embedder data. This data will be passed to - * the Dart_IsolateGroupCreateCallback when new isolates are spawned from - * this parent isolate. - * \param error Returns NULL if creation is successful, an error message - * otherwise. The caller is responsible for calling free() on the error - * message. - * - * \return The new isolate on success, or NULL if isolate creation failed. - */ -DART_EXPORT Dart_Isolate -Dart_CreateIsolateGroup(const char* script_uri, - const char* name, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instructions, - Dart_IsolateFlags* flags, - void* isolate_group_data, - void* isolate_data, - char** error); -/** - * Creates a new isolate inside the isolate group of [group_member]. - * - * Requires there to be no current isolate. - * - * \param group_member An isolate from the same group into which the newly created - * isolate should be born into. Other threads may not have entered / enter this - * member isolate. - * \param name A short name for the isolate for debugging purposes. - * \param shutdown_callback A callback to be called when the isolate is being - * shutdown (may be NULL). - * \param cleanup_callback A callback to be called when the isolate is being - * cleaned up (may be NULL). - * \param child_isolate_data The embedder-specific data associated with this isolate. - * \param error Set to NULL if creation is successful, set to an error - * message otherwise. The caller is responsible for calling free() on the - * error message. - * - * \return The newly created isolate on success, or NULL if isolate creation - * failed. - * - * If successful, the newly created isolate will become the current isolate. - */ -DART_EXPORT Dart_Isolate -Dart_CreateIsolateInGroup(Dart_Isolate group_member, - const char* name, - Dart_IsolateShutdownCallback shutdown_callback, - Dart_IsolateCleanupCallback cleanup_callback, - void* child_isolate_data, - char** error); - -/* TODO(turnidge): Document behavior when there is already a current - * isolate. */ - -/** - * Creates a new isolate from a Dart Kernel file. The new isolate - * becomes the current isolate. - * - * Requires there to be no current isolate. - * - * \param script_uri The main source file or snapshot this isolate will load. - * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a - * child isolate is created by Isolate.spawn. The embedder should use a URI that - * allows it to load the same program into such a child isolate. - * \param name A short name for the isolate to improve debugging messages. - * Typically of the format 'foo.dart:main()'. - * \param kernel_buffer A buffer which contains a kernel/DIL program. Must - * remain valid until isolate shutdown. - * \param kernel_buffer_size The size of `kernel_buffer`. - * \param flags Pointer to VM specific flags or NULL for default flags. - * \param isolate_group_data Embedder group data. This data can be obtained - * by calling Dart_IsolateGroupData and will be passed to the - * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and - * Dart_IsolateGroupCleanupCallback. - * \param isolate_data Embedder data. This data will be passed to - * the Dart_IsolateGroupCreateCallback when new isolates are spawned from - * this parent isolate. - * \param error Returns NULL if creation is successful, an error message - * otherwise. The caller is responsible for calling free() on the error - * message. - * - * \return The new isolate on success, or NULL if isolate creation failed. - */ -DART_EXPORT Dart_Isolate -Dart_CreateIsolateGroupFromKernel(const char* script_uri, - const char* name, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size, - Dart_IsolateFlags* flags, - void* isolate_group_data, - void* isolate_data, - char** error); -/** - * Shuts down the current isolate. After this call, the current isolate is NULL. - * Any current scopes created by Dart_EnterScope will be exited. Invokes the - * shutdown callback and any callbacks of remaining weak persistent handles. - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_ShutdownIsolate(void); -/* TODO(turnidge): Document behavior when there is no current isolate. */ - -/** - * Returns the current isolate. Will return NULL if there is no - * current isolate. - */ -DART_EXPORT Dart_Isolate Dart_CurrentIsolate(void); - -/** - * Returns the callback data associated with the current isolate. This - * data was set when the isolate got created or initialized. - */ -DART_EXPORT void* Dart_CurrentIsolateData(void); - -/** - * Returns the callback data associated with the given isolate. This - * data was set when the isolate got created or initialized. - */ -DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate); - -/** - * Returns the current isolate group. Will return NULL if there is no - * current isolate group. - */ -DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup(void); - -/** - * Returns the callback data associated with the current isolate group. This - * data was passed to the isolate group when it was created. - */ -DART_EXPORT void* Dart_CurrentIsolateGroupData(void); - -/** - * Gets an id that uniquely identifies current isolate group. - * - * It is the responsibility of the caller to free the returned ID. - */ -typedef int64_t Dart_IsolateGroupId; -DART_EXPORT Dart_IsolateGroupId Dart_CurrentIsolateGroupId(void); - -/** - * Returns the callback data associated with the specified isolate group. This - * data was passed to the isolate when it was created. - * The embedder is responsible for ensuring the consistency of this data - * with respect to the lifecycle of an isolate group. - */ -DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate); - -/** - * Returns the debugging name for the current isolate. - * - * This name is unique to each isolate and should only be used to make - * debugging messages more comprehensible. - */ -DART_EXPORT Dart_Handle Dart_DebugName(void); - -/** - * Returns the debugging name for the current isolate. - * - * This name is unique to each isolate and should only be used to make - * debugging messages more comprehensible. - * - * The returned string is scope allocated and is only valid until the next call - * to Dart_ExitScope. - */ -DART_EXPORT const char* Dart_DebugNameToCString(void); - -/** - * Returns the ID for an isolate which is used to query the service protocol. - * - * It is the responsibility of the caller to free the returned ID. - */ -DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate); - -/** - * Enters an isolate. After calling this function, - * the current isolate will be set to the provided isolate. - * - * Requires there to be no current isolate. Multiple threads may not be in - * the same isolate at once. - */ -DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate); - -/** - * Kills the given isolate. - * - * This function has the same effect as dart:isolate's - * Isolate.kill(priority:immediate). - * It can interrupt ordinary Dart code but not native code. If the isolate is - * in the middle of a long running native function, the isolate will not be - * killed until control returns to Dart. - * - * Does not require a current isolate. It is safe to kill the current isolate if - * there is one. - */ -DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate); - -/** - * Notifies the VM that the embedder expects to be idle until |deadline|. The VM - * may use this time to perform garbage collection or other tasks to avoid - * delays during execution of Dart code in the future. - * - * |deadline| is measured in microseconds against the system's monotonic time. - * This clock can be accessed via Dart_TimelineGetMicros(). - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_NotifyIdle(int64_t deadline); - -typedef void (*Dart_HeapSamplingReportCallback)(void* context, void* data); - -typedef void* (*Dart_HeapSamplingCreateCallback)( - Dart_Isolate isolate, - Dart_IsolateGroup isolate_group, - const char* cls_name, - intptr_t allocation_size); -typedef void (*Dart_HeapSamplingDeleteCallback)(void* data); - -/** - * Starts the heap sampling profiler for each thread in the VM. - */ -DART_EXPORT void Dart_EnableHeapSampling(void); - -/* - * Stops the heap sampling profiler for each thread in the VM. - */ -DART_EXPORT void Dart_DisableHeapSampling(void); - -/* Registers callbacks are invoked once per sampled allocation upon object - * allocation and garbage collection. - * - * |create_callback| can be used to associate additional data with the sampled - * allocation, such as a stack trace. This data pointer will be passed to - * |delete_callback| to allow for proper disposal when the object associated - * with the allocation sample is collected. - * - * The provided callbacks must not call into the VM and should do as little - * work as possible to avoid performance penalities during object allocation and - * garbage collection. - * - * NOTE: It is a fatal error to set either callback to null once they have been - * initialized. - */ -DART_EXPORT void Dart_RegisterHeapSamplingCallback( - Dart_HeapSamplingCreateCallback create_callback, - Dart_HeapSamplingDeleteCallback delete_callback); - -/* - * Reports the surviving allocation samples for all live isolate groups in the - * VM. - * - * When the callback is invoked: - * - |context| will be the context object provided when invoking - * |Dart_ReportSurvivingAllocations|. This can be safely set to null if not - * required. - * - |heap_size| will be equal to the size of the allocated object associated - * with the sample. - * - |cls_name| will be a C String representing - * the class name of the allocated object. This string is valid for the - * duration of the call to Dart_ReportSurvivingAllocations and can be - * freed by the VM at any point after the method returns. - * - |data| will be set to the data associated with the sample by - * |Dart_HeapSamplingCreateCallback|. - * - * If |force_gc| is true, a full GC will be performed before reporting the - * allocations. - */ -DART_EXPORT void Dart_ReportSurvivingAllocations( - Dart_HeapSamplingReportCallback callback, - void* context, - bool force_gc); - -/* - * Sets the average heap sampling rate based on a number of |bytes| for each - * thread. - * - * In other words, approximately every |bytes| allocated will create a sample. - * Defaults to 512 KiB. - */ -DART_EXPORT void Dart_SetHeapSamplingPeriod(intptr_t bytes); - -/** - * Notifies the VM that the embedder expects the application's working set has - * recently shrunk significantly and is not expected to rise in the near future. - * The VM may spend O(heap-size) time performing clean up work. - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_NotifyDestroyed(void); - -/** - * Notifies the VM that the system is running low on memory. - * - * Does not require a current isolate. Only valid after calling Dart_Initialize. - */ -DART_EXPORT void Dart_NotifyLowMemory(void); - -typedef enum { - /** - * Balanced - */ - Dart_PerformanceMode_Default, - /** - * Optimize for low latency, at the expense of throughput and memory overhead - * by performing work in smaller batches (requiring more overhead) or by - * delaying work (requiring more memory). An embedder should not remain in - * this mode indefinitely. - */ - Dart_PerformanceMode_Latency, - /** - * Optimize for high throughput, at the expense of latency and memory overhead - * by performing work in larger batches with more intervening growth. - */ - Dart_PerformanceMode_Throughput, - /** - * Optimize for low memory, at the expensive of throughput and latency by more - * frequently performing work. - */ - Dart_PerformanceMode_Memory, -} Dart_PerformanceMode; - -/** - * Set the desired performance trade-off. - * - * Requires a current isolate. - * - * Returns the previous performance mode. - */ -DART_EXPORT Dart_PerformanceMode -Dart_SetPerformanceMode(Dart_PerformanceMode mode); - -/** - * Starts the CPU sampling profiler. - */ -DART_EXPORT void Dart_StartProfiling(void); - -/** - * Stops the CPU sampling profiler. - * - * Note that some profile samples might still be taken after this function - * returns due to the asynchronous nature of the implementation on some - * platforms. - */ -DART_EXPORT void Dart_StopProfiling(void); - -/** - * Notifies the VM that the current thread should not be profiled until a - * matching call to Dart_ThreadEnableProfiling is made. - * - * NOTE: By default, if a thread has entered an isolate it will be profiled. - * This function should be used when an embedder knows a thread is about - * to make a blocking call and wants to avoid unnecessary interrupts by - * the profiler. - */ -DART_EXPORT void Dart_ThreadDisableProfiling(void); - -/** - * Notifies the VM that the current thread should be profiled. - * - * NOTE: It is only legal to call this function *after* calling - * Dart_ThreadDisableProfiling. - * - * NOTE: By default, if a thread has entered an isolate it will be profiled. - */ -DART_EXPORT void Dart_ThreadEnableProfiling(void); - -/** - * Register symbol information for the Dart VM's profiler and crash dumps. - * - * This consumes the output of //topaz/runtime/dart/profiler_symbols, which - * should be treated as opaque. - */ -DART_EXPORT void Dart_AddSymbols(const char* dso_name, - void* buffer, - intptr_t buffer_size); - -/** - * Exits an isolate. After this call, Dart_CurrentIsolate will - * return NULL. - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_ExitIsolate(void); -/* TODO(turnidge): We don't want users of the api to be able to exit a - * "pure" dart isolate. Implement and document. */ - -/** - * Creates a full snapshot of the current isolate heap. - * - * A full snapshot is a compact representation of the dart vm isolate heap - * and dart isolate heap states. These snapshots are used to initialize - * the vm isolate on startup and fast initialization of an isolate. - * A Snapshot of the heap is created before any dart code has executed. - * - * Requires there to be a current isolate. Not available in the precompiled - * runtime (check Dart_IsPrecompiledRuntime). - * - * \param vm_snapshot_data_buffer Returns a pointer to a buffer containing the - * vm snapshot. This buffer is scope allocated and is only valid - * until the next call to Dart_ExitScope. - * \param vm_snapshot_data_size Returns the size of vm_snapshot_data_buffer. - * \param isolate_snapshot_data_buffer Returns a pointer to a buffer containing - * the isolate snapshot. This buffer is scope allocated and is only valid - * until the next call to Dart_ExitScope. - * \param isolate_snapshot_data_size Returns the size of - * isolate_snapshot_data_buffer. - * \param is_core Create a snapshot containing core libraries. - * Such snapshot should be agnostic to null safety mode. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer, - intptr_t* vm_snapshot_data_size, - uint8_t** isolate_snapshot_data_buffer, - intptr_t* isolate_snapshot_data_size, - bool is_core); - -/** - * Returns whether the buffer contains a kernel file. - * - * \param buffer Pointer to a buffer that might contain a kernel binary. - * \param buffer_size Size of the buffer. - * - * \return Whether the buffer contains a kernel binary (full or partial). - */ -DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size); - -/** - * Make isolate runnable. - * - * When isolates are spawned, this function is used to indicate that - * the creation and initialization (including script loading) of the - * isolate is complete and the isolate can start. - * This function expects there to be no current isolate. - * - * \param isolate The isolate to be made runnable. - * - * \return NULL if successful. Returns an error message otherwise. The caller - * is responsible for freeing the error message. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable( - Dart_Isolate isolate); - -/* - * ================== - * Messages and Ports - * ================== - */ - -/** - * A port is used to send or receive inter-isolate messages - */ -typedef int64_t Dart_Port; -typedef struct { - int64_t port_id; - int64_t origin_id; -} Dart_PortEx; - -/** - * ILLEGAL_PORT is a port number guaranteed never to be associated with a valid - * port. - */ -#define ILLEGAL_PORT ((Dart_Port)0) - -/** - * A message notification callback. - * - * This callback allows the embedder to provide a custom wakeup mechanism for - * the delivery of inter-isolate messages. This function is called once per - * message on an arbitrary thread. It is the responsibility of the embedder to - * eventually call Dart_HandleMessage once per callback received with the - * destination isolate set as the current isolate to process the message. - */ -typedef void (*Dart_MessageNotifyCallback)(Dart_Isolate destination_isolate); - -/** - * Allows embedders to provide a custom wakeup mechanism for the delivery of - * inter-isolate messages. This setting only applies to the current isolate. - * - * This mechanism is optional: if not provided, the isolate will be scheduled on - * a VM-managed thread pool. An embedder should provide this callback if it - * wants to run an isolate on a specific thread or to interleave handling of - * inter-isolate messages with other event sources. - * - * Most embedders will only call this function once, before isolate - * execution begins. If this function is called after isolate - * execution begins, the embedder is responsible for threading issues. - */ -DART_EXPORT void Dart_SetMessageNotifyCallback( - Dart_MessageNotifyCallback message_notify_callback); -/* TODO(turnidge): Consider moving this to isolate creation so that it - * is impossible to mess up. */ - -/** - * Query the current message notify callback for the isolate. - * - * \return The current message notify callback for the isolate. - */ -DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback(void); - -/** - * The VM's default message handler supports pausing an isolate before it - * processes the first message and right after the it processes the isolate's - * final message. This can be controlled for all isolates by two VM flags: - * - * `--pause-isolates-on-start` - * `--pause-isolates-on-exit` - * - * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be - * used to control this behaviour on a per-isolate basis. - * - * When an embedder is using a Dart_MessageNotifyCallback the embedder - * needs to cooperate with the VM so that the service protocol can report - * accurate information about isolates and so that tools such as debuggers - * work reliably. - * - * The following functions can be used to implement pausing on start and exit. - */ - -/** - * If the VM flag `--pause-isolates-on-start` was passed this will be true. - * - * \return A boolean value indicating if pause on start was requested. - */ -DART_EXPORT bool Dart_ShouldPauseOnStart(void); - -/** - * Override the VM flag `--pause-isolates-on-start` for the current isolate. - * - * \param should_pause Should the isolate be paused on start? - * - * NOTE: This must be called before Dart_IsolateMakeRunnable. - */ -DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause); - -/** - * Is the current isolate paused on start? - * - * \return A boolean value indicating if the isolate is paused on start. - */ -DART_EXPORT bool Dart_IsPausedOnStart(void); - -/** - * Called when the embedder has paused the current isolate on start and when - * the embedder has resumed the isolate. - * - * \param paused Is the isolate paused on start? - */ -DART_EXPORT void Dart_SetPausedOnStart(bool paused); - -/** - * If the VM flag `--pause-isolates-on-exit` was passed this will be true. - * - * \return A boolean value indicating if pause on exit was requested. - */ -DART_EXPORT bool Dart_ShouldPauseOnExit(void); - -/** - * Override the VM flag `--pause-isolates-on-exit` for the current isolate. - * - * \param should_pause Should the isolate be paused on exit? - * - */ -DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause); - -/** - * Is the current isolate paused on exit? - * - * \return A boolean value indicating if the isolate is paused on exit. - */ -DART_EXPORT bool Dart_IsPausedOnExit(void); - -/** - * Called when the embedder has paused the current isolate on exit and when - * the embedder has resumed the isolate. - * - * \param paused Is the isolate paused on exit? - */ -DART_EXPORT void Dart_SetPausedOnExit(bool paused); - -/** - * Called when the embedder has caught a top level unhandled exception error - * in the current isolate. - * - * NOTE: It is illegal to call this twice on the same isolate without first - * clearing the sticky error to null. - * - * \param error The unhandled exception error. - */ -DART_EXPORT void Dart_SetStickyError(Dart_Handle error); - -/** - * Does the current isolate have a sticky error? - */ -DART_EXPORT bool Dart_HasStickyError(void); - -/** - * Gets the sticky error for the current isolate. - * - * \return A handle to the sticky error object or null. - */ -DART_EXPORT Dart_Handle Dart_GetStickyError(void); - -/** - * Handles the next pending message for the current isolate. - * - * May generate an unhandled exception error. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_HandleMessage(void); - -/** - * Handles any pending messages for the vm service for the current - * isolate. - * - * This function may be used by an embedder at a breakpoint to avoid - * pausing the vm service. - * - * This function can indirectly cause the message notify callback to - * be called. - * - * \return true if the vm service requests the program resume - * execution, false otherwise - */ -DART_EXPORT bool Dart_HandleServiceMessages(void); - -/** - * Does the current isolate have pending service messages? - * - * \return true if the isolate has pending service messages, false otherwise. - */ -DART_EXPORT bool Dart_HasServiceMessages(void); - -/** - * Processes any incoming messages for the current isolate. - * - * This function may only be used when the embedder has not provided - * an alternate message delivery mechanism with - * Dart_SetMessageCallbacks. It is provided for convenience. - * - * This function waits for incoming messages for the current - * isolate. As new messages arrive, they are handled using - * Dart_HandleMessage. The routine exits when all ports to the - * current isolate are closed. - * - * \return A valid handle if the run loop exited successfully. If an - * exception or other error occurs while processing messages, an - * error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_RunLoop(void); - -/** - * Lets the VM run message processing for the isolate. - * - * This function expects there to a current isolate and the current isolate - * must not have an active api scope. The VM will take care of making the - * isolate runnable (if not already), handles its message loop and will take - * care of shutting the isolate down once it's done. - * - * \param errors_are_fatal Whether uncaught errors should be fatal. - * \param on_error_port A port to notify on uncaught errors (or ILLEGAL_PORT). - * \param on_exit_port A port to notify on exit (or ILLEGAL_PORT). - * \param error A non-NULL pointer which will hold an error message if the call - * fails. The error has to be free()ed by the caller. - * - * \return If successful the VM takes ownership of the isolate and takes care - * of its message loop. If not successful the caller retains ownership of the - * isolate. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT bool Dart_RunLoopAsync( - bool errors_are_fatal, - Dart_Port on_error_port, - Dart_Port on_exit_port, - char** error); - -/* TODO(turnidge): Should this be removed from the public api? */ - -/** - * Gets the main port id for the current isolate. - */ -DART_EXPORT Dart_Port Dart_GetMainPortId(void); - -/** - * Does the current isolate have live ReceivePorts? - * - * A ReceivePort is live when it has not been closed. - */ -DART_EXPORT bool Dart_HasLivePorts(void); - -/** - * Posts a message for some isolate. The message is a serialized - * object. - * - * Requires there to be a current isolate. - * - * For posting messages outside of an isolate see \ref Dart_PostCObject. - * - * \param port_id The destination port. - * \param object An object from the current isolate. - * - * \return True if the message was posted. - */ -DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object); - -/** - * Returns a new SendPort with the provided port id. - * - * If there is a possibility of a port closing since port_id was acquired - * for a SendPort, one should use Dart_NewSendPortEx and - * Dart_SendPortGetIdEx. - * - * \param port_id The destination port. - * - * \return A new SendPort if no errors occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id); - -/** - * Returns a new SendPort with the provided port id and origin id. - * - * \param portex_id The destination composte port id. - * - * \return A new SendPort if no errors occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewSendPortEx(Dart_PortEx portex_id); - -/** - * Gets the SendPort id for the provided SendPort. - * \param port A SendPort object whose id is desired. - * \param port_id Returns the id of the SendPort. - * \return Success if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port, - Dart_Port* port_id); - -/** - * Gets the SendPort and Origin ids for the provided SendPort. - * \param port A SendPort object whose id is desired. - * \param portex_id Returns composite id of the SendPort. - * \return Success if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_SendPortGetIdEx(Dart_Handle port, - Dart_PortEx* portex_id); -/* - * ====== - * Scopes - * ====== - */ - -/** - * Enters a new scope. - * - * All new local handles will be created in this scope. Additionally, - * some functions may return "scope allocated" memory which is only - * valid within this scope. - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_EnterScope(void); - -/** - * Exits a scope. - * - * The previous scope (if any) becomes the current scope. - * - * Requires there to be a current isolate. - */ -DART_EXPORT void Dart_ExitScope(void); - -/** - * The Dart VM uses "zone allocation" for temporary structures. Zones - * support very fast allocation of small chunks of memory. The chunks - * cannot be deallocated individually, but instead zones support - * deallocating all chunks in one fast operation. - * - * This function makes it possible for the embedder to allocate - * temporary data in the VMs zone allocator. - * - * Zone allocation is possible: - * 1. when inside a scope where local handles can be allocated - * 2. when processing a message from a native port in a native port - * handler - * - * All the memory allocated this way will be reclaimed either on the - * next call to Dart_ExitScope or when the native port handler exits. - * - * \param size Size of the memory to allocate. - * - * \return A pointer to the allocated memory. NULL if allocation - * failed. Failure might due to is no current VM zone. - */ -DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size); - -/* - * ======= - * Objects - * ======= - */ - -/** - * Returns the null object. - * - * \return A handle to the null object. - */ -DART_EXPORT Dart_Handle Dart_Null(void); - -/** - * Is this object null? - */ -DART_EXPORT bool Dart_IsNull(Dart_Handle object); - -/** - * Returns the empty string object. - * - * \return A handle to the empty string object. - */ -DART_EXPORT Dart_Handle Dart_EmptyString(void); - -/** - * Returns types that are not classes, and which therefore cannot be looked up - * as library members by Dart_GetType. - * - * \return A handle to the dynamic, void or Never type. - */ -DART_EXPORT Dart_Handle Dart_TypeDynamic(void); -DART_EXPORT Dart_Handle Dart_TypeVoid(void); -DART_EXPORT Dart_Handle Dart_TypeNever(void); - -/** - * Checks if the two objects are equal. - * - * The result of the comparison is returned through the 'equal' - * parameter. The return value itself is used to indicate success or - * failure, not equality. - * - * May generate an unhandled exception error. - * - * \param obj1 An object to be compared. - * \param obj2 An object to be compared. - * \param equal Returns the result of the equality comparison. - * - * \return A valid handle if no error occurs during the comparison. - */ -DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1, - Dart_Handle obj2, - bool* equal); - -/** - * Is this object an instance of some type? - * - * The result of the test is returned through the 'instanceof' parameter. - * The return value itself is used to indicate success or failure. - * - * \param object An object. - * \param type A type. - * \param instanceof Return true if 'object' is an instance of type 'type'. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object, - Dart_Handle type, - bool* instanceof); - -/** - * Query object type. - * - * \param object Some Object. - * - * \return true if Object is of the specified type. - */ -DART_EXPORT bool Dart_IsInstance(Dart_Handle object); -DART_EXPORT bool Dart_IsNumber(Dart_Handle object); -DART_EXPORT bool Dart_IsInteger(Dart_Handle object); -DART_EXPORT bool Dart_IsDouble(Dart_Handle object); -DART_EXPORT bool Dart_IsBoolean(Dart_Handle object); -DART_EXPORT bool Dart_IsString(Dart_Handle object); -DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */ -DART_EXPORT bool Dart_IsList(Dart_Handle object); -DART_EXPORT bool Dart_IsMap(Dart_Handle object); -DART_EXPORT bool Dart_IsLibrary(Dart_Handle object); -DART_EXPORT bool Dart_IsType(Dart_Handle handle); -DART_EXPORT bool Dart_IsFunction(Dart_Handle handle); -DART_EXPORT bool Dart_IsVariable(Dart_Handle handle); -DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle); -DART_EXPORT bool Dart_IsClosure(Dart_Handle object); -DART_EXPORT bool Dart_IsTypedData(Dart_Handle object); -DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle object); -DART_EXPORT bool Dart_IsFuture(Dart_Handle object); - -/* - * ========= - * Instances - * ========= - */ - -/* - * For the purposes of the embedding api, not all objects returned are - * Dart language objects. Within the api, we use the term 'Instance' - * to indicate handles which refer to true Dart language objects. - * - * TODO(turnidge): Reorganize the "Object" section above, pulling down - * any functions that more properly belong here. */ - -/** - * Gets the type of a Dart language object. - * - * \param instance Some Dart object. - * - * \return If no error occurs, the type is returned. Otherwise an - * error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance); - -/** - * Returns the name for the provided class type. - * - * \return A valid string handle if no error occurs during the - * operation. - */ -DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type); - -/** - * Returns the name for the provided function or method. - * - * \return A valid string handle if no error occurs during the - * operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function); - -/** - * Returns a handle to the owner of a function. - * - * The owner of an instance method or a static method is its defining - * class. The owner of a top-level function is its defining - * library. The owner of the function of a non-implicit closure is the - * function of the method or closure that defines the non-implicit - * closure. - * - * \return A valid handle to the owner of the function, or an error - * handle if the argument is not a valid handle to a function. - */ -DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function); - -/** - * Determines whether a function handle refers to a static function - * of method. - * - * For the purposes of the embedding API, a top-level function is - * implicitly declared static. - * - * \param function A handle to a function or method declaration. - * \param is_static Returns whether the function or method is declared static. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function, - bool* is_static); - -/** - * Is this object a closure resulting from a tear-off (closurized method)? - * - * Returns true for closures produced when an ordinary method is accessed - * through a getter call. Returns false otherwise, in particular for closures - * produced from local function declarations. - * - * \param object Some Object. - * - * \return true if Object is a tear-off. - */ -DART_EXPORT bool Dart_IsTearOff(Dart_Handle object); - -/** - * Retrieves the function of a closure. - * - * \return A handle to the function of the closure, or an error handle if the - * argument is not a closure. - */ -DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure); - -/** - * Returns a handle to the library which contains class. - * - * \return A valid handle to the library with owns class, null if the class - * has no library or an error handle if the argument is not a valid handle - * to a class type. - */ -DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type); - -/* - * ============================= - * Numbers, Integers and Doubles - * ============================= - */ - -/** - * Does this Integer fit into a 64-bit signed integer? - * - * \param integer An integer. - * \param fits Returns true if the integer fits into a 64-bit signed integer. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer, - bool* fits); - -/** - * Does this Integer fit into a 64-bit unsigned integer? - * - * \param integer An integer. - * \param fits Returns true if the integer fits into a 64-bit unsigned integer. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer, - bool* fits); - -/** - * Returns an Integer with the provided value. - * - * \param value The value of the integer. - * - * \return The Integer object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value); - -/** - * Returns an Integer with the provided value. - * - * \param value The unsigned value of the integer. - * - * \return The Integer object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value); - -/** - * Returns an Integer with the provided value. - * - * \param value The value of the integer represented as a C string - * containing a hexadecimal number. - * - * \return The Integer object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value); - -/** - * Gets the value of an Integer. - * - * The integer must fit into a 64-bit signed integer, otherwise an error occurs. - * - * \param integer An Integer. - * \param value Returns the value of the Integer. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, - int64_t* value); - -/** - * Gets the value of an Integer. - * - * The integer must fit into a 64-bit unsigned integer, otherwise an - * error occurs. - * - * \param integer An Integer. - * \param value Returns the value of the Integer. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer, - uint64_t* value); - -/** - * Gets the value of an integer as a hexadecimal C string. - * - * \param integer An Integer. - * \param value Returns the value of the Integer as a hexadecimal C - * string. This C string is scope allocated and is only valid until - * the next call to Dart_ExitScope. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer, - const char** value); - -/** - * Returns a Double with the provided value. - * - * \param value A double. - * - * \return The Double object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewDouble(double value); - -/** - * Gets the value of a Double - * - * \param double_obj A Double - * \param value Returns the value of the Double. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value); - -/** - * Returns a closure of static function 'function_name' in the class 'class_name' - * in the exported namespace of specified 'library'. - * - * \param library Library object - * \param cls_type Type object representing a Class - * \param function_name Name of the static function in the class - * - * \return A valid Dart instance if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library, - Dart_Handle cls_type, - Dart_Handle function_name); - -/* - * ======== - * Booleans - * ======== - */ - -/** - * Returns the True object. - * - * Requires there to be a current isolate. - * - * \return A handle to the True object. - */ -DART_EXPORT Dart_Handle Dart_True(void); - -/** - * Returns the False object. - * - * Requires there to be a current isolate. - * - * \return A handle to the False object. - */ -DART_EXPORT Dart_Handle Dart_False(void); - -/** - * Returns a Boolean with the provided value. - * - * \param value true or false. - * - * \return The Boolean object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewBoolean(bool value); - -/** - * Gets the value of a Boolean - * - * \param boolean_obj A Boolean - * \param value Returns the value of the Boolean. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value); - -/* - * ======= - * Strings - * ======= - */ - -/** - * Gets the length of a String. - * - * \param str A String. - * \param length Returns the length of the String. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length); - -/** - * Gets the length of UTF-8 encoded representation for a string. - * - * \param str A String. - * \param length Returns the length of UTF-8 encoded representation for string. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringUTF8Length(Dart_Handle str, - intptr_t* length); - -/** - * Returns a String built from the provided C string - * (There is an implicit assumption that the C string passed in contains - * UTF-8 encoded characters and '\0' is considered as a termination - * character). - * - * \param str A C String - * - * \return The String object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str); -/* TODO(turnidge): Document what happens when we run out of memory - * during this call. */ - -/** - * Returns a String built from an array of UTF-8 encoded characters. - * - * \param utf8_array An array of UTF-8 encoded characters. - * \param length The length of the codepoints array. - * - * \return The String object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array, - intptr_t length); - -/** - * Returns a String built from an array of UTF-16 encoded characters. - * - * \param utf16_array An array of UTF-16 encoded characters. - * \param length The length of the codepoints array. - * - * \return The String object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array, - intptr_t length); - -/** - * Returns a String built from an array of UTF-32 encoded characters. - * - * \param utf32_array An array of UTF-32 encoded characters. - * \param length The length of the codepoints array. - * - * \return The String object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array, - intptr_t length); - -/** - * Gets the C string representation of a String. - * (It is a sequence of UTF-8 encoded values with a '\0' termination.) - * - * \param str A string. - * \param cstr Returns the String represented as a C string. - * This C string is scope allocated and is only valid until - * the next call to Dart_ExitScope. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str, - const char** cstr); - -/** - * Gets a UTF-8 encoded representation of a String. - * - * Any unpaired surrogate code points in the string will be converted as - * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need - * to preserve unpaired surrogates, use the Dart_StringToUTF16 function. - * - * \param str A string. - * \param utf8_array Returns the String represented as UTF-8 code - * units. This UTF-8 array is scope allocated and is only valid - * until the next call to Dart_ExitScope. - * \param length Used to return the length of the array which was - * actually used. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str, - uint8_t** utf8_array, - intptr_t* length); - -/** - * Copies the UTF-8 encoded representation of a String into specified buffer. - * - * Any unpaired surrogate code points in the string will be converted as - * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). - * - * \param str A string. - * \param utf8_array Buffer into which the UTF-8 encoded representation of - * the string is copied into. - * The buffer is allocated and managed by the caller. - * \param length Specifies the length of the buffer passed in. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_CopyUTF8EncodingOfString(Dart_Handle str, - uint8_t* utf8_array, - intptr_t length); - -/** - * Gets the data corresponding to the string object. This function returns - * the data only for Latin-1 (ISO-8859-1) string objects. For all other - * string objects it returns an error. - * - * \param str A string. - * \param latin1_array An array allocated by the caller, used to return - * the string data. - * \param length Used to pass in the length of the provided array. - * Used to return the length of the array which was actually used. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str, - uint8_t* latin1_array, - intptr_t* length); - -/** - * Gets the UTF-16 encoded representation of a string. - * - * \param str A string. - * \param utf16_array An array allocated by the caller, used to return - * the array of UTF-16 encoded characters. - * \param length Used to pass in the length of the provided array. - * Used to return the length of the array which was actually used. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str, - uint16_t* utf16_array, - intptr_t* length); - -/** - * Gets the storage size in bytes of a String. - * - * \param str A String. - * \param size Returns the storage size in bytes of the String. - * This is the size in bytes needed to store the String. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size); - -/** - * Retrieves some properties associated with a String. - * Properties retrieved are: - * - character size of the string (one or two byte) - * - length of the string - * - peer pointer of string if it is an external string. - * \param str A String. - * \param char_size Returns the character size of the String. - * \param str_len Returns the length of the String. - * \param peer Returns the peer pointer associated with the String or 0 if - * there is no peer pointer for it. - * \return Success if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str, - intptr_t* char_size, - intptr_t* str_len, - void** peer); - -/* - * ===== - * Lists - * ===== - */ - -/** - * Returns a List of the desired length. - * - * \param length The length of the list. - * - * \return The List object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewList(intptr_t length); - -/** - * Returns a List of the desired length with the desired element type. - * - * \param element_type Handle to a nullable type object. E.g., from - * Dart_GetType or Dart_GetNullableType. - * - * \param length The length of the list. - * - * \return The List object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type, - intptr_t length); - -/** - * Returns a List of the desired length with the desired element type, filled - * with the provided object. - * - * \param element_type Handle to a type object. E.g., from Dart_GetType. - * - * \param fill_object Handle to an object of type 'element_type' that will be - * used to populate the list. This parameter can only be Dart_Null() if the - * length of the list is 0 or 'element_type' is a nullable type. - * - * \param length The length of the list. - * - * \return The List object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type, - Dart_Handle fill_object, - intptr_t length); - -/** - * Gets the length of a List. - * - * May generate an unhandled exception error. - * - * \param list A List. - * \param length Returns the length of the List. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* length); - -/** - * Gets the Object at some index of a List. - * - * If the index is out of bounds, an error occurs. - * - * May generate an unhandled exception error. - * - * \param list A List. - * \param index A valid index into the List. - * - * \return The Object in the List at the specified index if no error - * occurs. Otherwise returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index); - -/** -* Gets a range of Objects from a List. -* -* If any of the requested index values are out of bounds, an error occurs. -* -* May generate an unhandled exception error. -* -* \param list A List. -* \param offset The offset of the first item to get. -* \param length The number of items to get. -* \param result A pointer to fill with the objects. -* -* \return Success if no error occurs during the operation. -*/ -DART_EXPORT Dart_Handle Dart_ListGetRange(Dart_Handle list, - intptr_t offset, - intptr_t length, - Dart_Handle* result); - -/** - * Sets the Object at some index of a List. - * - * If the index is out of bounds, an error occurs. - * - * May generate an unhandled exception error. - * - * \param list A List. - * \param index A valid index into the List. - * \param value The Object to put in the List. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list, - intptr_t index, - Dart_Handle value); - -/** - * May generate an unhandled exception error. - */ -DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list, - intptr_t offset, - uint8_t* native_array, - intptr_t length); - -/** - * May generate an unhandled exception error. - */ -DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list, - intptr_t offset, - const uint8_t* native_array, - intptr_t length); - -/* - * ==== - * Maps - * ==== - */ - -/** - * Gets the Object at some key of a Map. - * - * May generate an unhandled exception error. - * - * \param map A Map. - * \param key An Object. - * - * \return The value in the map at the specified key, null if the map does not - * contain the key, or an error handle. - */ -DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key); - -/** - * Returns whether the Map contains a given key. - * - * May generate an unhandled exception error. - * - * \param map A Map. - * - * \return A handle on a boolean indicating whether map contains the key. - * Otherwise returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key); - -/** - * Gets the list of keys of a Map. - * - * May generate an unhandled exception error. - * - * \param map A Map. - * - * \return The list of key Objects if no error occurs. Otherwise returns an - * error handle. - */ -DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map); - -/* - * ========== - * Typed Data - * ========== - */ - -typedef enum { - Dart_TypedData_kByteData = 0, - Dart_TypedData_kInt8, - Dart_TypedData_kUint8, - Dart_TypedData_kUint8Clamped, - Dart_TypedData_kInt16, - Dart_TypedData_kUint16, - Dart_TypedData_kInt32, - Dart_TypedData_kUint32, - Dart_TypedData_kInt64, - Dart_TypedData_kUint64, - Dart_TypedData_kFloat32, - Dart_TypedData_kFloat64, - Dart_TypedData_kInt32x4, - Dart_TypedData_kFloat32x4, - Dart_TypedData_kFloat64x2, - Dart_TypedData_kInvalid -} Dart_TypedData_Type; - -/** - * Return type if this object is a TypedData object. - * - * \return kInvalid if the object is not a TypedData object or the appropriate - * Dart_TypedData_Type. - */ -DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object); - -/** - * Return type if this object is an external TypedData object. - * - * \return kInvalid if the object is not an external TypedData object or - * the appropriate Dart_TypedData_Type. - */ -DART_EXPORT Dart_TypedData_Type -Dart_GetTypeOfExternalTypedData(Dart_Handle object); - -/** - * Returns a TypedData object of the desired length and type. - * - * \param type The type of the TypedData object. - * \param length The length of the TypedData object (length in type units). - * - * \return The TypedData object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type, - intptr_t length); - -/** - * Returns a TypedData object which references an external data array. - * - * \param type The type of the data array. - * \param data A data array. This array must not move. - * \param length The length of the data array (length in type units). - * - * \return The TypedData object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type, - void* data, - intptr_t length); - -/** - * Returns a TypedData object which references an external data array. - * - * \param type The type of the data array. - * \param data A data array. This array must not move. - * \param length The length of the data array (length in type units). - * \param peer A pointer to a native object or NULL. This value is - * provided to callback when it is invoked. - * \param external_allocation_size The number of externally allocated - * bytes for peer. Used to inform the garbage collector. - * \param callback A function pointer that will be invoked sometime - * after the object is garbage collected, unless the handle has been deleted. - * A valid callback needs to be specified it cannot be NULL. - * - * \return The TypedData object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle -Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type, - void* data, - intptr_t length, - void* peer, - intptr_t external_allocation_size, - Dart_HandleFinalizer callback); -DART_EXPORT Dart_Handle Dart_NewUnmodifiableExternalTypedDataWithFinalizer( - Dart_TypedData_Type type, - const void* data, - intptr_t length, - void* peer, - intptr_t external_allocation_size, - Dart_HandleFinalizer callback); - -/** - * Returns a ByteBuffer object for the typed data. - * - * \param typed_data The TypedData object. - * - * \return The ByteBuffer object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data); - -/** - * Acquires access to the internal data address of a TypedData object. - * - * \param object The typed data object whose internal data address is to - * be accessed. - * \param type The type of the object is returned here. - * \param data The internal data address is returned here. - * \param len Size of the typed array is returned here. - * - * Notes: - * When the internal address of the object is acquired any calls to a - * Dart API function that could potentially allocate an object or run - * any Dart code will return an error. - * - * Any Dart API functions for accessing the data should not be called - * before the corresponding release. In particular, the object should - * not be acquired again before its release. This leads to undefined - * behavior. - * - * \return Success if the internal data address is acquired successfully. - * Otherwise, returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, - Dart_TypedData_Type* type, - void** data, - intptr_t* len); - -/** - * Releases access to the internal data address that was acquired earlier using - * Dart_TypedDataAcquireData. - * - * \param object The typed data object whose internal data address is to be - * released. - * - * \return Success if the internal data address is released successfully. - * Otherwise, returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object); - -/** - * Returns the TypedData object associated with the ByteBuffer object. - * - * \param byte_buffer The ByteBuffer object. - * - * \return The TypedData object if no error occurs. Otherwise returns - * an error handle. - */ -DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle byte_buffer); - -/* - * ============================================================ - * Invoking Constructors, Methods, Closures and Field accessors - * ============================================================ - */ - -/** - * Invokes a constructor, creating a new object. - * - * This function allows hidden constructors (constructors with leading - * underscores) to be called. - * - * \param type Type of object to be constructed. - * \param constructor_name The name of the constructor to invoke. Use - * Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor. - * This name should not include the name of the class. - * \param number_of_arguments Size of the arguments array. - * \param arguments An array of arguments to the constructor. - * - * \return If the constructor is called and completes successfully, - * then the new object. If an error occurs during execution, then an - * error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_New(Dart_Handle type, - Dart_Handle constructor_name, - int number_of_arguments, - Dart_Handle* arguments); - -/** - * Allocate a new object without invoking a constructor. - * - * \param type The type of an object to be allocated. - * - * \return The new object. If an error occurs during execution, then an - * error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_Allocate(Dart_Handle type); - -/** - * Allocate a new object without invoking a constructor, and sets specified - * native fields. - * - * \param type The type of an object to be allocated. - * \param num_native_fields The number of native fields to set. - * \param native_fields An array containing the value of native fields. - * - * \return The new object. If an error occurs during execution, then an - * error handle is returned. - */ -DART_EXPORT Dart_Handle -Dart_AllocateWithNativeFields(Dart_Handle type, - intptr_t num_native_fields, - const intptr_t* native_fields); - -/** - * Invokes a method or function. - * - * The 'target' parameter may be an object, type, or library. If - * 'target' is an object, then this function will invoke an instance - * method. If 'target' is a type, then this function will invoke a - * static method. If 'target' is a library, then this function will - * invoke a top-level function from that library. - * NOTE: This API call cannot be used to invoke methods of a type object. - * - * This function ignores visibility (leading underscores in names). - * - * May generate an unhandled exception error. - * - * \param target An object, type, or library. - * \param name The name of the function or method to invoke. - * \param number_of_arguments Size of the arguments array. - * \param arguments An array of arguments to the function. - * - * \return If the function or method is called and completes - * successfully, then the return value is returned. If an error - * occurs during execution, then an error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_Invoke(Dart_Handle target, - Dart_Handle name, - int number_of_arguments, - Dart_Handle* arguments); -/* TODO(turnidge): Document how to invoke operators. */ - -/** - * Invokes a Closure with the given arguments. - * - * May generate an unhandled exception error. - * - * \return If no error occurs during execution, then the result of - * invoking the closure is returned. If an error occurs during - * execution, then an error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_InvokeClosure(Dart_Handle closure, - int number_of_arguments, - Dart_Handle* arguments); - -/** - * Invokes a Generative Constructor on an object that was previously - * allocated using Dart_Allocate/Dart_AllocateWithNativeFields. - * - * The 'object' parameter must be an object. - * - * This function ignores visibility (leading underscores in names). - * - * May generate an unhandled exception error. - * - * \param object An object. - * \param name The name of the constructor to invoke. - * Use Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor. - * \param number_of_arguments Size of the arguments array. - * \param arguments An array of arguments to the function. - * - * \return If the constructor is called and completes - * successfully, then the object is returned. If an error - * occurs during execution, then an error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_InvokeConstructor(Dart_Handle object, - Dart_Handle name, - int number_of_arguments, - Dart_Handle* arguments); - -/** - * Gets the value of a field. - * - * The 'container' parameter may be an object, type, or library. If - * 'container' is an object, then this function will access an - * instance field. If 'container' is a type, then this function will - * access a static field. If 'container' is a library, then this - * function will access a top-level variable. - * NOTE: This API call cannot be used to access fields of a type object. - * - * This function ignores field visibility (leading underscores in names). - * - * May generate an unhandled exception error. - * - * \param container An object, type, or library. - * \param name A field name. - * - * \return If no error occurs, then the value of the field is - * returned. Otherwise an error handle is returned. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_GetField(Dart_Handle container, Dart_Handle name); - -/** - * Sets the value of a field. - * - * The 'container' parameter may actually be an object, type, or - * library. If 'container' is an object, then this function will - * access an instance field. If 'container' is a type, then this - * function will access a static field. If 'container' is a library, - * then this function will access a top-level variable. - * NOTE: This API call cannot be used to access fields of a type object. - * - * This function ignores field visibility (leading underscores in names). - * - * May generate an unhandled exception error. - * - * \param container An object, type, or library. - * \param name A field name. - * \param value The new field value. - * - * \return A valid handle if no error occurs. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value); - -/* - * ========== - * Exceptions - * ========== - */ - -/* - * TODO(turnidge): Remove these functions from the api and replace all - * uses with Dart_NewUnhandledExceptionError. */ - -/** - * Throws an exception. - * - * This function causes a Dart language exception to be thrown. This - * will proceed in the standard way, walking up Dart frames until an - * appropriate 'catch' block is found, executing 'finally' blocks, - * etc. - * - * If an error handle is passed into this function, the error is - * propagated immediately. See Dart_PropagateError for a discussion - * of error propagation. - * - * If successful, this function does not return. Note that this means - * that the destructors of any stack-allocated C++ objects will not be - * called. If there are no Dart frames on the stack, an error occurs. - * - * \return An error handle if the exception was not thrown. - * Otherwise the function does not return. - */ -DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception); - -/** - * Rethrows an exception. - * - * Rethrows an exception, unwinding all dart frames on the stack. If - * successful, this function does not return. Note that this means - * that the destructors of any stack-allocated C++ objects will not be - * called. If there are no Dart frames on the stack, an error occurs. - * - * \return An error handle if the exception was not thrown. - * Otherwise the function does not return. - */ -DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception, - Dart_Handle stacktrace); - -/* - * =========================== - * Native fields and functions - * =========================== - */ - -/** - * Gets the number of native instance fields in an object. - */ -DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj, - int* count); - -/** - * Gets the value of a native field. - * - * TODO(turnidge): Document. - */ -DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, - int index, - intptr_t* value); - -/** - * Sets the value of a native field. - * - * TODO(turnidge): Document. - */ -DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, - int index, - intptr_t value); - -/** - * The arguments to a native function. - * - * This object is passed to a native function to represent its - * arguments and return value. It allows access to the arguments to a - * native function by index. It also allows the return value of a - * native function to be set. - */ -typedef struct _Dart_NativeArguments* Dart_NativeArguments; - -/** - * Extracts current isolate group data from the native arguments structure. - */ -DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args); - -typedef enum { - Dart_NativeArgument_kBool = 0, - Dart_NativeArgument_kInt32, - Dart_NativeArgument_kUint32, - Dart_NativeArgument_kInt64, - Dart_NativeArgument_kUint64, - Dart_NativeArgument_kDouble, - Dart_NativeArgument_kString, - Dart_NativeArgument_kInstance, - Dart_NativeArgument_kNativeFields, -} Dart_NativeArgument_Type; - -typedef struct _Dart_NativeArgument_Descriptor { - uint8_t type; - uint8_t index; -} Dart_NativeArgument_Descriptor; - -typedef union _Dart_NativeArgument_Value { - bool as_bool; - int32_t as_int32; - uint32_t as_uint32; - int64_t as_int64; - uint64_t as_uint64; - double as_double; - struct { - Dart_Handle dart_str; - void* peer; - } as_string; - struct { - intptr_t num_fields; - intptr_t* values; - } as_native_fields; - Dart_Handle as_instance; -} Dart_NativeArgument_Value; - -enum { - kNativeArgNumberPos = 0, - kNativeArgNumberSize = 8, - kNativeArgTypePos = kNativeArgNumberPos + kNativeArgNumberSize, - kNativeArgTypeSize = 8, -}; - -#define BITMASK(size) ((1 << size) - 1) -#define DART_NATIVE_ARG_DESCRIPTOR(type, position) \ - (((type & BITMASK(kNativeArgTypeSize)) << kNativeArgTypePos) | \ - (position & BITMASK(kNativeArgNumberSize))) - -/** - * Gets the native arguments based on the types passed in and populates - * the passed arguments buffer with appropriate native values. - * - * \param args the Native arguments block passed into the native call. - * \param num_arguments length of argument descriptor array and argument - * values array passed in. - * \param arg_descriptors an array that describes the arguments that - * need to be retrieved. For each argument to be retrieved the descriptor - * contains the argument number (0, 1 etc.) and the argument type - * described using Dart_NativeArgument_Type, e.g: - * DART_NATIVE_ARG_DESCRIPTOR(Dart_NativeArgument_kBool, 1) indicates - * that the first argument is to be retrieved and it should be a boolean. - * \param arg_values array into which the native arguments need to be - * extracted into, the array is allocated by the caller (it could be - * stack allocated to avoid the malloc/free performance overhead). - * - * \return Success if all the arguments could be extracted correctly, - * returns an error handle if there were any errors while extracting the - * arguments (mismatched number of arguments, incorrect types, etc.). - */ -DART_EXPORT Dart_Handle -Dart_GetNativeArguments(Dart_NativeArguments args, - int num_arguments, - const Dart_NativeArgument_Descriptor* arg_descriptors, - Dart_NativeArgument_Value* arg_values); - -/** - * Gets the native argument at some index. - */ -DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, - int index); -/* TODO(turnidge): Specify the behavior of an out-of-bounds access. */ - -/** - * Gets the number of native arguments. - */ -DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args); - -/** - * Gets all the native fields of the native argument at some index. - * \param args Native arguments structure. - * \param arg_index Index of the desired argument in the structure above. - * \param num_fields size of the intptr_t array 'field_values' passed in. - * \param field_values intptr_t array in which native field values are returned. - * \return Success if the native fields where copied in successfully. Otherwise - * returns an error handle. On success the native field values are copied - * into the 'field_values' array, if the argument at 'arg_index' is a - * null object then 0 is copied as the native field values into the - * 'field_values' array. - */ -DART_EXPORT Dart_Handle -Dart_GetNativeFieldsOfArgument(Dart_NativeArguments args, - int arg_index, - int num_fields, - intptr_t* field_values); - -/** - * Gets the native field of the receiver. - */ -DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args, - intptr_t* value); - -/** - * Gets a string native argument at some index. - * \param args Native arguments structure. - * \param arg_index Index of the desired argument in the structure above. - * \param peer Returns the peer pointer if the string argument has one. - * \return Success if the string argument has a peer, if it does not - * have a peer then the String object is returned. Otherwise returns - * an error handle (argument is not a String object). - */ -DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args, - int arg_index, - void** peer); - -/** - * Gets an integer native argument at some index. - * \param args Native arguments structure. - * \param index Index of the desired argument in the structure above. - * \param value Returns the integer value if the argument is an Integer. - * \return Success if no error occurs. Otherwise returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args, - int index, - int64_t* value); - -/** - * Gets a boolean native argument at some index. - * \param args Native arguments structure. - * \param index Index of the desired argument in the structure above. - * \param value Returns the boolean value if the argument is a Boolean. - * \return Success if no error occurs. Otherwise returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args, - int index, - bool* value); - -/** - * Gets a double native argument at some index. - * \param args Native arguments structure. - * \param index Index of the desired argument in the structure above. - * \param value Returns the double value if the argument is a double. - * \return Success if no error occurs. Otherwise returns an error handle. - */ -DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args, - int index, - double* value); - -/** - * Sets the return value for a native function. - * - * If retval is an Error handle, then error will be propagated once - * the native functions exits. See Dart_PropagateError for a - * discussion of how different types of errors are propagated. - */ -DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, - Dart_Handle retval); - -DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args, - Dart_WeakPersistentHandle rval); - -DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args, - bool retval); - -DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args, - int64_t retval); - -DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args, - double retval); - -/** - * A native function. - */ -typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments); - -/** - * Native entry resolution callback. - * - * For libraries and scripts which have native functions, the embedder - * can provide a native entry resolver. This callback is used to map a - * name/arity to a Dart_NativeFunction. If no function is found, the - * callback should return NULL. - * - * The parameters to the native resolver function are: - * \param name a Dart string which is the name of the native function. - * \param num_of_arguments is the number of arguments expected by the - * native function. - * \param auto_setup_scope is a boolean flag that can be set by the resolver - * to indicate if this function needs a Dart API scope (see Dart_EnterScope/ - * Dart_ExitScope) to be setup automatically by the VM before calling into - * the native function. By default most native functions would require this - * to be true but some light weight native functions which do not call back - * into the VM through the Dart API may not require a Dart scope to be - * setup automatically. - * - * \return A valid Dart_NativeFunction which resolves to a native entry point - * for the native function. - * - * See Dart_SetNativeResolver. - */ -typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name, - int num_of_arguments, - bool* auto_setup_scope); -/* TODO(turnidge): Consider renaming to NativeFunctionResolver or - * NativeResolver. */ - -/** - * Native entry symbol lookup callback. - * - * For libraries and scripts which have native functions, the embedder - * can provide a callback for mapping a native entry to a symbol. This callback - * maps a native function entry PC to the native function name. If no native - * entry symbol can be found, the callback should return NULL. - * - * The parameters to the native reverse resolver function are: - * \param nf A Dart_NativeFunction. - * - * \return A const UTF-8 string containing the symbol name or NULL. - * - * See Dart_SetNativeResolver. - */ -typedef const uint8_t* (*Dart_NativeEntrySymbol)(Dart_NativeFunction nf); - -/** - * FFI Native C function pointer resolver callback. - * - * See Dart_SetFfiNativeResolver. - */ -typedef void* (*Dart_FfiNativeResolver)(const char* name, uintptr_t args_n); - -/* - * =========== - * Environment - * =========== - */ - -/** - * An environment lookup callback function. - * - * \param name The name of the value to lookup in the environment. - * - * \return A valid handle to a string if the name exists in the - * current environment or Dart_Null() if not. - */ -typedef Dart_Handle (*Dart_EnvironmentCallback)(Dart_Handle name); - -/** - * Sets the environment callback for the current isolate. This - * callback is used to lookup environment values by name in the - * current environment. This enables the embedder to supply values for - * the const constructors bool.fromEnvironment, int.fromEnvironment - * and String.fromEnvironment. - */ -DART_EXPORT Dart_Handle -Dart_SetEnvironmentCallback(Dart_EnvironmentCallback callback); - -/** - * Sets the callback used to resolve native functions for a library. - * - * \param library A library. - * \param resolver A native entry resolver. - * - * \return A valid handle if the native resolver was set successfully. - */ -DART_EXPORT Dart_Handle -Dart_SetNativeResolver(Dart_Handle library, - Dart_NativeEntryResolver resolver, - Dart_NativeEntrySymbol symbol); -/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */ - -/** - * Returns the callback used to resolve native functions for a library. - * - * \param library A library. - * \param resolver a pointer to a Dart_NativeEntryResolver - * - * \return A valid handle if the library was found. - */ -DART_EXPORT Dart_Handle -Dart_GetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver* resolver); - -/** - * Returns the callback used to resolve native function symbols for a library. - * - * \param library A library. - * \param resolver a pointer to a Dart_NativeEntrySymbol. - * - * \return A valid handle if the library was found. - */ -DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library, - Dart_NativeEntrySymbol* resolver); - -/** - * Sets the callback used to resolve FFI native functions for a library. - * The resolved functions are expected to be a C function pointer of the - * correct signature (as specified in the `@Native()` function - * annotation in Dart code). - * - * NOTE: This is an experimental feature and might change in the future. - * - * \param library A library. - * \param resolver A native function resolver. - * - * \return A valid handle if the native resolver was set successfully. - */ -DART_EXPORT Dart_Handle -Dart_SetFfiNativeResolver(Dart_Handle library, Dart_FfiNativeResolver resolver); - -/** - * Callback provided by the embedder that is used by the VM to resolve asset - * paths. - * - * The VM is responsible for looking up the asset path with the asset id in the - * kernel mapping. The embedder is responsible for providing the asset mapping - * during kernel compilation and using the asset path to return a library handle - * in this function. - * - * \param path The string in the asset path as passed in native_assets.yaml - * during kernel compilation. - * - * \param error Returns NULL if successful, an error message otherwise. The - * caller is responsible for calling free() on the error message. - * - * \return The library handle. If |error| is not-null, the return value is - * undefined. - */ -typedef void* (*Dart_NativeAssetsDlopenCallback)(const char* path, - char** error); -typedef void* (*Dart_NativeAssetsDlopenCallbackNoPath)(char** error); - -/** - * Callback provided by the embedder that is used by the VM to resolve asset - * ids. - * - * The embedder can freely chose how to bundle asset id to asset path mappings - * and how to perform this lookup. - * - * If the embedder provides this callback, it must also provide - * `Dart_NativeAssetsAvailableAssets`. - * - * If provided, takes prescedence over `Dart_NativeAssetsDlopenCallback`. - * - * \param path The asset id requested in the `@Native` external function. - * - * \param error Returns NULL if successful, an error message otherwise. The - * caller is responsible for calling free() on the error message. - * - * \return The library handle. If |error| is not-null, the return value is - * undefined. - */ -typedef void* (*Dart_NativeAssetsDlopenAssetId)(const char* asset_id, - char** error); - -/** - * Callback provided by the embedder that is used by the VM to request a - * description of the available assets - * - * \return A malloced string containing all asset ids. The caller must free this - * string. - */ -typedef char* (*Dart_NativeAssetsAvailableAssets)(); - -/** - * Callback provided by the embedder that is used by the VM to lookup symbols - * in native code assets. - * If no callback is provided, using `@Native`s with `native_asset.yaml`s will - * fail. - * - * \param handle The library handle returned from a - * `Dart_NativeAssetsDlopenCallback` or - * `Dart_NativeAssetsDlopenCallbackNoPath`. - * - * \param symbol The symbol to look up. Is a string. - * - * \param error Returns NULL if creation is successful, an error message - * otherwise. The caller is responsible for calling free() on the error - * message. - * - * \return The symbol address. If |error| is not-null, the return value is - * undefined. - */ -typedef void* (*Dart_NativeAssetsDlsymCallback)(void* handle, - const char* symbol, - char** error); - -typedef struct { - Dart_NativeAssetsDlopenCallback dlopen_absolute; - Dart_NativeAssetsDlopenCallback dlopen_relative; - Dart_NativeAssetsDlopenCallback dlopen_system; - Dart_NativeAssetsDlopenCallbackNoPath dlopen_process; - Dart_NativeAssetsDlopenCallbackNoPath dlopen_executable; - Dart_NativeAssetsDlsymCallback dlsym; - Dart_NativeAssetsDlopenAssetId dlopen; - Dart_NativeAssetsAvailableAssets available_assets; -} NativeAssetsApi; - -/** - * Initializes native asset resolution for the current isolate group. - * - * The caller is responsible for ensuring this is called right after isolate - * group creation, and before running any dart code (or spawning isolates). - * - * @param native_assets_api The callbacks used by native assets resolution. - * The VM does not take ownership of the parameter, - * it can be freed immediately after the call. - */ -DART_EXPORT void Dart_InitializeNativeAssetsResolver( - NativeAssetsApi* native_assets_api); - -/* - * ===================== - * Scripts and Libraries - * ===================== - */ - -typedef enum { - Dart_kCanonicalizeUrl = 0, - Dart_kImportTag, - Dart_kKernelTag, -} Dart_LibraryTag; - -/** - * The library tag handler is a multi-purpose callback provided by the - * embedder to the Dart VM. The embedder implements the tag handler to - * provide the ability to load Dart scripts and imports. - * - * -- TAGS -- - * - * Dart_kCanonicalizeUrl - * - * This tag indicates that the embedder should canonicalize 'url' with - * respect to 'library'. For most embedders, this is resolving the `url` - * relative to the `library`s url (see `Dart_LibraryUrl`). - * - * Dart_kImportTag - * - * This tag is used to load a library from IsolateMirror.loadUri. The embedder - * should call Dart_LoadLibraryFromKernel to provide the library to the VM. The - * return value should be an error or library (the result from - * Dart_LoadLibraryFromKernel). - * - * Dart_kKernelTag - * - * This tag is used to load the intermediate file (kernel) generated by - * the Dart front end. This tag is typically used when a 'hot-reload' - * of an application is needed and the VM is 'use dart front end' mode. - * The dart front end typically compiles all the scripts, imports and part - * files into one intermediate file hence we don't use the source/import or - * script tags. The return value should be an error or a TypedData containing - * the kernel bytes. - * - */ -typedef Dart_Handle (*Dart_LibraryTagHandler)( - Dart_LibraryTag tag, - Dart_Handle library_or_package_map_url, - Dart_Handle url); - -/** - * Sets library tag handler for the current isolate. This handler is - * used to handle the various tags encountered while loading libraries - * or scripts in the isolate. - * - * \param handler Handler code to be used for handling the various tags - * encountered while loading libraries or scripts in the isolate. - * - * \return If no error occurs, the handler is set for the isolate. - * Otherwise an error handle is returned. - * - * TODO(turnidge): Document. - */ -DART_EXPORT Dart_Handle -Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler); - -/** - * Handles deferred loading requests. When this handler is invoked, it should - * eventually load the deferred loading unit with the given id and call - * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is - * recommended that the loading occur asynchronously, but it is permitted to - * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the - * handler returns. - * - * If an error is returned, it will be propagated through - * `prefix.loadLibrary()`. This is useful for synchronous - * implementations, which must propagate any unwind errors from - * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler - * should return a non-error such as `Dart_Null()`. - */ -typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id); - -/** - * Sets the deferred load handler for the current isolate. This handler is - * used to handle loading deferred imports in an AppJIT or AppAOT program. - */ -DART_EXPORT Dart_Handle -Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler); - -/** - * Notifies the VM that a deferred load completed successfully. This function - * will eventually cause the corresponding `prefix.loadLibrary()` futures to - * complete. - * - * Requires the current isolate to be the same current isolate during the - * invocation of the Dart_DeferredLoadHandler. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_DeferredLoadComplete(intptr_t loading_unit_id, - const uint8_t* snapshot_data, - const uint8_t* snapshot_instructions); - -/** - * Notifies the VM that a deferred load failed. This function - * will eventually cause the corresponding `prefix.loadLibrary()` futures to - * complete with an error. - * - * If `transient` is true, future invocations of `prefix.loadLibrary()` will - * trigger new load requests. If false, futures invocation will complete with - * the same error. - * - * Requires the current isolate to be the same current isolate during the - * invocation of the Dart_DeferredLoadHandler. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_DeferredLoadCompleteError(intptr_t loading_unit_id, - const char* error_message, - bool transient); - -/** - * Loads the root library for the current isolate. - * - * Requires there to be no current root library. - * - * \param kernel_buffer A buffer which contains a kernel binary (see - * pkg/kernel/binary.md). Must remain valid until isolate group shutdown. - * \param kernel_size Length of the passed in buffer. - * - * \return A handle to the root library, or an error. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer, intptr_t kernel_size); - -/** - * Gets the library for the root script for the current isolate. - * - * If the root script has not yet been set for the current isolate, - * this function returns Dart_Null(). This function never returns an - * error handle. - * - * \return Returns the root Library for the current isolate or Dart_Null(). - */ -DART_EXPORT Dart_Handle Dart_RootLibrary(void); - -/** - * Sets the root library for the current isolate. - * - * \return Returns an error handle if `library` is not a library handle. - */ -DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library); - -/** - * Lookup or instantiate a legacy type by name and type arguments from a - * Library. - * - * \param library The library containing the class or interface. - * \param class_name The class name for the type. - * \param number_of_type_arguments Number of type arguments. - * For non parametric types the number of type arguments would be 0. - * \param type_arguments Pointer to an array of type arguments. - * For non parametric types a NULL would be passed in for this argument. - * - * \return If no error occurs, the type is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library, - Dart_Handle class_name, - intptr_t number_of_type_arguments, - Dart_Handle* type_arguments); - -/** - * Lookup or instantiate a nullable type by name and type arguments from - * Library. - * - * \param library The library containing the class or interface. - * \param class_name The class name for the type. - * \param number_of_type_arguments Number of type arguments. - * For non parametric types the number of type arguments would be 0. - * \param type_arguments Pointer to an array of type arguments. - * For non parametric types a NULL would be passed in for this argument. - * - * \return If no error occurs, the type is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library, - Dart_Handle class_name, - intptr_t number_of_type_arguments, - Dart_Handle* type_arguments); - -/** - * Lookup or instantiate a non-nullable type by name and type arguments from - * Library. - * - * \param library The library containing the class or interface. - * \param class_name The class name for the type. - * \param number_of_type_arguments Number of type arguments. - * For non parametric types the number of type arguments would be 0. - * \param type_arguments Pointer to an array of type arguments. - * For non parametric types a NULL would be passed in for this argument. - * - * \return If no error occurs, the type is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle -Dart_GetNonNullableType(Dart_Handle library, - Dart_Handle class_name, - intptr_t number_of_type_arguments, - Dart_Handle* type_arguments); - -/** - * Creates a nullable version of the provided type. - * - * \param type The type to be converted to a nullable type. - * - * \return If no error occurs, a nullable type is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type); - -/** - * Creates a non-nullable version of the provided type. - * - * \param type The type to be converted to a non-nullable type. - * - * \return If no error occurs, a non-nullable type is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type); - -/** - * A type's nullability. - * - * \param type A Dart type. - * \param result An out parameter containing the result of the check. True if - * the type is of the specified nullability, false otherwise. - * - * \return Returns an error handle if type is not of type Type. - */ -DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result); -DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result); - -/** - * Lookup a class or interface by name from a Library. - * - * \param library The library containing the class or interface. - * \param class_name The name of the class or interface. - * - * \return If no error occurs, the class or interface is - * returned. Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, - Dart_Handle class_name); -/* TODO(asiva): The above method needs to be removed once all uses - * of it are removed from the embedder code. */ - -/** - * Returns an import path to a Library, such as "file:///test.dart" or - * "dart:core". - */ -DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library); - -/** - * Returns a URL from which a Library was loaded. - */ -DART_EXPORT Dart_Handle Dart_LibraryResolvedUrl(Dart_Handle library); - -/** - * \return An array of libraries. - */ -DART_EXPORT Dart_Handle Dart_GetLoadedLibraries(void); - -DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url); -/* TODO(turnidge): Consider returning Dart_Null() when the library is - * not found to distinguish that from a true error case. */ - -/** - * Report an loading error for the library. - * - * \param library The library that failed to load. - * \param error The Dart error instance containing the load error. - * - * \return If the VM handles the error, the return value is - * a null handle. If it doesn't handle the error, the error - * object is returned. - */ -DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library, - Dart_Handle error); - -/** - * Called by the embedder to load a partial program. Does not set the root - * library. - * - * \param kernel_buffer A buffer which contains a kernel binary (see - * pkg/kernel/binary.md). Must remain valid until isolate shutdown. - * \param kernel_buffer_size Length of the passed in buffer. - * - * \return A handle to the main library of the compilation unit, or an error. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size); -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_LoadLibrary(Dart_Handle kernel_buffer); - -/** - * Indicates that all outstanding load requests have been satisfied. - * This finalizes all the new classes loaded and optionally completes - * deferred library futures. - * - * Requires there to be a current isolate. - * - * \param complete_futures Specify true if all deferred library - * futures should be completed, false otherwise. - * - * \return Success if all classes have been finalized and deferred library - * futures are completed. Otherwise, returns an error. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_FinalizeLoading(bool complete_futures); - -/* - * ===== - * Peers - * ===== - */ - -/** - * The peer field is a lazily allocated field intended for storage of - * an uncommonly used values. Most instances types can have a peer - * field allocated. The exceptions are subtypes of Null, num, and - * bool. - */ - -/** - * Returns the value of peer field of 'object' in 'peer'. - * - * \param object An object. - * \param peer An out parameter that returns the value of the peer - * field. - * - * \return Returns an error if 'object' is a subtype of Null, num, or - * bool. - */ -DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer); - -/** - * Sets the value of the peer field of 'object' to the value of - * 'peer'. - * - * \param object An object. - * \param peer A value to store in the peer field. - * - * \return Returns an error if 'object' is a subtype of Null, num, or - * bool. - */ -DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer); - -/* - * ====== - * Kernel - * ====== - */ - -/** - * Experimental support for Dart to Kernel parser isolate. - * - * TODO(hausner): Document finalized interface. - * - */ - -// TODO(33433): Remove kernel service from the embedding API. - -typedef enum { - Dart_KernelCompilationStatus_Unknown = -1, - Dart_KernelCompilationStatus_Ok = 0, - Dart_KernelCompilationStatus_Error = 1, - Dart_KernelCompilationStatus_Crash = 2, - Dart_KernelCompilationStatus_MsgFailed = 3, -} Dart_KernelCompilationStatus; - -typedef struct { - Dart_KernelCompilationStatus status; - char* error; - uint8_t* kernel; - intptr_t kernel_size; -} Dart_KernelCompilationResult; - -typedef enum { - Dart_KernelCompilationVerbosityLevel_Error = 0, - Dart_KernelCompilationVerbosityLevel_Warning, - Dart_KernelCompilationVerbosityLevel_Info, - Dart_KernelCompilationVerbosityLevel_All, -} Dart_KernelCompilationVerbosityLevel; - -DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate); -DART_EXPORT bool Dart_KernelIsolateIsRunning(void); -DART_EXPORT Dart_Port Dart_KernelPort(void); - -/** - * Compiles the given `script_uri` to a kernel file. - * - * \param platform_kernel A buffer containing the kernel of the platform (e.g. - * `vm_platform_strong.dill`). The VM does not take ownership of this memory. - * - * \param platform_kernel_size The length of the platform_kernel buffer. - * - * \param snapshot_compile Set to `true` when the compilation is for a snapshot. - * This is used by the frontend to determine if compilation related information - * should be printed to console (e.g., null safety mode). - * - * \param embed_sources Set to `true` when sources should be embedded in the - * kernel file. - * - * \param verbosity Specifies the logging behavior of the kernel compilation - * service. - * - * \return Returns the result of the compilation. - * - * On a successful compilation the returned [Dart_KernelCompilationResult] has - * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size` - * fields are set. The caller takes ownership of the malloc()ed buffer. - * - * On a failed compilation the `error` might be set describing the reason for - * the failed compilation. The caller takes ownership of the malloc()ed - * error. - * - * Requires there to be a current isolate. - */ -DART_EXPORT Dart_KernelCompilationResult -Dart_CompileToKernel(const char* script_uri, - const uint8_t* platform_kernel, - const intptr_t platform_kernel_size, - bool incremental_compile, - bool snapshot_compile, - bool embed_sources, - const char* package_config, - Dart_KernelCompilationVerbosityLevel verbosity); - -typedef struct { - const char* uri; - const char* source; -} Dart_SourceFile; - -DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(void); - -/** - * Sets the kernel buffer which will be used to load Dart SDK sources - * dynamically at runtime. - * - * \param platform_kernel A buffer containing kernel which has sources for the - * Dart SDK populated. Note: The VM does not take ownership of this memory. - * - * \param platform_kernel_size The length of the platform_kernel buffer. - */ -DART_EXPORT void Dart_SetDartLibrarySourcesKernel( - const uint8_t* platform_kernel, - const intptr_t platform_kernel_size); - -/** - * Always return true as the VM only supports strong null safety. - */ -DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri, - const char* package_config, - const char* original_working_directory, - const uint8_t* snapshot_data, - const uint8_t* snapshot_instructions, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size); - -#define DART_KERNEL_ISOLATE_NAME "kernel-service" - -/* - * ======= - * Service - * ======= - */ - -#define DART_VM_SERVICE_ISOLATE_NAME "vm-service" - -/** - * Returns true if isolate is the service isolate. - * - * \param isolate An isolate - * - * \return Returns true if 'isolate' is the service isolate. - */ -DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate); - -/** - * Writes the CPU profile to the timeline as a series of 'instant' events. - * - * Note that this is an expensive operation. - * - * \param main_port The main port of the Isolate whose profile samples to write. - * \param error An optional error, must be free()ed by caller. - * - * \return Returns true if the profile is successfully written and false - * otherwise. - */ -DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error); - -/* - * ============== - * Precompilation - * ============== - */ - -/** - * Compiles all functions reachable from entry points and marks - * the isolate to disallow future compilation. - * - * Entry points should be specified using `@pragma("vm:entry-point")` - * annotation. - * - * \return An error handle if a compilation error or runtime error running const - * constructors was encountered. - */ -DART_EXPORT Dart_Handle Dart_Precompile(void); - -typedef void (*Dart_CreateLoadingUnitCallback)( - void* callback_data, - intptr_t loading_unit_id, - void** write_callback_data, - void** write_debug_callback_data); -typedef void (*Dart_StreamingWriteCallback)(void* callback_data, - const uint8_t* buffer, - intptr_t size); -typedef void (*Dart_StreamingCloseCallback)(void* callback_data); - -DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id); - -// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name. -// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual -// symbol names in the objects are given by the '...AsmSymbol' definitions. -#if defined(__APPLE__) -#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId" -#define kVmSnapshotDataCSymbol "kDartVmSnapshotData" -#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions" -#define kVmSnapshotBssCSymbol "kDartVmSnapshotBss" -#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData" -#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions" -#define kIsolateSnapshotBssCSymbol "kDartIsolateSnapshotBss" -#else -#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId" -#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData" -#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions" -#define kVmSnapshotBssCSymbol "_kDartVmSnapshotBss" -#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData" -#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions" -#define kIsolateSnapshotBssCSymbol "_kDartIsolateSnapshotBss" -#endif - -#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId" -#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData" -#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions" -#define kVmSnapshotBssAsmSymbol "_kDartVmSnapshotBss" -#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData" -#define kIsolateSnapshotInstructionsAsmSymbol \ - "_kDartIsolateSnapshotInstructions" -#define kIsolateSnapshotBssAsmSymbol "_kDartIsolateSnapshotBss" - -/** - * Creates a precompiled snapshot. - * - A root library must have been loaded. - * - Dart_Precompile must have been called. - * - * Outputs an assembly file defining the symbols listed in the definitions - * above. - * - * The assembly should be compiled as a static or shared library and linked or - * loaded by the embedder. Running this snapshot requires a VM compiled with - * DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and - * kDartVmSnapshotInstructions should be passed to Dart_Initialize. The - * kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be - * passed to Dart_CreateIsolateGroup. - * - * The callback will be invoked one or more times to provide the assembly code. - * - * If stripped is true, then the assembly code will not include DWARF - * debugging sections. - * - * If debug_callback_data is provided, debug_callback_data will be used with - * the callback to provide separate debugging information. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, - void* callback_data, - bool stripped, - void* debug_callback_data); -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppAOTSnapshotAsAssemblies( - Dart_CreateLoadingUnitCallback next_callback, - void* next_callback_data, - bool stripped, - Dart_StreamingWriteCallback write_callback, - Dart_StreamingCloseCallback close_callback); - -/** - * Creates a precompiled snapshot. - * - A root library must have been loaded. - * - Dart_Precompile must have been called. - * - * Outputs an ELF shared library defining the symbols - * - _kDartVmSnapshotData - * - _kDartVmSnapshotInstructions - * - _kDartIsolateSnapshotData - * - _kDartIsolateSnapshotInstructions - * - * The shared library should be dynamically loaded by the embedder. - * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT. - * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to - * Dart_Initialize. The kDartIsolateSnapshotData and - * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate. - * - * The callback will be invoked one or more times to provide the binary output. - * - * If stripped is true, then the binary output will not include DWARF - * debugging sections. - * - * If debug_callback_data is provided, debug_callback_data will be used with - * the callback to provide separate debugging information. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback, - void* callback_data, - bool stripped, - void* debug_callback_data); -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, - void* next_callback_data, - bool stripped, - Dart_StreamingWriteCallback write_callback, - Dart_StreamingCloseCallback close_callback); - -/** - * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes - * kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does - * not strip DWARF information from the generated assembly or allow for - * separate debug information. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, - void* callback_data); - -/** - * Sorts the class-ids in depth first traversal order of the inheritance - * tree. This is a costly operation, but it can make method dispatch - * more efficient and is done before writing snapshots. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(void); - -/** - * Creates a snapshot that caches compiled code and type feedback for faster - * startup and quicker warmup in a subsequent process. - * - * Outputs a snapshot in two pieces. The pieces should be passed to - * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the - * current VM. The instructions piece must be loaded with read and execute - * permissions; the data piece may be loaded as read-only. - * - * - Requires the VM to have not been started with --precompilation. - * - Not supported when targeting IA32. - * - The VM writing the snapshot and the VM reading the snapshot must be the - * same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must - * be targeting the same architecture, and must both be in checked mode or - * both in unchecked mode. - * - * The buffers are scope allocated and are only valid until the next call to - * Dart_ExitScope. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer, - intptr_t* isolate_snapshot_data_size, - uint8_t** isolate_snapshot_instructions_buffer, - intptr_t* isolate_snapshot_instructions_size); - -/** - * Get obfuscation map for precompiled code. - * - * Obfuscation map is encoded as a JSON array of pairs (original name, - * obfuscated name). - * - * \return Returns an error handler if the VM was built in a mode that does not - * support obfuscation. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length); - -/** - * Returns whether the VM only supports running from precompiled snapshots and - * not from any other kind of snapshot or from source (that is, the VM was - * compiled with DART_PRECOMPILED_RUNTIME). - */ -DART_EXPORT bool Dart_IsPrecompiledRuntime(void); - -/** - * Print a native stack trace. Used for crash handling. - * - * If context is NULL, prints the current stack trace. Otherwise, context - * should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler - * running on the current thread. - */ -DART_EXPORT void Dart_DumpNativeStackTrace(void* context); - -/** - * Indicate that the process is about to abort, and the Dart VM should not - * attempt to cleanup resources. - */ -DART_EXPORT void Dart_PrepareToAbort(void); - -/** - * Callback provided by the embedder that is used by the VM to - * produce footnotes appended to DWARF stack traces. - * - * Whenever VM formats a stack trace as a string it would call this callback - * passing raw program counters for each frame in the stack trace. - * - * Embedder can then return a string which if not-null will be appended to the - * formatted stack trace. - * - * Returned string is expected to be `malloc()` allocated. VM takes ownership - * of the returned string and will `free()` it. - * - * \param addresses raw program counter addresses for each frame - * \param count number of elements in the addresses array - */ -typedef char* (*Dart_DwarfStackTraceFootnoteCallback)(void* addresses[], - intptr_t count); - -/** - * Configure DWARF stack trace footnote callback. - */ -DART_EXPORT void Dart_SetDwarfStackTraceFootnoteCallback( - Dart_DwarfStackTraceFootnoteCallback callback); - -#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/dart_api_dl.c b/src/serious_python_bridge/native/dart_api/dart_api_dl.c deleted file mode 100644 index 48fb54e7..00000000 --- a/src/serious_python_bridge/native/dart_api/dart_api_dl.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#include "dart_api_dl.h" /* NOLINT */ -#include "dart_version.h" /* NOLINT */ -#include "internal/dart_api_dl_impl.h" /* NOLINT */ - -#include -#include - -#define DART_API_DL_DEFINITIONS(name, R, A) name##_Type name##_DL = NULL; - -DART_API_ALL_DL_SYMBOLS(DART_API_DL_DEFINITIONS) -DART_API_DEPRECATED_DL_SYMBOLS(DART_API_DL_DEFINITIONS) - -#undef DART_API_DL_DEFINITIONS - -typedef void* DartApiEntry_function; - -DartApiEntry_function FindFunctionPointer(const DartApiEntry* entries, - const char* name) { - while (entries->name != NULL) { - if (strcmp(entries->name, name) == 0) return entries->function; - entries++; - } - return NULL; -} - -DART_EXPORT void Dart_UpdateExternalSize_Deprecated( - Dart_WeakPersistentHandle object, intptr_t external_size) { - printf("Dart_UpdateExternalSize is a nop, it has been deprecated\n"); -} - -DART_EXPORT void Dart_UpdateFinalizableExternalSize_Deprecated( - Dart_FinalizableHandle object, - Dart_Handle strong_ref_to_object, - intptr_t external_allocation_size) { - printf("Dart_UpdateFinalizableExternalSize is a nop, " - "it has been deprecated\n"); -} - -intptr_t Dart_InitializeApiDL(void* data) { - DartApi* dart_api_data = (DartApi*)data; - - if (dart_api_data->major != DART_API_DL_MAJOR_VERSION) { - // If the DartVM we're running on does not have the same version as this - // file was compiled against, refuse to initialize. The symbols are not - // compatible. - return -1; - } - // Minor versions are allowed to be different. - // If the DartVM has a higher minor version, it will provide more symbols - // than we initialize here. - // If the DartVM has a lower minor version, it will not provide all symbols. - // In that case, we leave the missing symbols un-initialized. Those symbols - // should not be used by the Dart and native code. The client is responsible - // for checking the minor version number himself based on which symbols it - // is using. - // (If we would error out on this case, recompiling native code against a - // newer SDK would break all uses on older SDKs, which is too strict.) - - const DartApiEntry* dart_api_function_pointers = dart_api_data->functions; - -#define DART_API_DL_INIT(name, R, A) \ - name##_DL = \ - (name##_Type)(FindFunctionPointer(dart_api_function_pointers, #name)); - DART_API_ALL_DL_SYMBOLS(DART_API_DL_INIT) -#undef DART_API_DL_INIT - -#define DART_API_DEPRECATED_DL_INIT(name, R, A) \ - name##_DL = name##_Deprecated; - DART_API_DEPRECATED_DL_SYMBOLS(DART_API_DEPRECATED_DL_INIT) -#undef DART_API_DEPRECATED_DL_INIT - - return 0; -} diff --git a/src/serious_python_bridge/native/dart_api/dart_api_dl.h b/src/serious_python_bridge/native/dart_api/dart_api_dl.h deleted file mode 100644 index 2b4c8d4f..00000000 --- a/src/serious_python_bridge/native/dart_api/dart_api_dl.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#ifndef RUNTIME_INCLUDE_DART_API_DL_H_ -#define RUNTIME_INCLUDE_DART_API_DL_H_ - -#include "dart_api.h" /* NOLINT */ -#include "dart_native_api.h" /* NOLINT */ - -/** \mainpage Dynamically Linked Dart API - * - * This exposes a subset of symbols from dart_api.h and dart_native_api.h - * available in every Dart embedder through dynamic linking. - * - * All symbols are postfixed with _DL to indicate that they are dynamically - * linked and to prevent conflicts with the original symbol. - * - * Link `dart_api_dl.c` file into your library and invoke - * `Dart_InitializeApiDL` with `NativeApi.initializeApiDLData`. - * - * Returns 0 on success. - */ - -DART_EXPORT intptr_t Dart_InitializeApiDL(void* data); - -// ============================================================================ -// IMPORTANT! Never update these signatures without properly updating -// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION. -// -// Verbatim copy of `dart_native_api.h` and `dart_api.h` symbol names and types -// to trigger compile-time errors if the symbols in those files are updated -// without updating these. -// -// Function return and argument types, and typedefs are carbon copied. Structs -// are typechecked nominally in C/C++, so they are not copied, instead a -// comment is added to their definition. -typedef int64_t Dart_Port_DL; -typedef struct { - int64_t port_id; - int64_t origin_id; -} Dart_PortEx_DL; - -typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id, - Dart_CObject* message); - -// dart_native_api.h symbols can be called on any thread. -#define DART_NATIVE_API_DL_SYMBOLS(F) \ - /***** dart_native_api.h *****/ \ - /* Dart_Port */ \ - F(Dart_PostCObject, bool, (Dart_Port_DL port_id, Dart_CObject * message)) \ - F(Dart_PostInteger, bool, (Dart_Port_DL port_id, int64_t message)) \ - F(Dart_NewNativePort, Dart_Port_DL, \ - (const char* name, Dart_NativeMessageHandler_DL handler, \ - bool handle_concurrently)) \ - F(Dart_CloseNativePort, bool, (Dart_Port_DL native_port_id)) - -// dart_api.h symbols can only be called on Dart threads. -#define DART_API_DL_SYMBOLS(F) \ - /***** dart_api.h *****/ \ - /* Errors */ \ - F(Dart_IsError, bool, (Dart_Handle handle)) \ - F(Dart_IsApiError, bool, (Dart_Handle handle)) \ - F(Dart_IsUnhandledExceptionError, bool, (Dart_Handle handle)) \ - F(Dart_IsCompilationError, bool, (Dart_Handle handle)) \ - F(Dart_IsFatalError, bool, (Dart_Handle handle)) \ - F(Dart_GetError, const char*, (Dart_Handle handle)) \ - F(Dart_ErrorHasException, bool, (Dart_Handle handle)) \ - F(Dart_ErrorGetException, Dart_Handle, (Dart_Handle handle)) \ - F(Dart_ErrorGetStackTrace, Dart_Handle, (Dart_Handle handle)) \ - F(Dart_NewApiError, Dart_Handle, (const char* error)) \ - F(Dart_NewCompilationError, Dart_Handle, (const char* error)) \ - F(Dart_NewUnhandledExceptionError, Dart_Handle, (Dart_Handle exception)) \ - F(Dart_PropagateError, void, (Dart_Handle handle)) \ - /* Dart_Handle, Dart_PersistentHandle, Dart_WeakPersistentHandle */ \ - F(Dart_HandleFromPersistent, Dart_Handle, (Dart_PersistentHandle object)) \ - F(Dart_HandleFromWeakPersistent, Dart_Handle, \ - (Dart_WeakPersistentHandle object)) \ - F(Dart_NewPersistentHandle, Dart_PersistentHandle, (Dart_Handle object)) \ - F(Dart_SetPersistentHandle, void, \ - (Dart_PersistentHandle obj1, Dart_Handle obj2)) \ - F(Dart_DeletePersistentHandle, void, (Dart_PersistentHandle object)) \ - F(Dart_NewWeakPersistentHandle, Dart_WeakPersistentHandle, \ - (Dart_Handle object, void* peer, intptr_t external_allocation_size, \ - Dart_HandleFinalizer callback)) \ - F(Dart_DeleteWeakPersistentHandle, void, (Dart_WeakPersistentHandle object)) \ - F(Dart_NewFinalizableHandle, Dart_FinalizableHandle, \ - (Dart_Handle object, void* peer, intptr_t external_allocation_size, \ - Dart_HandleFinalizer callback)) \ - F(Dart_DeleteFinalizableHandle, void, \ - (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object)) \ - /* Isolates */ \ - F(Dart_CurrentIsolate, Dart_Isolate, (void)) \ - F(Dart_ExitIsolate, void, (void)) \ - F(Dart_EnterIsolate, void, (Dart_Isolate)) \ - /* Dart_Port */ \ - F(Dart_Post, bool, (Dart_Port_DL port_id, Dart_Handle object)) \ - F(Dart_NewSendPort, Dart_Handle, (Dart_Port_DL port_id)) \ - F(Dart_NewSendPortEx, Dart_Handle, (Dart_PortEx_DL portex_id)) \ - F(Dart_SendPortGetId, Dart_Handle, \ - (Dart_Handle port, Dart_Port_DL * port_id)) \ - F(Dart_SendPortGetIdEx, Dart_Handle, \ - (Dart_Handle port, Dart_PortEx_DL * portex_id)) \ - /* Scopes */ \ - F(Dart_EnterScope, void, (void)) \ - F(Dart_ExitScope, void, (void)) \ - /* Objects */ \ - F(Dart_IsNull, bool, (Dart_Handle)) \ - F(Dart_Null, Dart_Handle, (void)) - -// dart_api.h symbols that have been deprecated but are retained here -// until we can make a breaking change bumping the major version number -// (DART_API_DL_MAJOR_VERSION) -#define DART_API_DEPRECATED_DL_SYMBOLS(F) \ - F(Dart_UpdateExternalSize, void, \ - (Dart_WeakPersistentHandle object, intptr_t external_allocation_size)) \ - F(Dart_UpdateFinalizableExternalSize, void, \ - (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object, \ - intptr_t external_allocation_size)) - -#define DART_API_ALL_DL_SYMBOLS(F) \ - DART_NATIVE_API_DL_SYMBOLS(F) \ - DART_API_DL_SYMBOLS(F) -// IMPORTANT! Never update these signatures without properly updating -// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION. -// -// End of verbatim copy. -// ============================================================================ - -// Copy of definition of DART_EXPORT without 'used' attribute. -// -// The 'used' attribute cannot be used with DART_API_ALL_DL_SYMBOLS because -// they are not function declarations, but variable declarations with a -// function pointer type. -// -// The function pointer variables are initialized with the addresses of the -// functions in the VM. If we were to use function declarations instead, we -// would need to forward the call to the VM adding indirection. -#if defined(__CYGWIN__) -#error Tool chain and platform not supported. -#elif defined(_WIN32) -#if defined(DART_SHARED_LIB) -#define DART_EXPORT_DL DART_EXTERN_C __declspec(dllexport) -#else -#define DART_EXPORT_DL DART_EXTERN_C -#endif -#else -#if __GNUC__ >= 4 -#if defined(DART_SHARED_LIB) -#define DART_EXPORT_DL DART_EXTERN_C __attribute__((visibility("default"))) -#else -#define DART_EXPORT_DL DART_EXTERN_C -#endif -#else -#error Tool chain not supported. -#endif -#endif - -#define DART_API_DL_DECLARATIONS(name, R, A) \ - typedef R(*name##_Type) A; \ - DART_EXPORT_DL name##_Type name##_DL; - -DART_API_ALL_DL_SYMBOLS(DART_API_DL_DECLARATIONS) -DART_API_DEPRECATED_DL_SYMBOLS(DART_API_DL_DECLARATIONS) - -#undef DART_API_DL_DECLARATIONS - -#undef DART_EXPORT_DL - -#endif /* RUNTIME_INCLUDE_DART_API_DL_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/dart_native_api.h b/src/serious_python_bridge/native/dart_api/dart_native_api.h deleted file mode 100644 index dbdaeb32..00000000 --- a/src/serious_python_bridge/native/dart_api/dart_native_api.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#ifndef RUNTIME_INCLUDE_DART_NATIVE_API_H_ -#define RUNTIME_INCLUDE_DART_NATIVE_API_H_ - -#include "dart_api.h" /* NOLINT */ - -/* - * ========================================== - * Message sending/receiving from native code - * ========================================== - */ - -/** - * A Dart_CObject is used for representing Dart objects as native C - * data outside the Dart heap. These objects are totally detached from - * the Dart heap. Only a subset of the Dart objects have a - * representation as a Dart_CObject. - * - * The string encoding in the 'value.as_string' is UTF-8. - * - * All the different types from dart:typed_data are exposed as type - * kTypedData. The specific type from dart:typed_data is in the type - * field of the as_typed_data structure. The length in the - * as_typed_data structure is always in bytes. - * - * The data for kTypedData is copied on message send and ownership remains with - * the caller. The ownership of data for kExternalTyped is passed to the VM on - * message send and returned when the VM invokes the - * Dart_HandleFinalizer callback; a non-NULL callback must be provided. - * - * Note that Dart_CObject_kNativePointer is intended for internal use by - * dart:io implementation and has no connection to dart:ffi Pointer class. - * It represents a pointer to a native resource of a known type. - * The receiving side will only see this pointer as an integer and will not - * see the specified finalizer. - * The specified finalizer will only be invoked if the message is not delivered. - */ -typedef enum { - Dart_CObject_kNull = 0, - Dart_CObject_kBool, - Dart_CObject_kInt32, - Dart_CObject_kInt64, - Dart_CObject_kDouble, - Dart_CObject_kString, - Dart_CObject_kArray, - Dart_CObject_kTypedData, - Dart_CObject_kExternalTypedData, - Dart_CObject_kSendPort, - Dart_CObject_kCapability, - Dart_CObject_kNativePointer, - Dart_CObject_kUnsupported, - Dart_CObject_kUnmodifiableExternalTypedData, - Dart_CObject_kNumberOfTypes -} Dart_CObject_Type; -// This enum is versioned by DART_API_DL_MAJOR_VERSION, only add at the end -// and bump the DART_API_DL_MINOR_VERSION. - -typedef struct _Dart_CObject { - Dart_CObject_Type type; - union { - bool as_bool; - int32_t as_int32; - int64_t as_int64; - double as_double; - const char* as_string; - struct { - Dart_Port id; - Dart_Port origin_id; - } as_send_port; - struct { - int64_t id; - } as_capability; - struct { - intptr_t length; - struct _Dart_CObject** values; - } as_array; - struct { - Dart_TypedData_Type type; - intptr_t length; /* in elements, not bytes */ - const uint8_t* values; - } as_typed_data; - struct { - Dart_TypedData_Type type; - intptr_t length; /* in elements, not bytes */ - uint8_t* data; - void* peer; - Dart_HandleFinalizer callback; - } as_external_typed_data; - struct { - intptr_t ptr; - intptr_t size; - Dart_HandleFinalizer callback; - } as_native_pointer; - } value; -} Dart_CObject; -// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when -// changing this struct. - -/** - * Posts a message on some port. The message will contain the Dart_CObject - * object graph rooted in 'message'. - * - * While the message is being sent the state of the graph of Dart_CObject - * structures rooted in 'message' should not be accessed, as the message - * generation will make temporary modifications to the data. When the message - * has been sent the graph will be fully restored. - * - * If true is returned, the message was enqueued, and finalizers for external - * typed data will eventually run, even if the receiving isolate shuts down - * before processing the message. If false is returned, the message was not - * enqueued and ownership of external typed data in the message remains with the - * caller. - * - * This function may be called on any thread when the VM is running (that is, - * after Dart_Initialize has returned and before Dart_Cleanup has been called). - * - * \param port_id The destination port. - * \param message The message to send. - * - * \return True if the message was posted. - */ -DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message); - -/** - * Posts a message on some port. The message will contain the integer 'message'. - * - * \param port_id The destination port. - * \param message The message to send. - * - * \return True if the message was posted. - */ -DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message); - -/** - * A native message handler. - * - * This handler is associated with a native port by calling - * Dart_NewNativePort. - * - * The message received is decoded into the message structure. The - * lifetime of the message data is controlled by the caller. All the - * data references from the message are allocated by the caller and - * will be reclaimed when returning to it. - */ -typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id, - Dart_CObject* message); - -/** - * Creates a new native port. When messages are received on this - * native port, then they will be dispatched to the provided native - * message handler. - * - * \param name The name of this port in debugging messages. - * \param handler The C handler to run when messages arrive on the port. - * \param handle_concurrently Is it okay to process requests on this - * native port concurrently? - * - * \return If successful, returns the port id for the native port. In - * case of error, returns ILLEGAL_PORT. - */ -DART_EXPORT Dart_Port Dart_NewNativePort(const char* name, - Dart_NativeMessageHandler handler, - bool handle_concurrently); - -/** - * Creates a new native port. When messages are received on this - * native port, then they will be dispatched to the provided native - * message handler using up to |max_concurrency| concurrent threads. - * - * \param name The name of this port in debugging messages. - * \param handler The C handler to run when messages arrive on the port. - * \param max_concurrency Size of the thread pool used by the native port. - * - * \return If successful, returns the port id for the native port. In - * case of error, returns ILLEGAL_PORT. - */ -DART_EXPORT Dart_Port -Dart_NewConcurrentNativePort(const char* name, - Dart_NativeMessageHandler handler, - intptr_t max_concurrency); - -/** - * Closes the native port with the given id. - * - * The port must have been allocated by a call to Dart_NewNativePort. - * - * \param native_port_id The id of the native port to close. - * - * \return Returns true if the port was closed successfully. - */ -DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id); - -/* - * ================== - * Verification Tools - * ================== - */ - -/** - * Forces all loaded classes and functions to be compiled eagerly in - * the current isolate.. - * - * TODO(turnidge): Document. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll(void); - -/** - * Finalizes all classes. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT Dart_Handle -Dart_FinalizeAllClasses(void); - -/* This function is intentionally undocumented. - * - * It should not be used outside internal tests. - */ -DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg); - -#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/dart_tools_api.h b/src/serious_python_bridge/native/dart_api/dart_tools_api.h deleted file mode 100644 index 367e1eb5..00000000 --- a/src/serious_python_bridge/native/dart_api/dart_tools_api.h +++ /dev/null @@ -1,627 +0,0 @@ -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#ifndef RUNTIME_INCLUDE_DART_TOOLS_API_H_ -#define RUNTIME_INCLUDE_DART_TOOLS_API_H_ - -#include "dart_api.h" /* NOLINT */ - -/** \mainpage Dart Tools Embedding API Reference - * - * This reference describes the Dart embedding API for tools. Tools include - * a debugger, service protocol, and timeline. - * - * NOTE: The APIs described in this file are unstable and subject to change. - * - * This reference is generated from the header include/dart_tools_api.h. - */ - -/* - * ======== - * Debugger - * ======== - */ - -/** - * ILLEGAL_ISOLATE_ID is a number guaranteed never to be associated with a - * valid isolate. - */ -#define ILLEGAL_ISOLATE_ID ILLEGAL_PORT - -/** - * ILLEGAL_ISOLATE_GROUP_ID is a number guaranteed never to be associated with a - * valid isolate group. - */ -#define ILLEGAL_ISOLATE_GROUP_ID 0 - -/* - * ======= - * Service - * ======= - */ - -/** - * A service request callback function. - * - * These callbacks, registered by the embedder, are called when the VM receives - * a service request it can't handle and the service request command name - * matches one of the embedder registered handlers. - * - * The return value of the callback indicates whether the response - * should be used as a regular result or an error result. - * Specifically, if the callback returns true, a regular JSON-RPC - * response is built in the following way: - * - * { - * "jsonrpc": "2.0", - * "result": , - * "id": , - * } - * - * If the callback returns false, a JSON-RPC error is built like this: - * - * { - * "jsonrpc": "2.0", - * "error": , - * "id": , - * } - * - * \param method The rpc method name. - * \param param_keys Service requests can have key-value pair parameters. The - * keys and values are flattened and stored in arrays. - * \param param_values The values associated with the keys. - * \param num_params The length of the param_keys and param_values arrays. - * \param user_data The user_data pointer registered with this handler. - * \param result A C string containing a valid JSON object. The returned - * pointer will be freed by the VM by calling free. - * - * \return True if the result is a regular JSON-RPC response, false if the - * result is a JSON-RPC error. - */ -typedef bool (*Dart_ServiceRequestCallback)(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - -/** - * Register a Dart_ServiceRequestCallback to be called to handle - * requests for the named rpc on a specific isolate. The callback will - * be invoked with the current isolate set to the request target. - * - * \param method The name of the method that this callback is responsible for. - * \param callback The callback to invoke. - * \param user_data The user data passed to the callback. - * - * NOTE: If multiple callbacks with the same name are registered, only - * the last callback registered will be remembered. - */ -DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback( - const char* method, - Dart_ServiceRequestCallback callback, - void* user_data); - -/** - * Register a Dart_ServiceRequestCallback to be called to handle - * requests for the named rpc. The callback will be invoked without a - * current isolate. - * - * \param method The name of the command that this callback is responsible for. - * \param callback The callback to invoke. - * \param user_data The user data passed to the callback. - * - * NOTE: If multiple callbacks with the same name are registered, only - * the last callback registered will be remembered. - */ -DART_EXPORT void Dart_RegisterRootServiceRequestCallback( - const char* method, - Dart_ServiceRequestCallback callback, - void* user_data); - -/** - * Embedder information which can be requested by the VM for internal or - * reporting purposes. - * - * The pointers in this structure are not going to be cached or freed by the VM. - */ - -#define DART_EMBEDDER_INFORMATION_CURRENT_VERSION (0x00000001) - -typedef struct { - int32_t version; - const char* name; // [optional] The name of the embedder - int64_t current_rss; // [optional] the current RSS of the embedder - int64_t max_rss; // [optional] the maximum RSS of the embedder -} Dart_EmbedderInformation; - -/** - * Callback provided by the embedder that is used by the VM to request - * information. - * - * \return Returns a pointer to a Dart_EmbedderInformation structure. - * The embedder keeps the ownership of the structure and any field in it. - * The embedder must ensure that the structure will remain valid until the - * next invocation of the callback. - */ -typedef void (*Dart_EmbedderInformationCallback)( - Dart_EmbedderInformation* info); - -/** - * Register a Dart_ServiceRequestCallback to be called to handle - * requests for the named rpc. The callback will be invoked without a - * current isolate. - * - * \param method The name of the command that this callback is responsible for. - * \param callback The callback to invoke. - * \param user_data The user data passed to the callback. - * - * NOTE: If multiple callbacks are registered, only the last callback registered - * will be remembered. - */ -DART_EXPORT void Dart_SetEmbedderInformationCallback( - Dart_EmbedderInformationCallback callback); - -/** - * Invoke a vm-service method and wait for its result. - * - * \param request_json The utf8-encoded json-rpc request. - * \param request_json_length The length of the json-rpc request. - * - * \param response_json The returned utf8-encoded json response, must be - * free()ed by caller. - * \param response_json_length The length of the returned json response. - * \param error An optional error, must be free()ed by caller. - * - * \return Whether the call was successfully performed. - * - * NOTE: This method does not need a current isolate and must not have the - * vm-isolate being the current isolate. It must be called after - * Dart_Initialize() and before Dart_Cleanup(). - */ -DART_EXPORT bool Dart_InvokeVMServiceMethod(uint8_t* request_json, - intptr_t request_json_length, - uint8_t** response_json, - intptr_t* response_json_length, - char** error); - -/* - * ======== - * Event Streams - * ======== - */ - -/** - * A callback invoked when the VM service gets a request to listen to - * some stream. - * - * \return Returns true iff the embedder supports the named stream id. - */ -typedef bool (*Dart_ServiceStreamListenCallback)(const char* stream_id); - -/** - * A callback invoked when the VM service gets a request to cancel - * some stream. - */ -typedef void (*Dart_ServiceStreamCancelCallback)(const char* stream_id); - -/** - * Adds VM service stream callbacks. - * - * \param listen_callback A function pointer to a listen callback function. - * A listen callback function should not be already set when this function - * is called. A NULL value removes the existing listen callback function - * if any. - * - * \param cancel_callback A function pointer to a cancel callback function. - * A cancel callback function should not be already set when this function - * is called. A NULL value removes the existing cancel callback function - * if any. - * - * \return Success if the callbacks were added. Otherwise, returns an - * error handle. - */ -DART_EXPORT char* Dart_SetServiceStreamCallbacks( - Dart_ServiceStreamListenCallback listen_callback, - Dart_ServiceStreamCancelCallback cancel_callback); - -/** - * Sends a data event to clients of the VM Service. - * - * A data event is used to pass an array of bytes to subscribed VM - * Service clients. For example, in the standalone embedder, this is - * function used to provide WriteEvents on the Stdout and Stderr - * streams. - * - * If the embedder passes in a stream id for which no client is - * subscribed, then the event is ignored. - * - * \param stream_id The id of the stream on which to post the event. - * - * \param event_kind A string identifying what kind of event this is. - * For example, 'WriteEvent'. - * - * \param bytes A pointer to an array of bytes. - * - * \param bytes_length The length of the byte array. - * - * \return NULL if the arguments are well formed. Otherwise, returns an - * error string. The caller is responsible for freeing the error message. - */ -DART_EXPORT char* Dart_ServiceSendDataEvent(const char* stream_id, - const char* event_kind, - const uint8_t* bytes, - intptr_t bytes_length); - -/* - * ======== - * Reload support - * ======== - * - * These functions are used to implement reloading in the Dart VM. - * This is an experimental feature, so embedders should be prepared - * for these functions to change. - */ - -/** - * A callback which determines whether the file at some url has been - * modified since some time. If the file cannot be found, true should - * be returned. - */ -typedef bool (*Dart_FileModifiedCallback)(const char* url, int64_t since); - -DART_EXPORT char* Dart_SetFileModifiedCallback( - Dart_FileModifiedCallback file_modified_callback); - -/** - * Returns true if isolate is currently reloading. - */ -DART_EXPORT bool Dart_IsReloading(); - -/* - * ======== - * Timeline - * ======== - */ - -/** - * Enable tracking of specified timeline category. This is operational - * only when systrace timeline functionality is turned on. - * - * \param categories A comma separated list of categories that need to - * be enabled, the categories are - * "all" : All categories - * "API" - Execution of Dart C API functions - * "Compiler" - Execution of Dart JIT compiler - * "CompilerVerbose" - More detailed Execution of Dart JIT compiler - * "Dart" - Execution of Dart code - * "Debugger" - Execution of Dart debugger - * "Embedder" - Execution of Dart embedder code - * "GC" - Execution of Dart Garbage Collector - * "Isolate" - Dart Isolate lifecycle execution - * "VM" - Execution in Dart VM runtime code - * "" - None - * - * When "all" is specified all the categories are enabled. - * When a comma separated list of categories is specified, the categories - * that are specified will be enabled and the rest will be disabled. - * When "" is specified all the categories are disabled. - * The category names are case sensitive. - * eg: Dart_EnableTimelineCategory("all"); - * Dart_EnableTimelineCategory("GC,API,Isolate"); - * Dart_EnableTimelineCategory("GC,Debugger,Dart"); - * - * \return True if the categories were successfully enabled, False otherwise. - */ -DART_EXPORT bool Dart_SetEnabledTimelineCategory(const char* categories); - -/** - * Returns a timestamp in microseconds. This timestamp is suitable for - * passing into the timeline system, and uses the same monotonic clock - * as dart:developer's Timeline.now. - * - * \return A timestamp that can be passed to the timeline system. - */ -DART_EXPORT int64_t Dart_TimelineGetMicros(); - -/** - * Returns a raw timestamp in from the monotonic clock. - * - * \return A raw timestamp from the monotonic clock. - */ -DART_EXPORT int64_t Dart_TimelineGetTicks(); - -/** - * Returns the frequency of the monotonic clock. - * - * \return The frequency of the monotonic clock. - */ -DART_EXPORT int64_t Dart_TimelineGetTicksFrequency(); - -typedef enum { - Dart_Timeline_Event_Begin, // Phase = 'B'. - Dart_Timeline_Event_End, // Phase = 'E'. - Dart_Timeline_Event_Instant, // Phase = 'i'. - Dart_Timeline_Event_Duration, // Phase = 'X'. - Dart_Timeline_Event_Async_Begin, // Phase = 'b'. - Dart_Timeline_Event_Async_End, // Phase = 'e'. - Dart_Timeline_Event_Async_Instant, // Phase = 'n'. - Dart_Timeline_Event_Counter, // Phase = 'C'. - Dart_Timeline_Event_Flow_Begin, // Phase = 's'. - Dart_Timeline_Event_Flow_Step, // Phase = 't'. - Dart_Timeline_Event_Flow_End, // Phase = 'f'. -} Dart_Timeline_Event_Type; - -/** - * Add a timeline event to the embedder stream. - * - * Note regarding flow events: events must be associated with flow IDs in two - * different ways to allow flow events to be serialized correctly in both - * Chrome's JSON trace event format and Perfetto's proto trace format. Events - * of type |Dart_Timeline_Event_Flow_Begin|, |Dart_Timeline_Event_Flow_Step|, - * and |Dart_Timeline_Event_Flow_End| must be reported to support serialization - * in Chrome's trace format. The |flow_ids| argument must be supplied when - * reporting events of type |Dart_Timeline_Event_Begin|, - * |Dart_Timeline_Event_Duration|, |Dart_Timeline_Event_Instant|, - * |Dart_Timeline_Event_Async_Begin|, and |Dart_Timeline_Event_Async_Instant| to - * support serialization in Perfetto's proto format. - * - * The Dart VM can use various underlying recorders depending on configuration - * and operating system. Many recorders do not support all event types; - * unsupported event types are siliently dropped. Some recorders do not accept - * timestamps as input, instead implicitly using the time the event is recorded. - * For maximum compatibility, record events with the Begin and End types as they - * occur instead of using the Duration type or buffering. - * - * \param label The name of the event. Its lifetime must extend at least until - * Dart_Cleanup. - * \param timestamp0 The first timestamp of the event. - * \param timestamp1_or_id When reporting an event of type - * |Dart_Timeline_Event_Duration|, the second (end) timestamp of the event - * should be passed through |timestamp1_or_id|. When reporting an event of - * type |Dart_Timeline_Event_Async_Begin|, |Dart_Timeline_Event_Async_End|, - * or |Dart_Timeline_Event_Async_Instant|, the async ID associated with the - * event should be passed through |timestamp1_or_id|. When reporting an - * event of type |Dart_Timeline_Event_Flow_Begin|, - * |Dart_Timeline_Event_Flow_Step|, or |Dart_Timeline_Event_Flow_End|, the - * flow ID associated with the event should be passed through - * |timestamp1_or_id|. When reporting an event of type - * |Dart_Timeline_Event_Begin| or |Dart_Timeline_Event_End|, the event ID - * associated with the event should be passed through |timestamp1_or_id|. - * Note that this event ID will only be used by the MacOS recorder. The - * argument to |timestamp1_or_id| will not be used when reporting events of - * other types. - * \param flow_id_count The number of flow IDs associated with this event. - * \param flow_ids An array of flow IDs associated with this event. The array - * may be reclaimed when this call returns. - * \param argument_count The number of argument names and values. - * \param argument_names An array of names of the arguments. The lifetime of the - * names must extend at least until Dart_Cleanup. The array may be reclaimed - * when this call returns. - * \param argument_values An array of values of the arguments. The values and - * the array may be reclaimed when this call returns. - */ -DART_EXPORT void Dart_RecordTimelineEvent(const char* label, - int64_t timestamp0, - int64_t timestamp1_or_id, - intptr_t flow_id_count, - const int64_t* flow_ids, - Dart_Timeline_Event_Type type, - intptr_t argument_count, - const char** argument_names, - const char** argument_values); - -/** - * Associates a name with the current thread. This name will be used to name - * threads in the timeline. Can only be called after a call to Dart_Initialize. - * - * \param name The name of the thread. - */ -DART_EXPORT void Dart_SetThreadName(const char* name); - -typedef struct { - const char* name; - const char* value; -} Dart_TimelineRecorderEvent_Argument; - -#define DART_TIMELINE_RECORDER_CURRENT_VERSION (0x00000002) - -typedef struct { - /* Set to DART_TIMELINE_RECORDER_CURRENT_VERSION */ - int32_t version; - - /* The event's type / phase. */ - Dart_Timeline_Event_Type type; - - /* The event's timestamp according to the same clock as - * Dart_TimelineGetMicros. For a duration event, this is the beginning time. - */ - int64_t timestamp0; - - /** - * For a duration event, this is the end time. For an async event, this is the - * async ID. For a flow event, this is the flow ID. For a begin or end event, - * this is the event ID (which is only referenced by the MacOS recorder). - */ - int64_t timestamp1_or_id; - - /* The current isolate of the event, as if by Dart_GetMainPortId, or - * ILLEGAL_PORT if the event had no current isolate. */ - Dart_Port isolate; - - /* The current isolate group of the event, as if by - * Dart_CurrentIsolateGroupId, or ILLEGAL_PORT if the event had no current - * isolate group. */ - Dart_IsolateGroupId isolate_group; - - /* The callback data associated with the isolate if any. */ - void* isolate_data; - - /* The callback data associated with the isolate group if any. */ - void* isolate_group_data; - - /* The name / label of the event. */ - const char* label; - - /* The stream / category of the event. */ - const char* stream; - - intptr_t argument_count; - Dart_TimelineRecorderEvent_Argument* arguments; -} Dart_TimelineRecorderEvent; - -/** - * Callback provided by the embedder to handle the completion of timeline - * events. - * - * \param event A timeline event that has just been completed. The VM keeps - * ownership of the event and any field in it (i.e., the embedder should copy - * any values it needs after the callback returns). - */ -typedef void (*Dart_TimelineRecorderCallback)( - Dart_TimelineRecorderEvent* event); - -/** - * Register a `Dart_TimelineRecorderCallback` to be called as timeline events - * are completed. - * - * The callback will be invoked without a current isolate. - * - * The callback will be invoked on the thread completing the event. Because - * `Dart_RecordTimelineEvent` may be called by any thread, the callback may be - * called on any thread. - * - * The callback may be invoked at any time after `Dart_Initialize` is called and - * before `Dart_Cleanup` returns. - * - * If multiple callbacks are registered, only the last callback registered - * will be remembered. Providing a NULL callback will clear the registration - * (i.e., a NULL callback produced a no-op instead of a crash). - * - * Setting a callback is insufficient to receive events through the callback. The - * VM flag `timeline_recorder` must also be set to `callback`. - */ -DART_EXPORT void Dart_SetTimelineRecorderCallback( - Dart_TimelineRecorderCallback callback); - -/* - * ======= - * Metrics - * ======= - */ - -/** - * Return metrics gathered for the VM and individual isolates. - */ -DART_EXPORT int64_t -Dart_IsolateGroupHeapOldUsedMetric(Dart_IsolateGroup group); // Byte -DART_EXPORT int64_t -Dart_IsolateGroupHeapOldCapacityMetric(Dart_IsolateGroup group); // Byte -DART_EXPORT int64_t -Dart_IsolateGroupHeapOldExternalMetric(Dart_IsolateGroup group); // Byte -DART_EXPORT int64_t -Dart_IsolateGroupHeapNewUsedMetric(Dart_IsolateGroup group); // Byte -DART_EXPORT int64_t -Dart_IsolateGroupHeapNewCapacityMetric(Dart_IsolateGroup group); // Byte -DART_EXPORT int64_t -Dart_IsolateGroupHeapNewExternalMetric(Dart_IsolateGroup group); // Byte - -/* - * ======== - * UserTags - * ======== - */ - -/* - * Gets the current isolate's currently set UserTag instance. - * - * \return The currently set UserTag instance. - */ -DART_EXPORT Dart_Handle Dart_GetCurrentUserTag(); - -/* - * Gets the current isolate's default UserTag instance. - * - * \return The default UserTag with label 'Default' - */ -DART_EXPORT Dart_Handle Dart_GetDefaultUserTag(); - -/* - * Creates a new UserTag instance. - * - * \param label The name of the new UserTag. - * - * \return The newly created UserTag instance or an error handle. - */ -DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label); - -/* - * Updates the current isolate's UserTag to a new value. - * - * \param user_tag The UserTag to be set as the current UserTag. - * - * \return The previously set UserTag instance or an error handle. - */ -DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag); - -/* - * Returns the label of a given UserTag instance. - * - * \param user_tag The UserTag from which the label will be retrieved. - * - * \return The UserTag's label. NULL if the user_tag is invalid. The caller is - * responsible for freeing the returned label. - */ -DART_EXPORT DART_API_WARN_UNUSED_RESULT char* Dart_GetUserTagLabel( - Dart_Handle user_tag); - -/* - * ======= - * Heap Snapshot - * ======= - */ - -/** - * Callback provided by the caller of `Dart_WriteHeapSnapshot` which is - * used to write out chunks of the requested heap snapshot. - * - * \param context An opaque context which was passed to `Dart_WriteHeapSnapshot` - * together with this callback. - * - * \param buffer Pointer to the buffer containing a chunk of the snapshot. - * The callback owns the buffer and needs to `free` it. - * - * \param size Number of bytes in the `buffer` to be written. - * - * \param is_last Set to `true` for the last chunk. The callback will not - * be invoked again after it was invoked once with `is_last` set to `true`. - */ -typedef void (*Dart_HeapSnapshotWriteChunkCallback)(void* context, - uint8_t* buffer, - intptr_t size, - bool is_last); - -/** - * Generate heap snapshot of the current isolate group and stream it into the - * given `callback`. VM would produce snapshot in chunks and send these chunks - * one by one back to the embedder by invoking the provided `callback`. - * - * This API enables embedder to stream snapshot into a file or socket without - * allocating a buffer to hold the whole snapshot in memory. - * - * The isolate group will be paused for the duration of this operation. - * - * \param write Callback used to write chunks of the heap snapshot. - * - * \param context Opaque context which would be passed on each invocation of - * `write` callback. - * - * \returns `nullptr` if the operation is successful otherwise error message. - * Caller owns error message string and needs to `free` it. - */ -DART_EXPORT char* Dart_WriteHeapSnapshot( - Dart_HeapSnapshotWriteChunkCallback write, - void* context); - -#endif // RUNTIME_INCLUDE_DART_TOOLS_API_H_ diff --git a/src/serious_python_bridge/native/dart_api/dart_version.h b/src/serious_python_bridge/native/dart_api/dart_version.h deleted file mode 100644 index 5ca0b683..00000000 --- a/src/serious_python_bridge/native/dart_api/dart_version.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#ifndef RUNTIME_INCLUDE_DART_VERSION_H_ -#define RUNTIME_INCLUDE_DART_VERSION_H_ - -// On breaking changes the major version is increased. -// On backwards compatible changes the minor version is increased. -// The versioning covers the symbols exposed in dart_api_dl.h -#define DART_API_DL_MAJOR_VERSION 2 -#define DART_API_DL_MINOR_VERSION 5 - -#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h b/src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h deleted file mode 100644 index e4a56893..00000000 --- a/src/serious_python_bridge/native/dart_api/internal/dart_api_dl_impl.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#ifndef RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ -#define RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ - -typedef struct { - const char* name; - void (*function)(void); -} DartApiEntry; - -typedef struct { - const int major; - const int minor; - const DartApiEntry* const functions; -} DartApi; - -#endif /* RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ */ /* NOLINT */ diff --git a/src/serious_python_bridge/native/dart_bridge.c b/src/serious_python_bridge/native/dart_bridge.c deleted file mode 100644 index 11f948f3..00000000 --- a/src/serious_python_bridge/native/dart_bridge.c +++ /dev/null @@ -1,102 +0,0 @@ -#define PY_SSIZE_T_CLEAN -// Build against the CPython Limited API so a single compiled .so works across -// all Python 3.12+ minor versions (abi3 stable ABI). Every Py* symbol used -// below is in the Limited API since 3.2 (3.4 for PyGILState_*). -#define Py_LIMITED_API 0x030c0000 -#include -#include -#include -#include "dart_api/dart_api_dl.h" - -#if defined(_WIN32) -#define EXPORT __declspec(dllexport) -#else -#define EXPORT __attribute__((visibility("default"))) -#endif - -// --------------------------------------------------------------------------- -// Core: symbols called from Dart via FFI plus exported helpers the Python-side -// shim (dart_bridge_shim.c) resolves at runtime via dlsym. Compiled into -// libflet_bridge.{so,dll,dylib} by the Flutter plugin build. On Apple -// platforms also compiled into the static archive linked into the -// serious_python framework alongside dart_bridge_shim.c. -// -// The shim NEVER defines its own copy of these symbols — it always looks them -// up at runtime. That keeps Dart's view of `global_enqueue_handler_func` and -// the Python shim's view as a single shared cell on every platform. -// --------------------------------------------------------------------------- - -// Exported (non-static) so dart_bridge_shim.c's set_enqueue_handler_func can -// write to it via dlsym. Initialised to NULL; the shim swaps in a PyObject* -// callable when Python registers a handler. -EXPORT PyObject* dart_bridge_global_enqueue_handler_func = NULL; - -EXPORT intptr_t DartBridge_InitDartApiDL(void* data) { - return Dart_InitializeApiDL(data); -} - -EXPORT void DartBridge_EnqueueMessage(const char* data, size_t len) { - // Drop messages sent before Python has finished Py_Initialize. Acquiring - // the GIL against an uninitialized interpreter triggers a fatal - // PyMUTEX_LOCK failure (the gil->mutex is uninitialized). Dart's retry - // loop will resend until Python is up. - if (!Py_IsInitialized()) { - return; - } - - PyGILState_STATE gstate = PyGILState_Ensure(); - - if (!dart_bridge_global_enqueue_handler_func) { - fprintf(stderr, "[dart_bridge] enqueue handler is not registered\n"); - PyGILState_Release(gstate); - return; - } - - PyObject* arg = PyBytes_FromStringAndSize(data, len); - if (!arg) { - PyErr_Print(); - PyGILState_Release(gstate); - return; - } - - PyObject* result = PyObject_CallFunctionObjArgs( - dart_bridge_global_enqueue_handler_func, arg, NULL); - if (!result) { - PyErr_Print(); - } - - Py_XDECREF(arg); - Py_XDECREF(result); - PyGILState_Release(gstate); -} - -// Exported helper called by the shim's send_bytes(). Keeps the -// Dart_PostCObject_DL invocation in this translation unit so the shim doesn't -// need its own copy of dart_api_dl.c. Returns 0 on success, -1 on failure with -// a Python exception set. -EXPORT int dart_bridge_post_to_dart(int64_t port, const char* buffer, size_t length) { - if (port == 0) { - PyErr_SetString(PyExc_RuntimeError, "Dart port is 0 (invalid)"); - return -1; - } - - // Dart_PostCObject_DL is a function pointer populated by Dart_InitializeApiDL. - // Calling it before init segfaults; surface a clean error instead. - if (Dart_PostCObject_DL == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Dart API DL not initialized (call DartBridge_InitDartApiDL from Dart first)"); - return -1; - } - - Dart_CObject obj; - obj.type = Dart_CObject_kTypedData; - obj.value.as_typed_data.type = Dart_TypedData_kUint8; - obj.value.as_typed_data.length = (int32_t)length; - obj.value.as_typed_data.values = (void*)buffer; - - if (!Dart_PostCObject_DL(port, &obj)) { - PyErr_SetString(PyExc_RuntimeError, "Dart_PostCObject_DL failed"); - return -1; - } - return 0; -} diff --git a/src/serious_python_bridge/native/dart_bridge_shim.c b/src/serious_python_bridge/native/dart_bridge_shim.c deleted file mode 100644 index 8ac720cc..00000000 --- a/src/serious_python_bridge/native/dart_bridge_shim.c +++ /dev/null @@ -1,240 +0,0 @@ -// Python-callable shim for the dart_bridge module. -// -// This file is the *only* source compiled into the dart_bridge wheel built by -// cibuildwheel. It contains no Dart-callable symbols and no copy of the -// shared `dart_bridge_global_enqueue_handler_func` cell — instead it resolves -// the core's exports (defined in dart_bridge.c, linked into libflet_bridge) -// at PyInit time via dlsym/GetProcAddress. That keeps Dart's view and -// Python's view of the global as the SAME cell on Linux/Windows/Android. -// -// On Apple platforms this same file is also static-linked into the -// serious_python framework alongside dart_bridge.c — the runtime lookup -// then resolves to the symbols statically linked into the host binary -// (dlopen of libflet_bridge is skipped because there's no such file). - -#define PY_SSIZE_T_CLEAN -#define Py_LIMITED_API 0x030c0000 -#include -#include -#include - -#include - -#if defined(_WIN32) -#include -#else -#include -#endif - -// Function-pointer + global types resolved at PyInit time. -typedef int (*PostToDartFn)(int64_t port, const char* buffer, size_t length); - -static PyObject** g_handler_slot = NULL; // points at dart_bridge_global_enqueue_handler_func in libflet_bridge -static PostToDartFn g_post_to_dart = NULL; // dart_bridge_post_to_dart in libflet_bridge - -#if defined(_WIN32) -#include - -// Diagnostic log file — Python's stderr is not captured by flutter test on -// Windows, so we tee the shim's progress to a known absolute path the -// workflow can dump after the test fails. We write next to the running -// .exe (runner/Debug/) since GetTempPathA's return value varies depending -// on how the embedded Python's environment is set up. -static void shim_log_path(char* out) { - DWORD n = GetModuleFileNameA(NULL, out, MAX_PATH); - if (n == 0 || n >= MAX_PATH) { out[0] = '\0'; return; } - for (DWORD i = n; i > 0; i--) { - if (out[i - 1] == '\\' || out[i - 1] == '/') { - out[i] = '\0'; - break; - } - } - if (strlen(out) + strlen("dart_bridge_shim.log") + 1 >= MAX_PATH) { - out[0] = '\0'; - return; - } - strcat(out, "dart_bridge_shim.log"); -} - -static void shim_log(const char* fmt, ...) { - char path[MAX_PATH]; - shim_log_path(path); - if (!path[0]) return; - FILE* f = fopen(path, "a"); - if (!f) return; - va_list ap; - va_start(ap, fmt); - vfprintf(f, fmt, ap); - va_end(ap); - fclose(f); -} - -// Marker call so we can detect whether PyInit ran at all (helps distinguish -// "PyInit ran but flet_bridge.dll lookup failed" from "PyInit never ran -// because the .pyd failed to load"). -static void shim_log_init(const char* phase) { - char path[MAX_PATH]; - shim_log_path(path); - if (!path[0]) return; - FILE* f = fopen(path, "a"); - if (!f) return; - fprintf(f, "[shim] === %s ===\n", phase); - fclose(f); -} - -static HMODULE shim_find_flet_bridge_module(void) { - // 1. GetModuleHandleA looks at modules already loaded into the process - // (e.g. by Dart's DynamicLibrary.open). Returns NULL without loading - // anything if not already mapped. - HMODULE flet = GetModuleHandleA("flet_bridge.dll"); - if (flet) { - shim_log("[shim] GetModuleHandleA(flet_bridge.dll) -> %p\n", (void*)flet); - return flet; - } - shim_log("[shim] GetModuleHandleA(flet_bridge.dll) -> NULL (err=%lu)\n", - (unsigned long)GetLastError()); - - // 2. LoadLibraryA with default DLL search. Reaches the calling module's - // directory (dart_bridge.pyd's dir) + system paths + PATH. - flet = LoadLibraryA("flet_bridge.dll"); - if (flet) { - shim_log("[shim] LoadLibraryA(flet_bridge.dll) -> %p\n", (void*)flet); - return flet; - } - shim_log("[shim] LoadLibraryA(flet_bridge.dll) -> NULL (err=%lu)\n", - (unsigned long)GetLastError()); - - // 3. Construct an absolute path next to the running .exe (where Flutter - // places plugin DLLs) and try that. - char exePath[MAX_PATH]; - DWORD len = GetModuleFileNameA(NULL, exePath, MAX_PATH); - if (len == 0 || len >= MAX_PATH) { - shim_log("[shim] GetModuleFileNameA failed (len=%lu)\n", (unsigned long)len); - return NULL; - } - for (DWORD i = len; i > 0; i--) { - if (exePath[i - 1] == '\\' || exePath[i - 1] == '/') { - exePath[i] = '\0'; - break; - } - } - if (strlen(exePath) + strlen("flet_bridge.dll") + 1 >= MAX_PATH) return NULL; - strcat(exePath, "flet_bridge.dll"); - shim_log("[shim] trying absolute path: %s\n", exePath); - flet = LoadLibraryA(exePath); - if (!flet) { - shim_log("[shim] LoadLibraryA(absolute) -> NULL (err=%lu)\n", - (unsigned long)GetLastError()); - } else { - shim_log("[shim] LoadLibraryA(absolute) -> %p\n", (void*)flet); - } - return flet; -} - -static void* shim_sym_lookup(const char* name) { - HMODULE flet = shim_find_flet_bridge_module(); - if (!flet) { - shim_log("[shim] flet_bridge.dll not found anywhere\n"); - return NULL; - } - void* p = (void*)GetProcAddress(flet, name); - if (!p) { - shim_log("[shim] GetProcAddress(%s) -> NULL (err=%lu)\n", name, - (unsigned long)GetLastError()); - } else { - shim_log("[shim] GetProcAddress(%s) -> %p\n", name, p); - } - return p; -} -#else -static void* shim_sym_lookup(const char* name) { - // RTLD_DEFAULT searches every library already loaded into the process - // including ones loaded with RTLD_LOCAL by Dart's DynamicLibrary.open. - void* p = dlsym(RTLD_DEFAULT, name); - if (p) return p; - // Not visible globally (Dart loaded libflet_bridge with RTLD_LOCAL). Try - // an explicit RTLD_GLOBAL dlopen so subsequent lookups see it. dlopen of - // an already-loaded library returns the existing handle — single instance, - // same memory, just promoted into the global namespace. -#if defined(__APPLE__) - void* h = dlopen("libflet_bridge.dylib", RTLD_NOW | RTLD_GLOBAL); -#else - void* h = dlopen("libflet_bridge.so", RTLD_NOW | RTLD_GLOBAL); -#endif - if (!h) return NULL; - return dlsym(h, name); -} -#endif - -static PyObject* set_enqueue_handler_func(PyObject* self, PyObject* args) { - PyObject* func; - - if (!PyArg_ParseTuple(args, "O:set_enqueue_handler_func", &func)) { - return NULL; - } - if (!PyCallable_Check(func)) { - PyErr_SetString(PyExc_TypeError, "parameter must be callable"); - return NULL; - } - if (!g_handler_slot) { - PyErr_SetString(PyExc_RuntimeError, - "dart_bridge: libflet_bridge symbol not resolved (was the bridge plugin loaded?)"); - return NULL; - } - - Py_XINCREF(func); - Py_XDECREF(*g_handler_slot); - *g_handler_slot = func; - - Py_RETURN_NONE; -} - -static PyObject* send_bytes(PyObject* self, PyObject* args) { - int64_t port; - const char* buffer; - Py_ssize_t length; - - if (!PyArg_ParseTuple(args, "Ly#", &port, &buffer, &length)) { - return NULL; - } - if (!g_post_to_dart) { - PyErr_SetString(PyExc_RuntimeError, - "dart_bridge: libflet_bridge symbol not resolved (was the bridge plugin loaded?)"); - return NULL; - } - if (g_post_to_dart(port, buffer, (size_t)length) != 0) { - // Helper sets the exception. - return NULL; - } - Py_RETURN_TRUE; -} - -static PyMethodDef methods[] = { - {"send_bytes", send_bytes, METH_VARARGS, "Post a bytes payload to a Dart ReceivePort."}, - {"set_enqueue_handler_func", set_enqueue_handler_func, METH_VARARGS, - "Register the Python callable that receives bytes posted from Dart."}, - {NULL, NULL, 0, NULL} -}; - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "dart_bridge", NULL, -1, methods -}; - -PyMODINIT_FUNC PyInit_dart_bridge(void) { -#if defined(_WIN32) - shim_log_init("PyInit_dart_bridge entered"); -#endif - // Resolve the libflet_bridge exports we depend on. Surface a clean - // ImportError if the lookup fails — typically means the bridge plugin's - // native library wasn't loaded into the process before Python ran. - g_handler_slot = (PyObject**)shim_sym_lookup("dart_bridge_global_enqueue_handler_func"); - g_post_to_dart = (PostToDartFn)shim_sym_lookup("dart_bridge_post_to_dart"); - if (!g_handler_slot || !g_post_to_dart) { - PyErr_SetString(PyExc_ImportError, - "dart_bridge: failed to resolve libflet_bridge symbols " - "(is serious_python_bridge's native library loaded into the process?)"); - return NULL; - } - return PyModule_Create(&moduledef); -} diff --git a/src/serious_python_bridge/pubspec.yaml b/src/serious_python_bridge/pubspec.yaml deleted file mode 100644 index a32faff1..00000000 --- a/src/serious_python_bridge/pubspec.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: serious_python_bridge -description: Generic in-process Dart ↔ Python byte transport for the embedded Python runtime provided by serious_python. -homepage: https://flet.dev -repository: https://github.com/flet-dev/serious-python -version: 2.0.0 - -environment: - sdk: ">=3.0.0 <4.0.0" - flutter: ">=3.7.0" - -dependencies: - flutter: - sdk: flutter - ffi: ^2.1.0 - serious_python: - path: ../serious_python - serious_python_darwin: - path: ../serious_python_darwin - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^2.0.0 - -flutter: - plugin: - platforms: - android: - ffiPlugin: true - ios: - pluginClass: SeriousPythonBridgePlugin - ffiPlugin: true - sharedDarwinSource: true - macos: - pluginClass: SeriousPythonBridgePlugin - ffiPlugin: true - sharedDarwinSource: true - linux: - ffiPlugin: true - windows: - ffiPlugin: true diff --git a/src/serious_python_bridge/python/MANIFEST.in b/src/serious_python_bridge/python/MANIFEST.in deleted file mode 100644 index 4ff3dbf2..00000000 --- a/src/serious_python_bridge/python/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include ../native/dart_bridge.c -include ../native/dart_api/*.h -include ../native/dart_api/*.c -include ../native/dart_api/internal/*.h diff --git a/src/serious_python_bridge/python/pyproject.toml b/src/serious_python_bridge/python/pyproject.toml deleted file mode 100644 index 75109542..00000000 --- a/src/serious_python_bridge/python/pyproject.toml +++ /dev/null @@ -1,36 +0,0 @@ -[build-system] -requires = ["setuptools>=61.0.0", "wheel"] -build-backend = "setuptools.build_meta" - -[project] -name = "dart_bridge" -version = "0.0.0" -description = "Python C extension exposing the dart_bridge module — bidirectional Dart ↔ Python byte transport for serious_python_bridge." -authors = [ - { name = "Flet Team", email = "hello@flet.dev" }, -] -requires-python = ">=3.12" -classifiers = [ - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Programming Language :: C", - "Operating System :: POSIX", - "Operating System :: MacOS", - "Operating System :: Microsoft :: Windows", - "Topic :: Software Development :: Libraries :: Python Modules", -] -keywords = ["dart", "ffi", "bridge", "serious_python", "flet"] - -[project.urls] -Homepage = "https://github.com/flet-dev/serious-python" -Issues = "https://github.com/flet-dev/serious-python/issues" - -[tool.cibuildwheel] -# Limited API / abi3: a single wheel built against Python 3.12's stable ABI -# loads on any Python 3.12+ minor version, so we only need cp312-* here. -build = "cp312-*" -# Flet targets only 64-bit desktop, so skip 32-bit (i686 / win32). Also skip -# PyPy and musllinux (alternative libc, not what python-build-standalone uses). -skip = ["pp*", "*-musllinux_*", "*_i686", "*-win32"] diff --git a/src/serious_python_bridge/python/setup.cfg b/src/serious_python_bridge/python/setup.cfg deleted file mode 100644 index 12a1329c..00000000 --- a/src/serious_python_bridge/python/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[bdist_wheel] -# Tag the produced wheel as abi3 so pip / package_command.dart install it on -# any Python 3.12+ minor version. Keep in lockstep with Py_LIMITED_API in -# dart_bridge.c and the py_limited_api flag in setup.py. -py_limited_api = cp312 diff --git a/src/serious_python_bridge/python/setup.py b/src/serious_python_bridge/python/setup.py deleted file mode 100644 index 623eddea..00000000 --- a/src/serious_python_bridge/python/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys -from setuptools import Extension, setup - -NATIVE_ROOT = "../native" - -extra_link_args = [] -# dlopen/dlsym on Linux live in libdl. macOS rolls them into libSystem. -# Windows uses LoadLibrary/GetProcAddress from kernel32 (implicit). -if sys.platform.startswith("linux"): - extra_link_args.append("-ldl") - -setup( - ext_modules=[ - Extension( - "dart_bridge", - # Shim only — the Dart-callable core and its dart_api_dl.c live in - # libflet_bridge (built by the Flutter plugin) and are resolved at - # PyInit time via dlsym / GetProcAddress. - sources=[f"{NATIVE_ROOT}/dart_bridge_shim.c"], - # Limited API / abi3: one .so per platform works for any Python - # 3.12+. Keep this in lockstep with Py_LIMITED_API in - # dart_bridge_shim.c. - define_macros=[("Py_LIMITED_API", "0x030c0000")], - py_limited_api=True, - extra_link_args=extra_link_args, - ) - ], -) diff --git a/src/serious_python_bridge/windows/CMakeLists.txt b/src/serious_python_bridge/windows/CMakeLists.txt deleted file mode 100644 index 68badac2..00000000 --- a/src/serious_python_bridge/windows/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -cmake_minimum_required(VERSION 3.15) - -set(PROJECT_NAME "serious_python_bridge") -project(${PROJECT_NAME} LANGUAGES C) - -cmake_policy(VERSION 3.15...3.25) - -# flet_bridge.dll's import table must reference python3.dll in Release Flutter -# builds and python3_d.dll in Debug builds — to match the python(_d).dll -# bundled by serious_python_windows. find_package(Python3) only points at the -# system Python's libs/ folder, which typically lacks python_d.lib, so -# Debug builds would fail to link (the auto-link pragma in pyconfig.h asks for -# python_d.lib). Download the same python-windows-for-dart tarball that -# serious_python_windows uses — it ships both Release and Debug abi3 stubs -# (libs/python3.lib + libs/python3_d.lib) plus Debug-variant pythonXY_d.lib. -if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) - set(PYTHON_VERSION "$ENV{SERIOUS_PYTHON_VERSION}") -else() - set(PYTHON_VERSION "3.14") -endif() -set(PYTHON_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/python_dist") -set(PYTHON_ZIP "${CMAKE_BINARY_DIR}/python-windows-for-dart-${PYTHON_VERSION}.zip") -if(NOT EXISTS "${PYTHON_DOWNLOAD_DIR}/include/Python.h") - if(NOT EXISTS "${PYTHON_ZIP}") - file(DOWNLOAD - "https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-windows-for-dart-${PYTHON_VERSION}.zip" - "${PYTHON_ZIP}") - endif() - file(MAKE_DIRECTORY "${PYTHON_DOWNLOAD_DIR}") - file(ARCHIVE_EXTRACT INPUT "${PYTHON_ZIP}" - DESTINATION "${PYTHON_DOWNLOAD_DIR}") -endif() - -set(FLET_BRIDGE_PYTHON_INCLUDE_DIRS "${PYTHON_DOWNLOAD_DIR}/include") -# Pick Debug abi3 stub (python3_d.lib) when Flutter is building Debug, Release -# stub (python3.lib) otherwise. The corresponding python3(_d).dll is bundled -# by serious_python_windows. -set(FLET_BRIDGE_PYTHON_LIBRARIES - "${PYTHON_DOWNLOAD_DIR}/libs/python3$<$:_d>.lib" -) - -add_subdirectory("../native" "${CMAKE_CURRENT_BINARY_DIR}/shared") - -# Make python-windows-for-dart's libs/ visible to MSVC's auto-link. pyconfig.h -# emits `#pragma comment(lib, "pythonXY(_d).lib")` and MSVC's default LIB path -# wouldn't find the file otherwise. The tarball ships pythonXY.lib AND -# pythonXY_d.lib for every version, so both Debug and Release auto-link -# resolve. (We pass /NODEFAULTLIB in native/CMakeLists for the cibuildwheel -# setup.py build path, but here the request can be satisfied properly so we -# let it through.) -target_link_directories(flet_bridge PRIVATE "${PYTHON_DOWNLOAD_DIR}/libs") - -# Flutter picks up bundled libraries via this variable and copies the file -# alongside the app binary; Dart resolves it via DynamicLibrary.open. -# -# The bridge plugin only ships flet_bridge.dll. python3.dll / python3_d.dll -# (the abi3 stable-ABI loader that dart_bridge.pyd imports) is bundled by -# serious_python_windows, which already chooses the correct Debug/Release -# variant matching Flutter's build config. -set(serious_python_bridge_bundled_libraries - $ - PARENT_SCOPE -) From 11333b5a5fc4872c7b505f2f677193fe2a0db714 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:06:42 -0700 Subject: [PATCH 057/114] =?UTF-8?q?flet=5Fexample:=20bump=20flet=20^0.28.3?= =?UTF-8?q?=20=E2=86=92=20^0.85.3=20+=20rename=20version=20=E2=86=92=20fle?= =?UTF-8?q?t=5Fversion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/serious_python/example/flet_example/app/src/main.py | 5 ++--- src/serious_python/example/flet_example/pubspec.yaml | 7 +------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/serious_python/example/flet_example/app/src/main.py b/src/serious_python/example/flet_example/app/src/main.py index 2d4eec94..57069c80 100644 --- a/src/serious_python/example/flet_example/app/src/main.py +++ b/src/serious_python/example/flet_example/app/src/main.py @@ -1,10 +1,9 @@ -import logging import os import sys import urllib.request import flet as ft -from flet.version import version +from flet.version import flet_version # logging.basicConfig(level=logging.DEBUG) @@ -60,7 +59,7 @@ def check_ssl(e): ), ft.Row( [ - ft.Text(f"Flet version: {version}"), + ft.Text(f"Flet version: {flet_version}"), ft.OutlinedButton("Check SSL", on_click=check_ssl), ft.OutlinedButton("Exit app", on_click=lambda _: sys.exit(100)), ], diff --git a/src/serious_python/example/flet_example/pubspec.yaml b/src/serious_python/example/flet_example/pubspec.yaml index 31425e65..bb065dc8 100644 --- a/src/serious_python/example/flet_example/pubspec.yaml +++ b/src/serious_python/example/flet_example/pubspec.yaml @@ -35,12 +35,7 @@ dependencies: serious_python: path: ../../ - flet: ^0.28.3 - - path: ^1.8.3 - url_strategy: ^0.2.0 - path_provider: ^2.1.4 - package_info_plus: ^8.0.2 + flet: ^0.85.3 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. From 4bb8dd6e0ec0a84a9e85348a53ae47eb114024d2 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:16:19 -0700 Subject: [PATCH 058/114] flet_example: align with flet 0.85.x API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - macos/ios runners moved to macos-26 (latest tag is being reclaimed by GitHub; pin explicitly across all four macOS jobs). - pubspec adds flutter_web_plugins (for usePathUrlStrategy), restores path/path_provider/package_info_plus explicit deps. - main.dart: setPathUrlStrategy() → usePathUrlStrategy() (renamed in flutter_web_plugins; url_strategy package is no longer needed). - pubspec.lock churn in flask_example / run_example from `flutter pub get` running over the workspace. --- .github/workflows/ci.yml | 8 ++++---- .../example/flask_example/pubspec.lock | 12 ++++++------ .../example/flet_example/lib/main.dart | 4 ++-- src/serious_python/example/flet_example/pubspec.yaml | 8 +++++++- src/serious_python/example/run_example/pubspec.lock | 12 ++++++------ 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad53f10e..dc212054 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ env: jobs: macos: name: Test on macOS (Python ${{ matrix.python_version }}) - runs-on: macos-latest + runs-on: macos-26 strategy: fail-fast: false matrix: @@ -41,7 +41,7 @@ jobs: ios: name: Test on iOS (Python ${{ matrix.python_version }}) - runs-on: macos-latest + runs-on: macos-26 strategy: fail-fast: false matrix: @@ -236,7 +236,7 @@ jobs: bridge_example_macos: name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) - runs-on: macos-latest + runs-on: macos-26 strategy: fail-fast: false matrix: @@ -261,7 +261,7 @@ jobs: bridge_example_ios: name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) - runs-on: macos-latest + runs-on: macos-26 timeout-minutes: 25 strategy: fail-fast: false diff --git a/src/serious_python/example/flask_example/pubspec.lock b/src/serious_python/example/flask_example/pubspec.lock index 00d534ce..4f7e8f44 100644 --- a/src/serious_python/example/flask_example/pubspec.lock +++ b/src/serious_python/example/flask_example/pubspec.lock @@ -289,42 +289,42 @@ packages: path: "../.." relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "1.0.1" + version: "2.0.0" shelf: dependency: transitive description: diff --git a/src/serious_python/example/flet_example/lib/main.dart b/src/serious_python/example/flet_example/lib/main.dart index 547bfe22..b89ce87f 100644 --- a/src/serious_python/example/flet_example/lib/main.dart +++ b/src/serious_python/example/flet_example/lib/main.dart @@ -5,11 +5,11 @@ import 'package:flet/flet.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_web_plugins/url_strategy.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart' as path_provider; import 'package:serious_python/serious_python.dart'; -import 'package:url_strategy/url_strategy.dart'; const bool isProduction = bool.fromEnvironment('dart.vm.product'); @@ -129,7 +129,7 @@ Future prepareApp() async { pageUrl = Uri.base.toString(); var routeUrlStrategy = getFletRouteUrlStrategy(); if (routeUrlStrategy == "path") { - setPathUrlStrategy(); + usePathUrlStrategy(); } } else { await setupDesktop(); diff --git a/src/serious_python/example/flet_example/pubspec.yaml b/src/serious_python/example/flet_example/pubspec.yaml index bb065dc8..3aef736a 100644 --- a/src/serious_python/example/flet_example/pubspec.yaml +++ b/src/serious_python/example/flet_example/pubspec.yaml @@ -31,11 +31,17 @@ environment: dependencies: flutter: sdk: flutter - + flutter_web_plugins: + sdk: flutter + serious_python: path: ../../ flet: ^0.85.3 + + path: ^1.8.3 + path_provider: ^2.1.4 + package_info_plus: ^8.0.2 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/src/serious_python/example/run_example/pubspec.lock b/src/serious_python/example/run_example/pubspec.lock index 99555a02..7cd1c7e3 100644 --- a/src/serious_python/example/run_example/pubspec.lock +++ b/src/serious_python/example/run_example/pubspec.lock @@ -312,42 +312,42 @@ packages: path: "../.." relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "1.0.1" + version: "2.0.0" shelf: dependency: transitive description: From a7594bcb9ad5bc6f0d7003a33d592533f9e6a25b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:19:24 -0700 Subject: [PATCH 059/114] flet_example: bump package_info_plus to ^9.0.0 + regenerate plugin registrants --- .../flutter/generated_plugin_registrant.cc | 4 + .../linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 12 + .../example/flet_example/pubspec.lock | 412 +++++++++++++----- .../example/flet_example/pubspec.yaml | 4 +- .../flutter/generated_plugin_registrant.cc | 15 + .../windows/flutter/generated_plugins.cmake | 5 + 7 files changed, 345 insertions(+), 108 deletions(-) diff --git a/src/serious_python/example/flet_example/linux/flutter/generated_plugin_registrant.cc b/src/serious_python/example/flet_example/linux/flutter/generated_plugin_registrant.cc index b07cb4d1..142e738c 100644 --- a/src/serious_python/example/flet_example/linux/flutter/generated_plugin_registrant.cc +++ b/src/serious_python/example/flet_example/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -13,6 +14,9 @@ #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) pasteboard_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); + pasteboard_plugin_register_with_registrar(pasteboard_registrar); g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); diff --git a/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake index 5524b2d4..d94f7552 100644 --- a/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake +++ b/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + pasteboard screen_retriever_linux serious_python_linux url_launcher_linux diff --git a/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift index b65df49c..8ab11fa1 100644 --- a/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,26 +5,38 @@ import FlutterMacOS import Foundation +import battery_plus +import connectivity_plus import device_info_plus import file_picker import package_info_plus +import pasteboard import path_provider_foundation +import screen_brightness_macos import screen_retriever_macos import serious_python_darwin +import share_plus import shared_preferences_foundation import url_launcher_macos +import wakelock_plus import window_manager import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin")) + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) } diff --git a/src/serious_python/example/flet_example/pubspec.lock b/src/serious_python/example/flet_example/pubspec.lock index fd7dd747..ad761054 100644 --- a/src/serious_python/example/flet_example/pubspec.lock +++ b/src/serious_python/example/flet_example/pubspec.lock @@ -25,6 +25,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.12.0" + battery_plus: + dependency: transitive + description: + name: battery_plus + sha256: ad16fcb55b7384be6b4bbc763d5e2031ac7ea62b2d9b6b661490c7b9741155bf + url: "https://pub.dev" + source: hosted + version: "7.0.0" + battery_plus_platform_interface: + dependency: transitive + description: + name: battery_plus_platform_interface + sha256: e8342c0f32de4b1dfd0223114b6785e48e579bfc398da9471c9179b907fa4910 + url: "https://pub.dev" + source: hosted + version: "2.0.1" boolean_selector: dependency: transitive description: @@ -37,10 +53,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" clock: dependency: transitive description: @@ -57,6 +73,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: "62ffa266d9a23b79fb3fcbc206afc00bb979417ba57b1324c546b5aab95ba057" + url: "https://pub.dev" + source: hosted + version: "7.1.1" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "3c09627c536d22fd24691a905cdd8b14520de69da52c7a97499c8be5284a32ed" + url: "https://pub.dev" + source: hosted + version: "2.1.0" cross_file: dependency: transitive description: @@ -93,18 +125,18 @@ packages: dependency: transitive description: name: device_info_plus - sha256: "72d146c6d7098689ff5c5f66bcf593ac11efc530095385356e131070333e64da" + sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd url: "https://pub.dev" source: hosted - version: "11.3.0" + version: "12.4.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f url: "https://pub.dev" source: hosted - version: "7.0.2" + version: "7.0.3" equatable: dependency: transitive description: @@ -117,18 +149,18 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.0" file: dependency: transitive description: @@ -141,26 +173,26 @@ packages: dependency: transitive description: name: file_picker - sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22 + sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343" url: "https://pub.dev" source: hosted - version: "10.3.2" - fl_chart: + version: "10.3.10" + fixnum: dependency: transitive description: - name: fl_chart - sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08" + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "0.69.2" + version: "1.1.1" flet: dependency: "direct main" description: name: flet - sha256: "3be85b7d2e70e00d957966a7bcec2b290057d440b7aafd795a197a39ab3783cf" + sha256: "295d34600580bc00576ea2a0a3ab3f92062ca487e010e3bf0ee20d41cc5c262d" url: "https://pub.dev" source: hosted - version: "0.28.3" + version: "0.85.3" flutter: dependency: "direct main" description: flutter @@ -192,45 +224,53 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_markdown: + flutter_markdown_plus: dependency: transitive description: - name: flutter_markdown - sha256: f0e599ba89c9946c8e051780f0ec99aba4ba15895e0380a7ab68f420046fc44e + name: flutter_markdown_plus + sha256: "039177906850278e8fb1cd364115ee0a46281135932fa8ecea8455522166d2de" url: "https://pub.dev" source: hosted - version: "0.7.4+1" - flutter_plugin_android_lifecycle: + version: "1.0.7" + flutter_markdown_plus_latex: dependency: transitive description: - name: flutter_plugin_android_lifecycle - sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" + name: flutter_markdown_plus_latex + sha256: "2e7698b291f0657ca445efab730bb25a8c5851037e882cb7bf47d16a5c218de7" url: "https://pub.dev" source: hosted - version: "2.0.22" - flutter_redux: + version: "1.0.5" + flutter_math_fork: dependency: transitive description: - name: flutter_redux - sha256: "3b20be9e08d0038e1452fbfa1fdb1ea0a7c3738c997734530b3c6d0bb5fcdbdc" + name: flutter_math_fork + sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407" url: "https://pub.dev" source: hosted - version: "0.10.0" + version: "0.7.4" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" + url: "https://pub.dev" + source: hosted + version: "2.0.22" flutter_svg: dependency: transitive description: name: flutter_svg - sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.3.0" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: - dependency: transitive + dependency: "direct main" description: flutter source: sdk version: "0.0.0" @@ -259,10 +299,10 @@ packages: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.6.0" http_parser: dependency: transitive description: @@ -280,18 +320,10 @@ packages: dependency: transitive description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" + version: "0.20.2" json_annotation: dependency: transitive description: @@ -304,26 +336,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -344,50 +376,90 @@ packages: dependency: transitive description: name: markdown - sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "7.3.1" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + msgpack_dart: + dependency: transitive + description: + name: msgpack_dart + sha256: c2d235ed01f364719b5296aecf43ac330f0d7bc865fa134d0d7910a40454dffb + url: "https://pub.dev" + source: hosted + version: "1.0.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "0.5.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918 + sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20" url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "9.0.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.2.1" + pasteboard: + dependency: transitive + description: + name: pasteboard + sha256: "9ff73ada33f79a59ff91f6c01881fd4ed0a0031cfc4ae2d86c0384471525fca1" + url: "https://pub.dev" + source: hosted + version: "0.4.0" path: dependency: "direct main" description: @@ -408,10 +480,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: @@ -492,14 +564,70 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.3" - redux: + provider: + dependency: transitive + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + screen_brightness: + dependency: transitive + description: + name: screen_brightness + sha256: "7ea1c037422f007f022dcff3ee955bf8e61a474d5426b29be9290fd976c3e46b" + url: "https://pub.dev" + source: hosted + version: "2.1.9" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "0e4b0a07d5f730b91a8780d8436f3a92be8a8cc2066032ed88b93c8fa153fadf" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: "0792d8f98852558f831b4b75241c46047b884598b3f4d982b37dc2dd43e2b2e1" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "278712cf5288db57bd335968cbfb2ec5441028f1ee2fcbdc8d1582d8210a3442" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + screen_brightness_ohos: + dependency: transitive + description: + name: screen_brightness_ohos + sha256: "33f495741d5aa53104d3f5875dcb4b6a119f29ef595be17129ee03a5b78e76a9" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: "59d50850d6735d677780fc7359c8e997d0ff6df91c8465161c9e617a7b0a11d8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + screen_brightness_windows: dependency: transitive description: - name: redux - sha256: "1e86ed5b1a9a717922d0a0ca41f9bf49c1a587d50050e9426fc65b14e85ec4d7" + name: screen_brightness_windows + sha256: "121f9dd6d62585bfb4e468c2170804ce4f2a2303ae6b2efc3a065c94937505d7" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "2.1.1" screen_retriever: dependency: transitive description: @@ -540,80 +668,104 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + screenshot: + dependency: transitive + description: + name: screenshot + sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sensors_plus: dependency: transitive description: name: sensors_plus - sha256: "8e7fa79b4940442bb595bfc0ee9da4af5a22a0fe6ebacc74998245ee9496a82d" + sha256: "56e8cd4260d9ed8e00ecd8da5d9fdc8a1b2ec12345a750dfa51ff83fcf12e3fa" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "7.0.0" sensors_plus_platform_interface: dependency: transitive description: name: sensors_plus_platform_interface - sha256: bc472d6cfd622acb4f020e726433ee31788b038056691ba433fec80e448a094f + sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.0.1" serious_python: dependency: "direct main" description: path: "../.." relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "1.0.1" + version: "2.0.0" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "1.0.1" + version: "2.0.0" + share_plus: + dependency: transitive + description: + name: share_plus + sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa" + url: "https://pub.dev" + source: hosted + version: "12.0.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + url: "https://pub.dev" + source: hosted + version: "6.1.0" shared_preferences: dependency: transitive description: name: shared_preferences - sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.23" shared_preferences_foundation: dependency: transitive description: @@ -662,6 +814,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + shimmer: + dependency: transitive + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -719,10 +879,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.10" toml: dependency: transitive description: @@ -731,6 +891,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.0" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: @@ -739,14 +907,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + upower: + dependency: transitive + description: + name: upower + sha256: cf042403154751180affa1d15614db7fa50234bc2373cd21c3db666c38543ebf + url: "https://pub.dev" + source: hosted + version: "0.7.0" url_launcher: dependency: transitive description: name: url_launcher - sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_android: dependency: transitive description: @@ -803,22 +979,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" - url_strategy: - dependency: "direct main" + uuid: + dependency: transitive description: - name: url_strategy - sha256: "42b68b42a9864c4d710401add17ad06e28f1c1d5500c93b98c431f6b0ea4ab87" + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "4.5.3" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" + sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d" url: "https://pub.dev" source: hosted - version: "1.1.18" + version: "1.2.2" vector_graphics_codec: dependency: transitive description: @@ -839,10 +1015,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -851,22 +1027,46 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.1" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b + url: "https://pub.dev" + source: hosted + version: "1.5.1" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "3.0.3" webdriver: dependency: transitive description: @@ -887,18 +1087,18 @@ packages: dependency: transitive description: name: win32_registry - sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" url: "https://pub.dev" source: hosted - version: "1.1.5" + version: "2.1.0" window_manager: dependency: transitive description: name: window_manager - sha256: "732896e1416297c63c9e3fb95aea72d0355f61390263982a47fd519169dc5059" + sha256: "7eb6d6c4164ec08e1bf978d6e733f3cebe792e2a23fb07cbca25c2872bfdbdcd" url: "https://pub.dev" source: hosted - version: "0.4.3" + version: "0.5.1" window_to_front: dependency: transitive description: @@ -924,5 +1124,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.7.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.10.0 <4.0.0" + flutter: ">=3.38.0" diff --git a/src/serious_python/example/flet_example/pubspec.yaml b/src/serious_python/example/flet_example/pubspec.yaml index 3aef736a..87d8865c 100644 --- a/src/serious_python/example/flet_example/pubspec.yaml +++ b/src/serious_python/example/flet_example/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - + serious_python: path: ../../ @@ -41,7 +41,7 @@ dependencies: path: ^1.8.3 path_provider: ^2.1.4 - package_info_plus: ^8.0.2 + package_info_plus: ^9.0.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/src/serious_python/example/flet_example/windows/flutter/generated_plugin_registrant.cc b/src/serious_python/example/flet_example/windows/flutter/generated_plugin_registrant.cc index 3ed709b3..5280993c 100644 --- a/src/serious_python/example/flet_example/windows/flutter/generated_plugin_registrant.cc +++ b/src/serious_python/example/flet_example/windows/flutter/generated_plugin_registrant.cc @@ -6,17 +6,32 @@ #include "generated_plugin_registrant.h" +#include +#include +#include +#include #include #include +#include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + BatteryPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + PasteboardPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PasteboardPlugin")); + ScreenBrightnessWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); SeriousPythonWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SeriousPythonWindowsPluginCApi")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowManagerPluginRegisterWithRegistrar( diff --git a/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake index 571b9237..a1fa5aad 100644 --- a/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake +++ b/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake @@ -3,8 +3,13 @@ # list(APPEND FLUTTER_PLUGIN_LIST + battery_plus + connectivity_plus + pasteboard + screen_brightness_windows screen_retriever_windows serious_python_windows + share_plus url_launcher_windows window_manager window_to_front From 1059ad1eb0ab006626c63b89cf89d2a7f54ee672 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:29:16 -0700 Subject: [PATCH 060/114] =?UTF-8?q?ci:=20bump=20--requirements=20flet=20pi?= =?UTF-8?q?n=200.28.3=20=E2=86=92=200.85.3=20(match=20Dart=20side)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc212054..df338f69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} ios: @@ -72,7 +72,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} android: @@ -131,7 +131,7 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 + cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 cd src/serious_python/example/flet_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} windows: @@ -156,7 +156,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} linux: @@ -231,7 +231,7 @@ jobs: working-directory: src/serious_python/example/flet_example run: | flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: From 5c6bd9e2d956aebe668aada0892dee8f05373e2a Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:30:07 -0700 Subject: [PATCH 061/114] =?UTF-8?q?ci:=20iOS=20simulator=20os=5Fversion=20?= =?UTF-8?q?=E2=86=92=20'latest'=20(macos-26=20no=20longer=20has=20iOS=2018?= =?UTF-8?q?.6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df338f69..427d967d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: # https://github.com/futureware-tech/simulator-action/wiki/Devices-macos-latest model: 'iPhone 16 Pro Max' os: "iOS" - os_version: "^18.6" + os_version: "latest" shutdown_after_job: true wait_for_boot: true @@ -295,7 +295,7 @@ jobs: with: model: 'iPhone 16 Pro Max' os: "iOS" - os_version: "^18.6" + os_version: "latest" shutdown_after_job: true wait_for_boot: true From ec963aa62187576235eb6e4631ad2aca41eba22d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 14:30:46 -0700 Subject: [PATCH 062/114] ci: drop flet version pin (use latest) --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 427d967d..ca928a19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} ios: @@ -72,7 +72,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} android: @@ -131,7 +131,7 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 + cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet cd src/serious_python/example/flet_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} windows: @@ -156,7 +156,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} linux: @@ -231,7 +231,7 @@ jobs: working-directory: src/serious_python/example/flet_example run: | flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==0.85.3 + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: From 860aa094207aa6c93f916d6aebf2a8523a48a2d6 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 17:36:17 -0700 Subject: [PATCH 063/114] =?UTF-8?q?ci:=20iOS=20simulator=20=E2=86=92=20iPh?= =?UTF-8?q?one=2017=20Pro=20Max=20/=20iOS=2026.5=20(matches=20macos-26=20d?= =?UTF-8?q?evice=20lineup)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 8 ++-- .../example/flet_example/app/app.zip.hash | 2 +- .../example/flet_example/app/src/main.py | 6 ++- .../example/flet_example/macos/Podfile.lock | 48 ++++++++++++++++--- .../macos/Runner.xcodeproj/project.pbxproj | 18 +++++++ 5 files changed, 69 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca928a19..aa4b0796 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,9 +63,9 @@ jobs: uses: futureware-tech/simulator-action@v4 with: # https://github.com/futureware-tech/simulator-action/wiki/Devices-macos-latest - model: 'iPhone 16 Pro Max' + model: 'iPhone 17 Pro Max' os: "iOS" - os_version: "latest" + os_version: "26.5" shutdown_after_job: true wait_for_boot: true @@ -293,9 +293,9 @@ jobs: id: simulator uses: futureware-tech/simulator-action@v4 with: - model: 'iPhone 16 Pro Max' + model: 'iPhone 17 Pro Max' os: "iOS" - os_version: "latest" + os_version: "26.5" shutdown_after_job: true wait_for_boot: true diff --git a/src/serious_python/example/flet_example/app/app.zip.hash b/src/serious_python/example/flet_example/app/app.zip.hash index 4ef49a27..92f5773e 100644 --- a/src/serious_python/example/flet_example/app/app.zip.hash +++ b/src/serious_python/example/flet_example/app/app.zip.hash @@ -1 +1 @@ -c70dd39b2f894beb08c977300587fe6938c3a02649598f13b80d68d998d9cc07 \ No newline at end of file +a55b4f24b27b6384f1609f6b00f6f508bd5bdbe0cbb09ac13389b1d6fce33c98 \ No newline at end of file diff --git a/src/serious_python/example/flet_example/app/src/main.py b/src/serious_python/example/flet_example/app/src/main.py index 57069c80..dcb0757e 100644 --- a/src/serious_python/example/flet_example/app/src/main.py +++ b/src/serious_python/example/flet_example/app/src/main.py @@ -49,10 +49,12 @@ def check_ssl(e): ft.Row( [ ft.IconButton( - ft.Icons.REMOVE, key="test:decrement", on_click=minus_click + ft.Icons.REMOVE, key=ft.ValueKey("decrement"), on_click=minus_click ), txt_number, - ft.IconButton(ft.Icons.ADD, key="test:increment", on_click=plus_click), + ft.IconButton( + ft.Icons.ADD, key=ft.ValueKey("increment"), on_click=plus_click + ), ], alignment=ft.MainAxisAlignment.CENTER, expand=True, diff --git a/src/serious_python/example/flet_example/macos/Podfile.lock b/src/serious_python/example/flet_example/macos/Podfile.lock index 3cbcdcdf..dcf44461 100644 --- a/src/serious_python/example/flet_example/macos/Podfile.lock +++ b/src/serious_python/example/flet_example/macos/Podfile.lock @@ -1,4 +1,8 @@ PODS: + - battery_plus (0.0.1): + - FlutterMacOS + - connectivity_plus (0.0.1): + - FlutterMacOS - device_info_plus (0.0.1): - FlutterMacOS - file_picker (0.0.1): @@ -6,38 +10,56 @@ PODS: - FlutterMacOS (1.0.0) - package_info_plus (0.0.1): - FlutterMacOS + - pasteboard (0.0.1): + - FlutterMacOS - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - screen_brightness_macos (0.1.0): + - FlutterMacOS - screen_retriever_macos (0.0.1): - FlutterMacOS - - serious_python_darwin (0.9.8): + - serious_python_darwin (2.0.0): - Flutter - FlutterMacOS + - share_plus (0.0.1): + - FlutterMacOS - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS - - window_manager (0.2.0): + - wakelock_plus (0.0.1): + - FlutterMacOS + - window_manager (0.5.0): - FlutterMacOS - window_to_front (0.0.1): - FlutterMacOS DEPENDENCIES: + - battery_plus (from `Flutter/ephemeral/.symlinks/plugins/battery_plus/macos`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) - window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`) EXTERNAL SOURCES: + battery_plus: + :path: Flutter/ephemeral/.symlinks/plugins/battery_plus/macos + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos device_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos file_picker: @@ -46,32 +68,46 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral package_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + pasteboard: + :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + screen_brightness_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos screen_retriever_macos: :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos serious_python_darwin: :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos window_manager: :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos window_to_front: :path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos SPEC CHECKSUMS: + battery_plus: f51ad29136e025b714b96f7d096f44f604615da7 + connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - package_info_plus: a8a591e70e87ce97ce5d21b2594f69cea9e0312f + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + screen_brightness_macos: 1058c18b5e0570f48f93016487a5ed66d6977fe0 screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f - serious_python_darwin: d8fa26f4b226e433b51fdb0259c60b3ec9c48527 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 + share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 - window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c + wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b + window_manager: b729e31d38fb04905235df9ea896128991cad99e window_to_front: 9e76fd432e36700a197dac86a0011e49c89abe0a PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 diff --git a/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj index e1f5b26b..319e1e69 100644 --- a/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */, + 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -377,6 +378,23 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; From 34714f5777c9fc1e0f228b710d153357bf87f9d7 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 17:47:52 -0700 Subject: [PATCH 064/114] flet_example: use ValueKey explicitly in integration test (matches Flet's ControlWidget key) --- .../example/flet_example/integration_test/app_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serious_python/example/flet_example/integration_test/app_test.dart b/src/serious_python/example/flet_example/integration_test/app_test.dart index 254a6c73..768d8875 100644 --- a/src/serious_python/example/flet_example/integration_test/app_test.dart +++ b/src/serious_python/example/flet_example/integration_test/app_test.dart @@ -26,13 +26,13 @@ void main() { expect(counterFound, isTrue); // Tap increment button - final incrementButton = find.byKey(const Key('increment')); + final incrementButton = find.byKey(const ValueKey('increment')); await tester.tap(incrementButton); await tester.pumpAndSettle(); expect(find.text('1'), findsOneWidget); // Tap decrement button - final decrementButton = find.byKey(const Key('decrement')); + final decrementButton = find.byKey(const ValueKey('decrement')); await tester.tap(decrementButton); await tester.tap(decrementButton); await tester.pumpAndSettle(); From cf5f1a386606e26140a30637c2f17bb215d4e1de Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 17:57:48 -0700 Subject: [PATCH 065/114] flet_example: find by icon, not key (Flet's ValueKey doesn't match ValueKey) --- .../integration_test/app_test.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/serious_python/example/flet_example/integration_test/app_test.dart b/src/serious_python/example/flet_example/integration_test/app_test.dart index 768d8875..c9b748a5 100644 --- a/src/serious_python/example/flet_example/integration_test/app_test.dart +++ b/src/serious_python/example/flet_example/integration_test/app_test.dart @@ -1,5 +1,5 @@ import 'package:flet_example/main.dart' as app; -import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; @@ -25,16 +25,18 @@ void main() { expect(counterFound, isTrue); - // Tap increment button - final incrementButton = find.byKey(const ValueKey('increment')); - await tester.tap(incrementButton); + // Flet 0.85's ControlWidget builds `ValueKey(value)` for the + // user-side `key` prop. Flutter's `find.byKey` uses runtimeType-strict + // equality, so `Key('increment')` / `ValueKey('increment')` + // never matches `ValueKey('increment')`. Find by icon instead + // — the Python side uses ft.Icons.ADD/REMOVE which become Material + // Icons.add / Icons.remove in the widget tree and are unique here. + await tester.tap(find.byIcon(Icons.add)); await tester.pumpAndSettle(); expect(find.text('1'), findsOneWidget); - // Tap decrement button - final decrementButton = find.byKey(const ValueKey('decrement')); - await tester.tap(decrementButton); - await tester.tap(decrementButton); + await tester.tap(find.byIcon(Icons.remove)); + await tester.tap(find.byIcon(Icons.remove)); await tester.pumpAndSettle(); expect(find.text('-1'), findsOneWidget); From 399c75451706127cbb09b1d8583df87aa0b07eab Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 18:06:16 -0700 Subject: [PATCH 066/114] flet_example: pin flet to git dart-bridge branch (carries ValueKey fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from `flet: ^0.85.3` (pub.dev) to a git ref pointing at flet-dev/flet's dart-bridge branch. That branch fixes Flet's ControlWidget to construct `ValueKey` (not `ValueKey`) when the user's key is a String, so flutter_test's `find.byKey(Key('foo'))` actually matches. Revert app_test.dart to find by Key (now that Flet builds the correctly typed ValueKey, the original test code works); pubspec.lock churns to track the git revision. Local verification: `flutter test integration_test -d macos` → all tests passed. --- .../example/flet_example/app/app.zip.hash | 2 +- .../example/flet_example/app/src/main.py | 8 ++------ .../flet_example/integration_test/app_test.dart | 16 ++++++---------- .../example/flet_example/pubspec.lock | 9 +++++---- .../example/flet_example/pubspec.yaml | 6 +++++- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/serious_python/example/flet_example/app/app.zip.hash b/src/serious_python/example/flet_example/app/app.zip.hash index 92f5773e..e2ace746 100644 --- a/src/serious_python/example/flet_example/app/app.zip.hash +++ b/src/serious_python/example/flet_example/app/app.zip.hash @@ -1 +1 @@ -a55b4f24b27b6384f1609f6b00f6f508bd5bdbe0cbb09ac13389b1d6fce33c98 \ No newline at end of file +5034716fae4a090c25c3ab79e342de9a09f0972a4c76af1d5df41d5bc1e6770d \ No newline at end of file diff --git a/src/serious_python/example/flet_example/app/src/main.py b/src/serious_python/example/flet_example/app/src/main.py index dcb0757e..59cc8a5b 100644 --- a/src/serious_python/example/flet_example/app/src/main.py +++ b/src/serious_python/example/flet_example/app/src/main.py @@ -48,13 +48,9 @@ def check_ssl(e): page.add( ft.Row( [ - ft.IconButton( - ft.Icons.REMOVE, key=ft.ValueKey("decrement"), on_click=minus_click - ), + ft.IconButton(ft.Icons.REMOVE, key="decrement", on_click=minus_click), txt_number, - ft.IconButton( - ft.Icons.ADD, key=ft.ValueKey("increment"), on_click=plus_click - ), + ft.IconButton(ft.Icons.ADD, key="increment", on_click=plus_click), ], alignment=ft.MainAxisAlignment.CENTER, expand=True, diff --git a/src/serious_python/example/flet_example/integration_test/app_test.dart b/src/serious_python/example/flet_example/integration_test/app_test.dart index c9b748a5..10b5574c 100644 --- a/src/serious_python/example/flet_example/integration_test/app_test.dart +++ b/src/serious_python/example/flet_example/integration_test/app_test.dart @@ -1,5 +1,5 @@ import 'package:flet_example/main.dart' as app; -import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; @@ -25,18 +25,14 @@ void main() { expect(counterFound, isTrue); - // Flet 0.85's ControlWidget builds `ValueKey(value)` for the - // user-side `key` prop. Flutter's `find.byKey` uses runtimeType-strict - // equality, so `Key('increment')` / `ValueKey('increment')` - // never matches `ValueKey('increment')`. Find by icon instead - // — the Python side uses ft.Icons.ADD/REMOVE which become Material - // Icons.add / Icons.remove in the widget tree and are unique here. - await tester.tap(find.byIcon(Icons.add)); + // Tap increment button + await tester.tap(find.byKey(const Key('increment'))); await tester.pumpAndSettle(); expect(find.text('1'), findsOneWidget); - await tester.tap(find.byIcon(Icons.remove)); - await tester.tap(find.byIcon(Icons.remove)); + // Tap decrement button + await tester.tap(find.byKey(const Key('decrement'))); + await tester.tap(find.byKey(const Key('decrement'))); await tester.pumpAndSettle(); expect(find.text('-1'), findsOneWidget); diff --git a/src/serious_python/example/flet_example/pubspec.lock b/src/serious_python/example/flet_example/pubspec.lock index ad761054..30401dc7 100644 --- a/src/serious_python/example/flet_example/pubspec.lock +++ b/src/serious_python/example/flet_example/pubspec.lock @@ -188,10 +188,11 @@ packages: flet: dependency: "direct main" description: - name: flet - sha256: "295d34600580bc00576ea2a0a3ab3f92062ca487e010e3bf0ee20d41cc5c262d" - url: "https://pub.dev" - source: hosted + path: "packages/flet" + ref: dart-bridge + resolved-ref: "7367050f22edb02afebecaca5de70c3a0e389827" + url: "https://github.com/flet-dev/flet.git" + source: git version: "0.85.3" flutter: dependency: "direct main" diff --git a/src/serious_python/example/flet_example/pubspec.yaml b/src/serious_python/example/flet_example/pubspec.yaml index 87d8865c..4a314b64 100644 --- a/src/serious_python/example/flet_example/pubspec.yaml +++ b/src/serious_python/example/flet_example/pubspec.yaml @@ -37,7 +37,11 @@ dependencies: serious_python: path: ../../ - flet: ^0.85.3 + flet: + git: + url: https://github.com/flet-dev/flet.git + ref: dart-bridge + path: packages/flet path: ^1.8.3 path_provider: ^2.1.4 From 64018831824516165fdaf764eb616d4b604b194c Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 18:10:48 -0700 Subject: [PATCH 067/114] =?UTF-8?q?flet=5Fexample/android:=20bump=20Kotlin?= =?UTF-8?q?=20Gradle=20Plugin=201.8.22=20=E2=86=92=202.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flet's transitive dep screen_brightness_android 2.1.5 uses `kotlin.compilerOptions { ... }` DSL (introduced in KGP 2.0). With KGP 1.8.22 the Android Gradle build fails: Could not find method compilerOptions() for arguments [...] on extension 'kotlin' of type org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension. KGP 2.1 only requires AGP 7.4+, so AGP stays at 8.1.0 — no Gradle wrapper churn. --- .../example/flet_example/android/settings.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/serious_python/example/flet_example/android/settings.gradle b/src/serious_python/example/flet_example/android/settings.gradle index b9e43bd3..f0875199 100644 --- a/src/serious_python/example/flet_example/android/settings.gradle +++ b/src/serious_python/example/flet_example/android/settings.gradle @@ -19,7 +19,10 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + // Kotlin Gradle Plugin 2.0+ required by recent Flutter plugins (e.g. + // screen_brightness_android 2.1.5) which use the `kotlin.compilerOptions + // { ... }` DSL. KGP 2.1 only requires AGP 7.4+, so keeping AGP at 8.1.0. + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" From 9441342672a22f3722b9e4b2cd5e14c5fb8867c2 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 18:26:35 -0700 Subject: [PATCH 068/114] flet_example/android: bump AGP to 8.9.1 + Gradle to 8.11.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit androidx.core 1.18.0 (transitive via Flet) requires AGP 8.9.1+ — the previous build failed checkDebugAarMetadata with: Dependency 'androidx.core:core-ktx:1.18.0' requires Android Gradle plugin 8.9.1 or higher. This build currently uses Android Gradle plugin 8.1.0. AGP 8.9 in turn requires Gradle 8.11+, so bump the wrapper too. --- .../android/gradle/wrapper/gradle-wrapper.properties | 2 +- .../example/flet_example/android/settings.gradle | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6b..efdcc4ac 100644 --- a/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/src/serious_python/example/flet_example/android/settings.gradle b/src/serious_python/example/flet_example/android/settings.gradle index f0875199..5ddd68c2 100644 --- a/src/serious_python/example/flet_example/android/settings.gradle +++ b/src/serious_python/example/flet_example/android/settings.gradle @@ -18,10 +18,11 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - // Kotlin Gradle Plugin 2.0+ required by recent Flutter plugins (e.g. - // screen_brightness_android 2.1.5) which use the `kotlin.compilerOptions - // { ... }` DSL. KGP 2.1 only requires AGP 7.4+, so keeping AGP at 8.1.0. + // AGP 8.9.1+ required by androidx.core 1.18.0 (transitive via Flet); + // AGP 8.9 requires Gradle 8.11+ (see gradle-wrapper.properties). + id "com.android.application" version "8.9.1" apply false + // KGP 2.0+ required by screen_brightness_android 2.1.5's use of the + // `kotlin.compilerOptions { ... }` DSL. id "org.jetbrains.kotlin.android" version "2.1.0" apply false } From fb53f656339d084b8f2facf0def795c09db6133b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 18:38:29 -0700 Subject: [PATCH 069/114] =?UTF-8?q?flet=5Fexample/android:=20bump=20KGP=20?= =?UTF-8?q?2.1.0=20=E2=86=92=202.3.21=20(match=20screen=5Fbrightness=5Fand?= =?UTF-8?q?roid=20stdlib)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit screen_brightness_android 2.1.5 ships compiled against Kotlin 2.3.21 stdlib. KGP 2.1 couldn't read the metadata: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 2.3.0, expected version is 2.1.0. Bumping KGP to 2.3.21 matches the transitive stdlib version. --- .../example/flet_example/android/settings.gradle | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/serious_python/example/flet_example/android/settings.gradle b/src/serious_python/example/flet_example/android/settings.gradle index 5ddd68c2..01a36241 100644 --- a/src/serious_python/example/flet_example/android/settings.gradle +++ b/src/serious_python/example/flet_example/android/settings.gradle @@ -21,9 +21,10 @@ plugins { // AGP 8.9.1+ required by androidx.core 1.18.0 (transitive via Flet); // AGP 8.9 requires Gradle 8.11+ (see gradle-wrapper.properties). id "com.android.application" version "8.9.1" apply false - // KGP 2.0+ required by screen_brightness_android 2.1.5's use of the - // `kotlin.compilerOptions { ... }` DSL. - id "org.jetbrains.kotlin.android" version "2.1.0" apply false + // KGP 2.3.x required: screen_brightness_android 2.1.5 ships with a + // Kotlin 2.3.21 stdlib whose metadata format (binary version 2.3.0) + // can't be read by KGP < 2.3. + id "org.jetbrains.kotlin.android" version "2.3.21" apply false } include ":app" From 300cd94202cea097ad0e50ea019e4ef7d3d64604 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 18:54:23 -0700 Subject: [PATCH 070/114] flet_example/android: extractNativeLibs=true (match bridge_example) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serious_python_android ships libpythonbundle.so / libpythonsitepackages.so which are ZIP archives masquerading as .so files (so they ride the standard jniLibs packaging path). AGP 8.x defaults to NOT extracting native libs out of the APK at install time, leaving them inaccessible as on-disk files — which serious_python_android.dart's run() needs. Setting `android:extractNativeLibs="true"` on the tag restores the pre-AGP-8 behavior; matches the same setting in bridge_example/android/app/src/main/AndroidManifest.xml which has been green on Android. --- .../flet_example/android/app/src/main/AndroidManifest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/serious_python/example/flet_example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/flet_example/android/app/src/main/AndroidManifest.xml index 8f81c74b..3b5c35fb 100644 --- a/src/serious_python/example/flet_example/android/app/src/main/AndroidManifest.xml +++ b/src/serious_python/example/flet_example/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:icon="@mipmap/ic_launcher" + android:extractNativeLibs="true"> Date: Wed, 10 Jun 2026 19:50:34 -0700 Subject: [PATCH 071/114] ci: pin FLET_VERSION + scope flet_example matrix to Python 3.12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes addressing the same root cause: 1. Pin `--requirements flet==${FLET_VERSION}` (set at the workflow env level to 0.85.3). With `--only-binary :all:` (used for mobile targets), pip otherwise silently downgrades flet to an older version whose transitive deps have wheels for the target python_version / platform. The Dart side then talks the new protocol while Python runs an old flet — silent stall on the IPC socket. 2. Scope the flet_example matrix to Python 3.12 only. msgpack 1.x has no wheel for Android/iOS arm64 on Python 3.13/3.14, and pip with `--only-binary :all:` falls back to an incompatible flet version. Keeping the matrix uniform across platforms (vs. Python-version- filtered) to avoid skew between platform/version coverage. bridge_example keeps its full 3.12/3.13/3.14 × 5-platform matrix — it doesn't depend on flet, so it's a clean regression net for the absorption architecture across all Python minors. Once msgpack wheels for Android/iOS Python 3.13/3.14 land on pypi.flet.dev, the flet_example matrix can be widened back. --- .github/workflows/ci.yml | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa4b0796..1259558f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,11 @@ env: SCRIPTS: "${{ github.workspace }}/.github/scripts" SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" UV_PYTHON: "3.12" + # Pin flet so the Python side matches the Dart-side flet version. With + # `--only-binary :all:`, pip would otherwise silently downgrade to an + # older flet whose transitive deps (e.g. msgpack) have wheels for the + # target python_version / platform, leaving the two halves mismatched. + FLET_VERSION: "0.85.3" jobs: macos: @@ -20,7 +25,12 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12', '3.13', '3.14'] + # 3.13/3.14 disabled until msgpack wheels for those Python versions + # land on pypi.flet.dev for Android/iOS — with `--only-binary :all:` + # pip silently downgrades flet to an older version on the mobile + # platforms, leaving Python/Dart sides out of sync. Keeping the + # version matrix consistent across platforms for now. + python_version: ['3.12'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -36,7 +46,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} ios: @@ -45,7 +55,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12', '3.13', '3.14'] + python_version: ['3.12'] # see macos job for the 3.13/3.14 gate env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -72,7 +82,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} android: @@ -81,7 +91,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12', '3.13', '3.14'] + python_version: ['3.12'] # see macos job for the 3.13/3.14 gate env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -131,7 +141,7 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet + cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} cd src/serious_python/example/flet_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} windows: @@ -140,7 +150,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12', '3.13', '3.14'] + python_version: ['3.12'] # see macos job for the 3.13/3.14 gate env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -156,7 +166,7 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} linux: @@ -165,7 +175,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12', '3.13', '3.14'] + python_version: ['3.12'] # see macos job for the 3.13/3.14 gate arch: [arm64, amd64] include: - arch: arm64 @@ -231,7 +241,7 @@ jobs: working-directory: src/serious_python/example/flet_example run: | flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: From 36fb334096913f1ca3e719b12b6dc8e098a81a70 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 19:51:30 -0700 Subject: [PATCH 072/114] ci: limit only iOS+Android flet_example matrices to 3.12 (msgpack wheel gap is mobile-arm64-specific) --- .github/workflows/ci.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1259558f..8029ed96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,12 +25,7 @@ jobs: strategy: fail-fast: false matrix: - # 3.13/3.14 disabled until msgpack wheels for those Python versions - # land on pypi.flet.dev for Android/iOS — with `--only-binary :all:` - # pip silently downgrades flet to an older version on the mobile - # platforms, leaving Python/Dart sides out of sync. Keeping the - # version matrix consistent across platforms for now. - python_version: ['3.12'] + python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -55,7 +50,11 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12'] # see macos job for the 3.13/3.14 gate + # 3.13/3.14 disabled until msgpack 1.x ships iOS arm64 wheels for + # those Python versions on pypi.flet.dev — with `--only-binary :all:` + # pip otherwise silently downgrades flet to an older version, + # leaving Python/Dart out of sync. + python_version: ['3.12'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -91,7 +90,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12'] # see macos job for the 3.13/3.14 gate + python_version: ['3.12'] # see ios job for the 3.13/3.14 gate env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -150,7 +149,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12'] # see macos job for the 3.13/3.14 gate + python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -175,7 +174,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12'] # see macos job for the 3.13/3.14 gate + python_version: ['3.12', '3.13', '3.14'] arch: [arm64, amd64] include: - arch: arm64 From dc6a2659c25af163c751457dea2358e0cebde99f Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 19:55:48 -0700 Subject: [PATCH 073/114] =?UTF-8?q?ci:=20unify=20test=20job=20naming=20?= =?UTF-8?q?=E2=86=92=20'Test=20=20example=20on=20?= =?UTF-8?q?=20(Python=20)'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8029ed96..5e9084ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ env: jobs: macos: - name: Test on macOS (Python ${{ matrix.python_version }}) + name: Test Flet example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 strategy: fail-fast: false @@ -45,7 +45,7 @@ jobs: flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} ios: - name: Test on iOS (Python ${{ matrix.python_version }}) + name: Test Flet example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 strategy: fail-fast: false @@ -85,7 +85,7 @@ jobs: flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} android: - name: Test on Android (Python ${{ matrix.python_version }}) + name: Test Flet example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest strategy: fail-fast: false @@ -144,7 +144,7 @@ jobs: cd src/serious_python/example/flet_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} windows: - name: Test on Windows (Python ${{ matrix.python_version }}) + name: Test Flet example on Windows (Python ${{ matrix.python_version }}) runs-on: windows-latest strategy: fail-fast: false @@ -169,7 +169,7 @@ jobs: flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} linux: - name: Test on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) + name: Test Flet example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} strategy: fail-fast: false @@ -244,7 +244,7 @@ jobs: xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: - name: Bridge example macOS round-trip (Python ${{ matrix.python_version }}) + name: Test Bridge example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 strategy: fail-fast: false @@ -269,7 +269,7 @@ jobs: flutter test integration_test -d macos bridge_example_ios: - name: Bridge example iOS round-trip (Python ${{ matrix.python_version }}) + name: Test Bridge example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 timeout-minutes: 25 strategy: @@ -324,7 +324,7 @@ jobs: echo "[$(ts)] >>> done" bridge_example_android: - name: Bridge example Android round-trip (Python ${{ matrix.python_version }}) + name: Test Bridge example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest strategy: fail-fast: false @@ -403,7 +403,7 @@ jobs: fi bridge_example_windows: - name: Bridge example Windows round-trip (Python ${{ matrix.python_version }}) + name: Test Bridge example on Windows (Python ${{ matrix.python_version }}) runs-on: windows-latest strategy: fail-fast: false @@ -452,7 +452,7 @@ jobs: ls -la $DBG_DIR/site-packages/ || true bridge_example_linux: - name: Bridge example Linux round-trip (Python ${{ matrix.python_version }}) + name: Test Bridge example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} strategy: fail-fast: false @@ -462,8 +462,10 @@ jobs: include: - arch: amd64 runner: ubuntu-24.04 + title: AMD64 - arch: arm64 runner: ubuntu-24.04-arm + title: ARM64 env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: From 8a90cbcf4ed8a1e861fdec34f2e2915f78dcd2a2 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 19:57:03 -0700 Subject: [PATCH 074/114] ci: add concurrency group (cancel in-flight runs on same ref, preserve tags) --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e9084ed..8f17abf8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,13 @@ on: pull_request: workflow_dispatch: +# Auto-cancel in-flight runs when a new push lands on the same ref. +# Tag builds (refs/tags/*) get a unique-per-run group so release runs +# never cancel each other. +concurrency: + group: ${{ github.workflow }}-${{ startsWith(github.ref, 'refs/tags/') && github.run_id || github.ref }} + cancel-in-progress: true + env: ROOT: "${{ github.workspace }}" SCRIPTS: "${{ github.workspace }}/.github/scripts" From 1588d71f2a2d88bafcff3c354719da2fe044ffa3 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 21:20:53 -0700 Subject: [PATCH 075/114] add flet_ffi_example exercising dart_bridge FFI transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A copy of flet_example wired to use Flet's in-process dart_bridge transport (added in flet's dart-bridge branch) instead of the Unix-socket transport. Python user code is identical between the two examples; only the embedding side differs. lib/main.dart highlights: * Creates a long-lived PythonBridge before launching Python; its 64-bit Dart native port is the channel key in both directions. * Exports FLET_DART_BRIDGE_PORT into Python's environment so flet.app.run_async picks FletDartBridgeServer over FletSocketServer. * Injects a custom _DartBridgeBackendChannel into FletApp via the new channelBuilder param. The channel speaks the same MsgPack-framed protocol as FletSocketBackendChannel — only the byte transport changes. * Redirects Python stdout/stderr to \$FLET_APP_TEMP/flet_ffi_boot.log while the new transport stabilises (no stdout-callback socket). The flet package itself stays Python-independent — PythonBridge wiring lives entirely in this example. Python flet is pulled from the dart-bridge branch via a git source requirement (needs SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS =flet to bypass --only-binary :all: on mobile targets). See README for build commands. --- .../example/flet_ffi_example/.gitignore | 46 + .../example/flet_ffi_example/.metadata | 30 + .../example/flet_ffi_example/README.md | 48 + .../flet_ffi_example/analysis_options.yaml | 29 + .../flet_ffi_example/android/.gitignore | 14 + .../flet_ffi_example/android/app/build.gradle | 44 + .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 46 + .../com/example/flet_example/MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + .../flet_ffi_example/android/build.gradle | 18 + .../android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../flet_ffi_example/android/settings.gradle | 30 + .../example/flet_ffi_example/app/app.zip.hash | 1 + .../example/flet_ffi_example/app/src/main.py | 76 ++ .../flet_ffi_example/app/src/main_async.py | 36 + .../flet_ffi_example/app/src/requirements.txt | 1 + .../integration_test/app_test.dart | 61 + .../example/flet_ffi_example/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../ios/Flutter/Debug.xcconfig | 2 + .../ios/Flutter/Release.xcconfig | 2 + .../example/flet_ffi_example/ios/Podfile | 44 + .../example/flet_ffi_example/ios/Podfile.lock | 114 ++ .../ios/Runner.xcodeproj/project.pbxproj | 724 ++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 ++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 ++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../flet_ffi_example/ios/Runner/Info.plist | 51 + .../ios/Runner/Runner-Bridging-Header.h | 1 + .../ios/RunnerTests/RunnerTests.swift | 12 + .../example/flet_ffi_example/lib/main.dart | 315 +++++ .../example/flet_ffi_example/linux/.gitignore | 1 + .../flet_ffi_example/linux/CMakeLists.txt | 154 +++ .../linux/flutter/CMakeLists.txt | 88 ++ .../flutter/generated_plugin_registrant.cc | 35 + .../flutter/generated_plugin_registrant.h | 15 + .../linux/flutter/generated_plugins.cmake | 30 + .../example/flet_ffi_example/linux/main.cc | 6 + .../flet_ffi_example/linux/my_application.cc | 104 ++ .../flet_ffi_example/linux/my_application.h | 18 + .../example/flet_ffi_example/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 2 + .../macos/Flutter/Flutter-Release.xcconfig | 2 + .../Flutter/GeneratedPluginRegistrant.swift | 40 + .../example/flet_ffi_example/macos/Podfile | 43 + .../flet_ffi_example/macos/Podfile.lock | 108 ++ .../macos/Runner.xcodeproj/project.pbxproj | 809 +++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 99 ++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../macos/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 68 + .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 +++++ .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 12 + .../flet_ffi_example/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + .../macos/Runner/Release.entitlements | 8 + .../macos/RunnerTests/RunnerTests.swift | 12 + .../example/flet_ffi_example/pubspec.lock | 1201 +++++++++++++++++ .../example/flet_ffi_example/pubspec.yaml | 81 ++ .../flet_ffi_example/test/widget_test.dart | 10 + .../test_driver/integration_test.dart | 3 + .../example/flet_ffi_example/web/favicon.png | Bin 0 -> 917 bytes .../flet_ffi_example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../flet_ffi_example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes .../web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes .../example/flet_ffi_example/web/index.html | 59 + .../flet_ffi_example/web/manifest.json | 35 + .../flet_ffi_example/windows/.gitignore | 17 + .../flet_ffi_example/windows/CMakeLists.txt | 102 ++ .../windows/flutter/CMakeLists.txt | 109 ++ .../flutter/generated_plugin_registrant.cc | 41 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 34 + .../windows/runner/CMakeLists.txt | 40 + .../flet_ffi_example/windows/runner/Runner.rc | 121 ++ .../windows/runner/flutter_window.cpp | 71 + .../windows/runner/flutter_window.h | 33 + .../flet_ffi_example/windows/runner/main.cpp | 43 + .../windows/runner/resource.h | 16 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes .../windows/runner/runner.exe.manifest | 20 + .../flet_ffi_example/windows/runner/utils.cpp | 65 + .../flet_ffi_example/windows/runner/utils.h | 19 + .../windows/runner/win32_window.cpp | 288 ++++ .../windows/runner/win32_window.h | 102 ++ 138 files changed, 6911 insertions(+) create mode 100644 src/serious_python/example/flet_ffi_example/.gitignore create mode 100644 src/serious_python/example/flet_ffi_example/.metadata create mode 100644 src/serious_python/example/flet_ffi_example/README.md create mode 100644 src/serious_python/example/flet_ffi_example/analysis_options.yaml create mode 100644 src/serious_python/example/flet_ffi_example/android/.gitignore create mode 100644 src/serious_python/example/flet_ffi_example/android/app/build.gradle create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml create mode 100644 src/serious_python/example/flet_ffi_example/android/build.gradle create mode 100644 src/serious_python/example/flet_ffi_example/android/gradle.properties create mode 100644 src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 src/serious_python/example/flet_ffi_example/android/settings.gradle create mode 100644 src/serious_python/example/flet_ffi_example/app/app.zip.hash create mode 100644 src/serious_python/example/flet_ffi_example/app/src/main.py create mode 100644 src/serious_python/example/flet_ffi_example/app/src/main_async.py create mode 100644 src/serious_python/example/flet_ffi_example/app/src/requirements.txt create mode 100644 src/serious_python/example/flet_ffi_example/integration_test/app_test.dart create mode 100644 src/serious_python/example/flet_ffi_example/ios/.gitignore create mode 100644 src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/ios/Podfile create mode 100644 src/serious_python/example/flet_ffi_example/ios/Podfile.lock create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist create mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h create mode 100644 src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift create mode 100644 src/serious_python/example/flet_ffi_example/lib/main.dart create mode 100644 src/serious_python/example/flet_ffi_example/linux/.gitignore create mode 100644 src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt create mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt create mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc create mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h create mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake create mode 100644 src/serious_python/example/flet_ffi_example/linux/main.cc create mode 100644 src/serious_python/example/flet_ffi_example/linux/my_application.cc create mode 100644 src/serious_python/example/flet_ffi_example/linux/my_application.h create mode 100644 src/serious_python/example/flet_ffi_example/macos/.gitignore create mode 100644 src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 src/serious_python/example/flet_ffi_example/macos/Podfile create mode 100644 src/serious_python/example/flet_ffi_example/macos/Podfile.lock create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift create mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements create mode 100644 src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift create mode 100644 src/serious_python/example/flet_ffi_example/pubspec.lock create mode 100644 src/serious_python/example/flet_ffi_example/pubspec.yaml create mode 100644 src/serious_python/example/flet_ffi_example/test/widget_test.dart create mode 100644 src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart create mode 100644 src/serious_python/example/flet_ffi_example/web/favicon.png create mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-192.png create mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-512.png create mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-192.png create mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-512.png create mode 100644 src/serious_python/example/flet_ffi_example/web/index.html create mode 100644 src/serious_python/example/flet_ffi_example/web/manifest.json create mode 100644 src/serious_python/example/flet_ffi_example/windows/.gitignore create mode 100644 src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt create mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt create mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc create mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h create mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/main.cpp create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/resource.h create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/resources/app_icon.ico create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/utils.h create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp create mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h diff --git a/src/serious_python/example/flet_ffi_example/.gitignore b/src/serious_python/example/flet_ffi_example/.gitignore new file mode 100644 index 00000000..6c319542 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/src/serious_python/example/flet_ffi_example/.metadata b/src/serious_python/example/flet_ffi_example/.metadata new file mode 100644 index 00000000..c7222470 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 + base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 + - platform: android + create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 + base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/src/serious_python/example/flet_ffi_example/README.md b/src/serious_python/example/flet_ffi_example/README.md new file mode 100644 index 00000000..250f24f1 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/README.md @@ -0,0 +1,48 @@ +# flet_ffi_example + +A copy of [flet_example](../flet_example) wired to use the in-process +`dart_bridge` FFI transport (added in Flet 0.85+'s `dart-bridge` branch) +instead of the Unix-socket transport. The Python user code is identical; +only the embedding side differs: + +- `lib/main.dart` constructs a `PythonBridge` and hands a custom + `FletBackendChannel` to `FletApp` via the `channelBuilder` parameter. +- `FLET_DART_BRIDGE_PORT` is exported into the Python environment so + `flet.app.run_async()` selects `FletDartBridgeServer` instead of + `FletSocketServer`. + +The Dart `flet` package itself remains Python-independent — the +PythonBridge wiring lives entirely in this example. + +## Building + +The Python `flet` package needs the `dart-bridge` branch (because +`FletDartBridgeServer` is not on PyPI yet), so the `--requirements` arg +installs from git. Mobile targets use `pip install --only-binary :all:` +which would normally reject a git source — the +`SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet` env var opts `flet` +specifically into source installs by injecting `--no-binary flet`. + +For macOS: + +``` +export SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet +dart run serious_python:main package app/src \ + --platform Darwin \ + --requirements "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" +``` + +Replace `--platform Darwin` with `iOS`, `Android`, `Windows`, or `Linux` +as needed. The same `--requirements` works on every platform. + +## Running locally + +`sync_site_packages.sh` (in `serious_python_darwin`) requires +`SERIOUS_PYTHON_SITE_PACKAGES` pointing at the freshly-packaged +`build/site-packages/` directory so the .app bundle picks up the +git-installed flet instead of a stale copy from a previous run: + +``` +export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages +fvm flutter test integration_test --device-id macos +``` diff --git a/src/serious_python/example/flet_ffi_example/analysis_options.yaml b/src/serious_python/example/flet_ffi_example/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/src/serious_python/example/flet_ffi_example/android/.gitignore b/src/serious_python/example/flet_ffi_example/android/.gitignore new file mode 100644 index 00000000..5fed52d9 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +**/.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/src/serious_python/example/flet_ffi_example/android/app/build.gradle b/src/serious_python/example/flet_ffi_example/android/app/build.gradle new file mode 100644 index 00000000..852bab06 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/build.gradle @@ -0,0 +1,44 @@ +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +android { + namespace = "com.example.flet_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.flet_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug + } + } +} + +flutter { + source = "../.." +} diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml b/src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..3b5c35fb --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt b/src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt new file mode 100644 index 00000000..cc08d6a6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.flet_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml b/src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/src/serious_python/example/flet_ffi_example/android/build.gradle b/src/serious_python/example/flet_ffi_example/android/build.gradle new file mode 100644 index 00000000..d2ffbffa --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = "../build" +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/src/serious_python/example/flet_ffi_example/android/gradle.properties b/src/serious_python/example/flet_ffi_example/android/gradle.properties new file mode 100644 index 00000000..25971708 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..efdcc4ac --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/src/serious_python/example/flet_ffi_example/android/settings.gradle b/src/serious_python/example/flet_ffi_example/android/settings.gradle new file mode 100644 index 00000000..01a36241 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/android/settings.gradle @@ -0,0 +1,30 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + // AGP 8.9.1+ required by androidx.core 1.18.0 (transitive via Flet); + // AGP 8.9 requires Gradle 8.11+ (see gradle-wrapper.properties). + id "com.android.application" version "8.9.1" apply false + // KGP 2.3.x required: screen_brightness_android 2.1.5 ships with a + // Kotlin 2.3.21 stdlib whose metadata format (binary version 2.3.0) + // can't be read by KGP < 2.3. + id "org.jetbrains.kotlin.android" version "2.3.21" apply false +} + +include ":app" diff --git a/src/serious_python/example/flet_ffi_example/app/app.zip.hash b/src/serious_python/example/flet_ffi_example/app/app.zip.hash new file mode 100644 index 00000000..e5d849b8 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/app/app.zip.hash @@ -0,0 +1 @@ +b92d604f99e8c64859bd16e28c24a0b25eefdcdcb35ba99a08201d614a03772a \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/app/src/main.py b/src/serious_python/example/flet_ffi_example/app/src/main.py new file mode 100644 index 00000000..05c566f1 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/app/src/main.py @@ -0,0 +1,76 @@ +import os +import sys +import urllib.request + +import flet as ft +from flet.version import flet_version + +# logging.basicConfig(level=logging.DEBUG) + +print("Hello from Python!") +print(__name__) + +# import aaa +app_data = os.environ["FLET_APP_DATA"] +app_temp = os.environ["FLET_APP_TEMP"] + + +def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + py_ver = sys.version_info + python_version_text = ( + f"Python version: {py_ver.major}.{py_ver.minor}.{py_ver.micro}" + ) + print(python_version_text) + + txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + def minus_click(e): + print("Clicked minus button") + txt_number.value = str(int(txt_number.value) - 1) + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + page.update() + + def check_ssl(e): + try: + with urllib.request.urlopen("https://google.com") as res: + result = "OK" + except Exception as ex: + result = str(ex) + page.show_dialog(ft.AlertDialog(content=ft.Text(result))) + # print(result) + + page.add( + ft.Row( + [ + ft.IconButton(ft.Icons.REMOVE, key="decrement", on_click=minus_click), + txt_number, + ft.IconButton(ft.Icons.ADD, key="increment", on_click=plus_click), + ], + alignment=ft.MainAxisAlignment.CENTER, + expand=True, + ), + ft.Row( + [ + ft.Text(f"Flet version: {flet_version}"), + ft.OutlinedButton("Check SSL", on_click=check_ssl), + ft.OutlinedButton("Exit app", on_click=lambda _: sys.exit(100)), + ], + wrap=True, + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Text(f"App data dir: {app_data}"), + ft.Text(f"App temp dir: {app_temp}"), + ft.Text(python_version_text), + ) + + print("This is inside main() method!") + + +if __name__ == "__main__": + ft.run(main) diff --git a/src/serious_python/example/flet_ffi_example/app/src/main_async.py b/src/serious_python/example/flet_ffi_example/app/src/main_async.py new file mode 100644 index 00000000..38f363de --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/app/src/main_async.py @@ -0,0 +1,36 @@ +import logging + +import flet as ft + +logging.basicConfig(level=logging.DEBUG) + + +async def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + async def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + await page.update_async() + + async def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + await page.update_async() + + await page.add_async( + ft.Row( + [ + ft.IconButton( + ft.Icons.REMOVE, key="test:decrement", on_click=minus_click + ), + txt_number, + ft.IconButton(ft.Icons.ADD, key="test:increment", on_click=plus_click), + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + ) + + +ft.app(main) diff --git a/src/serious_python/example/flet_ffi_example/app/src/requirements.txt b/src/serious_python/example/flet_ffi_example/app/src/requirements.txt new file mode 100644 index 00000000..4c3173f6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/app/src/requirements.txt @@ -0,0 +1 @@ +flet \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/integration_test/app_test.dart b/src/serious_python/example/flet_ffi_example/integration_test/app_test.dart new file mode 100644 index 00000000..c1dc7f2c --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/integration_test/app_test.dart @@ -0,0 +1,61 @@ +import 'package:flet_ffi_example/main.dart' as app; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('end-to-end test', () { + testWidgets('make sure counter can be incremented and decremented', + (tester) async { + app.main(); + await tester.pumpAndSettle(const Duration(seconds: 5)); + + // Wait for up to 10 seconds for the app to start + bool counterFound = false; + for (int i = 0; i < 20; i++) { + await tester.pump(const Duration(seconds: 1)); + + if (find.text('0').evaluate().isNotEmpty) { + counterFound = true; + break; + } + } + + expect(counterFound, isTrue); + + // Tap increment button + await tester.tap(find.byKey(const Key('increment'))); + await tester.pumpAndSettle(); + expect(find.text('1'), findsOneWidget); + + // Tap decrement button + await tester.tap(find.byKey(const Key('decrement'))); + await tester.tap(find.byKey(const Key('decrement'))); + await tester.pumpAndSettle(); + expect(find.text('-1'), findsOneWidget); + + // Verify the bundled Python runtime matches what CI requested. Skipped + // outside CI (no --dart-define). + const expectedPyVersion = + String.fromEnvironment('EXPECTED_PYTHON_VERSION'); + if (expectedPyVersion.isNotEmpty) { + bool versionFound = false; + for (int i = 0; i < 20; i++) { + await tester.pump(const Duration(seconds: 1)); + if (find + .textContaining('Python version: $expectedPyVersion.') + .evaluate() + .isNotEmpty) { + versionFound = true; + break; + } + } + expect(versionFound, isTrue, + reason: + 'Expected `Python version: $expectedPyVersion.x` in the app UI'); + } + }); + }); +} diff --git a/src/serious_python/example/flet_ffi_example/ios/.gitignore b/src/serious_python/example/flet_ffi_example/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist b/src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..7c569640 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig b/src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig b/src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/ios/Podfile b/src/serious_python/example/flet_ffi_example/ios/Podfile new file mode 100644 index 00000000..164df534 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/src/serious_python/example/flet_ffi_example/ios/Podfile.lock b/src/serious_python/example/flet_ffi_example/ios/Podfile.lock new file mode 100644 index 00000000..a6e90d98 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Podfile.lock @@ -0,0 +1,114 @@ +PODS: + - DKImagePickerController/Core (4.3.4): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.4) + - DKImagePickerController/PhotoGallery (4.3.4): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.4) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Flutter (1.0.0) + - integration_test (0.0.1): + - Flutter + - package_info_plus (0.4.5): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - SDWebImage (5.18.5): + - SDWebImage/Core (= 5.18.5) + - SDWebImage/Core (5.18.5) + - sensors_plus (0.0.1): + - Flutter + - serious_python_darwin (0.8.0): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - SwiftyGif (5.4.4) + - url_launcher_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - Flutter (from `Flutter`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) + - serious_python_darwin (from `.symlinks/plugins/serious_python_darwin/darwin`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - SDWebImage + - SwiftyGif + +EXTERNAL SOURCES: + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + Flutter: + :path: Flutter + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + sensors_plus: + :path: ".symlinks/plugins/sensors_plus/ios" + serious_python_darwin: + :path: ".symlinks/plugins/serious_python_darwin/darwin" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + +SPEC CHECKSUMS: + DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + SDWebImage: 7ac2b7ddc5e8484c79aa90fc4e30b149d6a2c88f + sensors_plus: 42b9de1b8237675fa8d8121e4bb93be0f79fa61d + serious_python_darwin: 351e50099cb9e34f344f75af29b1d36d3c0922f2 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe + +PODFILE CHECKSUM: 7be2f5f74864d463a8ad433546ed1de7e0f29aef + +COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..92eb9c48 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,724 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 2405649350EFCEC25599DE23 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */; }; + 2CA3C271D8189DF194697D7D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28A203680D8105B35D530F31 /* Pods_Runner.framework */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1EE1648DA1E83A0AA44BC13A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 28A203680D8105B35D530F31 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 563D6173166309C998296F04 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 5FA1FBC3AE8269E16AA97AD1 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2CA3C271D8189DF194697D7D /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B920DD79982F64FC739571F8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2405649350EFCEC25599DE23 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 103F5AA3589F7D2F915BFF32 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 28A203680D8105B35D530F31 /* Pods_Runner.framework */, + D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + E36498D4F89A08F7B5C19AED /* Pods */, + 103F5AA3589F7D2F915BFF32 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + E36498D4F89A08F7B5C19AED /* Pods */ = { + isa = PBXGroup; + children = ( + 5FA1FBC3AE8269E16AA97AD1 /* Pods-Runner.debug.xcconfig */, + 563D6173166309C998296F04 /* Pods-Runner.release.xcconfig */, + 1EE1648DA1E83A0AA44BC13A /* Pods-Runner.profile.xcconfig */, + 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */, + 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */, + BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 90579612B1A4EF4E391E0626 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + B920DD79982F64FC739571F8 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + C8A57305F206317D5468F600 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + AE52A9CBDBBC66A5CB483F7A /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 90579612B1A4EF4E391E0626 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + AE52A9CBDBBC66A5CB483F7A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C8A57305F206317D5468F600 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = GXXRQJK434; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = GXXRQJK434; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = GXXRQJK434; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..8e3ca5df --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift b/src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..b6363034 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard b/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist b/src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist new file mode 100644 index 00000000..f536cf65 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Flet Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flet_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h b/src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift b/src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/src/serious_python/example/flet_ffi_example/lib/main.dart b/src/serious_python/example/flet_ffi_example/lib/main.dart new file mode 100644 index 00000000..1b3bd755 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/lib/main.dart @@ -0,0 +1,315 @@ +import 'dart:async'; + +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_web_plugins/url_strategy.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart' as path_provider; +import 'package:serious_python/bridge.dart'; +import 'package:serious_python/serious_python.dart'; + +const bool isProduction = bool.fromEnvironment('dart.vm.product'); + +const assetPath = "app/app.zip"; +const pythonModuleName = "main"; +final hideLoadingPage = + bool.tryParse("{{ cookiecutter.hide_loading_animation }}".toLowerCase()) ?? + true; +const errorExitCode = 100; + +/// The Python script is intentionally smaller than in `flet_example`. No +/// stdout-callback socket, no flet.sock — Python startup is just `runpy` +/// on the user module, and stdout/stderr stay attached to whatever the +/// embedded interpreter inherits. The dart_bridge transport in Flet 0.85+ +/// handles IPC directly. +const pythonScript = """ +import logging, os, runpy, sys, traceback + +# Redirect stdout/stderr to a file under FLET_APP_TEMP so we can inspect what +# Python is doing without a separate stdout-callback socket. Temporary — once +# the FFI transport is stable a more proper logging story can land. +_log_path = os.path.join( + os.environ.get("FLET_APP_TEMP", "/tmp"), "flet_ffi_boot.log" +) +_log = open(_log_path, "w", buffering=1) +sys.stdout = _log +sys.stderr = _log +logging.basicConfig(stream=_log, level=logging.DEBUG) +print(f"[boot] python {sys.version}", flush=True) +print(f"[boot] FLET_DART_BRIDGE_PORT={os.environ.get('FLET_DART_BRIDGE_PORT')}", flush=True) +print(f"[boot] FLET_PLATFORM={os.environ.get('FLET_PLATFORM')}", flush=True) + +try: + import certifi + os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() + os.environ["SSL_CERT_FILE"] = certifi.where() + + if os.getenv("FLET_PLATFORM") == "android": + import ssl + + def create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, *, + cafile=None, capath=None, cadata=None, + ): + return ssl.create_default_context( + purpose=purpose, + cafile=certifi.where(), + capath=capath, + cadata=cadata, + ) + + ssl._create_default_https_context = create_default_context +except ImportError as e: + print(f"[boot] certifi import failed: {e}", flush=True) + +print("[boot] about to runpy.run_module", flush=True) +try: + runpy.run_module("{module_name}", run_name="__main__") + print("[boot] runpy.run_module returned", flush=True) +except SystemExit as e: + print(f"[boot] SystemExit: {e.code}", flush=True) + raise +except Exception: + print("[boot] runpy.run_module raised:", flush=True) + traceback.print_exc() + sys.exit($errorExitCode) +"""; + +// global vars +String assetsDir = ""; +String appDir = ""; +late PythonBridge _bridge; +Map environmentVariables = {}; + +void main() async { + if (isProduction) { + // ignore: avoid_returning_null_for_void + debugPrint = (String? message, {int? wrapWidth}) => null; + } + + runApp(FutureBuilder( + future: prepareApp(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return FletApp( + pageUrl: "dartbridge://${_bridge.port}", + assetsDir: assetsDir, + channelBuilder: ({required onMessage, required onDisconnect}) => + _DartBridgeBackendChannel(_bridge, + onMessage: onMessage, onDisconnect: onDisconnect), + ); + } else if (snapshot.hasError) { + return MaterialApp( + home: ErrorScreen( + title: "Error starting app", + text: snapshot.error.toString())); + } else { + return const MaterialApp(home: BlankScreen()); + } + })); +} + +Future prepareApp() async { + if (kIsWeb) { + var routeUrlStrategy = getFletRouteUrlStrategy(); + if (routeUrlStrategy == "path") { + usePathUrlStrategy(); + } + return ""; + } + + await setupDesktop(); + + // Extract app from asset. + appDir = await extractAssetZip(assetPath, checkHash: true); + Directory.current = appDir; + assetsDir = path.join(appDir, "assets"); + + WidgetsFlutterBinding.ensureInitialized(); + var appTempPath = (await path_provider.getApplicationCacheDirectory()).path; + var appDataPath = + (await path_provider.getApplicationDocumentsDirectory()).path; + + if (defaultTargetPlatform != TargetPlatform.iOS && + defaultTargetPlatform != TargetPlatform.android) { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + appDataPath = path.join(appDataPath, "flet", packageInfo.packageName); + if (!await Directory(appDataPath).exists()) { + await Directory(appDataPath).create(recursive: true); + } + } + + // Create the PythonBridge before we hand its port to Python. It outlives + // the FletApp widget; the embedded interpreter only stops when the Flutter + // app exits. + _bridge = PythonBridge(); + + environmentVariables.addAll({ + "FLET_APP_DATA": appDataPath, + "FLET_APP_TEMP": appTempPath, + "FLET_PLATFORM": defaultTargetPlatform.name.toLowerCase(), + // Python reads this env var in flet.app.run_async() and starts the + // dart_bridge transport (added in flet's dart-bridge branch) bound to + // the same port. + "FLET_DART_BRIDGE_PORT": "${_bridge.port}", + }); + + // Fire-and-forget: Python lives for the duration of the app. SeriousPython + // dispatches it on a worker thread (sync=false default), so this returns + // immediately after spawning. + var script = pythonScript.replaceAll('{module_name}', pythonModuleName); + unawaited(SeriousPython.runProgram( + path.join(appDir, "$pythonModuleName.pyc"), + script: script, + environmentVariables: environmentVariables, + )); + + return ""; +} + +/// `FletBackendChannel` implementation backed by a [PythonBridge]. Bytes +/// flow Dart↔Python entirely in-process; no Unix socket, no kernel context +/// switch. The wire format is the same MsgPack-framed protocol the existing +/// socket-based `FletSocketBackendChannel` speaks. +class _DartBridgeBackendChannel implements FletBackendChannel { + _DartBridgeBackendChannel(this._bridge, + {required FletBackendChannelOnMessageCallback onMessage, + required FletBackendChannelOnDisconnectCallback onDisconnect}) + : _onMessage = onMessage, + _onDisconnect = onDisconnect, + _deserializer = + StreamingMsgpackDeserializer(extDecoder: FletMsgpackDecoder()); + + final PythonBridge _bridge; + final FletBackendChannelOnMessageCallback _onMessage; + final FletBackendChannelOnDisconnectCallback _onDisconnect; + final StreamingMsgpackDeserializer _deserializer; + StreamSubscription? _subscription; + + @override + Future connect() async { + _subscription = _bridge.messages.listen( + _onBytes, + onError: (error, stack) { + debugPrint("PythonBridge stream error: $error"); + _onDisconnect(); + }, + onDone: () { + debugPrint("PythonBridge stream closed."); + _onDisconnect(); + }, + cancelOnError: false, + ); + } + + void _onBytes(Uint8List bytes) { + _deserializer.addChunk(bytes); + final frames = _deserializer.decodeMessages(); + for (final frame in frames) { + _onMessage(Message.fromList(frame)); + } + } + + @override + void send(Message message) { + final encoded = Uint8List.fromList( + msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); + // Retry loop covers the brief startup window where Python hasn't yet + // called dart_bridge.set_enqueue_handler_func — bridge.send returns + // false in that case. Once the handler is registered (Flet's app.py + // dart_bridge server start() does it before run_module dispatch), + // bridge.send returns true synchronously. + if (_bridge.send(encoded)) return; + _retrySend(encoded); + } + + void _retrySend(Uint8List encoded) { + const interval = Duration(milliseconds: 50); + const deadline = Duration(seconds: 30); + final start = DateTime.now(); + Timer.periodic(interval, (timer) { + if (_bridge.send(encoded)) { + timer.cancel(); + } else if (DateTime.now().difference(start) > deadline) { + timer.cancel(); + debugPrint("PythonBridge send timed out: Python handler never registered."); + } + }); + } + + @override + bool get isLocalConnection => true; + + @override + int get defaultReconnectIntervalMs => 0; + + @override + void disconnect() { + _subscription?.cancel(); + _subscription = null; + } +} + +class ErrorScreen extends StatelessWidget { + final String title; + final String text; + + const ErrorScreen({super.key, required this.title, required this.text}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Container( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + title, + style: Theme.of(context).textTheme.titleMedium, + ), + TextButton.icon( + onPressed: () { + Clipboard.setData(ClipboardData(text: text)); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Copied to clipboard')), + ); + }, + icon: const Icon( + Icons.copy, + size: 16, + ), + label: const Text("Copy"), + ) + ], + ), + Expanded( + child: SingleChildScrollView( + child: SelectableText(text, + style: Theme.of(context).textTheme.bodySmall), + )) + ], + ), + )), + ); + } +} + +class BlankScreen extends StatelessWidget { + const BlankScreen({super.key}); + + @override + Widget build(BuildContext context) { + return const Scaffold( + body: SizedBox.shrink(), + ); + } +} diff --git a/src/serious_python/example/flet_ffi_example/linux/.gitignore b/src/serious_python/example/flet_ffi_example/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt new file mode 100644 index 00000000..7ef35274 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt @@ -0,0 +1,154 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "flet_example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.flet_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Link bundled libraries from plugins into main executable to enable dlopen +# with only library name. +# Will NOT be needed once: https://github.com/flutter/engine/pull/28525 lands in Flutter channel we are using +# Alternative approach is to update plugin's RUNPATH before packaging: +# chrpath -r \$ORIGIN ./build/linux/arm64/release/bundle/lib/libserious_python_linux_plugin.so +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + if(${plugin}_bundled_libraries) + target_link_libraries( + ${BINARY_NAME} + PRIVATE + ${${plugin}_bundled_libraries} + ) + endif() +endforeach(plugin) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..142e738c --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,35 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) pasteboard_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); + pasteboard_plugin_register_with_registrar(pasteboard_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); + g_autoptr(FlPluginRegistrar) serious_python_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "SeriousPythonLinuxPlugin"); + serious_python_linux_plugin_register_with_registrar(serious_python_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); + g_autoptr(FlPluginRegistrar) window_to_front_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin"); + window_to_front_plugin_register_with_registrar(window_to_front_registrar); +} diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..7d9bc28c --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,30 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + pasteboard + screen_retriever_linux + serious_python_linux + url_launcher_linux + window_manager + window_to_front +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/src/serious_python/example/flet_ffi_example/linux/main.cc b/src/serious_python/example/flet_ffi_example/linux/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/src/serious_python/example/flet_ffi_example/linux/my_application.cc b/src/serious_python/example/flet_ffi_example/linux/my_application.cc new file mode 100644 index 00000000..7f876fab --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "flet_example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "flet_example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/src/serious_python/example/flet_ffi_example/linux/my_application.h b/src/serious_python/example/flet_ffi_example/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/src/serious_python/example/flet_ffi_example/macos/.gitignore b/src/serious_python/example/flet_ffi_example/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..6d5caa62 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,40 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import battery_plus +import connectivity_plus +import device_info_plus +import file_picker +import package_info_plus +import pasteboard +import screen_brightness_macos +import screen_retriever_macos +import serious_python_darwin +import share_plus +import shared_preferences_foundation +import url_launcher_macos +import wakelock_plus +import window_manager +import window_to_front + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin")) + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) + ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) + ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) + SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) + WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) + WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) +} diff --git a/src/serious_python/example/flet_ffi_example/macos/Podfile b/src/serious_python/example/flet_ffi_example/macos/Podfile new file mode 100644 index 00000000..b52666a1 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/src/serious_python/example/flet_ffi_example/macos/Podfile.lock b/src/serious_python/example/flet_ffi_example/macos/Podfile.lock new file mode 100644 index 00000000..c631f6e1 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Podfile.lock @@ -0,0 +1,108 @@ +PODS: + - battery_plus (0.0.1): + - FlutterMacOS + - connectivity_plus (0.0.1): + - FlutterMacOS + - device_info_plus (0.0.1): + - FlutterMacOS + - file_picker (0.0.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - package_info_plus (0.0.1): + - FlutterMacOS + - pasteboard (0.0.1): + - FlutterMacOS + - screen_brightness_macos (0.1.0): + - FlutterMacOS + - screen_retriever_macos (0.0.1): + - FlutterMacOS + - serious_python_darwin (2.0.0): + - Flutter + - FlutterMacOS + - share_plus (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS + - window_manager (0.5.0): + - FlutterMacOS + - window_to_front (0.0.4): + - FlutterMacOS + +DEPENDENCIES: + - battery_plus (from `Flutter/ephemeral/.symlinks/plugins/battery_plus/macos`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) + - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) + - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) + - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) + - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + - window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`) + +EXTERNAL SOURCES: + battery_plus: + :path: Flutter/ephemeral/.symlinks/plugins/battery_plus/macos + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + file_picker: + :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos + FlutterMacOS: + :path: Flutter/ephemeral + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + pasteboard: + :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos + screen_brightness_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos + screen_retriever_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos + serious_python_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos + window_manager: + :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + window_to_front: + :path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos + +SPEC CHECKSUMS: + battery_plus: f51ad29136e025b714b96f7d096f44f604615da7 + connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e + device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 + file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 + screen_brightness_macos: 1058c18b5e0570f48f93016487a5ed66d6977fe0 + screen_retriever_macos: c5508cc3c66ff0d4db650480cf0ab691e220d933 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 + share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd + wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b + window_manager: b729e31d38fb04905235df9ea896128991cad99e + window_to_front: 2d7d31f268d0b13b7e63b26e31eb0a2e9612239e + +PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 + +COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..319e1e69 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,809 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 256EF705489316F00EF3962A /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 99AFA56BC7E7B7480D345FDA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 11E10455E245EB5F22EB7A9A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* flet_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flet_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + B126920E3C82A726215E0DE6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + F080949AB83300EBF0AAA1E4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 256EF705489316F00EF3962A /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 99AFA56BC7E7B7480D345FDA /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2FD1AA06884986EE36A305B7 /* Pods */ = { + isa = PBXGroup; + children = ( + 11E10455E245EB5F22EB7A9A /* Pods-Runner.debug.xcconfig */, + F080949AB83300EBF0AAA1E4 /* Pods-Runner.release.xcconfig */, + B126920E3C82A726215E0DE6 /* Pods-Runner.profile.xcconfig */, + 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */, + 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */, + FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 2FD1AA06884986EE36A305B7 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* flet_example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */, + 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 8F5527630CCCD1FAF8A7F717 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */, + 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* flet_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8F5527630CCCD1FAF8A7F717 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flet_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flet_example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flet_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flet_example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flet_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flet_example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..410c6419 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift b/src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..2cadea52 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = flet_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements b/src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..9f56413f --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist b/src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift b/src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements b/src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..e89b7f32 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift b/src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..5418c9f5 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/src/serious_python/example/flet_ffi_example/pubspec.lock b/src/serious_python/example/flet_ffi_example/pubspec.lock new file mode 100644 index 00000000..427dbdd5 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/pubspec.lock @@ -0,0 +1,1201 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + url: "https://pub.dev" + source: hosted + version: "4.0.9" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + battery_plus: + dependency: transitive + description: + name: battery_plus + sha256: ad16fcb55b7384be6b4bbc763d5e2031ac7ea62b2d9b6b661490c7b9741155bf + url: "https://pub.dev" + source: hosted + version: "7.0.0" + battery_plus_platform_interface: + dependency: transitive + description: + name: battery_plus_platform_interface + sha256: e8342c0f32de4b1dfd0223114b6785e48e579bfc398da9471c9179b907fa4910 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: "62ffa266d9a23b79fb3fcbc206afc00bb979417ba57b1324c546b5aab95ba057" + url: "https://pub.dev" + source: hosted + version: "7.1.1" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "3c09627c536d22fd24691a905cdd8b14520de69da52c7a97499c8be5284a32ed" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" + url: "https://pub.dev" + source: hosted + version: "0.3.5+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd + url: "https://pub.dev" + source: hosted + version: "12.4.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f + url: "https://pub.dev" + source: hosted + version: "7.0.3" + equatable: + dependency: transitive + description: + name: equatable + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" + url: "https://pub.dev" + source: hosted + version: "2.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_picker: + dependency: transitive + description: + name: file_picker + sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343" + url: "https://pub.dev" + source: hosted + version: "10.3.10" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flet: + dependency: "direct main" + description: + path: "packages/flet" + ref: dart-bridge + resolved-ref: "33b3b972373fb3f268fe7acc84876b87dbb9a31c" + url: "https://github.com/flet-dev/flet.git" + source: git + version: "0.85.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_highlight: + dependency: transitive + description: + name: flutter_highlight + sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_markdown_plus: + dependency: transitive + description: + name: flutter_markdown_plus + sha256: "039177906850278e8fb1cd364115ee0a46281135932fa8ecea8455522166d2de" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + flutter_markdown_plus_latex: + dependency: transitive + description: + name: flutter_markdown_plus_latex + sha256: "2e7698b291f0657ca445efab730bb25a8c5851037e882cb7bf47d16a5c218de7" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + flutter_math_fork: + dependency: transitive + description: + name: flutter_math_fork + sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407" + url: "https://pub.dev" + source: hosted + version: "0.7.4" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" + url: "https://pub.dev" + source: hosted + version: "2.0.35" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + highlight: + dependency: transitive + description: + name: highlight + sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + hooks: + dependency: transitive + description: + name: hooks + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + intl: + dependency: transitive + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" + url: "https://pub.dev" + source: hosted + version: "4.12.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 + url: "https://pub.dev" + source: hosted + version: "7.3.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + url: "https://pub.dev" + source: hosted + version: "0.12.19" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + msgpack_dart: + dependency: "direct main" + description: + name: msgpack_dart + sha256: c2d235ed01f364719b5296aecf43ac330f0d7bc865fa134d0d7910a40454dffb + url: "https://pub.dev" + source: hosted + version: "1.0.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" + url: "https://pub.dev" + source: hosted + version: "9.4.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20" + url: "https://pub.dev" + source: hosted + version: "9.0.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + pasteboard: + dependency: transitive + description: + name: pasteboard + sha256: "9ff73ada33f79a59ff91f6c01881fd4ed0a0031cfc4ae2d86c0384471525fca1" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + path: + dependency: "direct main" + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.dev" + source: hosted + version: "6.5.0" + process: + dependency: transitive + description: + name: process + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + url: "https://pub.dev" + source: hosted + version: "5.0.5" + provider: + dependency: transitive + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + screen_brightness: + dependency: transitive + description: + name: screen_brightness + sha256: "7ea1c037422f007f022dcff3ee955bf8e61a474d5426b29be9290fd976c3e46b" + url: "https://pub.dev" + source: hosted + version: "2.1.9" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "0e4b0a07d5f730b91a8780d8436f3a92be8a8cc2066032ed88b93c8fa153fadf" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: "0792d8f98852558f831b4b75241c46047b884598b3f4d982b37dc2dd43e2b2e1" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "278712cf5288db57bd335968cbfb2ec5441028f1ee2fcbdc8d1582d8210a3442" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + screen_brightness_ohos: + dependency: transitive + description: + name: screen_brightness_ohos + sha256: "33f495741d5aa53104d3f5875dcb4b6a119f29ef595be17129ee03a5b78e76a9" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: "59d50850d6735d677780fc7359c8e997d0ff6df91c8465161c9e617a7b0a11d8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + screen_brightness_windows: + dependency: transitive + description: + name: screen_brightness_windows + sha256: "121f9dd6d62585bfb4e468c2170804ce4f2a2303ae6b2efc3a065c94937505d7" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + screen_retriever: + dependency: transitive + description: + name: screen_retriever + sha256: "42cc3b402a0f67d2455a0d067553d0f13453f6a008d98eababf8b63958d506bd" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + screen_retriever_linux: + dependency: transitive + description: + name: screen_retriever_linux + sha256: "2a476f1a5538065bc5badf376cfdc83d6ecf07d77eb2391b9c2bff5a76970048" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + screen_retriever_macos: + dependency: transitive + description: + name: screen_retriever_macos + sha256: b5abb900fcb86614ff10b738b34e37b9e1d03b0447280668e2bc8a98bdc7bd59 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + screen_retriever_platform_interface: + dependency: transitive + description: + name: screen_retriever_platform_interface + sha256: "3af22d926bedf20c2caa308eea376776451a3af125919ce072e56525fded8901" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + screen_retriever_windows: + dependency: transitive + description: + name: screen_retriever_windows + sha256: c44b38a4c4bab34af259180a70a4eee1e29384e7b82e627c9faa68afcdab2e73 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + screenshot: + dependency: transitive + description: + name: screenshot + sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + sensors_plus: + dependency: transitive + description: + name: sensors_plus + sha256: "56e8cd4260d9ed8e00ecd8da5d9fdc8a1b2ec12345a750dfa51ff83fcf12e3fa" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sensors_plus_platform_interface: + dependency: transitive + description: + name: sensors_plus_platform_interface + sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + serious_python: + dependency: "direct main" + description: + path: "../.." + relative: true + source: path + version: "2.0.0" + serious_python_android: + dependency: transitive + description: + path: "../../../serious_python_android" + relative: true + source: path + version: "2.0.0" + serious_python_darwin: + dependency: transitive + description: + path: "../../../serious_python_darwin" + relative: true + source: path + version: "2.0.0" + serious_python_linux: + dependency: transitive + description: + path: "../../../serious_python_linux" + relative: true + source: path + version: "2.0.0" + serious_python_platform_interface: + dependency: transitive + description: + path: "../../../serious_python_platform_interface" + relative: true + source: path + version: "2.0.0" + serious_python_windows: + dependency: transitive + description: + path: "../../../serious_python_windows" + relative: true + source: path + version: "2.0.0" + share_plus: + dependency: transitive + description: + name: share_plus + sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa" + url: "https://pub.dev" + source: hosted + version: "12.0.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf + url: "https://pub.dev" + source: hosted + version: "2.5.5" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + url: "https://pub.dev" + source: hosted + version: "2.4.23" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shimmer: + dependency: transitive + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + toml: + dependency: transitive + description: + name: toml + sha256: "9968de24e45b632bf1a654fe1ac7b6fe5261c349243df83fd262397799c45a2d" + url: "https://pub.dev" + source: hosted + version: "0.15.0" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + upower: + dependency: transitive + description: + name: upower + sha256: cf042403154751180affa1d15614db7fa50234bc2373cd21c3db666c38543ebf + url: "https://pub.dev" + source: hosted + version: "0.7.0" + url_launcher: + dependency: transitive + description: + name: url_launcher + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" + url: "https://pub.dev" + source: hosted + version: "6.3.30" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + url: "https://pub.dev" + source: hosted + version: "3.2.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" + url: "https://pub.dev" + source: hosted + version: "2.4.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "7ee12e6dffe0fc8e755179d6d91b3b34f5924223fc104d85572ef9180d73d172" + url: "https://pub.dev" + source: hosted + version: "1.2.5" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" + url: "https://pub.dev" + source: hosted + version: "15.2.0" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: ddf3db70eaa10c37558ff817519b85d527dbd21034fd5d8e1c2e85f31588f1c1 + url: "https://pub.dev" + source: hosted + version: "1.5.2" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b + url: "https://pub.dev" + source: hosted + version: "1.5.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + window_manager: + dependency: transitive + description: + name: window_manager + sha256: "7eb6d6c4164ec08e1bf978d6e733f3cebe792e2a23fb07cbca25c2872bfdbdcd" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + window_to_front: + dependency: transitive + description: + name: window_to_front + sha256: "14fad8984db4415e2eeb30b04bb77140b180e260d6cb66b26de126a8657a9241" + url: "https://pub.dev" + source: hosted + version: "0.0.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" diff --git a/src/serious_python/example/flet_ffi_example/pubspec.yaml b/src/serious_python/example/flet_ffi_example/pubspec.yaml new file mode 100644 index 00000000..c6f51e1b --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/pubspec.yaml @@ -0,0 +1,81 @@ +name: flet_ffi_example +description: Flet counter example exercising the in-process dart_bridge transport (instead of the Unix socket). +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ">=3.0.3 <4.0.0" + flutter: ">=3.7.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + + serious_python: + path: ../../ + + flet: + git: + url: https://github.com/flet-dev/flet.git + ref: dart-bridge + path: packages/flet + + path: ^1.8.3 + path_provider: ^2.1.4 + package_info_plus: ^9.0.0 + # msgpack_dart is the wire format Flet uses. _DartBridgeBackendChannel + # (in lib/main.dart) encodes outbound frames before handing them to + # PythonBridge.send. + msgpack_dart: ^1.0.1 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + integration_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + uses-material-design: true + + assets: + - app/app.zip + - app/app.zip.hash \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/test/widget_test.dart b/src/serious_python/example/flet_ffi_example/test/widget_test.dart new file mode 100644 index 00000000..49c1e76c --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/test/widget_test.dart @@ -0,0 +1,10 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +void main() { + // todo +} diff --git a/src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart b/src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/src/serious_python/example/flet_ffi_example/web/favicon.png b/src/serious_python/example/flet_ffi_example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-192.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-512.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-192.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-512.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 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 MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/web/index.html b/src/serious_python/example/flet_ffi_example/web/index.html new file mode 100644 index 00000000..41f4ced7 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + flet_example + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/web/manifest.json b/src/serious_python/example/flet_ffi_example/web/manifest.json new file mode 100644 index 00000000..58b0e920 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "flet_example", + "short_name": "flet_example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/src/serious_python/example/flet_ffi_example/windows/.gitignore b/src/serious_python/example/flet_ffi_example/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt new file mode 100644 index 00000000..cee1b1bd --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt @@ -0,0 +1,102 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(flet_example LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "flet_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..5280993c --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,41 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + BatteryPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + PasteboardPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PasteboardPlugin")); + ScreenBrightnessWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); + ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); + SeriousPythonWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SeriousPythonWindowsPluginCApi")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); + WindowManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowManagerPlugin")); + WindowToFrontPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowToFrontPlugin")); +} diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..ec8b95fd --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,34 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + battery_plus + connectivity_plus + pasteboard + screen_brightness_windows + screen_retriever_windows + serious_python_windows + share_plus + url_launcher_windows + window_manager + window_to_front +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc b/src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc new file mode 100644 index 00000000..320618d6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "flet_example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "flet_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "flet_example.exe" "\0" + VALUE "ProductName", "flet_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h b/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/main.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/main.cpp new file mode 100644 index 00000000..ea917ad4 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"flet_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/resource.h b/src/serious_python/example/flet_ffi_example/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/resources/app_icon.ico b/src/serious_python/example/flet_ffi_example/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 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 literal 0 HcmV?d00001 diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest b/src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..a42ea768 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp new file mode 100644 index 00000000..b2b08734 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/utils.h b/src/serious_python/example/flet_ffi_example/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h b/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ From d58f22f3819a4f8a1e73a68b87660c7ff281bdde Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 10 Jun 2026 21:24:08 -0700 Subject: [PATCH 076/114] ci: add flet_ffi_example matrix; gate other apps off for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds 5 jobs covering macOS×3, iOS×1, Android×1, Windows×3, Linux×6 (amd64+arm64). Same shape as the flet_example matrix; difference is: --requirements "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" plus SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet so pip's --only-binary :all: on mobile targets accepts the git source. The requirement is parameterised via FLET_FFI_REQUIREMENT in the top-level env block. The existing flet_example and bridge_example matrices are flipped to `if: false` while the dart_bridge transport stabilises — single-app CI is faster to iterate on. Flip them back on before merging the flet PR to confirm the socket transport still works end-to-end. --- .github/workflows/ci.yml | 244 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f17abf8..7a694ecf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,11 +24,20 @@ env: # older flet whose transitive deps (e.g. msgpack) have wheels for the # target python_version / platform, leaving the two halves mismatched. FLET_VERSION: "0.85.3" + # Python flet for the FFI-transport example is pulled from a git ref — + # FletDartBridgeServer isn't on PyPI yet. Source installs require + # SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet on mobile targets to + # bypass --only-binary :all:; see package_command.dart. + FLET_FFI_REQUIREMENT: "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" jobs: macos: name: Test Flet example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 + # Temporarily disabled — focusing CI on flet_ffi_example while the + # dart_bridge transport stabilises. Flip back on before merging the + # flet PR to confirm the socket transport still works. + if: false strategy: fail-fast: false matrix: @@ -54,6 +63,7 @@ jobs: ios: name: Test Flet example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -94,6 +104,7 @@ jobs: android: name: Test Flet example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -153,6 +164,7 @@ jobs: windows: name: Test Flet example on Windows (Python ${{ matrix.python_version }}) runs-on: windows-latest + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -178,6 +190,7 @@ jobs: linux: name: Test Flet example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -250,9 +263,236 @@ jobs: dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flet_ffi_macos: + name: Test Flet FFI example on macOS (Python ${{ matrix.python_version }}) + runs-on: macos-26 + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Run tests + working-directory: "src/serious_python/example/flet_ffi_example" + run: | + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + + flet_ffi_ios: + name: Test Flet FFI example on iOS (Python ${{ matrix.python_version }}) + runs-on: macos-26 + strategy: + fail-fast: false + matrix: + # 3.13/3.14 gated on msgpack iOS arm64 wheels landing on pypi.flet.dev + # — see the flet_example ios job for the same rationale. + python_version: ['3.12'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Setup iOS Simulator + id: simulator + uses: futureware-tech/simulator-action@v4 + with: + model: 'iPhone 17 Pro Max' + os: "iOS" + os_version: "26.5" + shutdown_after_job: true + wait_for_boot: true + + - name: Run tests + working-directory: "src/serious_python/example/flet_ffi_example" + run: | + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + + flet_ffi_android: + name: Test Flet FFI example on Android (Python ${{ matrix.python_version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12'] # see ios job for the 3.13/3.14 gate + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Gradle cache + uses: gradle/actions/setup-gradle@v3 + + - name: AVD cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-ffi + + - name: Setup Android Emulator + Run tests + uses: reactivecircus/android-emulator-runner@v2 + env: + EMULATOR_PORT: 5554 + with: + avd-name: android_emulator + api-level: 33 + target: google_atd + arch: x86_64 + profile: pixel_5 + sdcard-path-or-size: 128M + ram-size: 2048M + disk-size: 4096M + emulator-port: ${{ env.EMULATOR_PORT }} + disable-animations: true + emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 + pre-emulator-launch-script: | + sdkmanager --list_installed + script: | + cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + cd src/serious_python/example/flet_ffi_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + + flet_ffi_windows: + name: Test Flet FFI example on Windows (Python ${{ matrix.python_version }}) + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Run tests + working-directory: "src/serious_python/example/flet_ffi_example" + run: | + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + + flet_ffi_linux: + name: Test Flet FFI example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + python_version: ['3.12', '3.13', '3.14'] + arch: [arm64, amd64] + include: + - arch: arm64 + runner: ubuntu-24.04-arm + title: ARM64 + - arch: amd64 + runner: ubuntu-24.04 + title: AMD64 + env: + SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} + SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Get Flutter version from ".fvmrc" + uses: kuhnroyal/flutter-fvm-config-action/config@v3 + id: fvm-config-action + with: + path: '.fvmrc' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} + cache: true + + - name: Install dependencies + run: | + sudo apt-get update --allow-releaseinfo-change + sudo apt-get install -y xvfb libgtk-3-dev + + if [ "${{ matrix.arch }}" = "amd64" ]; then + sudo apt-get install -y \ + libgstreamer1.0-dev \ + libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev \ + gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly \ + gstreamer1.0-libav \ + gstreamer1.0-tools \ + gstreamer1.0-x \ + gstreamer1.0-alsa \ + gstreamer1.0-gl \ + gstreamer1.0-gtk3 \ + gstreamer1.0-qt5 \ + gstreamer1.0-pulseaudio + else + sudo apt-get install -y \ + clang \ + ninja-build \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly \ + gstreamer1.0-libav + fi + + - name: Run tests + working-directory: src/serious_python/example/flet_ffi_example + run: | + flutter pub get + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + bridge_example_macos: name: Test Bridge example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -279,6 +519,7 @@ jobs: name: Test Bridge example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 timeout-minutes: 25 + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -333,6 +574,7 @@ jobs: bridge_example_android: name: Test Bridge example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -412,6 +654,7 @@ jobs: bridge_example_windows: name: Test Bridge example on Windows (Python ${{ matrix.python_version }}) runs-on: windows-latest + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -461,6 +704,7 @@ jobs: bridge_example_linux: name: Test Bridge example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} + if: false # see `macos:` for rationale strategy: fail-fast: false matrix: From 5137fd0f5f8bbb030fa6218e66956a72546acbf0 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 06:17:29 -0700 Subject: [PATCH 077/114] ci: pre-clone flet shallowly; surface package-command progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes to debug the Windows hang from run 27323701393 — Windows jobs sat for 40min without log output after "Extracting Python distributive". package_command.dart: explicitly log "Python distributive extracted to …" once tar finishes, and log the python.exe invocation that follows (previously gated behind --verbose). With these, a silent pip git clone won't look like a hang any more. ci.yml: each flet_ffi_* job now does an explicit `git clone --depth 1 --branch dart-bridge https://github.com/flet-dev/flet.git` into runner.temp and passes the local sdk/python/packages/flet path as --requirements. This bypasses pip's git source install path — pip's internal git clone has no progress output and on Windows is the most plausible source of the 40-minute black hole. Also temporarily gating off the macOS/iOS/Android/Linux FFI jobs so the next CI run focuses on Windows debugging only. Re-enable once Windows goes green. --- .github/workflows/ci.yml | 53 +++++++++++++++++---- src/serious_python/bin/package_command.dart | 7 ++- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a694ecf..2ff037ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,11 +24,17 @@ env: # older flet whose transitive deps (e.g. msgpack) have wheels for the # target python_version / platform, leaving the two halves mismatched. FLET_VERSION: "0.85.3" - # Python flet for the FFI-transport example is pulled from a git ref — - # FletDartBridgeServer isn't on PyPI yet. Source installs require - # SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet on mobile targets to - # bypass --only-binary :all:; see package_command.dart. - FLET_FFI_REQUIREMENT: "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" + # Python flet for the FFI-transport example is pinned to a git ref — + # FletDartBridgeServer isn't on PyPI yet. The git URL is given to pip via + # --requirements, which would normally clone the whole flet repo (large) + # inside pip itself. On Windows this can take 30+ minutes and looks like + # a hang because pip emits no progress during git clone. So the FFI jobs + # first do an explicit `git clone --depth 1` into ${{ runner.temp }}/flet + # and then pass the local subpath as the requirement. + FLET_GIT_REF: "dart-bridge" + FLET_GIT_URL: "https://github.com/flet-dev/flet.git" + # Source installs additionally require SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet + # on mobile targets to bypass --only-binary :all:; see package_command.dart. jobs: macos: @@ -266,6 +272,8 @@ jobs: flet_ffi_macos: name: Test Flet FFI example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 + # Temporarily gated off while we debug the Windows hang — re-enable after. + if: false strategy: fail-fast: false matrix: @@ -283,15 +291,20 @@ jobs: path: '.fvmrc' cache: true + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_ios: name: Test Flet FFI example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 + if: false # see `flet_ffi_macos:` rationale strategy: fail-fast: false matrix: @@ -321,15 +334,20 @@ jobs: shutdown_after_job: true wait_for_boot: true + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_android: name: Test Flet FFI example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest + if: false # see `flet_ffi_macos:` rationale strategy: fail-fast: false matrix: @@ -365,6 +383,10 @@ jobs: ~/.android/adb* key: avd-ffi + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Setup Android Emulator + Run tests uses: reactivecircus/android-emulator-runner@v2 env: @@ -384,7 +406,7 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" cd src/serious_python/example/flet_ffi_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_windows: @@ -407,15 +429,22 @@ jobs: path: '.fvmrc' cache: true + - name: Shallow-clone flet (dart-bridge) + shell: bash + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${RUNNER_TEMP}/flet-src" + - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" + shell: bash run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${RUNNER_TEMP}/flet-src/sdk/python/packages/flet" flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_linux: name: Test Flet FFI example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} + if: false # see `flet_ffi_macos:` rationale strategy: fail-fast: false matrix: @@ -482,11 +511,15 @@ jobs: gstreamer1.0-libav fi + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Run tests working-directory: src/serious_python/example/flet_ffi_example run: | flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index b21541b8..9d47b83c 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -727,6 +727,8 @@ class PackageCommand extends Command { await Process.run( 'tar', ['-xzf', pythonArchivePath, '-C', _pythonDir!.path]); + stdout.writeln("Python distributive extracted to ${_pythonDir!.path}"); + if (Platform.isMacOS) { duplicateSysconfigFile(_pythonDir!.path); } @@ -737,8 +739,9 @@ class PackageCommand extends Command { ? path.join(_pythonDir!.path, 'python', 'python.exe') : path.join(_pythonDir!.path, 'python', 'bin', 'python3'); - // Run the python executable - verbose([pythonExePath, ...args].join(" ")); + // Always log the Python command so a silent pip install (typical during + // `pip install git+…` while git is cloning) doesn't look like a hang. + stdout.writeln("Running: ${[pythonExePath, ...args].join(" ")}"); return await runExec(pythonExePath, args, environment: environment); } From ce5942df2924568fcf289f710cf47d81050b4352 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 06:27:20 -0700 Subject: [PATCH 078/114] ci: drop the shallow-clone workaround, pip git source install was fine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yesterday's 40-minute Windows hang reproduced on retry but resolved on today's runner — likely Windows VM flakiness, not a deterministic problem with pip's git source install. Today the package_command logged "Python distributive extracted to …" within a second, so the extraction step was fine all along. Reverting the explicit `git clone --depth 1` step in each flet_ffi_* job and restoring the FLET_FFI_REQUIREMENT env var. Keeping the package_command.dart progress lines from the previous commit — they made it obvious what was happening this time around. The macOS/iOS/Android/Linux FFI jobs stay gated off; flipping those back on once Windows confirms green with the simpler config. --- .github/workflows/ci.yml | 48 +++++++++------------------------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ff037ce..7abe73c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,17 +24,11 @@ env: # older flet whose transitive deps (e.g. msgpack) have wheels for the # target python_version / platform, leaving the two halves mismatched. FLET_VERSION: "0.85.3" - # Python flet for the FFI-transport example is pinned to a git ref — - # FletDartBridgeServer isn't on PyPI yet. The git URL is given to pip via - # --requirements, which would normally clone the whole flet repo (large) - # inside pip itself. On Windows this can take 30+ minutes and looks like - # a hang because pip emits no progress during git clone. So the FFI jobs - # first do an explicit `git clone --depth 1` into ${{ runner.temp }}/flet - # and then pass the local subpath as the requirement. - FLET_GIT_REF: "dart-bridge" - FLET_GIT_URL: "https://github.com/flet-dev/flet.git" - # Source installs additionally require SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet - # on mobile targets to bypass --only-binary :all:; see package_command.dart. + # Python flet for the FFI-transport example is pulled from a git ref — + # FletDartBridgeServer isn't on PyPI yet. Source installs require + # SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet on mobile targets to + # bypass --only-binary :all:; see package_command.dart. + FLET_FFI_REQUIREMENT: "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" jobs: macos: @@ -291,14 +285,10 @@ jobs: path: '.fvmrc' cache: true - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_ios: @@ -334,14 +324,10 @@ jobs: shutdown_after_job: true wait_for_boot: true - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_android: @@ -383,10 +369,6 @@ jobs: ~/.android/adb* key: avd-ffi - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - name: Setup Android Emulator + Run tests uses: reactivecircus/android-emulator-runner@v2 env: @@ -406,7 +388,7 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" + cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" cd src/serious_python/example/flet_ffi_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_windows: @@ -429,16 +411,10 @@ jobs: path: '.fvmrc' cache: true - - name: Shallow-clone flet (dart-bridge) - shell: bash - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${RUNNER_TEMP}/flet-src" - - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" - shell: bash run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${RUNNER_TEMP}/flet-src/sdk/python/packages/flet" + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_linux: @@ -511,15 +487,11 @@ jobs: gstreamer1.0-libav fi - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - name: Run tests working-directory: src/serious_python/example/flet_ffi_example run: | flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: From 0ee751d5ee898ffe6dd799cba25028f1f20b2377 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 06:38:28 -0700 Subject: [PATCH 079/114] Revert "ci: drop the shallow-clone workaround, pip git source install was fine" This reverts commit ce5942df2924568fcf289f710cf47d81050b4352. --- .github/workflows/ci.yml | 48 +++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7abe73c4..2ff037ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,11 +24,17 @@ env: # older flet whose transitive deps (e.g. msgpack) have wheels for the # target python_version / platform, leaving the two halves mismatched. FLET_VERSION: "0.85.3" - # Python flet for the FFI-transport example is pulled from a git ref — - # FletDartBridgeServer isn't on PyPI yet. Source installs require - # SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet on mobile targets to - # bypass --only-binary :all:; see package_command.dart. - FLET_FFI_REQUIREMENT: "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" + # Python flet for the FFI-transport example is pinned to a git ref — + # FletDartBridgeServer isn't on PyPI yet. The git URL is given to pip via + # --requirements, which would normally clone the whole flet repo (large) + # inside pip itself. On Windows this can take 30+ minutes and looks like + # a hang because pip emits no progress during git clone. So the FFI jobs + # first do an explicit `git clone --depth 1` into ${{ runner.temp }}/flet + # and then pass the local subpath as the requirement. + FLET_GIT_REF: "dart-bridge" + FLET_GIT_URL: "https://github.com/flet-dev/flet.git" + # Source installs additionally require SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet + # on mobile targets to bypass --only-binary :all:; see package_command.dart. jobs: macos: @@ -285,10 +291,14 @@ jobs: path: '.fvmrc' cache: true + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_ios: @@ -324,10 +334,14 @@ jobs: shutdown_after_job: true wait_for_boot: true + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_android: @@ -369,6 +383,10 @@ jobs: ~/.android/adb* key: avd-ffi + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Setup Android Emulator + Run tests uses: reactivecircus/android-emulator-runner@v2 env: @@ -388,7 +406,7 @@ jobs: pre-emulator-launch-script: | sdkmanager --list_installed script: | - cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" cd src/serious_python/example/flet_ffi_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_windows: @@ -411,10 +429,16 @@ jobs: path: '.fvmrc' cache: true + - name: Shallow-clone flet (dart-bridge) + shell: bash + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${RUNNER_TEMP}/flet-src" + - name: Run tests working-directory: "src/serious_python/example/flet_ffi_example" + shell: bash run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${RUNNER_TEMP}/flet-src/sdk/python/packages/flet" flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} flet_ffi_linux: @@ -487,11 +511,15 @@ jobs: gstreamer1.0-libav fi + - name: Shallow-clone flet (dart-bridge) + run: | + git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" + - name: Run tests working-directory: src/serious_python/example/flet_ffi_example run: | flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ env.FLET_FFI_REQUIREMENT }}" + dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_macos: From a3ce583169a94a3a8cbbecc9d258cbd6aff36b84 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 06:40:11 -0700 Subject: [PATCH 080/114] ci: expand iOS/Android matrices to 3.12+3.13+3.14 msgpack 1.x wheels for iOS arm64 and Android Python 3.13/3.14 are now on pypi.flet.dev, so pip's `--only-binary :all:` no longer silently downgrades flet on those targets. Expand the four 3.12-gated matrices (flet_example ios/android, flet_ffi_example ios/android) to the full Python range. --- .github/workflows/ci.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ff037ce..7721567c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,11 +73,7 @@ jobs: strategy: fail-fast: false matrix: - # 3.13/3.14 disabled until msgpack 1.x ships iOS arm64 wheels for - # those Python versions on pypi.flet.dev — with `--only-binary :all:` - # pip otherwise silently downgrades flet to an older version, - # leaving Python/Dart out of sync. - python_version: ['3.12'] + python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -114,7 +110,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12'] # see ios job for the 3.13/3.14 gate + python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: @@ -308,9 +304,7 @@ jobs: strategy: fail-fast: false matrix: - # 3.13/3.14 gated on msgpack iOS arm64 wheels landing on pypi.flet.dev - # — see the flet_example ios job for the same rationale. - python_version: ['3.12'] + python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet @@ -351,7 +345,7 @@ jobs: strategy: fail-fast: false matrix: - python_version: ['3.12'] # see ios job for the 3.13/3.14 gate + python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet From 1dd6ae90c96438b5f81de91213b1a952d8d258a5 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 06:52:48 -0700 Subject: [PATCH 081/114] ci: un-gate flet_ffi_macos/ios/android/linux now that Windows is green MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 27350959373: all 3 flet_ffi_windows jobs passed in 4-7 minutes with the shallow-clone in place. Lifting the if: false on the other flet_ffi_* matrices so the full FFI surface (macOS×3, iOS×3, Android×3, Windows×3, Linux×6) runs going forward. The legacy flet_example and bridge_example matrices stay gated off until we're confident the FFI transport is stable end-to-end; flip those back on before tagging. --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7721567c..880f690f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -268,8 +268,6 @@ jobs: flet_ffi_macos: name: Test Flet FFI example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 - # Temporarily gated off while we debug the Windows hang — re-enable after. - if: false strategy: fail-fast: false matrix: @@ -300,7 +298,6 @@ jobs: flet_ffi_ios: name: Test Flet FFI example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 - if: false # see `flet_ffi_macos:` rationale strategy: fail-fast: false matrix: @@ -341,7 +338,6 @@ jobs: flet_ffi_android: name: Test Flet FFI example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest - if: false # see `flet_ffi_macos:` rationale strategy: fail-fast: false matrix: @@ -438,7 +434,6 @@ jobs: flet_ffi_linux: name: Test Flet FFI example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} - if: false # see `flet_ffi_macos:` rationale strategy: fail-fast: false matrix: From 6a87c5e091f7d108aab98143a0aef9003c485a35 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 08:04:34 -0700 Subject: [PATCH 082/114] cache downloads in ~/.flet/cache (FLET_CACHE_DIR) across all plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Dart packager, Darwin scripts, Windows CMake, and Linux CMake all used to download GitHub Release artifacts into ephemeral build trees (example/build/, CMAKE_BINARY_DIR/, …) — a `flutter clean` or CI runner restart cost ~300 MB of redownload every time. Android already had the right pattern: FLET_CACHE_DIR (default ~/.flet/cache) with versioned subdirs python-build/v/ and dart-bridge/v/. Lifted it. Layout (all five plugins consume the same root): $FLET_CACHE_DIR/ # default ~/.flet/cache python-build/v/ # flet-dev/python-build releases python-build-standalone// # astral-sh tarball used by packager dart-bridge/v/ # flet-dev/dart-bridge prebuilts Every site: * resolves FLET_CACHE_DIR with a HOME/USERPROFILE fallback, * downloads with a .tmp + rename to avoid poisoning on Ctrl-C, * skips the download iff the cached file exists, * extracts into its own build/dist tree on every run (cheap; network is what we're saving). CI: replaced the lone dist_ios cache with a unified actions/cache@v4 ~/.flet/cache step in every flet_ffi_* job. Key composes runner.os, runner.arch, matrix.python_version, and hashFiles() over the six version-pinning sources, so any pin bump invalidates automatically. Two restore-keys rows allow partial recovery on pin-only and on brand-new matrix entries. Verified locally on macOS: ~/.flet/cache populated with python-build-standalone/20260602/, python-build/v3.14/, and dart-bridge/v1.2.1/ subdirs on a cold run. (Full integration test rerun deferred to CI — local lipo wedge on a partial .app build that's unrelated to the cache changes.) --- .github/workflows/ci.yml | 58 ++++++++++++++--- src/serious_python/bin/package_command.dart | 29 ++++++++- .../darwin/prepare_ios.sh | 45 ++++++++----- .../darwin/prepare_macos.sh | 46 +++++++++---- src/serious_python_linux/linux/CMakeLists.txt | 65 +++++++++++++------ .../windows/CMakeLists.txt | 57 +++++++++++----- 6 files changed, 221 insertions(+), 79 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 880f690f..2c7cc7b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -285,6 +285,15 @@ jobs: path: '.fvmrc' cache: true + - name: Cache flet downloads + uses: actions/cache@v4 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Shallow-clone flet (dart-bridge) run: | git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" @@ -315,6 +324,15 @@ jobs: path: '.fvmrc' cache: true + - name: Cache flet downloads + uses: actions/cache@v4 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Setup iOS Simulator id: simulator uses: futureware-tech/simulator-action@v4 @@ -355,6 +373,15 @@ jobs: path: '.fvmrc' cache: true + - name: Cache flet downloads + uses: actions/cache@v4 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -419,6 +446,15 @@ jobs: path: '.fvmrc' cache: true + - name: Cache flet downloads + uses: actions/cache@v4 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Shallow-clone flet (dart-bridge) shell: bash run: | @@ -469,6 +505,15 @@ jobs: channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} cache: true + - name: Cache flet downloads + uses: actions/cache@v4 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Install dependencies run: | sudo apt-get update --allow-releaseinfo-change @@ -558,15 +603,10 @@ jobs: path: '.fvmrc' cache: true - # serious_python_darwin's prepare_ios.sh downloads python-ios-dart-.tar.gz - # (~100MB) into src/serious_python_darwin/darwin/dist_ios/ and skips the - # download if the directory already exists. Cache it so reruns and - # subsequent matrix jobs don't re-fetch from GitHub Releases. - - name: Cache iOS Python framework - uses: actions/cache@v4 - with: - path: src/serious_python_darwin/darwin/dist_ios - key: ios-python-dist-${{ matrix.python_version }}-v2 + # Replaced by the unified ~/.flet/cache step lifted to every job; left + # the comment for git-blame breadcrumb. The bridge_example matrix is + # gated off pending re-enable; once flipped back on, add the cache + # step here too (copy from any flet_ffi_* job). - name: Setup iOS Simulator id: simulator diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index 9d47b83c..8ae0b91d 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -160,6 +160,20 @@ class PackageCommand extends Command { String get _pyodideRootUrl => "https://cdn.jsdelivr.net/pyodide/v${_release.pyodideVersion}/full"; + /// Root of the cross-plugin download cache. Honors `FLET_CACHE_DIR` (the + /// same env var `flet build` and the Android gradle task already use) and + /// otherwise falls back to `~/.flet/cache` (`%USERPROFILE%\.flet\cache` + /// on Windows). The CMake/shell plugins resolve this independently to the + /// same path — keep the layout in sync. + String _fletCacheRoot() { + final env = Platform.environment['FLET_CACHE_DIR']; + if (env != null && env.isNotEmpty) return env; + final home = Platform.environment['HOME'] ?? + Platform.environment['USERPROFILE'] ?? + _buildDir!.path; + return path.join(home, '.flet', 'cache'); + } + @override final name = "package"; @@ -696,8 +710,13 @@ class PackageCommand extends Command { var pythonArchiveFilename = "cpython-${_release.standaloneVersion}+${_release.standaloneReleaseDate}-$arch-install_only_stripped.tar.gz"; + // Cache CPython by release date: the same tarball is reused across + // every example/project until `_release.standaloneReleaseDate` bumps. + var pythonCacheDir = Directory(path.join(_fletCacheRoot(), + 'python-build-standalone', _release.standaloneReleaseDate)); + await pythonCacheDir.create(recursive: true); var pythonArchivePath = - path.join(_buildDir!.path, pythonArchiveFilename); + path.join(pythonCacheDir.path, pythonArchiveFilename); if (!await File(pythonArchivePath).exists()) { // download Python distr from GitHub @@ -709,11 +728,15 @@ class PackageCommand extends Command { "Downloading Python distributive from $url to $pythonArchivePath"); } else { stdout.writeln( - "Downloading Python distributive from $url to a build directory"); + "Downloading Python distributive from $url to $pythonArchivePath"); } + // Write to a .tmp sibling first so a Ctrl-C / network blip doesn't + // poison the cache with a truncated archive on the next run. + var tmpPath = "$pythonArchivePath.tmp"; var response = await http.get(Uri.parse(url)); - await File(pythonArchivePath).writeAsBytes(response.bodyBytes); + await File(tmpPath).writeAsBytes(response.bodyBytes); + await File(tmpPath).rename(pythonArchivePath); } // extract Python from archive diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index d2496699..5d27d850 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -7,26 +7,39 @@ dist=$script_dir/dist_ios # version-independent of CPython, so one binary covers all 3.12+ Python versions. dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} -if [ ! -d "$dist" ]; then - mkdir -p $dist +# Cross-plugin download cache; see prepare_macos.sh for the convention. +cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" +pb_cache="$cache_root/python-build/v$python_version" +db_cache="$cache_root/dart-bridge/v$dart_bridge_version" +mkdir -p "$pb_cache" "$db_cache" - python_ios_dist_file="python-ios-dart-$python_version.tar.gz" +# ---- flet-dev/python-build (iOS embedded Python runtime) ------------------ +python_ios_dist_file="python-ios-dart-$python_version.tar.gz" +python_ios_dist_path="$pb_cache/$python_ios_dist_file" +if [ ! -f "$python_ios_dist_path" ]; then python_ios_dist_url="https://github.com/flet-dev/python-build/releases/download/v$python_version/$python_ios_dist_file" + curl -fL -o "$python_ios_dist_path.tmp" "$python_ios_dist_url" + mv "$python_ios_dist_path.tmp" "$python_ios_dist_path" +fi + +if [ ! -d "$dist" ]; then + mkdir -p "$dist" + tar -xzf "$python_ios_dist_path" -C "$dist" + mv "$dist/python-stdlib" "$dist/stdlib" +fi - # download iOS dist - curl -LO $python_ios_dist_url - tar -xzf $python_ios_dist_file -C $dist - mv $dist/python-stdlib $dist/stdlib - rm $python_ios_dist_file +# ---- flet-dev/dart-bridge (xcframework) ----------------------------------- +# Separate cache guard so a stale $dist from before this change still picks +# up the new artifact on first re-prepare. +dart_bridge_file="dart_bridge-apple.xcframework.zip" +dart_bridge_path="$db_cache/$dart_bridge_file" +if [ ! -f "$dart_bridge_path" ]; then + dart_bridge_url="https://github.com/flet-dev/dart-bridge/releases/download/v$dart_bridge_version/$dart_bridge_file" + curl -fL -o "$dart_bridge_path.tmp" "$dart_bridge_url" + mv "$dart_bridge_path.tmp" "$dart_bridge_path" fi -# dart_bridge.xcframework — separate cache guard so a stale dist_ios from before -# this change still picks up the new artifact on first re-prepare. if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ]; then mkdir -p "$dist/xcframeworks" - dart_bridge_file="dart_bridge-apple.xcframework.zip" - dart_bridge_url="https://github.com/flet-dev/dart-bridge/releases/download/v$dart_bridge_version/$dart_bridge_file" - curl -fL -o "$dart_bridge_file" "$dart_bridge_url" - unzip -q "$dart_bridge_file" -d "$dist/xcframeworks/" - rm "$dart_bridge_file" -fi \ No newline at end of file + unzip -q "$dart_bridge_path" -d "$dist/xcframeworks/" +fi diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index 82c1d210..eda06627 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -7,24 +7,42 @@ dist=$script_dir/dist_macos # across iOS and macOS — it carries slices for both. dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} -if [ ! -d "$dist" ]; then - mkdir -p $dist +# Cross-plugin download cache. FLET_CACHE_DIR is the same env var the Android +# gradle task + flet build's external tooling already use; ~/.flet/cache is +# the shared default. Tarballs land here and survive `flutter clean`. +cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" +pb_cache="$cache_root/python-build/v$python_version" +db_cache="$cache_root/dart-bridge/v$dart_bridge_version" +mkdir -p "$pb_cache" "$db_cache" - python_macos_dist_file="python-macos-dart-$python_version.tar.gz" +# ---- flet-dev/python-build (macOS embedded Python runtime) ---------------- +python_macos_dist_file="python-macos-dart-$python_version.tar.gz" +python_macos_dist_path="$pb_cache/$python_macos_dist_file" +if [ ! -f "$python_macos_dist_path" ]; then python_macos_dist_url="https://github.com/flet-dev/python-build/releases/download/v$python_version/$python_macos_dist_file" + # .tmp + mv so a Ctrl-C / network blip doesn't poison the cache. + curl -fL -o "$python_macos_dist_path.tmp" "$python_macos_dist_url" + mv "$python_macos_dist_path.tmp" "$python_macos_dist_path" +fi + +if [ ! -d "$dist" ]; then + mkdir -p "$dist" + tar -xzf "$python_macos_dist_path" -C "$dist" + mv "$dist/python-stdlib" "$dist/stdlib" +fi - # download macos dist - curl -LO $python_macos_dist_url - tar -xzf $python_macos_dist_file -C $dist - mv $dist/python-stdlib $dist/stdlib - rm $python_macos_dist_file +# ---- flet-dev/dart-bridge (xcframework, same archive for macOS + iOS) ----- +# Separate cache guard so a stale $dist from before this change still picks +# up the new artifact on first re-prepare. +dart_bridge_file="dart_bridge-apple.xcframework.zip" +dart_bridge_path="$db_cache/$dart_bridge_file" +if [ ! -f "$dart_bridge_path" ]; then + dart_bridge_url="https://github.com/flet-dev/dart-bridge/releases/download/v$dart_bridge_version/$dart_bridge_file" + curl -fL -o "$dart_bridge_path.tmp" "$dart_bridge_url" + mv "$dart_bridge_path.tmp" "$dart_bridge_path" fi if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ]; then mkdir -p "$dist/xcframeworks" - dart_bridge_file="dart_bridge-apple.xcframework.zip" - dart_bridge_url="https://github.com/flet-dev/dart-bridge/releases/download/v$dart_bridge_version/$dart_bridge_file" - curl -fL -o "$dart_bridge_file" "$dart_bridge_url" - unzip -q "$dart_bridge_file" -d "$dist/xcframeworks/" - rm "$dart_bridge_file" -fi \ No newline at end of file + unzip -q "$dart_bridge_path" -d "$dist/xcframeworks/" +fi diff --git a/src/serious_python_linux/linux/CMakeLists.txt b/src/serious_python_linux/linux/CMakeLists.txt index 46c9ae6e..6654c08b 100644 --- a/src/serious_python_linux/linux/CMakeLists.txt +++ b/src/serious_python_linux/linux/CMakeLists.txt @@ -19,39 +19,66 @@ if(DEFINED ENV{DART_BRIDGE_VERSION}) else() set(DART_BRIDGE_VERSION "1.2.3") endif() + +# Cross-plugin download cache. FLET_CACHE_DIR is the same env var used by the +# Android gradle task, the Darwin prepare_*.sh scripts, and Windows +# CMakeLists; defaulting to ~/.flet/cache keeps a single shared location. +if(DEFINED ENV{FLET_CACHE_DIR}) + set(FLET_CACHE_DIR "$ENV{FLET_CACHE_DIR}") +else() + set(FLET_CACHE_DIR "$ENV{HOME}/.flet/cache") +endif() +set(PB_CACHE "${FLET_CACHE_DIR}/python-build/v${PYTHON_VERSION}") +set(DB_CACHE "${FLET_CACHE_DIR}/dart-bridge/v${DART_BRIDGE_VERSION}") +file(MAKE_DIRECTORY "${PB_CACHE}" "${DB_CACHE}") + project(${PROJECT_NAME} LANGUAGES CXX) # This value is used when generating builds using this plugin, so it must # not be changed. set(PLUGIN_NAME "serious_python_linux_plugin") +function(_sp_download url dest) + if(EXISTS "${dest}") + return() + endif() + message(STATUS "Downloading: ${url}") + # .tmp + rename so a Ctrl-C / network blip doesn't poison the cache. + file(DOWNLOAD "${url}" "${dest}.tmp" STATUS _dl_status SHOW_PROGRESS) + list(GET _dl_status 0 _dl_code) + list(GET _dl_status 1 _dl_message) + if(NOT _dl_code EQUAL 0) + file(REMOVE "${dest}.tmp") + message(FATAL_ERROR "Failed to download ${url}: ${_dl_message}") + endif() + file(RENAME "${dest}.tmp" "${dest}") +endfunction() + # ---- python-linux-dart tarball (libpython + stdlib) ----------------------- +# Tarball lives in the shared cache; extraction targets the per-plugin build +# tree so a `flutter clean` doesn't force a re-download. set(PYTHON_PACKAGE ${CMAKE_BINARY_DIR}/python) set(PYTHON_URL https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz) -set(PYTHON_FILE ${CMAKE_BINARY_DIR}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz) -if (NOT EXISTS ${PYTHON_FILE}) - file(DOWNLOAD ${PYTHON_URL} ${PYTHON_FILE}) - file(ARCHIVE_EXTRACT INPUT ${PYTHON_FILE} DESTINATION ${CMAKE_BINARY_DIR}/python) +set(PYTHON_FILE "${PB_CACHE}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz") +_sp_download("${PYTHON_URL}" "${PYTHON_FILE}") +if(NOT EXISTS "${PYTHON_PACKAGE}/lib/libpython3.so") + file(ARCHIVE_EXTRACT INPUT "${PYTHON_FILE}" DESTINATION "${PYTHON_PACKAGE}") endif() # ---- dart_bridge prebuilt .so --------------------------------------------- # abi3-linked against libpython3.so (the runtime linker finds libpython3.so # next to the consuming app's exe; the python-linux-dart tarball above -# provides it). -set(DART_BRIDGE_SO ${CMAKE_BINARY_DIR}/dart_bridge/libdart_bridge.so) -if(NOT EXISTS "${DART_BRIDGE_SO}") - file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dart_bridge) - file(DOWNLOAD - "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/libdart_bridge-linux-${PYTHON_ARCH}.so" - "${DART_BRIDGE_SO}" - STATUS _dl_status SHOW_PROGRESS) - list(GET _dl_status 0 _dl_code) - list(GET _dl_status 1 _dl_message) - if(NOT _dl_code EQUAL 0) - file(REMOVE "${DART_BRIDGE_SO}") - message(FATAL_ERROR "Failed to download libdart_bridge: ${_dl_message}") - endif() -endif() +# provides it). Cached under its arch-qualified name so multiple arches can +# co-exist in $FLET_CACHE_DIR; copied to a stable `libdart_bridge.so` in the +# build tree so Flutter's bundled_libraries machinery (and the Dart side's +# DynamicLibrary.open("libdart_bridge.so")) finds a deterministic name. +set(DART_BRIDGE_CACHED "${DB_CACHE}/libdart_bridge-linux-${PYTHON_ARCH}.so") +_sp_download( + "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/libdart_bridge-linux-${PYTHON_ARCH}.so" + "${DART_BRIDGE_CACHED}") +set(DART_BRIDGE_SO "${CMAKE_BINARY_DIR}/dart_bridge/libdart_bridge.so") +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/dart_bridge") +configure_file("${DART_BRIDGE_CACHED}" "${DART_BRIDGE_SO}" COPYONLY) # Any new source files that you add to the plugin should be added here. list(APPEND PLUGIN_SOURCES diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index f287ec91..c9ccc450 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -17,6 +17,24 @@ if(DEFINED ENV{DART_BRIDGE_VERSION}) else() set(DART_BRIDGE_VERSION "1.2.1") endif() + +# Cross-plugin download cache. FLET_CACHE_DIR is the same env var used by the +# Android gradle task and the prepare_*.sh scripts on Darwin; defaulting to +# ~/.flet/cache (%USERPROFILE%\.flet\cache on Windows) keeps a single shared +# location across all plugins. Files land in versioned subdirs so a Python +# or dart_bridge version bump pulls a fresh artifact without invalidating the +# others. +if(DEFINED ENV{FLET_CACHE_DIR}) + set(FLET_CACHE_DIR "$ENV{FLET_CACHE_DIR}") +elseif(DEFINED ENV{USERPROFILE}) + set(FLET_CACHE_DIR "$ENV{USERPROFILE}/.flet/cache") +else() + set(FLET_CACHE_DIR "$ENV{HOME}/.flet/cache") +endif() +set(PB_CACHE "${FLET_CACHE_DIR}/python-build/v${PYTHON_VERSION}") +set(DB_CACHE "${FLET_CACHE_DIR}/dart-bridge/v${DART_BRIDGE_VERSION}") +file(MAKE_DIRECTORY "${PB_CACHE}" "${DB_CACHE}") + project(${PROJECT_NAME} LANGUAGES CXX) # Explicitly opt in to modern CMake behaviors to avoid warnings with recent @@ -34,36 +52,39 @@ set(PLUGIN_NAME "serious_python_windows_plugin") # here because no Python C API call sites live in this plugin anymore. set(PYTHON_PACKAGE ${CMAKE_BINARY_DIR}/python) set(PYTHON_URL "https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-windows-for-dart-${PYTHON_VERSION}.zip") -set(PYTHON_FILE ${CMAKE_BINARY_DIR}/python-windows-for-dart.zip) -if (NOT EXISTS ${PYTHON_FILE}) - file(DOWNLOAD ${PYTHON_URL} ${PYTHON_FILE}) - file(ARCHIVE_EXTRACT INPUT ${PYTHON_FILE} DESTINATION ${PYTHON_PACKAGE}) -endif() - -# ---- dart_bridge prebuilt DLLs -------------------------------------------- -# Release CRT (.dll) is what Release Flutter builds consume; Debug CRT -# (_d.dll) is what `fvm flutter run` / Debug builds consume. Both ship in -# every release of flet-dev/dart-bridge; we bundle both and let Flutter's -# CONFIG-aware copy machinery pick the right one at app launch time. -set(DART_BRIDGE_DIR ${CMAKE_BINARY_DIR}/dart_bridge) -set(DART_BRIDGE_RELEASE_DLL "${DART_BRIDGE_DIR}/dart_bridge.dll") -set(DART_BRIDGE_DEBUG_DLL "${DART_BRIDGE_DIR}/dart_bridge_d.dll") -file(MAKE_DIRECTORY ${DART_BRIDGE_DIR}) +# Tarball lives in the shared cache; extraction targets the per-plugin build +# tree so a `flutter clean` doesn't force a re-download. +set(PYTHON_FILE "${PB_CACHE}/python-windows-for-dart-${PYTHON_VERSION}.zip") function(_sp_download url dest) if(EXISTS "${dest}") return() endif() - message(STATUS "Downloading dart_bridge: ${url}") - file(DOWNLOAD "${url}" "${dest}" STATUS _dl_status SHOW_PROGRESS) + message(STATUS "Downloading: ${url}") + # .tmp + rename so a Ctrl-C / network blip doesn't poison the cache. + file(DOWNLOAD "${url}" "${dest}.tmp" STATUS _dl_status SHOW_PROGRESS) list(GET _dl_status 0 _dl_code) list(GET _dl_status 1 _dl_message) if(NOT _dl_code EQUAL 0) - file(REMOVE "${dest}") + file(REMOVE "${dest}.tmp") message(FATAL_ERROR "Failed to download ${url}: ${_dl_message}") endif() + file(RENAME "${dest}.tmp" "${dest}") endfunction() +_sp_download("${PYTHON_URL}" "${PYTHON_FILE}") +if(NOT EXISTS "${PYTHON_PACKAGE}/python.exe") + file(ARCHIVE_EXTRACT INPUT "${PYTHON_FILE}" DESTINATION "${PYTHON_PACKAGE}") +endif() + +# ---- dart_bridge prebuilt DLLs -------------------------------------------- +# Release CRT (.dll) is what Release Flutter builds consume; Debug CRT +# (_d.dll) is what `fvm flutter run` / Debug builds consume. Both ship in +# every release of flet-dev/dart-bridge; we bundle both and let Flutter's +# CONFIG-aware copy machinery pick the right one at app launch time. +set(DART_BRIDGE_RELEASE_DLL "${DB_CACHE}/dart_bridge-windows-x86_64.dll") +set(DART_BRIDGE_DEBUG_DLL "${DB_CACHE}/dart_bridge_d-windows-x86_64.dll") + _sp_download( "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge-windows-x86_64.dll" "${DART_BRIDGE_RELEASE_DLL}") From ddf88294a9f1e4952d07ee92ee4bdfd0dade4e63 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 10:00:47 -0700 Subject: [PATCH 083/114] windows: copy cached dart_bridge DLLs to stable name in build tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows jobs in run 27356505799 hit `Failed to load dynamic library 'dart_bridge_d.dll': The specified module could not be found (error code 126)` — same shape as the Linux issue I caught while writing the cache patch. Flutter's bundled_libraries machinery preserves filenames as-is, so pointing bundled_libraries at the arch-suffixed cache file (`dart_bridge-windows-x86_64.dll`) lands it in the .app under that name. The Dart side opens by the unsuffixed `dart_bridge[_d].dll`, so the loader can't find it. Mirror the Linux fix: download into cache under the upstream filename, then `configure_file(... COPYONLY)` to a stable `dart_bridge.dll` / `dart_bridge_d.dll` in CMAKE_BINARY_DIR/dart_bridge/, and have bundled_libraries reference the build-tree names. iOS 3.14 timed out in the same run with 1h35m of silence after Xcode build (iOS 3.12 + 3.13 both passed) — simulator flake, unrelated. --- .../windows/CMakeLists.txt | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index c9ccc450..a5de6603 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -82,15 +82,28 @@ endif() # (_d.dll) is what `fvm flutter run` / Debug builds consume. Both ship in # every release of flet-dev/dart-bridge; we bundle both and let Flutter's # CONFIG-aware copy machinery pick the right one at app launch time. -set(DART_BRIDGE_RELEASE_DLL "${DB_CACHE}/dart_bridge-windows-x86_64.dll") -set(DART_BRIDGE_DEBUG_DLL "${DB_CACHE}/dart_bridge_d-windows-x86_64.dll") +# +# Cached under the upstream arch-qualified filenames so multiple flet-dev/ +# dart-bridge versions can coexist in $FLET_CACHE_DIR. Copied to stable +# unqualified names in the build tree because Flutter's bundled_libraries +# machinery preserves filenames as-is, and the Dart side opens the DLL by +# `dart_bridge[_d].dll` (no arch suffix). +set(DART_BRIDGE_RELEASE_CACHED "${DB_CACHE}/dart_bridge-windows-x86_64.dll") +set(DART_BRIDGE_DEBUG_CACHED "${DB_CACHE}/dart_bridge_d-windows-x86_64.dll") _sp_download( "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge-windows-x86_64.dll" - "${DART_BRIDGE_RELEASE_DLL}") + "${DART_BRIDGE_RELEASE_CACHED}") _sp_download( "https://github.com/flet-dev/dart-bridge/releases/download/v${DART_BRIDGE_VERSION}/dart_bridge_d-windows-x86_64.dll" - "${DART_BRIDGE_DEBUG_DLL}") + "${DART_BRIDGE_DEBUG_CACHED}") + +set(DART_BRIDGE_DIR "${CMAKE_BINARY_DIR}/dart_bridge") +set(DART_BRIDGE_RELEASE_DLL "${DART_BRIDGE_DIR}/dart_bridge.dll") +set(DART_BRIDGE_DEBUG_DLL "${DART_BRIDGE_DIR}/dart_bridge_d.dll") +file(MAKE_DIRECTORY "${DART_BRIDGE_DIR}") +configure_file("${DART_BRIDGE_RELEASE_CACHED}" "${DART_BRIDGE_RELEASE_DLL}" COPYONLY) +configure_file("${DART_BRIDGE_DEBUG_CACHED}" "${DART_BRIDGE_DEBUG_DLL}" COPYONLY) # Any new source files that you add to the plugin should be added here. list(APPEND PLUGIN_SOURCES From fdb3bf7e7b4cfb6af908244dea33af8e24dd0118 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 11:11:01 -0700 Subject: [PATCH 084/114] darwin: stop leaking the .pod symlink into the production .app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit symlink_pod.sh creates a `.pod` symlink in $SERIOUS_PYTHON_SITE_PACKAGES pointing at the plugin's source tree so package_command.dart can invoke sync_site_packages.sh from a stable path. That symlink is fine for the host build step but should NOT end up in the production app bundle. sync_site_packages.sh's macOS path used `rsync -av` which copies symlinks as symlinks. The .pod symlink then landed in dist_macos/site-packages/ and CocoaPods packaged it into python.bundle/Contents/Resources/ site-packages/.pod. Two cascading failures observed during `flet build`: 1. The .pod symlink resolved into the plugin source tree, which contains dist_macos/xcframeworks/Python.xcframework/.../Python.app (a small launcher inside the framework). macOS LaunchServices scanned the .app, found the embedded Python.app, and tried to launch it — DYLD couldn't resolve the framework binary at `Python.framework/Versions/3.14/Python`, repeated crash report popups. 2. flet-cli's copy_tree from the codesigned Release .app to the final build/macos/.app followed the symlink into the source tree. The xcframework files inside were treated as code-signed bundle resources, every copy attempt failed with `[Errno 1] Operation not permitted`, flooding the build log. Excluding `.pod` from the rsync stops the leak at source. The iOS path already happens to skip it (`cp -R src/*` doesn't expand dotfiles). After this lands, existing local broken state needs cleanup once: - rm -rf the broken .app in your project's build/macos/.app - rm -rf src/serious_python_darwin/darwin/dist_macos - re-run `flet build` --- .../darwin/sync_site_packages.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/serious_python_darwin/darwin/sync_site_packages.sh b/src/serious_python_darwin/darwin/sync_site_packages.sh index 4864d631..82d99374 100755 --- a/src/serious_python_darwin/darwin/sync_site_packages.sh +++ b/src/serious_python_darwin/darwin/sync_site_packages.sh @@ -43,7 +43,16 @@ if [[ -n "$SERIOUS_PYTHON_SITE_PACKAGES" && -d "$SERIOUS_PYTHON_SITE_PACKAGES" ] dist=$script_dir/dist_macos mkdir -p $dist/site-packages - rsync -av --delete "$SERIOUS_PYTHON_SITE_PACKAGES/" "$dist/site-packages/" + # Exclude the .pod symlink created by symlink_pod.sh — it points at + # this plugin's source tree. If it lands in dist_macos/site-packages, + # CocoaPods packages it into the production .app, where macOS + # LaunchServices finds the embedded Python.app inside the symlinked + # Python.xcframework and tries to launch it (DYLD failure, repeated + # crash report popups), and `flet build`'s copy_tree follows the + # symlink into a code-signed source tree and hits EPERM on every + # file. .pod is only needed by package_command.dart at packaging + # time to invoke this sync script; it does not belong in the bundle. + rsync -av --delete --exclude '.pod' "$SERIOUS_PYTHON_SITE_PACKAGES/" "$dist/site-packages/" fi else echo "SERIOUS_PYTHON_SITE_PACKAGES is not set." From 2dd3c963aea59658944b22bc0ca791495b538eec Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 11:21:40 -0700 Subject: [PATCH 085/114] darwin: strip embedded Python.app from Python.framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit python-build-standalone bakes a standalone launcher Python.app into Python.framework/Versions//Resources/. Its Mach-O has a hardcoded load command: /Users/runner/work/python-build/python-build/darwin/install/macOS/ macosx/python-3.X.Y/Python.framework/Versions/X.Y/Python — literally the CI runner's build path. DYLD can't resolve it anywhere else, so any attempt to launch the Python.app fails with "Library missing". macOS LaunchServices scans nested .app bundles inside a .app's Contents/Frameworks/ on launch (`flet debug macos`, `flet run`, or just opening the built .app) and reliably triggers a flood of "Python quit unexpectedly" crash report dialogs. The launcher is only useful for standalone interpreter sessions (the GUI Python.app you launch from /Applications); libdart_bridge dlopens the framework's main binary directly and ignores it. Strip it after extraction. Existing both in 3.12 and 3.14 tarballs from flet-dev/python-build — the previous serious_python (pub.dev 1.0.x) packaging path apparently didn't expose it to LaunchServices, which is why it never surfaced before the dart-bridge rewrite started routing Python.xcframework through CocoaPods' vendored_frameworks into Contents/Frameworks/. --- src/serious_python_darwin/darwin/prepare_macos.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index eda06627..3e3e5c88 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -29,6 +29,17 @@ if [ ! -d "$dist" ]; then mkdir -p "$dist" tar -xzf "$python_macos_dist_path" -C "$dist" mv "$dist/python-stdlib" "$dist/stdlib" + + # python-build-standalone bakes a standalone launcher Python.app into + # Python.framework/Versions//Resources/. Its Mach-O has a hardcoded + # load command pointing at the CI runner's build path + # (/Users/runner/work/python-build/.../Python.framework/Versions/X.Y/Python), + # so DYLD can't resolve it on any other machine. When the host .app is + # built, macOS LaunchServices scans nested .app bundles and tries to + # launch this Python.app — every scan produces a "Python quit + # unexpectedly" crash dialog. We don't need this launcher for embedded + # use; libdart_bridge dlopens Python.framework's main binary directly. + find "$dist/xcframeworks" -type d -name 'Python.app' -prune -exec rm -rf {} + fi # ---- flet-dev/dart-bridge (xcframework, same archive for macOS + iOS) ----- From cf666713c9aa951d53fb5674b8d87746db9f819d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Thu, 11 Jun 2026 13:21:08 -0700 Subject: [PATCH 086/114] ci: bump actions/checkout v4 -> v6 (Node 24) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub deprecated Node 20 in actions on 2026-06-16; v6 is the current Node 24 release line (v6.0.3 is latest). Only actions/checkout actually appears in this repo's workflows; the other in-flight bumps in python-build's PR — actions/{setup-python, upload-artifact,download-artifact} and softprops/action-gh-release — have no call sites here. --- .github/workflows/ci.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c7cc7b9..1bb89333 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -78,7 +78,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -115,7 +115,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -175,7 +175,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -209,7 +209,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup uv uses: astral-sh/setup-uv@v6 @@ -277,7 +277,7 @@ jobs: SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -316,7 +316,7 @@ jobs: SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -365,7 +365,7 @@ jobs: SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -438,7 +438,7 @@ jobs: SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -487,7 +487,7 @@ jobs: SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup uv uses: astral-sh/setup-uv@v6 @@ -568,7 +568,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -595,7 +595,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -647,7 +647,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -725,7 +725,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 @@ -783,7 +783,7 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Get Flutter version from .fvmrc uses: kuhnroyal/flutter-fvm-config-action/config@v3 @@ -862,7 +862,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 From 4329b6bb9651d2dd966697b35784f0044abfceb2 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 10:04:31 -0700 Subject: [PATCH 087/114] Bump 3.13.14 / 3.14.6 / Pyodide 314.0.0; migrate to date-based python-build scheme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `flet-dev/python-build` 20260611 switched from per-minor v-tags (`v3.14` + `python-*-3.14-*.tar.gz`) to date-keyed tags carrying the full patch version (`20260611` + `python-*-3.14.6-*.tar.gz`); one date release now ships every supported minor. Astral PBS advanced to 20260610 (now ships 3.13.14 / 3.14.6); Pyodide 314.0.0 GA'd. Registry (`_pythonReleases` in package_command.dart) updates: * 3.12 row: PBS date 20260610 (CPython 3.12.13 unchanged). * 3.13 row: CPython 3.13.14, PBS date 20260610. * 3.14 row: CPython 3.14.6, PBS date 20260610, Pyodide 314.0.0. * All three rows gain `pythonBuildReleaseDate: "20260611"`. The 3.13 wheel platform tag was also wrong — `pyodide-2025.0-wasm32` where it should have been `pyemscripten-2025.0-wasm32` (the prefix transition happened at Pyodide 0.28/0.29, not at 314.0). Anyone attempting `flet build web --python-version 3.13` against a Pyodide-built native wheel would have failed to match anything. Fixed in the registry. Plugin build scripts (android/build.gradle, darwin/prepare_{ios,macos}.sh, linux + windows CMakeLists.txt) now read two new env vars exported by `flet build`: * SERIOUS_PYTHON_FULL_VERSION (e.g. 3.14.6) — used in the URL filename * SERIOUS_PYTHON_BUILD_DATE (e.g. 20260611) — used as the URL tag Each plugin keeps a baked-in default so standalone (non-`flet build`) consumers keep working without setting the new vars. The per-plugin cache directory key (`$FLET_CACHE_DIR/python-build/v<…>/`) switches from short to full version so a patch bump doesn't reuse a stale tarball. README + 5 changelog entries updated. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/serious_python/CHANGELOG.md | 4 ++- src/serious_python/README.md | 17 +++++++--- src/serious_python/bin/package_command.dart | 34 ++++++++++++++----- src/serious_python_android/CHANGELOG.md | 1 + .../android/build.gradle | 8 +++-- src/serious_python_darwin/CHANGELOG.md | 1 + .../darwin/prepare_ios.sh | 8 +++-- .../darwin/prepare_macos.sh | 8 +++-- .../darwin/serious_python_darwin.podspec | 6 ++-- src/serious_python_linux/CHANGELOG.md | 1 + src/serious_python_linux/linux/CMakeLists.txt | 16 +++++++-- src/serious_python_windows/CHANGELOG.md | 1 + .../windows/CMakeLists.txt | 16 +++++++-- 13 files changed, 90 insertions(+), 31 deletions(-) diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 68ee1513..edc318ab 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -4,9 +4,11 @@ * **Breaking change:** Android `sysconfig.get_platform()` tag format changed from `android-24-arm64-v8a` to `android-24-arm64_v8a` (and similarly for `armeabi-v7a`). The emitted wheel tag (`android_24_arm64_v8a`) is unchanged, but anything reading the raw `sysconfig.get_platform()` string from `sitecustomize.py` should switch separators. * **Breaking change:** Windows host arch identifier dropped the `-shared` suffix (`x86_64-pc-windows-msvc-shared` → `x86_64-pc-windows-msvc`); follows astral-sh/python-build-standalone, which only publishes the combined (already shared) `install_only_stripped` build. * Multi-version Python support. The `package` command accepts `--python-version` (or `SERIOUS_PYTHON_VERSION` env var) to select between Python 3.12 / 3.13 / 3.14. The matching CPython-standalone build, Pyodide release, and Emscripten wheel platform tag are looked up from a new `_pythonReleases` table. Adding a future pre-release line (e.g. 3.15 beta) is a one-row append with `prerelease: true`; the Flet CLI uses that flag to keep open-ended `requires-python` specifiers (`>=3.14`) on stable, while still letting `--python-version 3.15` or `==3.15.*` opt in. -* The Emscripten pip platform tag is now derived per Python release (e.g. `pyodide-2024.0-wasm32` for 0.27.7, `pyemscripten-2026.0-wasm32` for 314.0.0a2), via a `pyodide_platform_tag` field in the version registry. The previous static `pyodide-2024.0-wasm32` entry in `platforms["Emscripten"]` has been removed. +* The Emscripten pip platform tag is now derived per Python release (e.g. `pyodide-2024.0-wasm32` for 0.27.7, `pyemscripten-2026.0-wasm32` for 314.0.0), via a `pyodide_platform_tag` field in the version registry. The previous static `pyodide-2024.0-wasm32` entry in `platforms["Emscripten"]` has been removed. * `sitecustomize.py` now shims `platform.android_ver` so the new pip / packaging that ships with python-build-standalone 20260602+ can compute Android wheel tags on Python 3.12 hosts (where `android_ver` didn't exist) and on Python 3.13+ hosts (where it returns `api_level=0` off-device). * Skip 32-bit Android ABIs (`armeabi-v7a`, `x86`) when Python ≥ 3.13 — PEP 738 dropped 32-bit Android support, and `flet-dev/python-build` no longer publishes those runtimes for those versions. +* Migrate the platform-plugin download URLs to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-*--*.tar.gz`) — one release tag now ships every supported Python patch instead of per-minor `v3.X` releases. Plugins (Android `build.gradle`, Darwin `prepare_*.sh`, Linux/Windows `CMakeLists.txt`) read two new env vars set by `flet build`: `SERIOUS_PYTHON_FULL_VERSION` (e.g. `3.14.6`) and `SERIOUS_PYTHON_BUILD_DATE` (e.g. `20260611`); both fall back to baked-in defaults so standalone (non-`flet build`) usage continues to work. Bump bundled versions to **3.12.13 / 3.13.14 / 3.14.6** (Astral PBS `20260610`, python-build `20260611`) and Pyodide for 3.14 to **314.0.0** (GA). +* **Bug fix:** the Pyodide 0.29 wheel platform tag for the 3.13 row in the version registry was `pyodide-2025.0-wasm32`, but Pyodide actually publishes its wheels under `pyemscripten_2025_0_wasm32` (the `pyodide_` → `pyemscripten_` prefix transition happened at 0.28/0.29, not at 314.0). `flet build web --python-version 3.13` would have failed to match any Pyodide-built native wheel; corrected to `pyemscripten-2025.0-wasm32` in the registry. ## 1.0.1 diff --git a/src/serious_python/README.md b/src/serious_python/README.md index 6c921c59..8d913b1e 100644 --- a/src/serious_python/README.md +++ b/src/serious_python/README.md @@ -22,11 +22,11 @@ the `--python-version X.Y` flag of `serious_python:main package` (or the plugin build scripts). Defaults to the latest supported version when nothing is specified. -| Short | CPython runtime | Pyodide (web) | Pyodide wheel platform tag | -| ----- | --------------- | ------------- | -------------------------- | -| 3.12 | 3.12.13 | 0.27.7 | `pyodide-2024.0-wasm32` | -| 3.13 | 3.13.13 | 0.29.4 | `pyodide-2025.0-wasm32` | -| 3.14 | 3.14.5 | 314.0.0a2 | `pyemscripten-2026.0-wasm32`| +| Short | CPython runtime | Pyodide (web) | Pyodide wheel platform tag | +| ----- | --------------- | ------------- | -------------------------------- | +| 3.12 | 3.12.13 | 0.27.7 | `pyodide-2024.0-wasm32` | +| 3.13 | 3.13.14 | 0.29.4 | `pyemscripten-2025.0-wasm32` | +| 3.14 | 3.14.6 | 314.0.0 | `pyemscripten-2026.0-wasm32` | The default is the latest stable row (currently **3.14**) when neither `--python-version` nor `SERIOUS_PYTHON_VERSION` is set. When running through @@ -34,6 +34,13 @@ The default is the latest stable row (currently **3.14**) when neither applied to `[project].requires-python` in your `pyproject.toml`, so most users never need to touch this flag directly. +`SERIOUS_PYTHON_VERSION` (short, e.g. `3.14`) is the only input most users +need to set. When `flet build` invokes the platform plugins it also exports +`SERIOUS_PYTHON_FULL_VERSION` (e.g. `3.14.6`) and `SERIOUS_PYTHON_BUILD_DATE` +(e.g. `20260611` — the `flet-dev/python-build` release tag); the plugin build +scripts pick them up automatically and combine them into the +`…//python-*--*` download URLs. + Source of truth: the `_pythonReleases` map in [`bin/package_command.dart`](bin/package_command.dart) (Dart side) and `flet_cli/utils/python_versions.py` (Python side). Adding a new short version diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index 8ae0b91d..66e2a8f7 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -25,7 +25,9 @@ const allowSourceDistrosEnvironmentVariable = "SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS"; const pythonVersionEnvironmentVariable = "SERIOUS_PYTHON_VERSION"; +const pythonFullVersionEnvironmentVariable = "SERIOUS_PYTHON_FULL_VERSION"; const pythonDistReleaseEnvironmentVariable = "SERIOUS_PYTHON_DIST_RELEASE"; +const pythonBuildDateEnvironmentVariable = "SERIOUS_PYTHON_BUILD_DATE"; const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION"; const defaultPythonVersion = "3.14"; @@ -34,6 +36,7 @@ class _PythonRelease { const _PythonRelease({ required this.standaloneVersion, required this.standaloneReleaseDate, + required this.pythonBuildReleaseDate, required this.pyodideVersion, required this.pyodidePlatformTag, required this.prerelease, @@ -41,6 +44,12 @@ class _PythonRelease { final String standaloneVersion; final String standaloneReleaseDate; + + // Release date tag of the matching `flet-dev/python-build` release + // (e.g. "20260611"). Combined with `standaloneVersion` to construct the + // platform-plugin download URLs. + final String pythonBuildReleaseDate; + final String pyodideVersion; final String pyodidePlatformTag; @@ -55,22 +64,25 @@ class _PythonRelease { const _pythonReleases = { "3.12": _PythonRelease( standaloneVersion: "3.12.13", - standaloneReleaseDate: "20260602", + standaloneReleaseDate: "20260610", + pythonBuildReleaseDate: "20260611", pyodideVersion: "0.27.7", pyodidePlatformTag: "pyodide-2024.0-wasm32", prerelease: false, ), "3.13": _PythonRelease( - standaloneVersion: "3.13.13", - standaloneReleaseDate: "20260602", + standaloneVersion: "3.13.14", + standaloneReleaseDate: "20260610", + pythonBuildReleaseDate: "20260611", pyodideVersion: "0.29.4", - pyodidePlatformTag: "pyodide-2025.0-wasm32", + pyodidePlatformTag: "pyemscripten-2025.0-wasm32", prerelease: false, ), "3.14": _PythonRelease( - standaloneVersion: "3.14.5", - standaloneReleaseDate: "20260602", - pyodideVersion: "314.0.0a2", + standaloneVersion: "3.14.6", + standaloneReleaseDate: "20260610", + pythonBuildReleaseDate: "20260611", + pyodideVersion: "314.0.0", pyodidePlatformTag: "pyemscripten-2026.0-wasm32", prerelease: false, ), @@ -82,6 +94,7 @@ const _pythonReleases = { // "3.15": _PythonRelease( // standaloneVersion: "3.15.0", // standaloneReleaseDate: "...", + // pythonBuildReleaseDate: "...", // pyodideVersion: "...", // pyodidePlatformTag: "...", // prerelease: true, @@ -274,10 +287,15 @@ class PackageCommand extends Command { exit(2); } _release = _PythonRelease( - standaloneVersion: baseRelease.standaloneVersion, + standaloneVersion: + Platform.environment[pythonFullVersionEnvironmentVariable] ?? + baseRelease.standaloneVersion, standaloneReleaseDate: Platform.environment[pythonDistReleaseEnvironmentVariable] ?? baseRelease.standaloneReleaseDate, + pythonBuildReleaseDate: + Platform.environment[pythonBuildDateEnvironmentVariable] ?? + baseRelease.pythonBuildReleaseDate, pyodideVersion: Platform.environment[pyodideVersionEnvironmentVariable] ?? baseRelease.pyodideVersion, diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 3c8afb96..63532f25 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -4,6 +4,7 @@ * Multi-version Python support. `python_version` in `android/build.gradle` reads from `SERIOUS_PYTHON_VERSION` and drives the `flet-dev/python-build` download URL. * The Dart runtime no longer hardcodes `libpython3.12.so` — it scans `nativeLibraryDir` for `libpython3.*.so` so whichever libpython the plugin bundled is loaded automatically. * `abiFilters` now branches on `python_version`: keep `armeabi-v7a` for 3.12, restrict to `arm64-v8a` + `x86_64` for 3.13+ (python-build dropped 32-bit Android per PEP 738). +* Migrate `downloadDistArchive_*` to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-android-dart--.tar.gz` instead of `…/v/python-android-dart--.tar.gz`). Two new env vars — `SERIOUS_PYTHON_FULL_VERSION` (e.g. `3.14.6`) and `SERIOUS_PYTHON_BUILD_DATE` (e.g. `20260611`) — are read alongside `SERIOUS_PYTHON_VERSION`, both with baked-in defaults so standalone (non-`flet build`) usage continues to work. The cache directory key (`$FLET_CACHE_DIR/python-build/v<…>/`) switches from short to full version so patch bumps don't reuse a stale tarball. ## 1.0.1 diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle index ae3ef1a1..69de4cdc 100644 --- a/src/serious_python_android/android/build.gradle +++ b/src/serious_python_android/android/build.gradle @@ -2,6 +2,8 @@ group 'com.flet.serious_python_android' version '2.0.0' def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: '3.14' +def python_full_version = System.getenv('SERIOUS_PYTHON_FULL_VERSION') ?: '3.14.6' +def python_build_date = System.getenv('SERIOUS_PYTHON_BUILD_DATE') ?: '20260611' def dart_bridge_version = System.getenv('DART_BRIDGE_VERSION') ?: '1.2.1' buildscript { @@ -70,7 +72,7 @@ import de.undercouch.gradle.tasks.download.Download def fletCacheRoot = System.getenv('FLET_CACHE_DIR') def pythonCacheDir = new File( fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), - "python-build/v${python_version}" + "python-build/v${python_full_version}" ) def dartBridgeCacheDir = new File( fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), @@ -102,8 +104,8 @@ android.defaultConfig.ndk.abiFilters.each { abi -> } tasks.register("downloadDistArchive_$abi", Download) { - src "https://github.com/flet-dev/python-build/releases/download/v${python_version}/python-android-dart-${python_version}-${abi}.tar.gz" - dest new File(pythonCacheDir, "python-android-dart-${python_version}-${abi}.tar.gz") + src "https://github.com/flet-dev/python-build/releases/download/${python_build_date}/python-android-dart-${python_full_version}-${abi}.tar.gz" + dest new File(pythonCacheDir, "python-android-dart-${python_full_version}-${abi}.tar.gz") onlyIfModified true useETag "all" tempAndMove true diff --git a/src/serious_python_darwin/CHANGELOG.md b/src/serious_python_darwin/CHANGELOG.md index df4e13d5..aa337eb7 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -2,6 +2,7 @@ * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). Apps built without an explicit `SERIOUS_PYTHON_VERSION` env var pull `python-ios-dart-3.14.tar.gz` / `python-macos-dart-3.14.tar.gz` from `flet-dev/python-build`. Set `SERIOUS_PYTHON_VERSION=3.12` to preserve the previous default. * Multi-version Python support. `python_version` in `serious_python_darwin.podspec` reads from `SERIOUS_PYTHON_VERSION`; `prepare_ios.sh` / `prepare_macos.sh` already took the version as `$1` and download the matching tarballs. +* Migrate `prepare_ios.sh` / `prepare_macos.sh` to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-{ios,macos}-dart-.tar.gz`). The podspec now reads `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` (defaults baked in) and passes them as positional args `$2` / `$3` to the prepare scripts. ## 1.0.1 diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index 5d27d850..bc9e2104 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -1,4 +1,6 @@ python_version=${1:?} +python_full_version=${2:?} +python_build_date=${3:?} script_dir=$(cd "$(dirname "$0")" && pwd -P) dist=$script_dir/dist_ios @@ -9,15 +11,15 @@ dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} # Cross-plugin download cache; see prepare_macos.sh for the convention. cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" -pb_cache="$cache_root/python-build/v$python_version" +pb_cache="$cache_root/python-build/v$python_full_version" db_cache="$cache_root/dart-bridge/v$dart_bridge_version" mkdir -p "$pb_cache" "$db_cache" # ---- flet-dev/python-build (iOS embedded Python runtime) ------------------ -python_ios_dist_file="python-ios-dart-$python_version.tar.gz" +python_ios_dist_file="python-ios-dart-$python_full_version.tar.gz" python_ios_dist_path="$pb_cache/$python_ios_dist_file" if [ ! -f "$python_ios_dist_path" ]; then - python_ios_dist_url="https://github.com/flet-dev/python-build/releases/download/v$python_version/$python_ios_dist_file" + python_ios_dist_url="https://github.com/flet-dev/python-build/releases/download/$python_build_date/$python_ios_dist_file" curl -fL -o "$python_ios_dist_path.tmp" "$python_ios_dist_url" mv "$python_ios_dist_path.tmp" "$python_ios_dist_path" fi diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index 3e3e5c88..8ec84880 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -1,4 +1,6 @@ python_version=${1:?} +python_full_version=${2:?} +python_build_date=${3:?} script_dir=$(cd "$(dirname "$0")" && pwd -P) dist=$script_dir/dist_macos @@ -11,15 +13,15 @@ dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} # gradle task + flet build's external tooling already use; ~/.flet/cache is # the shared default. Tarballs land here and survive `flutter clean`. cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" -pb_cache="$cache_root/python-build/v$python_version" +pb_cache="$cache_root/python-build/v$python_full_version" db_cache="$cache_root/dart-bridge/v$dart_bridge_version" mkdir -p "$pb_cache" "$db_cache" # ---- flet-dev/python-build (macOS embedded Python runtime) ---------------- -python_macos_dist_file="python-macos-dart-$python_version.tar.gz" +python_macos_dist_file="python-macos-dart-$python_full_version.tar.gz" python_macos_dist_path="$pb_cache/$python_macos_dist_file" if [ ! -f "$python_macos_dist_path" ]; then - python_macos_dist_url="https://github.com/flet-dev/python-build/releases/download/v$python_version/$python_macos_dist_file" + python_macos_dist_url="https://github.com/flet-dev/python-build/releases/download/$python_build_date/$python_macos_dist_file" # .tmp + mv so a Ctrl-C / network blip doesn't poison the cache. curl -fL -o "$python_macos_dist_path.tmp" "$python_macos_dist_url" mv "$python_macos_dist_path.tmp" "$python_macos_dist_path" diff --git a/src/serious_python_darwin/darwin/serious_python_darwin.podspec b/src/serious_python_darwin/darwin/serious_python_darwin.podspec index 1d313565..80a9d489 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin.podspec +++ b/src/serious_python_darwin/darwin/serious_python_darwin.podspec @@ -33,14 +33,16 @@ Pod::Spec.new do |s| s.swift_version = '5.0' python_version = ENV['SERIOUS_PYTHON_VERSION'] || "3.14" + python_full_version = ENV['SERIOUS_PYTHON_FULL_VERSION'] || "3.14.6" + python_build_date = ENV['SERIOUS_PYTHON_BUILD_DATE'] || "20260611" dist_ios = "dist_ios" dist_macos = "dist_macos" prepare_command = <<-CMD ./symlink_pod.sh - ./prepare_ios.sh #{python_version} - ./prepare_macos.sh #{python_version} + ./prepare_ios.sh #{python_version} #{python_full_version} #{python_build_date} + ./prepare_macos.sh #{python_version} #{python_full_version} #{python_build_date} ./sync_site_packages.sh CMD diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index 04fc548a..babf5411 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -2,6 +2,7 @@ * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). The plugin downloads `python-linux-dart-3.14-.tar.gz` from `flet-dev/python-build` and bundles `libpython3.14.so.1.0` unless `SERIOUS_PYTHON_VERSION=3.12` is set in the build environment. * Multi-version Python support. `PYTHON_VERSION` in `linux/CMakeLists.txt` reads from `SERIOUS_PYTHON_VERSION`, and all `python3.12` / `libpython3.12.so.1.0` / `lib/python3.12` paths are derived from it. The plugin source receives the version via a `SERIOUS_PYTHON_VERSION` compile-time macro so the runtime module path matches the bundled distro. +* Migrate the `python-linux-dart` download URL to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-linux-dart--.tar.gz`). `CMakeLists.txt` now reads `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` from the environment (with baked-in defaults) and the cache directory key uses the full version so patch bumps don't reuse a stale tarball. ## 1.0.1 diff --git a/src/serious_python_linux/linux/CMakeLists.txt b/src/serious_python_linux/linux/CMakeLists.txt index 6654c08b..877da21b 100644 --- a/src/serious_python_linux/linux/CMakeLists.txt +++ b/src/serious_python_linux/linux/CMakeLists.txt @@ -13,6 +13,16 @@ if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) else() set(PYTHON_VERSION "3.14") endif() +if(DEFINED ENV{SERIOUS_PYTHON_FULL_VERSION}) + set(PYTHON_FULL_VERSION "$ENV{SERIOUS_PYTHON_FULL_VERSION}") +else() + set(PYTHON_FULL_VERSION "3.14.6") +endif() +if(DEFINED ENV{SERIOUS_PYTHON_BUILD_DATE}) + set(PYTHON_BUILD_DATE "$ENV{SERIOUS_PYTHON_BUILD_DATE}") +else() + set(PYTHON_BUILD_DATE "20260611") +endif() set(PYTHON_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) if(DEFINED ENV{DART_BRIDGE_VERSION}) set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") @@ -28,7 +38,7 @@ if(DEFINED ENV{FLET_CACHE_DIR}) else() set(FLET_CACHE_DIR "$ENV{HOME}/.flet/cache") endif() -set(PB_CACHE "${FLET_CACHE_DIR}/python-build/v${PYTHON_VERSION}") +set(PB_CACHE "${FLET_CACHE_DIR}/python-build/v${PYTHON_FULL_VERSION}") set(DB_CACHE "${FLET_CACHE_DIR}/dart-bridge/v${DART_BRIDGE_VERSION}") file(MAKE_DIRECTORY "${PB_CACHE}" "${DB_CACHE}") @@ -58,8 +68,8 @@ endfunction() # Tarball lives in the shared cache; extraction targets the per-plugin build # tree so a `flutter clean` doesn't force a re-download. set(PYTHON_PACKAGE ${CMAKE_BINARY_DIR}/python) -set(PYTHON_URL https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz) -set(PYTHON_FILE "${PB_CACHE}/python-linux-dart-${PYTHON_VERSION}-${PYTHON_ARCH}.tar.gz") +set(PYTHON_URL https://github.com/flet-dev/python-build/releases/download/${PYTHON_BUILD_DATE}/python-linux-dart-${PYTHON_FULL_VERSION}-${PYTHON_ARCH}.tar.gz) +set(PYTHON_FILE "${PB_CACHE}/python-linux-dart-${PYTHON_FULL_VERSION}-${PYTHON_ARCH}.tar.gz") _sp_download("${PYTHON_URL}" "${PYTHON_FILE}") if(NOT EXISTS "${PYTHON_PACKAGE}/lib/libpython3.so") file(ARCHIVE_EXTRACT INPUT "${PYTHON_FILE}" DESTINATION "${PYTHON_PACKAGE}") diff --git a/src/serious_python_windows/CHANGELOG.md b/src/serious_python_windows/CHANGELOG.md index ca8b7b90..2abda4a4 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -2,6 +2,7 @@ * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). The plugin downloads `python-windows-for-dart-3.14.zip` and bundles `python314.dll` / `python314.lib` unless `SERIOUS_PYTHON_VERSION=3.12` is set in the build environment. * Multi-version Python support. `PYTHON_VERSION` in `windows/CMakeLists.txt` reads from `SERIOUS_PYTHON_VERSION`; the `python-build` download URL and the `python312.lib` / `python312.dll` filenames are derived from it (e.g. `python313.lib`, `python314.dll`). +* Migrate the `python-windows-for-dart` download URL to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-windows-for-dart-.zip`). `CMakeLists.txt` now reads `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` from the environment (with baked-in defaults) and the cache directory key uses the full version so patch bumps don't reuse a stale zip. ## 1.0.1 diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index a5de6603..dd1efe6c 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -11,6 +11,16 @@ if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) else() set(PYTHON_VERSION "3.14") endif() +if(DEFINED ENV{SERIOUS_PYTHON_FULL_VERSION}) + set(PYTHON_FULL_VERSION "$ENV{SERIOUS_PYTHON_FULL_VERSION}") +else() + set(PYTHON_FULL_VERSION "3.14.6") +endif() +if(DEFINED ENV{SERIOUS_PYTHON_BUILD_DATE}) + set(PYTHON_BUILD_DATE "$ENV{SERIOUS_PYTHON_BUILD_DATE}") +else() + set(PYTHON_BUILD_DATE "20260611") +endif() string(REPLACE "." "" PYTHON_VERSION_NODOT "${PYTHON_VERSION}") if(DEFINED ENV{DART_BRIDGE_VERSION}) set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") @@ -31,7 +41,7 @@ elseif(DEFINED ENV{USERPROFILE}) else() set(FLET_CACHE_DIR "$ENV{HOME}/.flet/cache") endif() -set(PB_CACHE "${FLET_CACHE_DIR}/python-build/v${PYTHON_VERSION}") +set(PB_CACHE "${FLET_CACHE_DIR}/python-build/v${PYTHON_FULL_VERSION}") set(DB_CACHE "${FLET_CACHE_DIR}/dart-bridge/v${DART_BRIDGE_VERSION}") file(MAKE_DIRECTORY "${PB_CACHE}" "${DB_CACHE}") @@ -51,10 +61,10 @@ set(PLUGIN_NAME "serious_python_windows_plugin") # python3.dll can forward to python3X.dll. We no longer need the .lib / headers # here because no Python C API call sites live in this plugin anymore. set(PYTHON_PACKAGE ${CMAKE_BINARY_DIR}/python) -set(PYTHON_URL "https://github.com/flet-dev/python-build/releases/download/v${PYTHON_VERSION}/python-windows-for-dart-${PYTHON_VERSION}.zip") +set(PYTHON_URL "https://github.com/flet-dev/python-build/releases/download/${PYTHON_BUILD_DATE}/python-windows-for-dart-${PYTHON_FULL_VERSION}.zip") # Tarball lives in the shared cache; extraction targets the per-plugin build # tree so a `flutter clean` doesn't force a re-download. -set(PYTHON_FILE "${PB_CACHE}/python-windows-for-dart-${PYTHON_VERSION}.zip") +set(PYTHON_FILE "${PB_CACHE}/python-windows-for-dart-${PYTHON_FULL_VERSION}.zip") function(_sp_download url dest) if(EXISTS "${dest}") From 9b4fa870b58f136a72f5e630623eceaa3aea4ea0 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 11:46:10 -0700 Subject: [PATCH 088/114] Add `serious_python:main version [--json]` + CI vars from registry The Dart `_pythonReleases` registry is the source of truth for the Python version matrix, but until now CI (and any other external consumer) needed a hand-maintained lookup table to derive the full patch version + python-build release date from the short SERIOUS_PYTHON_VERSION. Last CI run failed exactly because the new SERIOUS_PYTHON_FULL_VERSION / SERIOUS_PYTHON_BUILD_DATE env vars were unset in CI, the plugin scripts fell back to their 3.14.6/20260611 defaults, and Linux's ninja then complained that the 3.12 tarball was missing libpython3.14.so.1.0. New `version` subcommand emits the registry as either a human-readable summary or `--json` (machine-readable). Self-version comes from pubspec.yaml looked up via `package_config` (no Dart constant to keep in sync). Registry rows are sorted descending in the text output to match `flet --version` ordering. `_pythonReleases` and `_PythonRelease` promoted to `pythonReleases` / `PythonRelease` so the new file can reference them. Internal callers in `package_command.dart` updated to match. CI: new composite action `.github/actions/resolve-python-vars` runs `dart run serious_python:main version --json` + `jq` to write SERIOUS_PYTHON_FULL_VERSION and SERIOUS_PYTHON_BUILD_DATE into `$GITHUB_ENV`. Inserted as a `Resolve Python version vars` step right after `Setup Flutter` in all 15 test jobs (publish job left untouched). Future Python registry bumps need no CI changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../actions/resolve-python-vars/action.yml | 38 ++++++++ .github/workflows/ci.yml | 45 ++++++++++ src/serious_python/bin/main.dart | 4 +- src/serious_python/bin/package_command.dart | 26 +++--- src/serious_python/bin/version_command.dart | 89 +++++++++++++++++++ src/serious_python/pubspec.yaml | 1 + 6 files changed, 189 insertions(+), 14 deletions(-) create mode 100644 .github/actions/resolve-python-vars/action.yml create mode 100644 src/serious_python/bin/version_command.dart diff --git a/.github/actions/resolve-python-vars/action.yml b/.github/actions/resolve-python-vars/action.yml new file mode 100644 index 00000000..cb6e042d --- /dev/null +++ b/.github/actions/resolve-python-vars/action.yml @@ -0,0 +1,38 @@ +name: Resolve serious_python Python-version vars +description: | + Derive `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` for + the current `SERIOUS_PYTHON_VERSION` from `dart run serious_python:main + version --json` and export them to `$GITHUB_ENV` so subsequent steps — + including the platform plugin build scripts (Android `build.gradle`, + Darwin `prepare_{ios,macos}.sh`, Linux/Windows `CMakeLists.txt`) — pick + up the registry-correct values without having to hand-maintain a lookup + table in the workflow. + + Requires Flutter to be on PATH and `SERIOUS_PYTHON_VERSION` to be set in + env (typically by the caller's `env:` block, keyed off + `matrix.python_version`). + +runs: + using: composite + steps: + - name: Resolve full version + python-build date + shell: bash + working-directory: src/serious_python + run: | + set -euo pipefail + if [[ -z "${SERIOUS_PYTHON_VERSION:-}" ]]; then + echo "::error::SERIOUS_PYTHON_VERSION is not set in env." + exit 1 + fi + flutter pub get >/dev/null + json=$(dart run serious_python:main version --json) + full=$(echo "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".standalone_version") + date=$(echo "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".python_build_release_date") + if [[ -z "$full" || "$full" == "null" || -z "$date" || "$date" == "null" ]]; then + echo "::error::serious_python:main version --json did not return values for SERIOUS_PYTHON_VERSION=${SERIOUS_PYTHON_VERSION}" + echo "$json" + exit 1 + fi + echo "SERIOUS_PYTHON_FULL_VERSION=$full" >> "$GITHUB_ENV" + echo "SERIOUS_PYTHON_BUILD_DATE=$date" >> "$GITHUB_ENV" + echo "Resolved Python $SERIOUS_PYTHON_VERSION: full=$full, python-build date=$date" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bb89333..775a2c3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | @@ -86,6 +89,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Setup iOS Simulator id: simulator uses: futureware-tech/simulator-action@v4 @@ -123,6 +129,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -183,6 +192,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Run tests working-directory: "src/serious_python/example/flet_example" run: | @@ -227,6 +239,9 @@ jobs: channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} # https://github.com/subosito/flutter-action/issues/345#issuecomment-2657332687 cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Install dependencies run: | sudo apt-get update --allow-releaseinfo-change @@ -285,6 +300,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads uses: actions/cache@v4 with: @@ -324,6 +342,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads uses: actions/cache@v4 with: @@ -373,6 +394,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads uses: actions/cache@v4 with: @@ -446,6 +470,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads uses: actions/cache@v4 with: @@ -505,6 +532,9 @@ jobs: channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads uses: actions/cache@v4 with: @@ -576,6 +606,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Package + run integration test working-directory: "src/serious_python/example/bridge_example" run: | @@ -603,6 +636,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + # Replaced by the unified ~/.flet/cache step lifted to every job; left # the comment for git-blame breadcrumb. The bridge_example matrix is # gated off pending re-enable; once flipped back on, add the cache @@ -655,6 +691,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -733,6 +772,9 @@ jobs: path: '.fvmrc' cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Package + run integration test working-directory: "src/serious_python/example/bridge_example" shell: bash @@ -798,6 +840,9 @@ jobs: channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} cache: true + - name: Resolve Python version vars + uses: ./.github/actions/resolve-python-vars + - name: Install Linux desktop build deps run: | sudo apt-get update --allow-releaseinfo-change diff --git a/src/serious_python/bin/main.dart b/src/serious_python/bin/main.dart index 6beb72eb..7e03cff1 100644 --- a/src/serious_python/bin/main.dart +++ b/src/serious_python/bin/main.dart @@ -1,11 +1,13 @@ import 'package:args/command_runner.dart'; import 'package_command.dart'; +import 'version_command.dart'; void main(List arguments) async { var runner = CommandRunner("dart run serious_python:main", "A tool for packaging Python apps to work with serious_python package.") - ..addCommand(PackageCommand()); + ..addCommand(PackageCommand()) + ..addCommand(VersionCommand()); await runner.run(arguments); } diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index 66e2a8f7..70d78eea 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -32,8 +32,8 @@ const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION"; const defaultPythonVersion = "3.14"; -class _PythonRelease { - const _PythonRelease({ +class PythonRelease { + const PythonRelease({ required this.standaloneVersion, required this.standaloneReleaseDate, required this.pythonBuildReleaseDate, @@ -61,8 +61,8 @@ class _PythonRelease { // Source of truth for the Python <-> CPython standalone <-> Pyodide mapping. // Mirror any change here in flet-cli's python_versions.py. -const _pythonReleases = { - "3.12": _PythonRelease( +const pythonReleases = { + "3.12": PythonRelease( standaloneVersion: "3.12.13", standaloneReleaseDate: "20260610", pythonBuildReleaseDate: "20260611", @@ -70,7 +70,7 @@ const _pythonReleases = { pyodidePlatformTag: "pyodide-2024.0-wasm32", prerelease: false, ), - "3.13": _PythonRelease( + "3.13": PythonRelease( standaloneVersion: "3.13.14", standaloneReleaseDate: "20260610", pythonBuildReleaseDate: "20260611", @@ -78,7 +78,7 @@ const _pythonReleases = { pyodidePlatformTag: "pyemscripten-2025.0-wasm32", prerelease: false, ), - "3.14": _PythonRelease( + "3.14": PythonRelease( standaloneVersion: "3.14.6", standaloneReleaseDate: "20260610", pythonBuildReleaseDate: "20260611", @@ -91,7 +91,7 @@ const _pythonReleases = { // `requires-python = "==3.15.*"` on the Flet CLI side) without becoming // the default or matching open-ended `requires-python` specifiers. // - // "3.15": _PythonRelease( + // "3.15": PythonRelease( // standaloneVersion: "3.15.0", // standaloneReleaseDate: "...", // pythonBuildReleaseDate: "...", @@ -125,7 +125,7 @@ const platforms = { }, "Emscripten": { // The actual wheel platform tag is resolved per Python release from - // `_pythonReleases[...].pyodidePlatformTag` (see sitecustomize wiring + // `pythonReleases[...].pyodidePlatformTag` (see sitecustomize wiring // below) since it changes with each Pyodide ABI bump. "": {"tag": "", "mac_ver": ""} }, @@ -168,7 +168,7 @@ class PackageCommand extends Command { Directory? _buildDir; Directory? _pythonDir; late String _pythonShortVersion; - late _PythonRelease _release; + late PythonRelease _release; String get _pyodideRootUrl => "https://cdn.jsdelivr.net/pyodide/v${_release.pyodideVersion}/full"; @@ -200,7 +200,7 @@ class PackageCommand extends Command { mandatory: true, help: "Install dependencies for specific platform, e.g. 'Android'."); argParser.addOption('python-version', - allowed: _pythonReleases.keys.toList(), + allowed: pythonReleases.keys.toList(), help: "Short Python version to bundle (e.g. 3.13). Defaults to " "\$$pythonVersionEnvironmentVariable env var or " "'$defaultPythonVersion'."); @@ -280,13 +280,13 @@ class PackageCommand extends Command { _pythonShortVersion = argResults?['python-version'] ?? Platform.environment[pythonVersionEnvironmentVariable] ?? defaultPythonVersion; - final baseRelease = _pythonReleases[_pythonShortVersion]; + final baseRelease = pythonReleases[_pythonShortVersion]; if (baseRelease == null) { stderr.writeln( - "Unknown Python version: $_pythonShortVersion. Supported: ${_pythonReleases.keys.join(", ")}"); + "Unknown Python version: $_pythonShortVersion. Supported: ${pythonReleases.keys.join(", ")}"); exit(2); } - _release = _PythonRelease( + _release = PythonRelease( standaloneVersion: Platform.environment[pythonFullVersionEnvironmentVariable] ?? baseRelease.standaloneVersion, diff --git a/src/serious_python/bin/version_command.dart b/src/serious_python/bin/version_command.dart new file mode 100644 index 00000000..2801316c --- /dev/null +++ b/src/serious_python/bin/version_command.dart @@ -0,0 +1,89 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:package_config/package_config.dart'; + +import 'package_command.dart'; + +/// `version` subcommand: prints the serious_python package version, the +/// default Python version, and the supported-Python matrix sourced from +/// [pythonReleases] in `package_command.dart`. With `--json`, emits a +/// machine-readable document for CI / tooling consumption. +class VersionCommand extends Command { + @override + final name = "version"; + + @override + final description = + "Print serious_python version and the supported Python matrix."; + + VersionCommand() { + argParser.addFlag( + "json", + help: "Emit machine-readable JSON instead of the human-readable summary.", + negatable: false, + ); + } + + @override + Future run() async { + final version = await _readSeriousPythonVersion() ?? "unknown"; + final jsonMode = argResults?["json"] ?? false; + + if (jsonMode) { + final doc = { + "serious_python_version": version, + "default_python_version": defaultPythonVersion, + "python_releases": { + for (final entry in pythonReleases.entries) + entry.key: { + "standalone_version": entry.value.standaloneVersion, + "standalone_release_date": entry.value.standaloneReleaseDate, + "python_build_release_date": entry.value.pythonBuildReleaseDate, + "pyodide_version": entry.value.pyodideVersion, + "pyodide_platform_tag": entry.value.pyodidePlatformTag, + "prerelease": entry.value.prerelease, + }, + }, + }; + stdout.writeln(const JsonEncoder.withIndent(" ").convert(doc)); + return; + } + + stdout.writeln("serious_python $version"); + stdout.writeln("Default Python: $defaultPythonVersion"); + stdout.writeln("Supported Python versions:"); + // Sort descending so the default + newest stable is on top, matching the + // ordering convention used by `flet --version`. + final keys = pythonReleases.keys.toList() + ..sort((a, b) => b.compareTo(a)); + for (final k in keys) { + final r = pythonReleases[k]!; + final markers = []; + if (k == defaultPythonVersion) markers.add("default"); + if (r.prerelease) markers.add("pre-release"); + final markerSuffix = markers.isEmpty ? "" : " (${markers.join(", ")})"; + stdout.writeln( + " $k$markerSuffix: CPython ${r.standaloneVersion} / Pyodide ${r.pyodideVersion}"); + } + } + + /// Read this package's `version:` from its `pubspec.yaml`, found via the + /// caller's `package_config.json`. Returns `null` if the package_config + /// can't be located (e.g. invoked from a compiled snapshot outside any + /// pub workspace). + Future _readSeriousPythonVersion() async { + final config = await findPackageConfig(Directory.current); + final pkg = config?["serious_python"]; + if (pkg == null) return null; + final pubspec = File.fromUri(pkg.root.resolve("pubspec.yaml")); + if (!pubspec.existsSync()) return null; + final versionPattern = RegExp(r'^version:\s*(\S+)\s*$'); + for (final line in pubspec.readAsLinesSync()) { + final match = versionPattern.firstMatch(line); + if (match != null) return match.group(1); + } + return null; + } +} diff --git a/src/serious_python/pubspec.yaml b/src/serious_python/pubspec.yaml index d40242dd..89d28bd7 100644 --- a/src/serious_python/pubspec.yaml +++ b/src/serious_python/pubspec.yaml @@ -53,6 +53,7 @@ dependencies: crypto: ^3.0.5 glob: ^2.1.3 ffi: ^2.1.2 + package_config: ^2.1.0 dev_dependencies: flutter_test: From e9f8d306d260dd763a5b85294fcb9770ed6b45e4 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 11:51:34 -0700 Subject: [PATCH 089/114] fix(ci): strip `dart run`'s build preamble before piping JSON into jq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a cold pub-cache, `dart run serious_python:main version --json` prints "Building package executable..." (and "Built …") to stdout ahead of our JSON document. jq then trips on "Building" with "parse error: Invalid numeric literal at line 1, column 8". The resolve-python-vars composite action now pipes the output through `sed -n '/^{/,$p'` so jq sees the JSON document only. Warm-cache invocations (CI cache hits, local dev) are unaffected — the sed pass is a no-op when the first line is already `{`. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/actions/resolve-python-vars/action.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/actions/resolve-python-vars/action.yml b/.github/actions/resolve-python-vars/action.yml index cb6e042d..6499a147 100644 --- a/.github/actions/resolve-python-vars/action.yml +++ b/.github/actions/resolve-python-vars/action.yml @@ -25,7 +25,10 @@ runs: exit 1 fi flutter pub get >/dev/null - json=$(dart run serious_python:main version --json) + # `dart run` writes "Building package executable..." to stdout on a + # cold cache, ahead of our JSON. Strip everything before the opening + # `{` so `jq` sees only the document. + json=$(dart run serious_python:main version --json | sed -n '/^{/,$p') full=$(echo "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".standalone_version") date=$(echo "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".python_build_release_date") if [[ -z "$full" || "$full" == "null" || -z "$date" || "$date" == "null" ]]; then From 35d112eb5c89fa8691a73233bc00e7247a7952c1 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 11:51:50 -0700 Subject: [PATCH 090/114] Bump astral-sh/setup-uv to v8.2.0 Update CI workflow to use astral-sh/setup-uv@v8.2.0 instead of v6 in .github/workflows/ci.yml. Replaces three occurrences to ensure the workflow uses the newer setup-uv release. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 775a2c3b..3c241612 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -224,7 +224,7 @@ jobs: uses: actions/checkout@v6 - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v8.2.0 - name: Get Flutter version from ".fvmrc" uses: kuhnroyal/flutter-fvm-config-action/config@v3 @@ -517,7 +517,7 @@ jobs: uses: actions/checkout@v6 - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v8.2.0 - name: Get Flutter version from ".fvmrc" uses: kuhnroyal/flutter-fvm-config-action/config@v3 @@ -912,7 +912,7 @@ jobs: fetch-depth: 0 - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v8.2.0 - name: Setup Flutter uses: kuhnroyal/flutter-fvm-config-action/setup@v3 From e9611ab3a8f5932867f9de746b690b86919dbb69 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 11:53:37 -0700 Subject: [PATCH 091/114] Some examples cleanup --- .../example/flet_example/app/src/main.py | 2 +- .../flet_example/app/src/main_async.py | 36 ------------------- .../flet_ffi_example/app/src/main_async.py | 36 ------------------- 3 files changed, 1 insertion(+), 73 deletions(-) delete mode 100644 src/serious_python/example/flet_example/app/src/main_async.py delete mode 100644 src/serious_python/example/flet_ffi_example/app/src/main_async.py diff --git a/src/serious_python/example/flet_example/app/src/main.py b/src/serious_python/example/flet_example/app/src/main.py index 59cc8a5b..05c566f1 100644 --- a/src/serious_python/example/flet_example/app/src/main.py +++ b/src/serious_python/example/flet_example/app/src/main.py @@ -73,4 +73,4 @@ def check_ssl(e): if __name__ == "__main__": - ft.app(main) + ft.run(main) diff --git a/src/serious_python/example/flet_example/app/src/main_async.py b/src/serious_python/example/flet_example/app/src/main_async.py deleted file mode 100644 index 38f363de..00000000 --- a/src/serious_python/example/flet_example/app/src/main_async.py +++ /dev/null @@ -1,36 +0,0 @@ -import logging - -import flet as ft - -logging.basicConfig(level=logging.DEBUG) - - -async def main(page: ft.Page): - page.title = "Flet counter example" - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) - - async def minus_click(e): - txt_number.value = str(int(txt_number.value) - 1) - await page.update_async() - - async def plus_click(e): - txt_number.value = str(int(txt_number.value) + 1) - await page.update_async() - - await page.add_async( - ft.Row( - [ - ft.IconButton( - ft.Icons.REMOVE, key="test:decrement", on_click=minus_click - ), - txt_number, - ft.IconButton(ft.Icons.ADD, key="test:increment", on_click=plus_click), - ], - alignment=ft.MainAxisAlignment.CENTER, - ) - ) - - -ft.app(main) diff --git a/src/serious_python/example/flet_ffi_example/app/src/main_async.py b/src/serious_python/example/flet_ffi_example/app/src/main_async.py deleted file mode 100644 index 38f363de..00000000 --- a/src/serious_python/example/flet_ffi_example/app/src/main_async.py +++ /dev/null @@ -1,36 +0,0 @@ -import logging - -import flet as ft - -logging.basicConfig(level=logging.DEBUG) - - -async def main(page: ft.Page): - page.title = "Flet counter example" - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) - - async def minus_click(e): - txt_number.value = str(int(txt_number.value) - 1) - await page.update_async() - - async def plus_click(e): - txt_number.value = str(int(txt_number.value) + 1) - await page.update_async() - - await page.add_async( - ft.Row( - [ - ft.IconButton( - ft.Icons.REMOVE, key="test:decrement", on_click=minus_click - ), - txt_number, - ft.IconButton(ft.Icons.ADD, key="test:increment", on_click=plus_click), - ], - alignment=ft.MainAxisAlignment.CENTER, - ) - ) - - -ft.app(main) From f10dc84bb88f38ddfb0443d4251689374ff58a3e Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 11:58:01 -0700 Subject: [PATCH 092/114] ci(resolve-python-vars): surface dart run stdout+stderr for diagnosis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last CI run failed with "did not return values for SERIOUS_PYTHON_VERSION=3.12" but the composite action's debug `echo "$json"` printed nothing — couldn't tell from the log whether `dart run` errored silently or returned non-JSON. Capture stdout+stderr into a single var, print it verbatim before piping through sed/jq, and let `flutter pub get` print its own progress (was previously >/dev/null). Once we see the actual output we can decide if this is a Dart precompile hiccup, a package_config issue, or something else. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../actions/resolve-python-vars/action.yml | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/actions/resolve-python-vars/action.yml b/.github/actions/resolve-python-vars/action.yml index 6499a147..e0bfcfa5 100644 --- a/.github/actions/resolve-python-vars/action.yml +++ b/.github/actions/resolve-python-vars/action.yml @@ -24,16 +24,20 @@ runs: echo "::error::SERIOUS_PYTHON_VERSION is not set in env." exit 1 fi - flutter pub get >/dev/null - # `dart run` writes "Building package executable..." to stdout on a - # cold cache, ahead of our JSON. Strip everything before the opening - # `{` so `jq` sees only the document. - json=$(dart run serious_python:main version --json | sed -n '/^{/,$p') - full=$(echo "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".standalone_version") - date=$(echo "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".python_build_release_date") + flutter pub get + # Capture stdout+stderr of `dart run` so any failure prose is visible + # for diagnosis. `dart run` writes "Building package executable..." to + # stdout on a cold cache ahead of our JSON; strip everything before + # the opening `{` so `jq` sees only the document. + raw=$(dart run serious_python:main version --json 2>&1) + printf '%s\n' "--- raw output from dart run ---" + printf '%s\n' "$raw" + printf '%s\n' "--- end raw output ---" + json=$(printf '%s\n' "$raw" | sed -n '/^{/,$p') + full=$(printf '%s\n' "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".standalone_version") + date=$(printf '%s\n' "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".python_build_release_date") if [[ -z "$full" || "$full" == "null" || -z "$date" || "$date" == "null" ]]; then echo "::error::serious_python:main version --json did not return values for SERIOUS_PYTHON_VERSION=${SERIOUS_PYTHON_VERSION}" - echo "$json" exit 1 fi echo "SERIOUS_PYTHON_FULL_VERSION=$full" >> "$GITHUB_ENV" From 4d69b4b9b7b4777887cf289463cd696b77f3f66b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 12:02:09 -0700 Subject: [PATCH 093/114] fix(ci): strip dart-run noise via byte-level `{` extraction, not line-based sed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last run uncovered the actual prefix: `dart run` joins "Running build hooks..." (sometimes printed multiple times) onto the same line as our JSON's opening `{`, so my line-based `sed -n '/^{/,$p'` matched no line and ate the JSON entirely. Replace it with `json="{${raw#*\{}"` — bash parameter expansion that extracts from the first `{` byte forward, regardless of newlines. Guard the empty-output case explicitly so the error message is unambiguous. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../actions/resolve-python-vars/action.yml | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/actions/resolve-python-vars/action.yml b/.github/actions/resolve-python-vars/action.yml index e0bfcfa5..daa76eb0 100644 --- a/.github/actions/resolve-python-vars/action.yml +++ b/.github/actions/resolve-python-vars/action.yml @@ -24,20 +24,25 @@ runs: echo "::error::SERIOUS_PYTHON_VERSION is not set in env." exit 1 fi - flutter pub get - # Capture stdout+stderr of `dart run` so any failure prose is visible - # for diagnosis. `dart run` writes "Building package executable..." to - # stdout on a cold cache ahead of our JSON; strip everything before - # the opening `{` so `jq` sees only the document. + flutter pub get >/dev/null + # `dart run` writes mixed noise to stdout on a cold cache — + # "Building package executable...", "Running build hooks..." — and + # the build-hook line gets joined to our JSON's opening `{` with no + # newline, so line-based sed patterns like `^{` miss everything. + # Strip from the byte-level first `{` forward instead. stderr is + # captured alongside stdout so any genuine dart error is visible. raw=$(dart run serious_python:main version --json 2>&1) - printf '%s\n' "--- raw output from dart run ---" - printf '%s\n' "$raw" - printf '%s\n' "--- end raw output ---" - json=$(printf '%s\n' "$raw" | sed -n '/^{/,$p') + if [[ "$raw" != *"{"* ]]; then + echo "::error::dart run produced no JSON for SERIOUS_PYTHON_VERSION=${SERIOUS_PYTHON_VERSION}" + printf '%s\n' "$raw" + exit 1 + fi + json="{${raw#*\{}" full=$(printf '%s\n' "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".standalone_version") date=$(printf '%s\n' "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".python_build_release_date") if [[ -z "$full" || "$full" == "null" || -z "$date" || "$date" == "null" ]]; then echo "::error::serious_python:main version --json did not return values for SERIOUS_PYTHON_VERSION=${SERIOUS_PYTHON_VERSION}" + printf '%s\n' "$json" exit 1 fi echo "SERIOUS_PYTHON_FULL_VERSION=$full" >> "$GITHUB_ENV" From 96507e6f4aef3b5af25c8661f9f146f61e53894f Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 12:38:27 -0700 Subject: [PATCH 094/114] Bump actions/cache to v5 in CI workflow Update .github/workflows/ci.yml to use actions/cache@v5 (replacing actions/cache@v4) for multiple cache steps. The change applies to AVD cache steps and Flet download caches across the CI matrix to pick up fixes and improvements in the newer cache action. --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c241612..ee3e110c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -142,7 +142,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: AVD cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: avd-cache with: path: | @@ -304,7 +304,7 @@ jobs: uses: ./.github/actions/resolve-python-vars - name: Cache flet downloads - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.flet/cache key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} @@ -346,7 +346,7 @@ jobs: uses: ./.github/actions/resolve-python-vars - name: Cache flet downloads - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.flet/cache key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} @@ -398,7 +398,7 @@ jobs: uses: ./.github/actions/resolve-python-vars - name: Cache flet downloads - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.flet/cache key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} @@ -416,7 +416,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: AVD cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: avd-cache with: path: | @@ -474,7 +474,7 @@ jobs: uses: ./.github/actions/resolve-python-vars - name: Cache flet downloads - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.flet/cache key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} @@ -536,7 +536,7 @@ jobs: uses: ./.github/actions/resolve-python-vars - name: Cache flet downloads - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.flet/cache key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} @@ -704,7 +704,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: AVD cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: avd-cache with: path: | From d342a1ff3000ff42e1e151553fe5d1ebb59341d2 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 12:43:13 -0700 Subject: [PATCH 095/114] Bump simulator-action to v5 Update .github/workflows/ci.yml to use futureware-tech/simulator-action@v5 (was @v4) for all 'Setup iOS Simulator' steps across multiple CI jobs, ensuring the workflow uses the newer simulator-action release. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee3e110c..23159996 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: - name: Setup iOS Simulator id: simulator - uses: futureware-tech/simulator-action@v4 + uses: futureware-tech/simulator-action@v5 with: # https://github.com/futureware-tech/simulator-action/wiki/Devices-macos-latest model: 'iPhone 17 Pro Max' @@ -356,7 +356,7 @@ jobs: - name: Setup iOS Simulator id: simulator - uses: futureware-tech/simulator-action@v4 + uses: futureware-tech/simulator-action@v5 with: model: 'iPhone 17 Pro Max' os: "iOS" @@ -646,7 +646,7 @@ jobs: - name: Setup iOS Simulator id: simulator - uses: futureware-tech/simulator-action@v4 + uses: futureware-tech/simulator-action@v5 with: model: 'iPhone 17 Pro Max' os: "iOS" From 97ad66a7ccf8647cfebb464d06b594256e1a83f0 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 13:17:22 -0700 Subject: [PATCH 096/114] consolidate examples; extend bridge_example with perf + memory tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three example directories collapse into two: * `flet_example/` (was `flet_ffi_example/`) — the FFI-transport demo. Sample only; no longer runs in CI. * `bridge_example/` — the raw-PythonBridge CI gate. Extended with interactivity, throughput, and memory tests (details below). * Old `flet_example/` (socket transport) deleted. Its regression coverage is folded into bridge_example: the FFI byte transport underneath every flet example is what bridge_example now tests rigorously. Reasons: * The dart_bridge FFI transport has been green across the full matrix for a week; the socket path was kept around as a fallback that no Flet user will reach now that the template ships FFI. * Maintaining two parallel example apps for the same Python+Flet contract was duplicated work; renaming the FFI one back to flet_example removes the "wait, which one's the recommended path" confusion. CI surgery in .github/workflows/ci.yml: * Removed the five old `flet_example` jobs (macOS/iOS/Android/ Windows/Linux) — they were `if: false`-gated already. * Removed the five `flet_ffi_*` jobs and the FLET_GIT_REF/URL env vars that supported their shallow-clone hack. * Un-gated the five `bridge_example_*` jobs (15-job matrix: macOS×3 × iOS×3 × Android×3 × Windows×3 × Linux ARM/AMD64 ×3). * Added the unified ~/.flet/cache step to each bridge_example job (replaces the lone dist_ios cache). * All test invocations now pass --dart-define=EXPECTED_PYTHON_VERSION so the interactivity test can assert against the embedded interpreter's actual version. * `publish` job's `needs:` list pruned to just the bridge_example_* jobs. bridge_example transport changes: Two independent PythonBridge channels keep the perf/memory test's hot path free of any framing tax while interactivity stays self-describing: * **control** (BRIDGE_EXAMPLE_CONTROL_PORT): UTF-8 JSON frames. Dart sends {"op": "inc"|"dec"|"version"|"mem"}. Python responds with {"event": "count"|"version"|"mem", ...}. Used by the interactivity test and the memory test's snapshot probes. * **echo** (BRIDGE_EXAMPLE_ECHO_PORT): pure raw bytes, no framing. Python's handler is a one-liner that echoes the payload verbatim. Used by the throughput test and the memory test's hammer loop. bridge_example tests (replace the single bridge_echo_test.dart): * `interactivity_test.dart`: taps `Key('increment')` / `Key('decrement')` IconButtons, asserts the counter Text updates (1, then -1 after two decrements). When --dart-define=EXPECTED_PYTHON_VERSION is set, asserts the version Text matches. * `throughput_test.dart`: 100-iter sweep across 1 KB → 16 MB payloads. Logs min/p50/p95/mean per size + MB/s throughput. Asserts a 50 MB/s floor at ≥1 MB to catch order-of-magnitude regressions without flaking on slow Windows Debug runs. Measured on M2 Pro macOS, mean throughput: 1 KB → 23 MB/s (call-overhead-bound below ~64 KB) 64 KB → 1.3 GB/s 256 KB → 2.4 GB/s 1 MB → 4.5 GB/s 4 MB → 5.2 GB/s 16 MB → 7.2 GB/s * `memory_test.dart`: 1000 × 1 MB echo round-trips (~2 GB of bytes moved). Snapshots Python's tracemalloc + RSS before/after via the control channel. Asserts `traced_delta < 5 MB`. Measured on M2 Pro macOS: traced_delta = 0 B (Python heap unchanged across 2 GB throughput) rss_delta = 112 MB (OS-level page residency, expected; not retention) bridge_example Dart side (lib/main.dart): * Two PythonBridges created in main() before runApp() so the testable BridgeExampleHandle is available immediately. * Counter UI (decrement / display / increment) plus a "Python version: …" Text — same shape the old flet_example test asserted against, so the interactivity test pattern is familiar. * BridgeExampleHandle singleton exposes both bridges + ValueNotifiers for counter / version so tests can drive the transport without traversing the widget tree. bridge_example Python side (app/src/main.py): * Two handlers wired to the two ports: JSON dispatcher for control, verbatim echo for the bulk channel. * _rss_bytes() uses resource.getrusage on POSIX (macOS / Linux / Android / iOS) and falls back to ctypes → GetProcessMemoryInfo.WorkingSetSize on Windows. * tracemalloc is started lazily on the first 'mem' op so it doesn't perturb the throughput test. Renamed flet_example internals updated: * pubspec.yaml: name flet_ffi_example → flet_example. * integration_test import path matches the rename. * README rewritten without the "compared to legacy flet_example" framing — there is no other one to compare to now. * Python boot log filename: flet_ffi_boot.log → flet_boot.log. * Android Kotlin package, iOS bundle id, etc. left at their old com.example.fletExample values to avoid Pods churn. --- .github/workflows/ci.yml | 610 +-------- .../example/bridge_example/app/src/main.py | 128 +- .../integration_test/_helpers.dart | 121 ++ .../integration_test/bridge_echo_test.dart | 70 - .../integration_test/interactivity_test.dart | 39 + .../integration_test/memory_test.dart | 69 + .../integration_test/throughput_test.dart | 72 + .../example/bridge_example/lib/main.dart | 185 ++- .../example/bridge_example/macos/Podfile.lock | 10 +- .../macos/Runner.xcodeproj/project.pbxproj | 18 + .../example/flet_example/README.md | 94 +- .../example/flet_example/app/app.zip.hash | 2 +- .../example/flet_example/lib/main.dart | 355 ++--- .../linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 2 - .../example/flet_example/macos/Podfile.lock | 17 +- .../example/flet_example/pubspec.lock | 252 ++-- .../example/flet_example/pubspec.yaml | 6 +- .../windows/flutter/generated_plugins.cmake | 1 + .../example/flet_ffi_example/.gitignore | 46 - .../example/flet_ffi_example/.metadata | 30 - .../example/flet_ffi_example/README.md | 48 - .../flet_ffi_example/analysis_options.yaml | 29 - .../flet_ffi_example/android/.gitignore | 14 - .../flet_ffi_example/android/app/build.gradle | 44 - .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 46 - .../com/example/flet_example/MainActivity.kt | 5 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 - .../app/src/main/res/values/styles.xml | 18 - .../app/src/profile/AndroidManifest.xml | 7 - .../flet_ffi_example/android/build.gradle | 18 - .../android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 5 - .../flet_ffi_example/android/settings.gradle | 30 - .../example/flet_ffi_example/app/app.zip.hash | 1 - .../example/flet_ffi_example/app/src/main.py | 76 -- .../flet_ffi_example/app/src/requirements.txt | 1 - .../integration_test/app_test.dart | 61 - .../example/flet_ffi_example/ios/.gitignore | 34 - .../ios/Flutter/AppFrameworkInfo.plist | 26 - .../ios/Flutter/Debug.xcconfig | 2 - .../ios/Flutter/Release.xcconfig | 2 - .../example/flet_ffi_example/ios/Podfile | 44 - .../example/flet_ffi_example/ios/Podfile.lock | 114 -- .../ios/Runner.xcodeproj/project.pbxproj | 724 ---------- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 98 -- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 -- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 295 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 406 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 450 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 282 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 462 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 704 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 406 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 586 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 862 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 862 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 1674 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 762 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 1226 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 1418 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../flet_ffi_example/ios/Runner/Info.plist | 51 - .../ios/Runner/Runner-Bridging-Header.h | 1 - .../ios/RunnerTests/RunnerTests.swift | 12 - .../example/flet_ffi_example/lib/main.dart | 315 ----- .../example/flet_ffi_example/linux/.gitignore | 1 - .../flet_ffi_example/linux/CMakeLists.txt | 154 --- .../linux/flutter/CMakeLists.txt | 88 -- .../flutter/generated_plugin_registrant.cc | 35 - .../flutter/generated_plugin_registrant.h | 15 - .../linux/flutter/generated_plugins.cmake | 30 - .../example/flet_ffi_example/linux/main.cc | 6 - .../flet_ffi_example/linux/my_application.cc | 104 -- .../flet_ffi_example/linux/my_application.h | 18 - .../example/flet_ffi_example/macos/.gitignore | 7 - .../macos/Flutter/Flutter-Debug.xcconfig | 2 - .../macos/Flutter/Flutter-Release.xcconfig | 2 - .../Flutter/GeneratedPluginRegistrant.swift | 40 - .../example/flet_ffi_example/macos/Podfile | 43 - .../flet_ffi_example/macos/Podfile.lock | 108 -- .../macos/Runner.xcodeproj/project.pbxproj | 809 ----------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 99 -- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../macos/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 68 - .../AppIcon.appiconset/app_icon_1024.png | Bin 102994 -> 0 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 5680 -> 0 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 520 -> 0 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 14142 -> 0 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 1066 -> 0 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 36406 -> 0 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 2218 -> 0 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 ----- .../macos/Runner/Configs/AppInfo.xcconfig | 14 - .../macos/Runner/Configs/Debug.xcconfig | 2 - .../macos/Runner/Configs/Release.xcconfig | 2 - .../macos/Runner/Configs/Warnings.xcconfig | 13 - .../macos/Runner/DebugProfile.entitlements | 12 - .../flet_ffi_example/macos/Runner/Info.plist | 32 - .../macos/Runner/MainFlutterWindow.swift | 15 - .../macos/Runner/Release.entitlements | 8 - .../macos/RunnerTests/RunnerTests.swift | 12 - .../example/flet_ffi_example/pubspec.lock | 1201 ----------------- .../example/flet_ffi_example/pubspec.yaml | 81 -- .../flet_ffi_example/test/widget_test.dart | 10 - .../test_driver/integration_test.dart | 3 - .../example/flet_ffi_example/web/favicon.png | Bin 917 -> 0 bytes .../flet_ffi_example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes .../flet_ffi_example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes .../web/icons/Icon-maskable-192.png | Bin 5594 -> 0 bytes .../web/icons/Icon-maskable-512.png | Bin 20998 -> 0 bytes .../example/flet_ffi_example/web/index.html | 59 - .../flet_ffi_example/web/manifest.json | 35 - .../flet_ffi_example/windows/.gitignore | 17 - .../flet_ffi_example/windows/CMakeLists.txt | 102 -- .../windows/flutter/CMakeLists.txt | 109 -- .../flutter/generated_plugin_registrant.cc | 41 - .../flutter/generated_plugin_registrant.h | 15 - .../windows/flutter/generated_plugins.cmake | 34 - .../windows/runner/CMakeLists.txt | 40 - .../flet_ffi_example/windows/runner/Runner.rc | 121 -- .../windows/runner/flutter_window.cpp | 71 - .../windows/runner/flutter_window.h | 33 - .../flet_ffi_example/windows/runner/main.cpp | 43 - .../windows/runner/resource.h | 16 - .../windows/runner/resources/app_icon.ico | Bin 33772 -> 0 bytes .../windows/runner/runner.exe.manifest | 20 - .../flet_ffi_example/windows/runner/utils.cpp | 65 - .../flet_ffi_example/windows/runner/utils.h | 19 - .../windows/runner/win32_window.cpp | 288 ---- .../windows/runner/win32_window.h | 102 -- 156 files changed, 998 insertions(+), 7929 deletions(-) create mode 100644 src/serious_python/example/bridge_example/integration_test/_helpers.dart delete mode 100644 src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart create mode 100644 src/serious_python/example/bridge_example/integration_test/interactivity_test.dart create mode 100644 src/serious_python/example/bridge_example/integration_test/memory_test.dart create mode 100644 src/serious_python/example/bridge_example/integration_test/throughput_test.dart delete mode 100644 src/serious_python/example/flet_ffi_example/.gitignore delete mode 100644 src/serious_python/example/flet_ffi_example/.metadata delete mode 100644 src/serious_python/example/flet_ffi_example/README.md delete mode 100644 src/serious_python/example/flet_ffi_example/analysis_options.yaml delete mode 100644 src/serious_python/example/flet_ffi_example/android/.gitignore delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/build.gradle delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml delete mode 100644 src/serious_python/example/flet_ffi_example/android/build.gradle delete mode 100644 src/serious_python/example/flet_ffi_example/android/gradle.properties delete mode 100644 src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 src/serious_python/example/flet_ffi_example/android/settings.gradle delete mode 100644 src/serious_python/example/flet_ffi_example/app/app.zip.hash delete mode 100644 src/serious_python/example/flet_ffi_example/app/src/main.py delete mode 100644 src/serious_python/example/flet_ffi_example/app/src/requirements.txt delete mode 100644 src/serious_python/example/flet_ffi_example/integration_test/app_test.dart delete mode 100644 src/serious_python/example/flet_ffi_example/ios/.gitignore delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Podfile delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Podfile.lock delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist delete mode 100644 src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift delete mode 100644 src/serious_python/example/flet_ffi_example/lib/main.dart delete mode 100644 src/serious_python/example/flet_ffi_example/linux/.gitignore delete mode 100644 src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt delete mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt delete mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc delete mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h delete mode 100644 src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake delete mode 100644 src/serious_python/example/flet_ffi_example/linux/main.cc delete mode 100644 src/serious_python/example/flet_ffi_example/linux/my_application.cc delete mode 100644 src/serious_python/example/flet_ffi_example/linux/my_application.h delete mode 100644 src/serious_python/example/flet_ffi_example/macos/.gitignore delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Podfile delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Podfile.lock delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Base.lproj/MainMenu.xib delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift delete mode 100644 src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements delete mode 100644 src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift delete mode 100644 src/serious_python/example/flet_ffi_example/pubspec.lock delete mode 100644 src/serious_python/example/flet_ffi_example/pubspec.yaml delete mode 100644 src/serious_python/example/flet_ffi_example/test/widget_test.dart delete mode 100644 src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart delete mode 100644 src/serious_python/example/flet_ffi_example/web/favicon.png delete mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-192.png delete mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-512.png delete mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-192.png delete mode 100644 src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-512.png delete mode 100644 src/serious_python/example/flet_ffi_example/web/index.html delete mode 100644 src/serious_python/example/flet_ffi_example/web/manifest.json delete mode 100644 src/serious_python/example/flet_ffi_example/windows/.gitignore delete mode 100644 src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt delete mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt delete mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc delete mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h delete mode 100644 src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/main.cpp delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/resource.h delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/resources/app_icon.ico delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/utils.h delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp delete mode 100644 src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23159996..d22e4368 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,264 +24,10 @@ env: # older flet whose transitive deps (e.g. msgpack) have wheels for the # target python_version / platform, leaving the two halves mismatched. FLET_VERSION: "0.85.3" - # Python flet for the FFI-transport example is pinned to a git ref — - # FletDartBridgeServer isn't on PyPI yet. The git URL is given to pip via - # --requirements, which would normally clone the whole flet repo (large) - # inside pip itself. On Windows this can take 30+ minutes and looks like - # a hang because pip emits no progress during git clone. So the FFI jobs - # first do an explicit `git clone --depth 1` into ${{ runner.temp }}/flet - # and then pass the local subpath as the requirement. - FLET_GIT_REF: "dart-bridge" - FLET_GIT_URL: "https://github.com/flet-dev/flet.git" - # Source installs additionally require SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet - # on mobile targets to bypass --only-binary :all:; see package_command.dart. jobs: - macos: - name: Test Flet example on macOS (Python ${{ matrix.python_version }}) - runs-on: macos-26 - # Temporarily disabled — focusing CI on flet_ffi_example while the - # dart_bridge transport stabilises. Flip back on before merging the - # flet PR to confirm the socket transport still works. - if: false - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Run tests - working-directory: "src/serious_python/example/flet_example" - run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} - flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - ios: - name: Test Flet example on iOS (Python ${{ matrix.python_version }}) - runs-on: macos-26 - if: false # see `macos:` for rationale - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Setup iOS Simulator - id: simulator - uses: futureware-tech/simulator-action@v5 - with: - # https://github.com/futureware-tech/simulator-action/wiki/Devices-macos-latest - model: 'iPhone 17 Pro Max' - os: "iOS" - os_version: "26.5" - shutdown_after_job: true - wait_for_boot: true - - - name: Run tests - working-directory: "src/serious_python/example/flet_example" - run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} - flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - android: - name: Test Flet example on Android (Python ${{ matrix.python_version }}) - runs-on: ubuntu-latest - if: false # see `macos:` for rationale - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 - - - name: AVD cache - uses: actions/cache@v5 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd - - - name: Setup Android Emulator + Run tests - uses: reactivecircus/android-emulator-runner@v2 - env: - EMULATOR_PORT: 5554 - with: - avd-name: android_emulator - api-level: 33 - target: google_atd - arch: x86_64 - profile: pixel_5 - sdcard-path-or-size: 128M - ram-size: 2048M - disk-size: 4096M - emulator-port: ${{ env.EMULATOR_PORT }} - disable-animations: true - emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 - pre-emulator-launch-script: | - sdkmanager --list_installed - script: | - cd src/serious_python/example/flet_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} - cd src/serious_python/example/flet_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - windows: - name: Test Flet example on Windows (Python ${{ matrix.python_version }}) - runs-on: windows-latest - if: false # see `macos:` for rationale - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Run tests - working-directory: "src/serious_python/example/flet_example" - run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} - flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - linux: - name: Test Flet example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) - runs-on: ${{ matrix.runner }} - if: false # see `macos:` for rationale - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - arch: [arm64, amd64] - include: - - arch: arm64 - runner: ubuntu-24.04-arm - title: ARM64 - - arch: amd64 - runner: ubuntu-24.04 - title: AMD64 - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup uv - uses: astral-sh/setup-uv@v8.2.0 - - - name: Get Flutter version from ".fvmrc" - uses: kuhnroyal/flutter-fvm-config-action/config@v3 - id: fvm-config-action - with: - path: '.fvmrc' - - - name: Setup Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} - channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} # https://github.com/subosito/flutter-action/issues/345#issuecomment-2657332687 - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Install dependencies - run: | - sudo apt-get update --allow-releaseinfo-change - sudo apt-get install -y xvfb libgtk-3-dev - - if [ "${{ matrix.arch }}" = "amd64" ]; then - sudo apt-get install -y \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-libav \ - gstreamer1.0-tools \ - gstreamer1.0-x \ - gstreamer1.0-alsa \ - gstreamer1.0-gl \ - gstreamer1.0-gtk3 \ - gstreamer1.0-qt5 \ - gstreamer1.0-pulseaudio - else - sudo apt-get install -y \ - clang \ - ninja-build \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-libav - fi - - - name: Run tests - working-directory: src/serious_python/example/flet_example - run: | - flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements flet==${{ env.FLET_VERSION }} - xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - flet_ffi_macos: - name: Test Flet FFI example on macOS (Python ${{ matrix.python_version }}) + bridge_example_macos: + name: Test Bridge example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 strategy: fail-fast: false @@ -289,7 +35,6 @@ jobs: python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository uses: actions/checkout@v6 @@ -312,154 +57,22 @@ jobs: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - - name: Run tests - working-directory: "src/serious_python/example/flet_ffi_example" + - name: Package + run integration test + working-directory: "src/serious_python/example/bridge_example" run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" - flutter test integration_test --device-id macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} + flutter test integration_test -d macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - flet_ffi_ios: - name: Test Flet FFI example on iOS (Python ${{ matrix.python_version }}) + bridge_example_ios: + name: Test Bridge example on iOS (Python ${{ matrix.python_version }}) runs-on: macos-26 + timeout-minutes: 25 strategy: fail-fast: false matrix: python_version: ['3.12', '3.13', '3.14'] env: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Cache flet downloads - uses: actions/cache@v5 - with: - path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} - restore-keys: | - flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- - flet-cache-${{ runner.os }}-${{ runner.arch }}- - - - name: Setup iOS Simulator - id: simulator - uses: futureware-tech/simulator-action@v5 - with: - model: 'iPhone 17 Pro Max' - os: "iOS" - os_version: "26.5" - shutdown_after_job: true - wait_for_boot: true - - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - - name: Run tests - working-directory: "src/serious_python/example/flet_ffi_example" - run: | - dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" - flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - flet_ffi_android: - name: Test Flet FFI example on Android (Python ${{ matrix.python_version }}) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Cache flet downloads - uses: actions/cache@v5 - with: - path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} - restore-keys: | - flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- - flet-cache-${{ runner.os }}-${{ runner.arch }}- - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 - - - name: AVD cache - uses: actions/cache@v5 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-ffi - - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - - name: Setup Android Emulator + Run tests - uses: reactivecircus/android-emulator-runner@v2 - env: - EMULATOR_PORT: 5554 - with: - avd-name: android_emulator - api-level: 33 - target: google_atd - arch: x86_64 - profile: pixel_5 - sdcard-path-or-size: 128M - ram-size: 2048M - disk-size: 4096M - emulator-port: ${{ env.EMULATOR_PORT }} - disable-animations: true - emulator-options: -no-window -noaudio -no-boot-anim -wipe-data -cache-size 1000 -partition-size 8192 - pre-emulator-launch-script: | - sdkmanager --list_installed - script: | - cd src/serious_python/example/flet_ffi_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" - cd src/serious_python/example/flet_ffi_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - flet_ffi_windows: - name: Test Flet FFI example on Windows (Python ${{ matrix.python_version }}) - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet steps: - name: Checkout repository uses: actions/checkout@v6 @@ -482,168 +95,6 @@ jobs: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- - - name: Shallow-clone flet (dart-bridge) - shell: bash - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${RUNNER_TEMP}/flet-src" - - - name: Run tests - working-directory: "src/serious_python/example/flet_ffi_example" - shell: bash - run: | - dart run serious_python:main package app/src --platform Windows --python-version ${{ matrix.python_version }} --requirements "${RUNNER_TEMP}/flet-src/sdk/python/packages/flet" - flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - flet_ffi_linux: - name: Test Flet FFI example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - arch: [arm64, amd64] - include: - - arch: arm64 - runner: ubuntu-24.04-arm - title: ARM64 - - arch: amd64 - runner: ubuntu-24.04 - title: AMD64 - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS: flet - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup uv - uses: astral-sh/setup-uv@v8.2.0 - - - name: Get Flutter version from ".fvmrc" - uses: kuhnroyal/flutter-fvm-config-action/config@v3 - id: fvm-config-action - with: - path: '.fvmrc' - - - name: Setup Flutter - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} - channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Cache flet downloads - uses: actions/cache@v5 - with: - path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} - restore-keys: | - flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- - flet-cache-${{ runner.os }}-${{ runner.arch }}- - - - name: Install dependencies - run: | - sudo apt-get update --allow-releaseinfo-change - sudo apt-get install -y xvfb libgtk-3-dev - - if [ "${{ matrix.arch }}" = "amd64" ]; then - sudo apt-get install -y \ - libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-libav \ - gstreamer1.0-tools \ - gstreamer1.0-x \ - gstreamer1.0-alsa \ - gstreamer1.0-gl \ - gstreamer1.0-gtk3 \ - gstreamer1.0-qt5 \ - gstreamer1.0-pulseaudio - else - sudo apt-get install -y \ - clang \ - ninja-build \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-libav - fi - - - name: Shallow-clone flet (dart-bridge) - run: | - git clone --depth 1 --branch "${FLET_GIT_REF}" "${FLET_GIT_URL}" "${{ runner.temp }}/flet-src" - - - name: Run tests - working-directory: src/serious_python/example/flet_ffi_example - run: | - flutter pub get - dart run serious_python:main package app/src --platform Linux --python-version ${{ matrix.python_version }} --requirements "${{ runner.temp }}/flet-src/sdk/python/packages/flet" - xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - - bridge_example_macos: - name: Test Bridge example on macOS (Python ${{ matrix.python_version }}) - runs-on: macos-26 - if: false # see `macos:` for rationale - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - - name: Package + run integration test - working-directory: "src/serious_python/example/bridge_example" - run: | - dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} - flutter test integration_test -d macos - - bridge_example_ios: - name: Test Bridge example on iOS (Python ${{ matrix.python_version }}) - runs-on: macos-26 - timeout-minutes: 25 - if: false # see `macos:` for rationale - strategy: - fail-fast: false - matrix: - python_version: ['3.12', '3.13', '3.14'] - env: - SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - # Replaced by the unified ~/.flet/cache step lifted to every job; left - # the comment for git-blame breadcrumb. The bridge_example matrix is - # gated off pending re-enable; once flipped back on, add the cache - # step here too (copy from any flet_ffi_* job). - - name: Setup iOS Simulator id: simulator uses: futureware-tech/simulator-action@v5 @@ -666,13 +117,12 @@ jobs: # --requirements skips that branch and the build fails. dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi echo "[$(ts)] >>> flutter test integration_test" - flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} + flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} echo "[$(ts)] >>> done" bridge_example_android: name: Test Bridge example on Android (Python ${{ matrix.python_version }}) runs-on: ubuntu-latest - if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -694,6 +144,15 @@ jobs: - name: Resolve Python version vars uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads + uses: actions/cache@v5 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -732,7 +191,7 @@ jobs: sdkmanager --list_installed script: | cd src/serious_python/example/bridge_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} - cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} + cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - name: Diagnostics on failure if: failure() @@ -755,7 +214,6 @@ jobs: bridge_example_windows: name: Test Bridge example on Windows (Python ${{ matrix.python_version }}) runs-on: windows-latest - if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -775,6 +233,15 @@ jobs: - name: Resolve Python version vars uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads + uses: actions/cache@v5 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Package + run integration test working-directory: "src/serious_python/example/bridge_example" shell: bash @@ -784,7 +251,7 @@ jobs: # (default PowerShell shell on windows runners eats the failure when # piping into tail). set -o pipefail - flutter test integration_test -d windows -v 2>&1 | tail -300 + flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - name: Diagnostics on failure if: failure() @@ -808,7 +275,6 @@ jobs: bridge_example_linux: name: Test Bridge example on Linux ${{ matrix.title }} (Python ${{ matrix.python_version }}) runs-on: ${{ matrix.runner }} - if: false # see `macos:` for rationale strategy: fail-fast: false matrix: @@ -843,6 +309,15 @@ jobs: - name: Resolve Python version vars uses: ./.github/actions/resolve-python-vars + - name: Cache flet downloads + uses: actions/cache@v5 + with: + path: ~/.flet/cache + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + restore-keys: | + flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- + flet-cache-${{ runner.os }}-${{ runner.arch }}- + - name: Install Linux desktop build deps run: | sudo apt-get update --allow-releaseinfo-change @@ -867,7 +342,7 @@ jobs: --platform Linux \ --python-version ${{ matrix.python_version }} set -o pipefail - xvfb-run flutter test integration_test -d linux -v 2>&1 | tail -300 + xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - name: Diagnostics on failure if: failure() @@ -892,11 +367,6 @@ jobs: publish: name: Publish to pub.dev needs: - - macos - - ios - - android - - windows - - linux - bridge_example_macos - bridge_example_ios - bridge_example_android diff --git a/src/serious_python/example/bridge_example/app/src/main.py b/src/serious_python/example/bridge_example/app/src/main.py index e3eacfb3..1b10d4fb 100644 --- a/src/serious_python/example/bridge_example/app/src/main.py +++ b/src/serious_python/example/bridge_example/app/src/main.py @@ -1,40 +1,136 @@ -"""Echo loop exercising PythonBridge (dart_bridge v1.2.0 keyed-handlers API). +"""Two-channel PythonBridge harness for bridge_example. -Protocol: - Dart side creates a PythonBridge; its native port is handed to Python via - the BRIDGE_EXAMPLE_PORT env var. Python registers a handler for that port - and echoes each received frame back prefixed with b"echo: ". +Channels (matching dart_bridge v1.2+ keyed-handler API; each +PythonBridge instance has its own native port): -Python keeps the interpreter alive indefinitely so messages can keep arriving; -Dart drives the process lifetime (when the app exits, the embedded Python is -torn down). + - **control** (BRIDGE_EXAMPLE_CONTROL_PORT): UTF-8 JSON frames. Dart + sends `{"op": ...}`; Python responds with `{"event": ...}`. Used + by the interactivity test (counter + version) and the memory test + (rss + tracemalloc snapshots). + - **echo** (BRIDGE_EXAMPLE_ECHO_PORT): pure raw bytes. Python echoes + whatever it receives, verbatim. Used by the throughput test and + by the memory test's hammer loop — keeping the per-frame cost on + Python's side as close to zero as possible so any cost we measure + is the transport's. + +Python keeps the interpreter alive indefinitely so messages can keep +arriving; Dart drives the process lifetime. """ from __future__ import annotations +import json import os import sys import threading +import tracemalloc import dart_bridge -PORT_ENV = "BRIDGE_EXAMPLE_PORT" +CONTROL_PORT_ENV = "BRIDGE_EXAMPLE_CONTROL_PORT" +ECHO_PORT_ENV = "BRIDGE_EXAMPLE_ECHO_PORT" try: - bridge_port = int(os.environ[PORT_ENV]) + control_port = int(os.environ[CONTROL_PORT_ENV]) + echo_port = int(os.environ[ECHO_PORT_ENV]) except (KeyError, ValueError) as e: - print(f"[bridge_example] missing/invalid {PORT_ENV}: {e}", + print(f"[bridge_example] missing/invalid env var: {e}", file=sys.stderr, flush=True) raise SystemExit(1) +counter = 0 + + +def _rss_bytes() -> int: + """Resident set size, in bytes. + + POSIX: ``resource.getrusage(RUSAGE_SELF).ru_maxrss``. macOS reports + bytes; Linux/Android report kilobytes. We leave that unit quirk to + the Dart caller — the leak assertion relies on ``tracemalloc``'s + unit-stable bytes count, not on this number. + + Windows: ``resource`` isn't available — fall back to ctypes → + GetProcessMemoryInfo.WorkingSetSize. + """ + try: + import resource + return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + except (ImportError, AttributeError): + import ctypes + from ctypes import wintypes + + class _PMC(ctypes.Structure): + _fields_ = [ + ("cb", wintypes.DWORD), + ("PageFaultCount", wintypes.DWORD), + ("PeakWorkingSetSize", ctypes.c_size_t), + ("WorkingSetSize", ctypes.c_size_t), + ("QuotaPeakPagedPoolUsage", ctypes.c_size_t), + ("QuotaPagedPoolUsage", ctypes.c_size_t), + ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t), + ("QuotaNonPagedPoolUsage", ctypes.c_size_t), + ("PagefileUsage", ctypes.c_size_t), + ("PeakPagefileUsage", ctypes.c_size_t), + ] + + psapi = ctypes.WinDLL("psapi") + proc = ctypes.windll.kernel32.GetCurrentProcess() + pmc = _PMC() + pmc.cb = ctypes.sizeof(_PMC) + psapi.GetProcessMemoryInfo(proc, ctypes.byref(pmc), pmc.cb) + return pmc.WorkingSetSize + + +def _emit(event: dict) -> None: + dart_bridge.send_bytes(control_port, json.dumps(event).encode("utf-8")) + + +def on_control(payload: bytes) -> None: + global counter + if not payload: + return + try: + msg = json.loads(payload.decode("utf-8")) + except (UnicodeDecodeError, json.JSONDecodeError): + # Forward-compatible: unknown / unparseable frames are dropped + # silently rather than crashing the interpreter. + return + op = msg.get("op") + if op == "inc": + counter += 1 + _emit({"event": "count", "value": counter}) + elif op == "dec": + counter -= 1 + _emit({"event": "count", "value": counter}) + elif op == "version": + v = sys.version_info + _emit({"event": "version", "value": f"{v.major}.{v.minor}.{v.micro}"}) + elif op == "mem": + # tracemalloc adds ~10–20% overhead so we don't enable it until the + # memory test asks for it — keeps the throughput test pristine. + if not tracemalloc.is_tracing(): + tracemalloc.start() + cur, peak = tracemalloc.get_traced_memory() + _emit({ + "event": "mem", + "rss": _rss_bytes(), + "traced_current": cur, + "traced_peak": peak, + }) + -def on_dart_message(data: bytes) -> None: - print(f"[bridge_example] received {len(data)} bytes", flush=True) - dart_bridge.send_bytes(bridge_port, b"echo: " + data) +def on_echo(payload: bytes) -> None: + # Verbatim, zero framing. The Dart-side Stopwatch around send → + # bridge.messages.first wraps exactly the bridge transport. + dart_bridge.send_bytes(echo_port, payload) -dart_bridge.set_enqueue_handler_func(bridge_port, on_dart_message) -print(f"[bridge_example] handler registered on port {bridge_port}", flush=True) +dart_bridge.set_enqueue_handler_func(control_port, on_control) +dart_bridge.set_enqueue_handler_func(echo_port, on_echo) +print( + f"[bridge_example] control_port={control_port} echo_port={echo_port}", + flush=True, +) # Keep the embedded interpreter alive; Dart drives the process lifetime. threading.Event().wait() diff --git a/src/serious_python/example/bridge_example/integration_test/_helpers.dart b/src/serious_python/example/bridge_example/integration_test/_helpers.dart new file mode 100644 index 00000000..a0dc7f5e --- /dev/null +++ b/src/serious_python/example/bridge_example/integration_test/_helpers.dart @@ -0,0 +1,121 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:bridge_example/main.dart' as app; +import 'package:flutter_test/flutter_test.dart'; +import 'package:serious_python/bridge.dart'; + +/// Boot the host app and wait for both PythonBridge channels to be ready +/// (i.e. for Python to have registered its handlers via +/// `dart_bridge.set_enqueue_handler_func`). Once this returns, [sendControl] +/// and `echoRoundTrip` will succeed without retry overhead. +Future bootAndAwaitReady(WidgetTester tester) async { + app.main(); + // Give Flutter + Python a beat. Python starts on a worker thread and + // registers handlers before its `threading.Event().wait()` parks. + await tester.pumpAndSettle(const Duration(seconds: 2)); + + final handle = app.BridgeExampleHandle.instance; + + // Wait for the version event main() requested during initState. It only + // arrives after Python's handler is registered, so it's a natural + // readiness signal for the control channel. + final deadline = DateTime.now().add(const Duration(seconds: 30)); + while (handle.pythonVersion.value == null) { + if (DateTime.now().isAfter(deadline)) { + throw TimeoutException( + 'Python control handler never responded with version event'); + } + await tester.pump(const Duration(milliseconds: 100)); + } + + // Probe the echo channel separately — handlers register independently and + // there's no inherent ordering guarantee. + await _probeEchoReady(handle.echoBridge); + return handle; +} + +Future _probeEchoReady(PythonBridge echo) async { + final probe = Uint8List.fromList([0x00, 0x42]); + final reply = echo.messages + .firstWhere((b) => b.length == probe.length) + .timeout(const Duration(seconds: 30)); + const interval = Duration(milliseconds: 100); + const deadline = Duration(seconds: 30); + final start = DateTime.now(); + while (true) { + if (echo.send(probe)) break; + if (DateTime.now().difference(start) > deadline) { + throw TimeoutException( + 'Python echo handler never registered after $deadline'); + } + await Future.delayed(interval); + } + await reply; +} + +/// Send a JSON control op (Dart→Python). +void sendControl(app.BridgeExampleHandle handle, Map op) { + handle.sendControl(op); +} + +/// Wait for the next control frame with `event == name`, JSON-decoded. +Future> waitControlEvent( + app.BridgeExampleHandle handle, + String name, { + Duration timeout = const Duration(seconds: 5), +}) { + return handle.controlBridge.messages + .map((b) => jsonDecode(utf8.decode(b)) as Map) + .firstWhere((msg) => msg['event'] == name) + .timeout(timeout); +} + +/// One-shot echo round-trip: send `payload`, await the next frame whose +/// length matches, return it. No opcode parsing — the echo channel speaks +/// raw bytes only. +Future echoRoundTrip( + app.BridgeExampleHandle handle, + Uint8List payload, { + Duration timeout = const Duration(seconds: 30), +}) { + final reply = handle.echoBridge.messages + .firstWhere((b) => b.length == payload.length) + .timeout(timeout); + if (!handle.echoBridge.send(payload)) { + return Future.error(StateError( + 'echo bridge handler not registered — call bootAndAwaitReady first')); + } + return reply; +} + +/// Memory snapshot from the Python side (rss in bytes; tracemalloc current +/// and peak in bytes). Convenience wrapper over `sendControl({'op': 'mem'})` +/// + `waitControlEvent('mem')`. +class MemSnapshot { + MemSnapshot({ + required this.rss, + required this.tracedCurrent, + required this.tracedPeak, + }); + final int rss; + final int tracedCurrent; + final int tracedPeak; + + @override + String toString() => + 'MemSnapshot(rss=$rss, traced_current=$tracedCurrent, traced_peak=$tracedPeak)'; +} + +Future memSnapshot(app.BridgeExampleHandle handle) async { + final fut = waitControlEvent(handle, 'mem', + timeout: const Duration(seconds: 10)); + handle.sendControl({'op': 'mem'}); + final msg = await fut; + return MemSnapshot( + rss: msg['rss'] as int, + tracedCurrent: msg['traced_current'] as int, + tracedPeak: msg['traced_peak'] as int, + ); +} diff --git a/src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart b/src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart deleted file mode 100644 index 4b30bfe0..00000000 --- a/src/serious_python/example/bridge_example/integration_test/bridge_echo_test.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'dart:async'; -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; -import 'package:serious_python/bridge.dart'; -import 'package:serious_python/serious_python.dart'; - -/// Env-var name carrying the Dart-side native port to Python. Must match the -/// name read by `app/src/main.py`. -const _bridgePortEnv = 'BRIDGE_EXAMPLE_PORT'; - -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - testWidgets('round-trips a 1KB random payload byte-identically', - (tester) async { - // Pump a minimal widget so the Flutter binding + native plugin - // registration runs before we touch FFI. - await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); - - final bridge = PythonBridge(); - addTearDown(bridge.close); - - // Fire-and-forget: Python's main.py blocks waiting for messages and never - // returns. The port reaches Python via the env var — no in-band handshake. - unawaited(SeriousPython.run( - 'app/app.zip', - environmentVariables: {_bridgePortEnv: '${bridge.port}'}, - )); - - // Round-trip a 1KB random buffer. Seed is fixed so repeated runs assert - // against the same bytes — easier to debug regressions. - final rng = Random(0xC0FFEE); - final payload = Uint8List.fromList( - List.generate(1024, (_) => rng.nextInt(256)), - ); - final expectedPrefix = Uint8List.fromList('echo: '.codeUnits); - final expectedReply = Uint8List(expectedPrefix.length + payload.length) - ..setRange(0, expectedPrefix.length, expectedPrefix) - ..setRange(expectedPrefix.length, expectedPrefix.length + payload.length, - payload); - - // Pre-subscribe to the echo before sending. - final replyFuture = bridge.messages - .firstWhere((b) => b.length == expectedReply.length) - .timeout(const Duration(seconds: 30)); - - // Python may not have registered its handler yet; retry until it does. - await _sendUntilDelivered(bridge, payload); - - final reply = await replyFuture; - expect(reply, equals(expectedReply)); - }); -} - -Future _sendUntilDelivered(PythonBridge bridge, Uint8List payload) async { - const retryInterval = Duration(milliseconds: 200); - const overallTimeout = Duration(seconds: 30); - final deadline = DateTime.now().add(overallTimeout); - - while (DateTime.now().isBefore(deadline)) { - if (bridge.send(payload)) return; - await Future.delayed(retryInterval); - } - throw TimeoutException( - 'Python did not register a handler within ${overallTimeout.inSeconds}s'); -} diff --git a/src/serious_python/example/bridge_example/integration_test/interactivity_test.dart b/src/serious_python/example/bridge_example/integration_test/interactivity_test.dart new file mode 100644 index 00000000..218260fc --- /dev/null +++ b/src/serious_python/example/bridge_example/integration_test/interactivity_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import '_helpers.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('counter responds to inc/dec via control channel', + (tester) async { + final handle = await bootAndAwaitReady(tester); + expect(find.byKey(const Key('counter')), findsOneWidget); + expect(find.text('0'), findsOneWidget); + + // Increment once: Python returns {event: count, value: 1}. + await tester.tap(find.byKey(const Key('increment'))); + await tester.pumpAndSettle(); + expect(find.text('1'), findsOneWidget); + + // Decrement twice: 1 -> 0 -> -1. + await tester.tap(find.byKey(const Key('decrement'))); + await tester.tap(find.byKey(const Key('decrement'))); + await tester.pumpAndSettle(); + expect(find.text('-1'), findsOneWidget); + + // Optional version assertion: only when the test harness passes + // EXPECTED_PYTHON_VERSION (CI does; local runs may not). + const expected = String.fromEnvironment('EXPECTED_PYTHON_VERSION'); + if (expected.isNotEmpty) { + expect(handle.pythonVersion.value, isNotNull); + expect(handle.pythonVersion.value, startsWith('$expected.')); + expect( + find.text('Python version: ${handle.pythonVersion.value}'), + findsOneWidget, + ); + } + }); +} diff --git a/src/serious_python/example/bridge_example/integration_test/memory_test.dart b/src/serious_python/example/bridge_example/integration_test/memory_test.dart new file mode 100644 index 00000000..7beb62b7 --- /dev/null +++ b/src/serious_python/example/bridge_example/integration_test/memory_test.dart @@ -0,0 +1,69 @@ +import 'dart:io'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import '_helpers.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('1000×1MB echo loop does not leak', (tester) async { + final handle = await bootAndAwaitReady(tester); + + // First snapshot also primes tracemalloc on the Python side (the Python + // handler starts tracemalloc lazily on first `mem` op). The very first + // snapshot is intentionally discarded for the leak assertion so the + // tracemalloc warm-up doesn't count against the heap delta. + await memSnapshot(handle); + + // Now take the real baseline. + final dartRssBefore = ProcessInfo.currentRss; + final before = await memSnapshot(handle); + + // Hammer: 1000 × 1 MB round-trips through the echo channel. ~2 GB of + // bytes crossing the bridge total. A leak retaining even ~1% of that + // would show up well above noise in the after-snapshot. + final rng = Random(0xBEEF); + final payload = Uint8List.fromList( + List.generate(1024 * 1024, (_) => rng.nextInt(256))); + for (var i = 0; i < 1000; i++) { + await echoRoundTrip(handle, payload); + } + + // Encourage Python to collect what it can before the second snapshot — + // a noop if no garbage; cheap if there's any. + handle.sendControl({'op': 'mem'}); // triggers another tracemalloc tick + await Future.delayed(const Duration(milliseconds: 200)); + + final after = await memSnapshot(handle); + final dartRssAfter = ProcessInfo.currentRss; + + final tracedDelta = after.tracedCurrent - before.tracedCurrent; + final rssDelta = after.rss - before.rss; + final dartRssDelta = dartRssAfter - dartRssBefore; + + // ignore: avoid_print + print('[bridge_mem] before=$before'); + // ignore: avoid_print + print('[bridge_mem] after=$after'); + // ignore: avoid_print + print('[bridge_mem] traced_delta=${tracedDelta}B ' + 'rss_delta=${rssDelta}B ' + 'dart_rss_delta=${dartRssDelta}B ' + '(dart_rss may be 0 on iOS/Android)'); + + // tracemalloc is unit-stable (bytes) and is the load-bearing leak check. + // 5 MB is generous: a per-iteration leak of 1 KB across 100 rounds would + // be 100 KB, well within budget; a 5%+ leak of 1 MB payloads would not. + expect(tracedDelta, lessThan(5 * 1024 * 1024), + reason: 'Python heap grew >5MB across 100×1MB echo loop — ' + 'likely a Python-side leak (libdart_bridge buffer retained, etc.)'); + + // ru_maxrss has a unit quirk (kB on Linux/Android, bytes on macOS/iOS) + // and is influenced by OS-level page allocation patterns, so we + // log-only. Real assertion lives in tracedDelta above. + }); +} diff --git a/src/serious_python/example/bridge_example/integration_test/throughput_test.dart b/src/serious_python/example/bridge_example/integration_test/throughput_test.dart new file mode 100644 index 00000000..613b58d7 --- /dev/null +++ b/src/serious_python/example/bridge_example/integration_test/throughput_test.dart @@ -0,0 +1,72 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import '_helpers.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + // (payloadBytes, iterations) — sizes go up to 16 MB; iteration count drops + // for bigger payloads so total wall-time stays bounded (~30 s on macOS). + const sizes = <(int, int)>[ + (1024, 100), + (64 * 1024, 100), + (256 * 1024, 100), + (1024 * 1024, 100), + (4 * 1024 * 1024, 100), + (16 * 1024 * 1024, 100), + ]; + + testWidgets('echo channel throughput across size sweep', (tester) async { + final handle = await bootAndAwaitReady(tester); + for (final (size, iterations) in sizes) { + final rng = Random(0xC0FFEE ^ size); + final payload = + Uint8List.fromList(List.generate(size, (_) => rng.nextInt(256))); + + // Verify byte identity once per size; per-iteration assert would + // dominate the timing measurement. + final first = await echoRoundTrip(handle, payload); + expect(first, equals(payload), + reason: 'echo mutated payload at size=$size'); + + final samples = []; // microseconds per round-trip + for (var i = 0; i < iterations; i++) { + final sw = Stopwatch()..start(); + await echoRoundTrip(handle, payload); + sw.stop(); + samples.add(sw.elapsedMicroseconds); + } + + samples.sort(); + final min = samples.first; + final p50 = samples[samples.length ~/ 2]; + final p95 = + samples[(samples.length * 95 ~/ 100).clamp(0, samples.length - 1)]; + final mean = samples.reduce((a, b) => a + b) / samples.length; + + // Throughput in MB/s based on the mean. A round-trip moves 2×size + // bytes through the bridge (Dart→Py + Py→Dart). + final meanSeconds = mean / 1e6; + final mbPerSec = (2 * size) / (meanSeconds * 1024 * 1024); + + // ignore: avoid_print + print('[bridge_perf] size=$size N=$iterations ' + 'min=${(min / 1000).toStringAsFixed(2)}ms ' + 'p50=${(p50 / 1000).toStringAsFixed(2)}ms ' + 'p95=${(p95 / 1000).toStringAsFixed(2)}ms ' + 'mean=${(mean / 1000).toStringAsFixed(2)}ms ' + 'throughput=${mbPerSec.toStringAsFixed(1)}MB/s'); + + // Order-of-magnitude floor — catches >5× regressions without flaking + // on slow Windows Debug runs. Tune after a stable week. + if (size >= 1024 * 1024) { + expect(mbPerSec, greaterThan(50), + reason: 'echo throughput dropped below floor at size=$size'); + } + } + }); +} diff --git a/src/serious_python/example/bridge_example/lib/main.dart b/src/serious_python/example/bridge_example/lib/main.dart index 6c668064..9d7c995e 100644 --- a/src/serious_python/example/bridge_example/lib/main.dart +++ b/src/serious_python/example/bridge_example/lib/main.dart @@ -1,17 +1,87 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:serious_python/bridge.dart'; import 'package:serious_python/serious_python.dart'; -/// Env-var name carrying the Dart-side native port to Python. The bridge -/// library doesn't bake in a convention — the example picks one and Python -/// reads it from os.environ by the same name. -const _bridgePortEnv = 'BRIDGE_EXAMPLE_PORT'; +/// Env-var names carrying the Dart-side native ports to Python. The bridge +/// library doesn't bake in a convention — the example picks names and Python +/// reads them from os.environ. +const _controlPortEnv = 'BRIDGE_EXAMPLE_CONTROL_PORT'; +const _echoPortEnv = 'BRIDGE_EXAMPLE_ECHO_PORT'; + +/// Top-level handle exposing the two bridges + the latest counter/version to +/// integration tests, so they can interact with the transport without traversing +/// the widget tree. Populated by `main()` once both bridges are constructed. +class BridgeExampleHandle { + BridgeExampleHandle._(this.controlBridge, this.echoBridge); + + static BridgeExampleHandle? _instance; + static BridgeExampleHandle get instance { + final v = _instance; + if (v == null) { + throw StateError( + 'BridgeExampleHandle not initialised — main() must run first'); + } + return v; + } + + final PythonBridge controlBridge; + final PythonBridge echoBridge; + + /// Current counter value (updated when Python emits {event: count}). + final ValueNotifier counter = ValueNotifier(0); + + /// Python version string, e.g. "3.14.6". `null` until the first `version` + /// event arrives. + final ValueNotifier pythonVersion = ValueNotifier(null); + + /// Send a JSON control op (Dart → Python) on the control channel. + void sendControl(Map op) { + final bytes = Uint8List.fromList(utf8.encode(jsonEncode(op))); + if (controlBridge.send(bytes)) return; + _retrySend(controlBridge, bytes); + } + + /// Brief retry to cover the startup window where Python's handler hasn't + /// registered yet. Matches the pattern in flet_example's + /// `_DartBridgeBackendChannel._retrySend`. + static void _retrySend(PythonBridge bridge, Uint8List bytes) { + const interval = Duration(milliseconds: 50); + const deadline = Duration(seconds: 30); + final start = DateTime.now(); + Timer.periodic(interval, (timer) { + if (bridge.send(bytes)) { + timer.cancel(); + } else if (DateTime.now().difference(start) > deadline) { + timer.cancel(); + debugPrint( + '[bridge_example] send timed out — Python handler never registered'); + } + }); + } +} void main() { + // Bridges live for the app's lifetime; constructed before runApp so the + // testable handle is available immediately. + final control = PythonBridge(); + final echo = PythonBridge(); + BridgeExampleHandle._instance = + BridgeExampleHandle._(control, echo); + + // Fire-and-forget: Python's main.py blocks forever waiting for messages. + // Awaiting SeriousPython.run() would deadlock the UI. + unawaited(SeriousPython.run( + 'app/app.zip', + environmentVariables: { + _controlPortEnv: '${control.port}', + _echoPortEnv: '${echo.port}', + }, + )); + runApp(const BridgeExampleApp()); } @@ -23,58 +93,52 @@ class BridgeExampleApp extends StatefulWidget { } class _BridgeExampleAppState extends State { - PythonBridge? _bridge; - StreamSubscription? _subscription; + StreamSubscription? _controlSub; final List _log = []; - int _sendCounter = 0; @override void initState() { super.initState(); - _start(); - } - - Future _start() async { - final bridge = PythonBridge(); - debugPrint('[bridge_example] bridge.port=${bridge.port}'); - _subscription = bridge.messages.listen((bytes) { - setState(() { - _log.add('Python -> Dart: ${utf8.decode(bytes, allowMalformed: true)}'); - }); - }); - - // Fire-and-forget: Python's main.py blocks waiting for messages and never - // returns. Awaiting SeriousPython.run() would deadlock the UI. - unawaited(SeriousPython.run( - 'app/app.zip', - environmentVariables: {_bridgePortEnv: '${bridge.port}'}, - )); + final handle = BridgeExampleHandle.instance; + _controlSub = handle.controlBridge.messages.listen(_onControl); - setState(() { - _bridge = bridge; - _log.add('bridge ready (port=${bridge.port})'); - }); + // Request the Python version once Python has had a moment to register + // its handler. sendControl() retries internally if the handler isn't + // ready yet, so we can fire immediately. + handle.sendControl({'op': 'version'}); + _log.add('control_port=${handle.controlBridge.port} ' + 'echo_port=${handle.echoBridge.port}'); } - void _sendTestMessage() { - final bridge = _bridge; - if (bridge == null) return; - _sendCounter++; - final payload = utf8.encode('ping #$_sendCounter'); - final delivered = bridge.send(Uint8List.fromList(payload)); - setState(() => _log.add( - 'Dart -> Python: ping #$_sendCounter${delivered ? '' : ' (no handler yet)'}')); + void _onControl(Uint8List bytes) { + final handle = BridgeExampleHandle.instance; + Map msg; + try { + msg = jsonDecode(utf8.decode(bytes)) as Map; + } catch (e) { + debugPrint('[bridge_example] control parse error: $e'); + return; + } + final event = msg['event']; + if (event == 'count') { + handle.counter.value = msg['value'] as int; + } else if (event == 'version') { + handle.pythonVersion.value = msg['value'] as String; + } + // 'mem' events are consumed by the memory test directly via its own + // listener — no widget-visible state for them. + setState(() => _log.add('Python -> Dart: ${msg.toString()}')); } @override void dispose() { - _subscription?.cancel(); - _bridge?.close(); + _controlSub?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { + final handle = BridgeExampleHandle.instance; return MaterialApp( title: 'bridge_example', home: Scaffold( @@ -83,10 +147,43 @@ class _BridgeExampleAppState extends State { children: [ Padding( padding: const EdgeInsets.all(16), - child: ElevatedButton( - key: const Key('send'), - onPressed: _bridge != null ? _sendTestMessage : null, - child: const Text('Send ping to Python'), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + key: const Key('decrement'), + icon: const Icon(Icons.remove), + onPressed: () => handle.sendControl({'op': 'dec'}), + ), + ValueListenableBuilder( + valueListenable: handle.counter, + builder: (_, value, __) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + '$value', + key: const Key('counter'), + style: Theme.of(context).textTheme.headlineMedium, + ), + ), + ), + IconButton( + key: const Key('increment'), + icon: const Icon(Icons.add), + onPressed: () => handle.sendControl({'op': 'inc'}), + ), + ], + ), + ), + ValueListenableBuilder( + valueListenable: handle.pythonVersion, + builder: (_, version, __) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + version == null + ? 'Python version: …' + : 'Python version: $version', + key: const Key('version'), + ), ), ), const Divider(), diff --git a/src/serious_python/example/bridge_example/macos/Podfile.lock b/src/serious_python/example/bridge_example/macos/Podfile.lock index 70ae0b4d..8a6bd931 100644 --- a/src/serious_python/example/bridge_example/macos/Podfile.lock +++ b/src/serious_python/example/bridge_example/macos/Podfile.lock @@ -1,30 +1,22 @@ PODS: - FlutterMacOS (1.0.0) - - serious_python_bridge (2.0.0): - - Flutter - - FlutterMacOS - - serious_python_darwin - serious_python_darwin (2.0.0): - Flutter - FlutterMacOS DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) - - serious_python_bridge (from `Flutter/ephemeral/.symlinks/plugins/serious_python_bridge/darwin`) - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral - serious_python_bridge: - :path: Flutter/ephemeral/.symlinks/plugins/serious_python_bridge/darwin serious_python_darwin: :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin SPEC CHECKSUMS: FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - serious_python_bridge: 3c906c29f7b53d86374dc1f2d6ad7c325776932f - serious_python_darwin: 51cea45f3f6e3322e607b2d0716db26de8b6c512 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 diff --git a/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.pbxproj index 0a23e339..8dda9eb0 100644 --- a/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/bridge_example/macos/Runner.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, 5019070AFE2F41F3F49E930B /* [CP] Embed Pods Frameworks */, + 583F80258F9FB1DB887F6668 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -378,6 +379,23 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + 583F80258F9FB1DB887F6668 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; BBA99A121B65ED7E52DABCEE /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/src/serious_python/example/flet_example/README.md b/src/serious_python/example/flet_example/README.md index e4f079cd..18adcce8 100644 --- a/src/serious_python/example/flet_example/README.md +++ b/src/serious_python/example/flet_example/README.md @@ -1,75 +1,45 @@ # flet_example -Before running the app run the following command to package Python app to an asset. - -For Android: - -``` -export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages -dart run serious_python:main package app/src -p Android --requirements -r,app/src/requirements.txt -``` - -For iOS: - -``` -export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages -dart run serious_python:main package app/src -p iOS --requirements -r,app/src/requirements.txt -``` +A Flet counter app running on `serious_python`'s in-process +`dart_bridge` FFI transport. The Dart side constructs a `PythonBridge` +and hands a custom `FletBackendChannel` to `FletApp` via the +`channelBuilder` parameter; the Python side picks up +`FLET_DART_BRIDGE_PORT` from the environment and `flet.app.run_async()` +selects `FletDartBridgeServer` instead of the legacy +`FletSocketServer`. + +The `flet` Dart package itself stays Python-independent — the +PythonBridge wiring lives entirely in this example. + +## Building + +The Python `flet` package needs the `dart-bridge` branch (because +`FletDartBridgeServer` isn't on PyPI yet), so the `--requirements` arg +installs from git. Mobile targets use `pip install --only-binary :all:` +which would normally reject a git source — the +`SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet` env var opts `flet` +specifically into source installs by injecting `--no-binary flet`. For macOS: ``` -dart run serious_python:main package app/src -p Darwin --requirements -r,app/src/requirements.txt -``` - -For Windows: - -``` -dart run serious_python:main package app/src -p Windows --requirements -r,app/src/requirements.txt -``` - -For Linux: - -``` -dart run serious_python:main package app/src -p Linux --requirements -r,app/src/requirements.txt +export SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet +dart run serious_python:main package app/src \ + --platform Darwin \ + --requirements "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" ``` -For web: - -``` -dart run serious_python:main package app/src -p Emscripten --requirements -r,app/src/requirements.txt -``` +Replace `--platform Darwin` with `iOS`, `Android`, `Windows`, or `Linux` +as needed. The same `--requirements` works on every platform. -Important: to make `serious_python` work in your own Android app: +## Running locally -If you build an App Bundle Edit `android/gradle.properties` and add the flag: +`sync_site_packages.sh` (in `serious_python_darwin`) requires +`SERIOUS_PYTHON_SITE_PACKAGES` pointing at the freshly-packaged +`build/site-packages/` directory so the .app bundle picks up the +git-installed flet instead of a stale copy from a previous run: ``` -android.bundle.enableUncompressedNativeLibs=false -``` - - -If you build an APK Make sure `android/app/src/AndroidManifest.xml` has `android:extractNativeLibs="true"` in the `` tag. - -For more information, see the [public issue](https://issuetracker.google.com/issues/147096055). - -Add the following to `android/app/build.gradle`: - +export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages +fvm flutter test integration_test --device-id macos ``` -android { - ndkVersion "25.1.8937393" - - packagingOptions { - jniLibs { - useLegacyPackaging true - } - } - - packagingOptions { - doNotStrip "*/arm64-v8a/libpython*.so" - doNotStrip "*/armeabi-v7a/libpython*.so" - doNotStrip "*/x86/libpython*.so" - doNotStrip "*/x86_64/libpython*.so" - } -} -``` \ No newline at end of file diff --git a/src/serious_python/example/flet_example/app/app.zip.hash b/src/serious_python/example/flet_example/app/app.zip.hash index e2ace746..e5d849b8 100644 --- a/src/serious_python/example/flet_example/app/app.zip.hash +++ b/src/serious_python/example/flet_example/app/app.zip.hash @@ -1 +1 @@ -5034716fae4a090c25c3ab79e342de9a09f0972a4c76af1d5df41d5bc1e6770d \ No newline at end of file +b92d604f99e8c64859bd16e28c24a0b25eefdcdcb35ba99a08201d614a03772a \ No newline at end of file diff --git a/src/serious_python/example/flet_example/lib/main.dart b/src/serious_python/example/flet_example/lib/main.dart index b89ce87f..fe0920df 100644 --- a/src/serious_python/example/flet_example/lib/main.dart +++ b/src/serious_python/example/flet_example/lib/main.dart @@ -1,78 +1,88 @@ import 'dart:async'; -import 'dart:io'; import 'package:flet/flet.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_web_plugins/url_strategy.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; import 'package:package_info_plus/package_info_plus.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart' as path_provider; +import 'package:serious_python/bridge.dart'; import 'package:serious_python/serious_python.dart'; const bool isProduction = bool.fromEnvironment('dart.vm.product'); const assetPath = "app/app.zip"; -const pythonModuleName = "main"; // {{ cookiecutter.python_module_name }} +const pythonModuleName = "main"; final hideLoadingPage = bool.tryParse("{{ cookiecutter.hide_loading_animation }}".toLowerCase()) ?? true; -const outLogFilename = "out.log"; const errorExitCode = 100; +/// The Python script is intentionally smaller than in `flet_example`. No +/// stdout-callback socket, no flet.sock — Python startup is just `runpy` +/// on the user module, and stdout/stderr stay attached to whatever the +/// embedded interpreter inherits. The dart_bridge transport in Flet 0.85+ +/// handles IPC directly. const pythonScript = """ -import certifi, os, runpy, socket, sys, traceback +import logging, os, runpy, sys, traceback + +# Redirect stdout/stderr to a file under FLET_APP_TEMP so we can inspect what +# Python is doing without a separate stdout-callback socket. Temporary — once +# the FFI transport is stable a more proper logging story can land. +_log_path = os.path.join( + os.environ.get("FLET_APP_TEMP", "/tmp"), "flet_boot.log" +) +_log = open(_log_path, "w", buffering=1) +sys.stdout = _log +sys.stderr = _log +logging.basicConfig(stream=_log, level=logging.DEBUG) +print(f"[boot] python {sys.version}", flush=True) +print(f"[boot] FLET_DART_BRIDGE_PORT={os.environ.get('FLET_DART_BRIDGE_PORT')}", flush=True) +print(f"[boot] FLET_PLATFORM={os.environ.get('FLET_PLATFORM')}", flush=True) -os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() -os.environ["SSL_CERT_FILE"] = certifi.where() - -if os.getenv("FLET_PLATFORM") == "android": - import ssl - - def create_default_context( - purpose=ssl.Purpose.SERVER_AUTH, *, cafile=None, capath=None, cadata=None - ): - return ssl.create_default_context( - purpose=purpose, cafile=certifi.where(), capath=capath, cadata=cadata - ) - - ssl._create_default_https_context = create_default_context - -out_file = open("$outLogFilename", "w+", buffering=1) - -callback_socket_addr = os.environ.get("FLET_PYTHON_CALLBACK_SOCKET_ADDR") -if ":" in callback_socket_addr: - addr, port = callback_socket_addr.split(":") - callback_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - callback_socket.connect((addr, int(port))) -else: - callback_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - callback_socket.connect(callback_socket_addr) - -sys.stdout = sys.stderr = out_file - -def flet_exit(code=0): - callback_socket.sendall(str(code).encode()) - out_file.close() - callback_socket.close() - -sys.exit = flet_exit - -ex = None +try: + import certifi + os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() + os.environ["SSL_CERT_FILE"] = certifi.where() + + if os.getenv("FLET_PLATFORM") == "android": + import ssl + + def create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, *, + cafile=None, capath=None, cadata=None, + ): + return ssl.create_default_context( + purpose=purpose, + cafile=certifi.where(), + capath=capath, + cadata=cadata, + ) + + ssl._create_default_https_context = create_default_context +except ImportError as e: + print(f"[boot] certifi import failed: {e}", flush=True) + +print("[boot] about to runpy.run_module", flush=True) try: runpy.run_module("{module_name}", run_name="__main__") -except Exception as e: - ex = e - traceback.print_exception(e) - -sys.exit(0 if ex is None else $errorExitCode) + print("[boot] runpy.run_module returned", flush=True) +except SystemExit as e: + print(f"[boot] SystemExit: {e.code}", flush=True) + raise +except Exception: + print("[boot] runpy.run_module raised:", flush=True) + traceback.print_exc() + sys.exit($errorExitCode) """; // global vars -String pageUrl = ""; String assetsDir = ""; String appDir = ""; +late PythonBridge _bridge; Map environmentVariables = {}; void main() async { @@ -85,162 +95,163 @@ void main() async { future: prepareApp(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { - // OK - start Python program - return kIsWeb - ? FletApp( - pageUrl: pageUrl, - assetsDir: assetsDir, - ) - : FutureBuilder( - future: runPythonApp(), - builder: - (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData || snapshot.hasError) { - // error or premature finish - return MaterialApp( - home: ErrorScreen( - title: "Error running app", - text: snapshot.data ?? snapshot.error.toString()), - ); - } else { - // no result of error - return FletApp( - pageUrl: pageUrl, - assetsDir: assetsDir, - ); - } - }); + return FletApp( + pageUrl: "dartbridge://${_bridge.port}", + assetsDir: assetsDir, + channelBuilder: ({required onMessage, required onDisconnect}) => + _DartBridgeBackendChannel(_bridge, + onMessage: onMessage, onDisconnect: onDisconnect), + ); } else if (snapshot.hasError) { - // error return MaterialApp( home: ErrorScreen( title: "Error starting app", text: snapshot.error.toString())); } else { - // loading return const MaterialApp(home: BlankScreen()); } })); } -Future prepareApp() async { +Future prepareApp() async { if (kIsWeb) { - // web mode - connect via HTTP - pageUrl = Uri.base.toString(); var routeUrlStrategy = getFletRouteUrlStrategy(); if (routeUrlStrategy == "path") { usePathUrlStrategy(); } - } else { - await setupDesktop(); - - // extract app from asset - appDir = await extractAssetZip(assetPath, checkHash: true); - - // set current directory to app path - Directory.current = appDir; - - assetsDir = path.join(appDir, "assets"); + return ""; + } - // configure apps DATA and TEMP directories - WidgetsFlutterBinding.ensureInitialized(); + await setupDesktop(); - var appTempPath = (await path_provider.getApplicationCacheDirectory()).path; - var appDataPath = - (await path_provider.getApplicationDocumentsDirectory()).path; + // Extract app from asset. + appDir = await extractAssetZip(assetPath, checkHash: true); + Directory.current = appDir; + assetsDir = path.join(appDir, "assets"); - if (defaultTargetPlatform != TargetPlatform.iOS && - defaultTargetPlatform != TargetPlatform.android) { - // append app name to the path and create dir - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - appDataPath = path.join(appDataPath, "flet", packageInfo.packageName); - if (!await Directory(appDataPath).exists()) { - await Directory(appDataPath).create(recursive: true); - } - } + WidgetsFlutterBinding.ensureInitialized(); + var appTempPath = (await path_provider.getApplicationCacheDirectory()).path; + var appDataPath = + (await path_provider.getApplicationDocumentsDirectory()).path; - environmentVariables["FLET_APP_DATA"] = appDataPath; - environmentVariables["FLET_APP_TEMP"] = appTempPath; - - environmentVariables["FLET_PLATFORM"] = - defaultTargetPlatform.name.toLowerCase(); - - if (defaultTargetPlatform == TargetPlatform.windows) { - // use TCP on Windows - var tcpPort = await getUnusedPort(); - pageUrl = "tcp://localhost:$tcpPort"; - environmentVariables["FLET_SERVER_PORT"] = tcpPort.toString(); - } else { - // use UDS on other platforms - pageUrl = "flet.sock"; - environmentVariables["FLET_SERVER_UDS_PATH"] = pageUrl; + if (defaultTargetPlatform != TargetPlatform.iOS && + defaultTargetPlatform != TargetPlatform.android) { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + appDataPath = path.join(appDataPath, "flet", packageInfo.packageName); + if (!await Directory(appDataPath).exists()) { + await Directory(appDataPath).create(recursive: true); } } + // Create the PythonBridge before we hand its port to Python. It outlives + // the FletApp widget; the embedded interpreter only stops when the Flutter + // app exits. + _bridge = PythonBridge(); + + environmentVariables.addAll({ + "FLET_APP_DATA": appDataPath, + "FLET_APP_TEMP": appTempPath, + "FLET_PLATFORM": defaultTargetPlatform.name.toLowerCase(), + // Python reads this env var in flet.app.run_async() and starts the + // dart_bridge transport (added in flet's dart-bridge branch) bound to + // the same port. + "FLET_DART_BRIDGE_PORT": "${_bridge.port}", + }); + + // Fire-and-forget: Python lives for the duration of the app. SeriousPython + // dispatches it on a worker thread (sync=false default), so this returns + // immediately after spawning. + var script = pythonScript.replaceAll('{module_name}', pythonModuleName); + unawaited(SeriousPython.runProgram( + path.join(appDir, "$pythonModuleName.pyc"), + script: script, + environmentVariables: environmentVariables, + )); + return ""; } -Future runPythonApp() async { - var script = pythonScript.replaceAll('{module_name}', pythonModuleName); +/// `FletBackendChannel` implementation backed by a [PythonBridge]. Bytes +/// flow Dart↔Python entirely in-process; no Unix socket, no kernel context +/// switch. The wire format is the same MsgPack-framed protocol the existing +/// socket-based `FletSocketBackendChannel` speaks. +class _DartBridgeBackendChannel implements FletBackendChannel { + _DartBridgeBackendChannel(this._bridge, + {required FletBackendChannelOnMessageCallback onMessage, + required FletBackendChannelOnDisconnectCallback onDisconnect}) + : _onMessage = onMessage, + _onDisconnect = onDisconnect, + _deserializer = + StreamingMsgpackDeserializer(extDecoder: FletMsgpackDecoder()); + + final PythonBridge _bridge; + final FletBackendChannelOnMessageCallback _onMessage; + final FletBackendChannelOnDisconnectCallback _onDisconnect; + final StreamingMsgpackDeserializer _deserializer; + StreamSubscription? _subscription; - var completer = Completer(); - - ServerSocket outSocketServer; - String socketAddr = ""; - StringBuffer pythonOut = StringBuffer(); - - if (defaultTargetPlatform == TargetPlatform.windows) { - var tcpAddr = "127.0.0.1"; - outSocketServer = await ServerSocket.bind(tcpAddr, 0); - debugPrint( - 'Python output TCP Server is listening on port ${outSocketServer.port}'); - socketAddr = "$tcpAddr:${outSocketServer.port}"; - } else { - socketAddr = "stdout.sock"; - outSocketServer = await ServerSocket.bind( - InternetAddress(socketAddr, type: InternetAddressType.unix), 0); - debugPrint('Python output Socket Server is listening on $socketAddr'); + @override + Future connect() async { + _subscription = _bridge.messages.listen( + _onBytes, + onError: (error, stack) { + debugPrint("PythonBridge stream error: $error"); + _onDisconnect(); + }, + onDone: () { + debugPrint("PythonBridge stream closed."); + _onDisconnect(); + }, + cancelOnError: false, + ); } - environmentVariables["FLET_PYTHON_CALLBACK_SOCKET_ADDR"] = socketAddr; - - void closeOutServer() async { - outSocketServer.close(); + void _onBytes(Uint8List bytes) { + _deserializer.addChunk(bytes); + final frames = _deserializer.decodeMessages(); + for (final frame in frames) { + _onMessage(Message.fromList(frame)); + } + } - int exitCode = int.tryParse(pythonOut.toString().trim()) ?? 0; + @override + void send(Message message) { + final encoded = Uint8List.fromList( + msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); + // Retry loop covers the brief startup window where Python hasn't yet + // called dart_bridge.set_enqueue_handler_func — bridge.send returns + // false in that case. Once the handler is registered (Flet's app.py + // dart_bridge server start() does it before run_module dispatch), + // bridge.send returns true synchronously. + if (_bridge.send(encoded)) return; + _retrySend(encoded); + } - if (exitCode == errorExitCode) { - var out = ""; - if (await File(outLogFilename).exists()) { - out = await File(outLogFilename).readAsString(); + void _retrySend(Uint8List encoded) { + const interval = Duration(milliseconds: 50); + const deadline = Duration(seconds: 30); + final start = DateTime.now(); + Timer.periodic(interval, (timer) { + if (_bridge.send(encoded)) { + timer.cancel(); + } else if (DateTime.now().difference(start) > deadline) { + timer.cancel(); + debugPrint("PythonBridge send timed out: Python handler never registered."); } - completer.complete(out); - } else { - exit(exitCode); - } + }); } - outSocketServer.listen((client) { - debugPrint( - 'Connection from: ${client.remoteAddress.address}:${client.remotePort}'); - client.listen((data) { - var s = String.fromCharCodes(data); - pythonOut.write(s); - }, onError: (error) { - client.close(); - closeOutServer(); - }, onDone: () { - client.close(); - closeOutServer(); - }); - }); + @override + bool get isLocalConnection => true; - // run python async - SeriousPython.runProgram(path.join(appDir, "$pythonModuleName.pyc"), - script: script, environmentVariables: environmentVariables); + @override + int get defaultReconnectIntervalMs => 0; - // wait for client connection to close - return completer.future; + @override + void disconnect() { + _subscription?.cancel(); + _subscription = null; + } } class ErrorScreen extends StatelessWidget { @@ -293,9 +304,7 @@ class ErrorScreen extends StatelessWidget { } class BlankScreen extends StatelessWidget { - const BlankScreen({ - super.key, - }); + const BlankScreen({super.key}); @override Widget build(BuildContext context) { @@ -304,11 +313,3 @@ class BlankScreen extends StatelessWidget { ); } } - -Future getUnusedPort() { - return ServerSocket.bind("127.0.0.1", 0).then((socket) { - var port = socket.port; - socket.close(); - return port; - }); -} diff --git a/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake index d94f7552..7d9bc28c 100644 --- a/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake +++ b/src/serious_python/example/flet_example/linux/flutter/generated_plugins.cmake @@ -12,6 +12,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift index 8ab11fa1..6d5caa62 100644 --- a/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/src/serious_python/example/flet_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,7 +11,6 @@ import device_info_plus import file_picker import package_info_plus import pasteboard -import path_provider_foundation import screen_brightness_macos import screen_retriever_macos import serious_python_darwin @@ -29,7 +28,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) diff --git a/src/serious_python/example/flet_example/macos/Podfile.lock b/src/serious_python/example/flet_example/macos/Podfile.lock index dcf44461..c631f6e1 100644 --- a/src/serious_python/example/flet_example/macos/Podfile.lock +++ b/src/serious_python/example/flet_example/macos/Podfile.lock @@ -12,9 +12,6 @@ PODS: - FlutterMacOS - pasteboard (0.0.1): - FlutterMacOS - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - screen_brightness_macos (0.1.0): - FlutterMacOS - screen_retriever_macos (0.0.1): @@ -33,7 +30,7 @@ PODS: - FlutterMacOS - window_manager (0.5.0): - FlutterMacOS - - window_to_front (0.0.1): + - window_to_front (0.0.4): - FlutterMacOS DEPENDENCIES: @@ -44,7 +41,6 @@ DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) @@ -70,8 +66,6 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos pasteboard: :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin screen_brightness_macos: :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos screen_retriever_macos: @@ -99,16 +93,15 @@ SPEC CHECKSUMS: FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 package_info_plus: f0052d280d17aa382b932f399edf32507174e870 pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 screen_brightness_macos: 1058c18b5e0570f48f93016487a5ed66d6977fe0 - screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f + screen_retriever_macos: c5508cc3c66ff0d4db650480cf0ab691e220d933 serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 - url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b window_manager: b729e31d38fb04905235df9ea896128991cad99e - window_to_front: 9e76fd432e36700a197dac86a0011e49c89abe0a + window_to_front: 2d7d31f268d0b13b7e63b26e31eb0a2e9612239e PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 diff --git a/src/serious_python/example/flet_example/pubspec.lock b/src/serious_python/example/flet_example/pubspec.lock index 30401dc7..427dbdd5 100644 --- a/src/serious_python/example/flet_example/pubspec.lock +++ b/src/serious_python/example/flet_example/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.0.9" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" async: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.1" battery_plus: dependency: transitive description: @@ -65,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.dev" + source: hosted + version: "1.2.1" collection: dependency: transitive description: @@ -93,34 +101,34 @@ packages: dependency: transitive description: name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" url: "https://pub.dev" source: hosted - version: "0.3.4+2" + version: "0.3.5+2" crypto: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.7" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" dbus: dependency: transitive description: name: dbus - sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.12" device_info_plus: dependency: transitive description: @@ -141,10 +149,10 @@ packages: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.8" fake_async: dependency: transitive description: @@ -190,7 +198,7 @@ packages: description: path: "packages/flet" ref: dart-bridge - resolved-ref: "7367050f22edb02afebecaca5de70c3a0e389827" + resolved-ref: "33b3b972373fb3f268fe7acc84876b87dbb9a31c" url: "https://github.com/flet-dev/flet.git" source: git version: "0.85.3" @@ -253,10 +261,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" + sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.0.35" flutter_svg: dependency: transitive description: @@ -296,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" + hooks: + dependency: transitive + description: + name: hooks + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.dev" + source: hosted + version: "2.0.2" http: dependency: transitive description: @@ -308,10 +324,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" integration_test: dependency: "direct dev" description: flutter @@ -325,14 +341,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.2" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" json_annotation: dependency: transitive description: name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.12.0" leak_tracker: dependency: transitive description: @@ -369,10 +401,10 @@ packages: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" markdown: dependency: transitive description: @@ -414,7 +446,7 @@ packages: source: hosted version: "2.0.0" msgpack_dart: - dependency: transitive + dependency: "direct main" description: name: msgpack_dart sha256: c2d235ed01f364719b5296aecf43ac330f0d7bc865fa134d0d7910a40454dffb @@ -437,6 +469,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" + url: "https://pub.dev" + source: hosted + version: "9.4.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" package_info_plus: dependency: "direct main" description: @@ -473,10 +521,10 @@ packages: dependency: transitive description: name: path_parsing - sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -489,18 +537,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.3.1" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.0" path_provider_linux: dependency: transitive description: @@ -529,10 +577,10 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.0" platform: dependency: transitive description: @@ -553,18 +601,18 @@ packages: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.5.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.5" provider: dependency: transitive description: @@ -573,6 +621,22 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" screen_brightness: dependency: transitive description: @@ -633,42 +697,42 @@ packages: dependency: transitive description: name: screen_retriever - sha256: "570dbc8e4f70bac451e0efc9c9bb19fa2d6799a11e6ef04f946d7886d2e23d0c" + sha256: "42cc3b402a0f67d2455a0d067553d0f13453f6a008d98eababf8b63958d506bd" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" screen_retriever_linux: dependency: transitive description: name: screen_retriever_linux - sha256: f7f8120c92ef0784e58491ab664d01efda79a922b025ff286e29aa123ea3dd18 + sha256: "2a476f1a5538065bc5badf376cfdc83d6ecf07d77eb2391b9c2bff5a76970048" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" screen_retriever_macos: dependency: transitive description: name: screen_retriever_macos - sha256: "71f956e65c97315dd661d71f828708bd97b6d358e776f1a30d5aa7d22d78a149" + sha256: b5abb900fcb86614ff10b738b34e37b9e1d03b0447280668e2bc8a98bdc7bd59 url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" screen_retriever_platform_interface: dependency: transitive description: name: screen_retriever_platform_interface - sha256: ee197f4581ff0d5608587819af40490748e1e39e648d7680ecf95c05197240c0 + sha256: "3af22d926bedf20c2caa308eea376776451a3af125919ce072e56525fded8901" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" screen_retriever_windows: dependency: transitive description: name: screen_retriever_windows - sha256: "449ee257f03ca98a57288ee526a301a430a344a161f9202b4fcc38576716fe13" + sha256: c44b38a4c4bab34af259180a70a4eee1e29384e7b82e627c9faa68afcdab2e73 url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" screenshot: dependency: transitive description: @@ -771,10 +835,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.6" shared_preferences_linux: dependency: transitive description: @@ -787,18 +851,18 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: @@ -811,10 +875,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shimmer: dependency: transitive description: @@ -832,10 +896,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.2" stack_trace: dependency: transitive description: @@ -904,10 +968,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" upower: dependency: transitive description: @@ -928,34 +992,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79 + sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" url: "https://pub.dev" source: hosted - version: "6.3.9" + version: "6.3.30" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.4.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.5" url_launcher_platform_interface: dependency: transitive description: @@ -968,18 +1032,18 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.5" uuid: dependency: transitive description: @@ -1000,18 +1064,18 @@ packages: dependency: transitive description: name: vector_graphics_codec - sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.1.13" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + sha256: "7ee12e6dffe0fc8e755179d6d91b3b34f5924223fc104d85572ef9180d73d172" url: "https://pub.dev" source: hosted - version: "1.1.16" + version: "1.2.5" vector_math: dependency: transitive description: @@ -1024,18 +1088,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.2.0" wakelock_plus: dependency: transitive description: name: wakelock_plus - sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" + sha256: ddf3db70eaa10c37558ff817519b85d527dbd21034fd5d8e1c2e85f31588f1c1 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.2" wakelock_plus_platform_interface: dependency: transitive description: @@ -1072,18 +1136,18 @@ packages: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.1.0" win32: dependency: transitive description: name: win32 - sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e url: "https://pub.dev" source: hosted - version: "5.13.0" + version: "5.15.0" win32_registry: dependency: transitive description: @@ -1104,18 +1168,18 @@ packages: dependency: transitive description: name: window_to_front - sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee" + sha256: "14fad8984db4415e2eeb30b04bb77140b180e260d6cb66b26de126a8657a9241" url: "https://pub.dev" source: hosted - version: "0.0.3" + version: "0.0.4" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: @@ -1124,6 +1188,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.38.0" + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" diff --git a/src/serious_python/example/flet_example/pubspec.yaml b/src/serious_python/example/flet_example/pubspec.yaml index 4a314b64..d17c3e2c 100644 --- a/src/serious_python/example/flet_example/pubspec.yaml +++ b/src/serious_python/example/flet_example/pubspec.yaml @@ -1,5 +1,5 @@ name: flet_example -description: A new Flutter project. +description: Flet counter app running on the in-process dart_bridge FFI transport. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev @@ -46,6 +46,10 @@ dependencies: path: ^1.8.3 path_provider: ^2.1.4 package_info_plus: ^9.0.0 + # msgpack_dart is the wire format Flet uses. _DartBridgeBackendChannel + # (in lib/main.dart) encodes outbound frames before handing them to + # PythonBridge.send. + msgpack_dart: ^1.0.1 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake index a1fa5aad..ec8b95fd 100644 --- a/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake +++ b/src/serious_python/example/flet_example/windows/flutter/generated_plugins.cmake @@ -16,6 +16,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python/example/flet_ffi_example/.gitignore b/src/serious_python/example/flet_ffi_example/.gitignore deleted file mode 100644 index 6c319542..00000000 --- a/src/serious_python/example/flet_ffi_example/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/src/serious_python/example/flet_ffi_example/.metadata b/src/serious_python/example/flet_ffi_example/.metadata deleted file mode 100644 index c7222470..00000000 --- a/src/serious_python/example/flet_ffi_example/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 - base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 - - platform: android - create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 - base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/src/serious_python/example/flet_ffi_example/README.md b/src/serious_python/example/flet_ffi_example/README.md deleted file mode 100644 index 250f24f1..00000000 --- a/src/serious_python/example/flet_ffi_example/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# flet_ffi_example - -A copy of [flet_example](../flet_example) wired to use the in-process -`dart_bridge` FFI transport (added in Flet 0.85+'s `dart-bridge` branch) -instead of the Unix-socket transport. The Python user code is identical; -only the embedding side differs: - -- `lib/main.dart` constructs a `PythonBridge` and hands a custom - `FletBackendChannel` to `FletApp` via the `channelBuilder` parameter. -- `FLET_DART_BRIDGE_PORT` is exported into the Python environment so - `flet.app.run_async()` selects `FletDartBridgeServer` instead of - `FletSocketServer`. - -The Dart `flet` package itself remains Python-independent — the -PythonBridge wiring lives entirely in this example. - -## Building - -The Python `flet` package needs the `dart-bridge` branch (because -`FletDartBridgeServer` is not on PyPI yet), so the `--requirements` arg -installs from git. Mobile targets use `pip install --only-binary :all:` -which would normally reject a git source — the -`SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet` env var opts `flet` -specifically into source installs by injecting `--no-binary flet`. - -For macOS: - -``` -export SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS=flet -dart run serious_python:main package app/src \ - --platform Darwin \ - --requirements "flet @ git+https://github.com/flet-dev/flet.git@dart-bridge#subdirectory=sdk/python/packages/flet" -``` - -Replace `--platform Darwin` with `iOS`, `Android`, `Windows`, or `Linux` -as needed. The same `--requirements` works on every platform. - -## Running locally - -`sync_site_packages.sh` (in `serious_python_darwin`) requires -`SERIOUS_PYTHON_SITE_PACKAGES` pointing at the freshly-packaged -`build/site-packages/` directory so the .app bundle picks up the -git-installed flet instead of a stale copy from a previous run: - -``` -export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages -fvm flutter test integration_test --device-id macos -``` diff --git a/src/serious_python/example/flet_ffi_example/analysis_options.yaml b/src/serious_python/example/flet_ffi_example/analysis_options.yaml deleted file mode 100644 index 61b6c4de..00000000 --- a/src/serious_python/example/flet_ffi_example/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/src/serious_python/example/flet_ffi_example/android/.gitignore b/src/serious_python/example/flet_ffi_example/android/.gitignore deleted file mode 100644 index 5fed52d9..00000000 --- a/src/serious_python/example/flet_ffi_example/android/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java -**/.cxx/ - -# Remember to never publicly share your keystore. -# See https://flutter.dev/to/reference-keystore -key.properties -**/*.keystore -**/*.jks diff --git a/src/serious_python/example/flet_ffi_example/android/app/build.gradle b/src/serious_python/example/flet_ffi_example/android/app/build.gradle deleted file mode 100644 index 852bab06..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" -} - -android { - namespace = "com.example.flet_example" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.flet_example" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug - } - } -} - -flutter { - source = "../.." -} diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml b/src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 3b5c35fb..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt b/src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt deleted file mode 100644 index cc08d6a6..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.flet_example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be7..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml b/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef880..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml b/src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/src/serious_python/example/flet_ffi_example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/src/serious_python/example/flet_ffi_example/android/build.gradle b/src/serious_python/example/flet_ffi_example/android/build.gradle deleted file mode 100644 index d2ffbffa..00000000 --- a/src/serious_python/example/flet_ffi_example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/src/serious_python/example/flet_ffi_example/android/gradle.properties b/src/serious_python/example/flet_ffi_example/android/gradle.properties deleted file mode 100644 index 25971708..00000000 --- a/src/serious_python/example/flet_ffi_example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true -android.enableJetifier=true diff --git a/src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index efdcc4ac..00000000 --- a/src/serious_python/example/flet_ffi_example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/src/serious_python/example/flet_ffi_example/android/settings.gradle b/src/serious_python/example/flet_ffi_example/android/settings.gradle deleted file mode 100644 index 01a36241..00000000 --- a/src/serious_python/example/flet_ffi_example/android/settings.gradle +++ /dev/null @@ -1,30 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - // AGP 8.9.1+ required by androidx.core 1.18.0 (transitive via Flet); - // AGP 8.9 requires Gradle 8.11+ (see gradle-wrapper.properties). - id "com.android.application" version "8.9.1" apply false - // KGP 2.3.x required: screen_brightness_android 2.1.5 ships with a - // Kotlin 2.3.21 stdlib whose metadata format (binary version 2.3.0) - // can't be read by KGP < 2.3. - id "org.jetbrains.kotlin.android" version "2.3.21" apply false -} - -include ":app" diff --git a/src/serious_python/example/flet_ffi_example/app/app.zip.hash b/src/serious_python/example/flet_ffi_example/app/app.zip.hash deleted file mode 100644 index e5d849b8..00000000 --- a/src/serious_python/example/flet_ffi_example/app/app.zip.hash +++ /dev/null @@ -1 +0,0 @@ -b92d604f99e8c64859bd16e28c24a0b25eefdcdcb35ba99a08201d614a03772a \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/app/src/main.py b/src/serious_python/example/flet_ffi_example/app/src/main.py deleted file mode 100644 index 05c566f1..00000000 --- a/src/serious_python/example/flet_ffi_example/app/src/main.py +++ /dev/null @@ -1,76 +0,0 @@ -import os -import sys -import urllib.request - -import flet as ft -from flet.version import flet_version - -# logging.basicConfig(level=logging.DEBUG) - -print("Hello from Python!") -print(__name__) - -# import aaa -app_data = os.environ["FLET_APP_DATA"] -app_temp = os.environ["FLET_APP_TEMP"] - - -def main(page: ft.Page): - page.title = "Flet counter example" - page.vertical_alignment = ft.MainAxisAlignment.CENTER - - py_ver = sys.version_info - python_version_text = ( - f"Python version: {py_ver.major}.{py_ver.minor}.{py_ver.micro}" - ) - print(python_version_text) - - txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) - - def minus_click(e): - print("Clicked minus button") - txt_number.value = str(int(txt_number.value) - 1) - page.update() - - def plus_click(e): - txt_number.value = str(int(txt_number.value) + 1) - page.update() - - def check_ssl(e): - try: - with urllib.request.urlopen("https://google.com") as res: - result = "OK" - except Exception as ex: - result = str(ex) - page.show_dialog(ft.AlertDialog(content=ft.Text(result))) - # print(result) - - page.add( - ft.Row( - [ - ft.IconButton(ft.Icons.REMOVE, key="decrement", on_click=minus_click), - txt_number, - ft.IconButton(ft.Icons.ADD, key="increment", on_click=plus_click), - ], - alignment=ft.MainAxisAlignment.CENTER, - expand=True, - ), - ft.Row( - [ - ft.Text(f"Flet version: {flet_version}"), - ft.OutlinedButton("Check SSL", on_click=check_ssl), - ft.OutlinedButton("Exit app", on_click=lambda _: sys.exit(100)), - ], - wrap=True, - alignment=ft.MainAxisAlignment.CENTER, - ), - ft.Text(f"App data dir: {app_data}"), - ft.Text(f"App temp dir: {app_temp}"), - ft.Text(python_version_text), - ) - - print("This is inside main() method!") - - -if __name__ == "__main__": - ft.run(main) diff --git a/src/serious_python/example/flet_ffi_example/app/src/requirements.txt b/src/serious_python/example/flet_ffi_example/app/src/requirements.txt deleted file mode 100644 index 4c3173f6..00000000 --- a/src/serious_python/example/flet_ffi_example/app/src/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flet \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/integration_test/app_test.dart b/src/serious_python/example/flet_ffi_example/integration_test/app_test.dart deleted file mode 100644 index c1dc7f2c..00000000 --- a/src/serious_python/example/flet_ffi_example/integration_test/app_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flet_ffi_example/main.dart' as app; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - group('end-to-end test', () { - testWidgets('make sure counter can be incremented and decremented', - (tester) async { - app.main(); - await tester.pumpAndSettle(const Duration(seconds: 5)); - - // Wait for up to 10 seconds for the app to start - bool counterFound = false; - for (int i = 0; i < 20; i++) { - await tester.pump(const Duration(seconds: 1)); - - if (find.text('0').evaluate().isNotEmpty) { - counterFound = true; - break; - } - } - - expect(counterFound, isTrue); - - // Tap increment button - await tester.tap(find.byKey(const Key('increment'))); - await tester.pumpAndSettle(); - expect(find.text('1'), findsOneWidget); - - // Tap decrement button - await tester.tap(find.byKey(const Key('decrement'))); - await tester.tap(find.byKey(const Key('decrement'))); - await tester.pumpAndSettle(); - expect(find.text('-1'), findsOneWidget); - - // Verify the bundled Python runtime matches what CI requested. Skipped - // outside CI (no --dart-define). - const expectedPyVersion = - String.fromEnvironment('EXPECTED_PYTHON_VERSION'); - if (expectedPyVersion.isNotEmpty) { - bool versionFound = false; - for (int i = 0; i < 20; i++) { - await tester.pump(const Duration(seconds: 1)); - if (find - .textContaining('Python version: $expectedPyVersion.') - .evaluate() - .isNotEmpty) { - versionFound = true; - break; - } - } - expect(versionFound, isTrue, - reason: - 'Expected `Python version: $expectedPyVersion.x` in the app UI'); - } - }); - }); -} diff --git a/src/serious_python/example/flet_ffi_example/ios/.gitignore b/src/serious_python/example/flet_ffi_example/ios/.gitignore deleted file mode 100644 index 7a7f9873..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist b/src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 7c569640..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 12.0 - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig b/src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig b/src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/ios/Podfile b/src/serious_python/example/flet_ffi_example/ios/Podfile deleted file mode 100644 index 164df534..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Podfile +++ /dev/null @@ -1,44 +0,0 @@ -# Uncomment this line to define a global platform for your project -platform :ios, '12.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/src/serious_python/example/flet_ffi_example/ios/Podfile.lock b/src/serious_python/example/flet_ffi_example/ios/Podfile.lock deleted file mode 100644 index a6e90d98..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Podfile.lock +++ /dev/null @@ -1,114 +0,0 @@ -PODS: - - DKImagePickerController/Core (4.3.4): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.4) - - DKImagePickerController/PhotoGallery (4.3.4): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.4) - - DKPhotoGallery (0.0.17): - - DKPhotoGallery/Core (= 0.0.17) - - DKPhotoGallery/Model (= 0.0.17) - - DKPhotoGallery/Preview (= 0.0.17) - - DKPhotoGallery/Resource (= 0.0.17) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.17): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.17): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Flutter (1.0.0) - - integration_test (0.0.1): - - Flutter - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - SDWebImage (5.18.5): - - SDWebImage/Core (= 5.18.5) - - SDWebImage/Core (5.18.5) - - sensors_plus (0.0.1): - - Flutter - - serious_python_darwin (0.8.0): - - Flutter - - FlutterMacOS - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - SwiftyGif (5.4.4) - - url_launcher_ios (0.0.1): - - Flutter - -DEPENDENCIES: - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - Flutter (from `Flutter`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) - - serious_python_darwin (from `.symlinks/plugins/serious_python_darwin/darwin`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - -SPEC REPOS: - trunk: - - DKImagePickerController - - DKPhotoGallery - - SDWebImage - - SwiftyGif - -EXTERNAL SOURCES: - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - Flutter: - :path: Flutter - integration_test: - :path: ".symlinks/plugins/integration_test/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" - sensors_plus: - :path: ".symlinks/plugins/sensors_plus/ios" - serious_python_darwin: - :path: ".symlinks/plugins/serious_python_darwin/darwin" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - -SPEC CHECKSUMS: - DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 - package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - SDWebImage: 7ac2b7ddc5e8484c79aa90fc4e30b149d6a2c88f - sensors_plus: 42b9de1b8237675fa8d8121e4bb93be0f79fa61d - serious_python_darwin: 351e50099cb9e34f344f75af29b1d36d3c0922f2 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - -PODFILE CHECKSUM: 7be2f5f74864d463a8ad433546ed1de7e0f29aef - -COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 92eb9c48..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,724 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2405649350EFCEC25599DE23 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */; }; - 2CA3C271D8189DF194697D7D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28A203680D8105B35D530F31 /* Pods_Runner.framework */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 97C146ED1CF9000F007C117D; - remoteInfo = Runner; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1EE1648DA1E83A0AA44BC13A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 28A203680D8105B35D530F31 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 563D6173166309C998296F04 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 5FA1FBC3AE8269E16AA97AD1 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2CA3C271D8189DF194697D7D /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B920DD79982F64FC739571F8 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2405649350EFCEC25599DE23 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 103F5AA3589F7D2F915BFF32 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 28A203680D8105B35D530F31 /* Pods_Runner.framework */, - D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - E36498D4F89A08F7B5C19AED /* Pods */, - 103F5AA3589F7D2F915BFF32 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - E36498D4F89A08F7B5C19AED /* Pods */ = { - isa = PBXGroup; - children = ( - 5FA1FBC3AE8269E16AA97AD1 /* Pods-Runner.debug.xcconfig */, - 563D6173166309C998296F04 /* Pods-Runner.release.xcconfig */, - 1EE1648DA1E83A0AA44BC13A /* Pods-Runner.profile.xcconfig */, - 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */, - 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */, - BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 90579612B1A4EF4E391E0626 /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - B920DD79982F64FC739571F8 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 331C8086294A63A400263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - C8A57305F206317D5468F600 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - AE52A9CBDBBC66A5CB483F7A /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - 331C8080294A63A400263BE5 /* RunnerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C807F294A63A400263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 90579612B1A4EF4E391E0626 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - AE52A9CBDBBC66A5CB483F7A /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - C8A57305F206317D5468F600 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C807D294A63A400263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Debug; - }; - 331C8089294A63A400263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Release; - }; - 331C808A294A63A400263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C8088294A63A400263BE5 /* Debug */, - 331C8089294A63A400263BE5 /* Release */, - 331C808A294A63A400263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 8e3ca5df..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift b/src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift deleted file mode 100644 index b6363034..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452e458972bab9d994556c8305db4c827017..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d933e1120817fe9182483a228007b18ab6ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b0099ca80c806f8fe495613e8d6c69460d76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe730945a01f64a61e2235dbe3f45b08f7729182..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463a9bc882b461c96aadf492d1729e49e725..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec303439225b78712f49115768196d8d76f6790..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea27c705180eb716271f41b582e76dcbd90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1674 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 diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf12aa4d28f374bb26596605a46dcbb3e7c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard b/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist b/src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist deleted file mode 100644 index f536cf65..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Info.plist +++ /dev/null @@ -1,51 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Flet Example - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - flet_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h b/src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift b/src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b1..00000000 --- a/src/serious_python/example/flet_ffi_example/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Flutter -import UIKit -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/src/serious_python/example/flet_ffi_example/lib/main.dart b/src/serious_python/example/flet_ffi_example/lib/main.dart deleted file mode 100644 index 1b3bd755..00000000 --- a/src/serious_python/example/flet_ffi_example/lib/main.dart +++ /dev/null @@ -1,315 +0,0 @@ -import 'dart:async'; - -import 'package:flet/flet.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_web_plugins/url_strategy.dart'; -import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart' as path_provider; -import 'package:serious_python/bridge.dart'; -import 'package:serious_python/serious_python.dart'; - -const bool isProduction = bool.fromEnvironment('dart.vm.product'); - -const assetPath = "app/app.zip"; -const pythonModuleName = "main"; -final hideLoadingPage = - bool.tryParse("{{ cookiecutter.hide_loading_animation }}".toLowerCase()) ?? - true; -const errorExitCode = 100; - -/// The Python script is intentionally smaller than in `flet_example`. No -/// stdout-callback socket, no flet.sock — Python startup is just `runpy` -/// on the user module, and stdout/stderr stay attached to whatever the -/// embedded interpreter inherits. The dart_bridge transport in Flet 0.85+ -/// handles IPC directly. -const pythonScript = """ -import logging, os, runpy, sys, traceback - -# Redirect stdout/stderr to a file under FLET_APP_TEMP so we can inspect what -# Python is doing without a separate stdout-callback socket. Temporary — once -# the FFI transport is stable a more proper logging story can land. -_log_path = os.path.join( - os.environ.get("FLET_APP_TEMP", "/tmp"), "flet_ffi_boot.log" -) -_log = open(_log_path, "w", buffering=1) -sys.stdout = _log -sys.stderr = _log -logging.basicConfig(stream=_log, level=logging.DEBUG) -print(f"[boot] python {sys.version}", flush=True) -print(f"[boot] FLET_DART_BRIDGE_PORT={os.environ.get('FLET_DART_BRIDGE_PORT')}", flush=True) -print(f"[boot] FLET_PLATFORM={os.environ.get('FLET_PLATFORM')}", flush=True) - -try: - import certifi - os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() - os.environ["SSL_CERT_FILE"] = certifi.where() - - if os.getenv("FLET_PLATFORM") == "android": - import ssl - - def create_default_context( - purpose=ssl.Purpose.SERVER_AUTH, *, - cafile=None, capath=None, cadata=None, - ): - return ssl.create_default_context( - purpose=purpose, - cafile=certifi.where(), - capath=capath, - cadata=cadata, - ) - - ssl._create_default_https_context = create_default_context -except ImportError as e: - print(f"[boot] certifi import failed: {e}", flush=True) - -print("[boot] about to runpy.run_module", flush=True) -try: - runpy.run_module("{module_name}", run_name="__main__") - print("[boot] runpy.run_module returned", flush=True) -except SystemExit as e: - print(f"[boot] SystemExit: {e.code}", flush=True) - raise -except Exception: - print("[boot] runpy.run_module raised:", flush=True) - traceback.print_exc() - sys.exit($errorExitCode) -"""; - -// global vars -String assetsDir = ""; -String appDir = ""; -late PythonBridge _bridge; -Map environmentVariables = {}; - -void main() async { - if (isProduction) { - // ignore: avoid_returning_null_for_void - debugPrint = (String? message, {int? wrapWidth}) => null; - } - - runApp(FutureBuilder( - future: prepareApp(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - return FletApp( - pageUrl: "dartbridge://${_bridge.port}", - assetsDir: assetsDir, - channelBuilder: ({required onMessage, required onDisconnect}) => - _DartBridgeBackendChannel(_bridge, - onMessage: onMessage, onDisconnect: onDisconnect), - ); - } else if (snapshot.hasError) { - return MaterialApp( - home: ErrorScreen( - title: "Error starting app", - text: snapshot.error.toString())); - } else { - return const MaterialApp(home: BlankScreen()); - } - })); -} - -Future prepareApp() async { - if (kIsWeb) { - var routeUrlStrategy = getFletRouteUrlStrategy(); - if (routeUrlStrategy == "path") { - usePathUrlStrategy(); - } - return ""; - } - - await setupDesktop(); - - // Extract app from asset. - appDir = await extractAssetZip(assetPath, checkHash: true); - Directory.current = appDir; - assetsDir = path.join(appDir, "assets"); - - WidgetsFlutterBinding.ensureInitialized(); - var appTempPath = (await path_provider.getApplicationCacheDirectory()).path; - var appDataPath = - (await path_provider.getApplicationDocumentsDirectory()).path; - - if (defaultTargetPlatform != TargetPlatform.iOS && - defaultTargetPlatform != TargetPlatform.android) { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - appDataPath = path.join(appDataPath, "flet", packageInfo.packageName); - if (!await Directory(appDataPath).exists()) { - await Directory(appDataPath).create(recursive: true); - } - } - - // Create the PythonBridge before we hand its port to Python. It outlives - // the FletApp widget; the embedded interpreter only stops when the Flutter - // app exits. - _bridge = PythonBridge(); - - environmentVariables.addAll({ - "FLET_APP_DATA": appDataPath, - "FLET_APP_TEMP": appTempPath, - "FLET_PLATFORM": defaultTargetPlatform.name.toLowerCase(), - // Python reads this env var in flet.app.run_async() and starts the - // dart_bridge transport (added in flet's dart-bridge branch) bound to - // the same port. - "FLET_DART_BRIDGE_PORT": "${_bridge.port}", - }); - - // Fire-and-forget: Python lives for the duration of the app. SeriousPython - // dispatches it on a worker thread (sync=false default), so this returns - // immediately after spawning. - var script = pythonScript.replaceAll('{module_name}', pythonModuleName); - unawaited(SeriousPython.runProgram( - path.join(appDir, "$pythonModuleName.pyc"), - script: script, - environmentVariables: environmentVariables, - )); - - return ""; -} - -/// `FletBackendChannel` implementation backed by a [PythonBridge]. Bytes -/// flow Dart↔Python entirely in-process; no Unix socket, no kernel context -/// switch. The wire format is the same MsgPack-framed protocol the existing -/// socket-based `FletSocketBackendChannel` speaks. -class _DartBridgeBackendChannel implements FletBackendChannel { - _DartBridgeBackendChannel(this._bridge, - {required FletBackendChannelOnMessageCallback onMessage, - required FletBackendChannelOnDisconnectCallback onDisconnect}) - : _onMessage = onMessage, - _onDisconnect = onDisconnect, - _deserializer = - StreamingMsgpackDeserializer(extDecoder: FletMsgpackDecoder()); - - final PythonBridge _bridge; - final FletBackendChannelOnMessageCallback _onMessage; - final FletBackendChannelOnDisconnectCallback _onDisconnect; - final StreamingMsgpackDeserializer _deserializer; - StreamSubscription? _subscription; - - @override - Future connect() async { - _subscription = _bridge.messages.listen( - _onBytes, - onError: (error, stack) { - debugPrint("PythonBridge stream error: $error"); - _onDisconnect(); - }, - onDone: () { - debugPrint("PythonBridge stream closed."); - _onDisconnect(); - }, - cancelOnError: false, - ); - } - - void _onBytes(Uint8List bytes) { - _deserializer.addChunk(bytes); - final frames = _deserializer.decodeMessages(); - for (final frame in frames) { - _onMessage(Message.fromList(frame)); - } - } - - @override - void send(Message message) { - final encoded = Uint8List.fromList( - msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); - // Retry loop covers the brief startup window where Python hasn't yet - // called dart_bridge.set_enqueue_handler_func — bridge.send returns - // false in that case. Once the handler is registered (Flet's app.py - // dart_bridge server start() does it before run_module dispatch), - // bridge.send returns true synchronously. - if (_bridge.send(encoded)) return; - _retrySend(encoded); - } - - void _retrySend(Uint8List encoded) { - const interval = Duration(milliseconds: 50); - const deadline = Duration(seconds: 30); - final start = DateTime.now(); - Timer.periodic(interval, (timer) { - if (_bridge.send(encoded)) { - timer.cancel(); - } else if (DateTime.now().difference(start) > deadline) { - timer.cancel(); - debugPrint("PythonBridge send timed out: Python handler never registered."); - } - }); - } - - @override - bool get isLocalConnection => true; - - @override - int get defaultReconnectIntervalMs => 0; - - @override - void disconnect() { - _subscription?.cancel(); - _subscription = null; - } -} - -class ErrorScreen extends StatelessWidget { - final String title; - final String text; - - const ErrorScreen({super.key, required this.title, required this.text}); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Container( - padding: const EdgeInsets.all(8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: Theme.of(context).textTheme.titleMedium, - ), - TextButton.icon( - onPressed: () { - Clipboard.setData(ClipboardData(text: text)); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Copied to clipboard')), - ); - }, - icon: const Icon( - Icons.copy, - size: 16, - ), - label: const Text("Copy"), - ) - ], - ), - Expanded( - child: SingleChildScrollView( - child: SelectableText(text, - style: Theme.of(context).textTheme.bodySmall), - )) - ], - ), - )), - ); - } -} - -class BlankScreen extends StatelessWidget { - const BlankScreen({super.key}); - - @override - Widget build(BuildContext context) { - return const Scaffold( - body: SizedBox.shrink(), - ); - } -} diff --git a/src/serious_python/example/flet_ffi_example/linux/.gitignore b/src/serious_python/example/flet_ffi_example/linux/.gitignore deleted file mode 100644 index d3896c98..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt deleted file mode 100644 index 7ef35274..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/CMakeLists.txt +++ /dev/null @@ -1,154 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "flet_example") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.flet_example") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Link bundled libraries from plugins into main executable to enable dlopen -# with only library name. -# Will NOT be needed once: https://github.com/flutter/engine/pull/28525 lands in Flutter channel we are using -# Alternative approach is to update plugin's RUNPATH before packaging: -# chrpath -r \$ORIGIN ./build/linux/arm64/release/bundle/lib/libserious_python_linux_plugin.so -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - if(${plugin}_bundled_libraries) - target_link_libraries( - ${BINARY_NAME} - PRIVATE - ${${plugin}_bundled_libraries} - ) - endif() -endforeach(plugin) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd0164..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 142e738c..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,35 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include -#include -#include -#include -#include -#include - -void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) pasteboard_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); - pasteboard_plugin_register_with_registrar(pasteboard_registrar); - g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); - screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); - g_autoptr(FlPluginRegistrar) serious_python_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "SeriousPythonLinuxPlugin"); - serious_python_linux_plugin_register_with_registrar(serious_python_linux_registrar); - g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); - url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); - g_autoptr(FlPluginRegistrar) window_manager_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); - window_manager_plugin_register_with_registrar(window_manager_registrar); - g_autoptr(FlPluginRegistrar) window_to_front_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin"); - window_to_front_plugin_register_with_registrar(window_to_front_registrar); -} diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47b..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 7d9bc28c..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,30 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - pasteboard - screen_retriever_linux - serious_python_linux - url_launcher_linux - window_manager - window_to_front -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST - jni -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/src/serious_python/example/flet_ffi_example/linux/main.cc b/src/serious_python/example/flet_ffi_example/linux/main.cc deleted file mode 100644 index e7c5c543..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/src/serious_python/example/flet_ffi_example/linux/my_application.cc b/src/serious_python/example/flet_ffi_example/linux/my_application.cc deleted file mode 100644 index 7f876fab..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/my_application.cc +++ /dev/null @@ -1,104 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "flet_example"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "flet_example"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/src/serious_python/example/flet_ffi_example/linux/my_application.h b/src/serious_python/example/flet_ffi_example/linux/my_application.h deleted file mode 100644 index 72271d5e..00000000 --- a/src/serious_python/example/flet_ffi_example/linux/my_application.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/src/serious_python/example/flet_ffi_example/macos/.gitignore b/src/serious_python/example/flet_ffi_example/macos/.gitignore deleted file mode 100644 index 746adbb6..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d15..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index 6d5caa62..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import battery_plus -import connectivity_plus -import device_info_plus -import file_picker -import package_info_plus -import pasteboard -import screen_brightness_macos -import screen_retriever_macos -import serious_python_darwin -import share_plus -import shared_preferences_foundation -import url_launcher_macos -import wakelock_plus -import window_manager -import window_to_front - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin")) - ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) - DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) - FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) - FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) - PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) - ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) - ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) - SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) - SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) - SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) - UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) - WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) - WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) - WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) -} diff --git a/src/serious_python/example/flet_ffi_example/macos/Podfile b/src/serious_python/example/flet_ffi_example/macos/Podfile deleted file mode 100644 index b52666a1..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -platform :osx, '10.15' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/src/serious_python/example/flet_ffi_example/macos/Podfile.lock b/src/serious_python/example/flet_ffi_example/macos/Podfile.lock deleted file mode 100644 index c631f6e1..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Podfile.lock +++ /dev/null @@ -1,108 +0,0 @@ -PODS: - - battery_plus (0.0.1): - - FlutterMacOS - - connectivity_plus (0.0.1): - - FlutterMacOS - - device_info_plus (0.0.1): - - FlutterMacOS - - file_picker (0.0.1): - - FlutterMacOS - - FlutterMacOS (1.0.0) - - package_info_plus (0.0.1): - - FlutterMacOS - - pasteboard (0.0.1): - - FlutterMacOS - - screen_brightness_macos (0.1.0): - - FlutterMacOS - - screen_retriever_macos (0.0.1): - - FlutterMacOS - - serious_python_darwin (2.0.0): - - Flutter - - FlutterMacOS - - share_plus (0.0.1): - - FlutterMacOS - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - url_launcher_macos (0.0.1): - - FlutterMacOS - - wakelock_plus (0.0.1): - - FlutterMacOS - - window_manager (0.5.0): - - FlutterMacOS - - window_to_front (0.0.4): - - FlutterMacOS - -DEPENDENCIES: - - battery_plus (from `Flutter/ephemeral/.symlinks/plugins/battery_plus/macos`) - - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) - - FlutterMacOS (from `Flutter/ephemeral`) - - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) - - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) - - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) - - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) - - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) - - window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`) - -EXTERNAL SOURCES: - battery_plus: - :path: Flutter/ephemeral/.symlinks/plugins/battery_plus/macos - connectivity_plus: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos - device_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos - file_picker: - :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos - FlutterMacOS: - :path: Flutter/ephemeral - package_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos - pasteboard: - :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos - screen_brightness_macos: - :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos - screen_retriever_macos: - :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos - serious_python_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin - share_plus: - :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos - shared_preferences_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin - url_launcher_macos: - :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos - wakelock_plus: - :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos - window_manager: - :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos - window_to_front: - :path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos - -SPEC CHECKSUMS: - battery_plus: f51ad29136e025b714b96f7d096f44f604615da7 - connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e - device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 - file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a - FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - package_info_plus: f0052d280d17aa382b932f399edf32507174e870 - pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 - screen_brightness_macos: 1058c18b5e0570f48f93016487a5ed66d6977fe0 - screen_retriever_macos: c5508cc3c66ff0d4db650480cf0ab691e220d933 - serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 - share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc - shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb - url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd - wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b - window_manager: b729e31d38fb04905235df9ea896128991cad99e - window_to_front: 2d7d31f268d0b13b7e63b26e31eb0a2e9612239e - -PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 - -COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 319e1e69..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,809 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 256EF705489316F00EF3962A /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */; }; - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 99AFA56BC7E7B7480D345FDA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 11E10455E245EB5F22EB7A9A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flet_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flet_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - B126920E3C82A726215E0DE6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - F080949AB83300EBF0AAA1E4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 256EF705489316F00EF3962A /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 99AFA56BC7E7B7480D345FDA /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2FD1AA06884986EE36A305B7 /* Pods */ = { - isa = PBXGroup; - children = ( - 11E10455E245EB5F22EB7A9A /* Pods-Runner.debug.xcconfig */, - F080949AB83300EBF0AAA1E4 /* Pods-Runner.release.xcconfig */, - B126920E3C82A726215E0DE6 /* Pods-Runner.profile.xcconfig */, - 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */, - 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */, - FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - 2FD1AA06884986EE36A305B7 /* Pods */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* flet_example.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */, - 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */, - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 8F5527630CCCD1FAF8A7F717 /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */, - 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* flet_example.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; - 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 8F5527630CCCD1FAF8A7F717 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flet_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flet_example"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flet_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flet_example"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/flet_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/flet_example"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 410c6419..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift b/src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c17614..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9a33e198f5747104729e1fcef999772a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102994 zcmeEugo5nb1G~3xi~y`}h6XHx5j$(L*3|5S2UfkG$|UCNI>}4f?MfqZ+HW-sRW5RKHEm z^unW*Xx{AH_X3Xdvb%C(Bh6POqg==@d9j=5*}oEny_IS;M3==J`P0R!eD6s~N<36C z*%-OGYqd0AdWClO!Z!}Y1@@RkfeiQ$Ib_ z&fk%T;K9h`{`cX3Hu#?({4WgtmkR!u3ICS~|NqH^fdNz>51-9)OF{|bRLy*RBv#&1 z3Oi_gk=Y5;>`KbHf~w!`u}!&O%ou*Jzf|Sf?J&*f*K8cftMOKswn6|nb1*|!;qSrlw= zr-@X;zGRKs&T$y8ENnFU@_Z~puu(4~Ir)>rbYp{zxcF*!EPS6{(&J}qYpWeqrPWW< zfaApz%<-=KqxrqLLFeV3w0-a0rEaz9&vv^0ZfU%gt9xJ8?=byvNSb%3hF^X_n7`(fMA;C&~( zM$cQvQ|g9X)1AqFvbp^B{JEX$o;4iPi?+v(!wYrN{L}l%e#5y{j+1NMiT-8=2VrCP zmFX9=IZyAYA5c2!QO96Ea-6;v6*$#ZKM-`%JCJtrA3d~6h{u+5oaTaGE)q2b+HvdZ zvHlY&9H&QJ5|uG@wDt1h99>DdHy5hsx)bN`&G@BpxAHh$17yWDyw_jQhhjSqZ=e_k z_|r3=_|`q~uA47y;hv=6-o6z~)gO}ZM9AqDJsR$KCHKH;QIULT)(d;oKTSPDJ}Jx~G#w-(^r<{GcBC*~4bNjfwHBumoPbU}M)O za6Hc2ik)2w37Yyg!YiMq<>Aov?F2l}wTe+>h^YXcK=aesey^i)QC_p~S zp%-lS5%)I29WfywP(r4@UZ@XmTkqo51zV$|U|~Lcap##PBJ}w2b4*kt7x6`agP34^ z5fzu_8rrH+)2u*CPcr6I`gL^cI`R2WUkLDE5*PX)eJU@H3HL$~o_y8oMRoQ0WF9w| z6^HZDKKRDG2g;r8Z4bn+iJNFV(CG;K-j2>aj229gl_C6n12Jh$$h!}KVhn>*f>KcH z;^8s3t(ccVZ5<{>ZJK@Z`hn_jL{bP8Yn(XkwfRm?GlEHy=T($8Z1Mq**IM`zxN9>-yXTjfB18m_$E^JEaYn>pj`V?n#Xu;Z}#$- zw0Vw;T*&9TK$tKI7nBk9NkHzL++dZ^;<|F6KBYh2+XP-b;u`Wy{~79b%IBZa3h*3^ zF&BKfQ@Ej{7ku_#W#mNJEYYp=)bRMUXhLy2+SPMfGn;oBsiG_6KNL8{p1DjuB$UZB zA)a~BkL)7?LJXlCc}bB~j9>4s7tlnRHC5|wnycQPF_jLl!Avs2C3^lWOlHH&v`nGd zf&U!fn!JcZWha`Pl-B3XEe;(ks^`=Z5R zWyQR0u|do2`K3ec=YmWGt5Bwbu|uBW;6D8}J3{Uep7_>L6b4%(d=V4m#(I=gkn4HT zYni3cnn>@F@Wr<hFAY3Y~dW+3bte;70;G?kTn4Aw5nZ^s5|47 z4$rCHCW%9qa4)4vE%^QPMGf!ET!^LutY$G zqdT(ub5T5b+wi+OrV}z3msoy<4)`IPdHsHJggmog0K*pFYMhH!oZcgc5a)WmL?;TPSrerTVPp<#s+imF3v#!FuBNNa`#6 z!GdTCF|IIpz#(eV^mrYKThA4Bnv&vQet@%v9kuRu3EHx1-2-it@E`%9#u`)HRN#M? z7aJ{wzKczn#w^`OZ>Jb898^Xxq)0zd{3Tu7+{-sge-rQ z&0PME&wIo6W&@F|%Z8@@N3)@a_ntJ#+g{pUP7i?~3FirqU`rdf8joMG^ld?(9b7Iv z>TJgBg#)(FcW)h!_if#cWBh}f+V08GKyg|$P#KTS&%=!+0a%}O${0$i)kn9@G!}En zv)_>s?glPiLbbx)xk(lD-QbY(OP3;MSXM5E*P&_`Zks2@46n|-h$Y2L7B)iH{GAAq19h5-y0q>d^oy^y+soJu9lXxAe%jcm?=pDLFEG2kla40e!5a}mpe zdL=WlZ=@U6{>g%5a+y-lx)01V-x;wh%F{=qy#XFEAqcd+m}_!lQ)-9iiOL%&G??t| z?&NSdaLqdPdbQs%y0?uIIHY7rw1EDxtQ=DU!i{)Dkn~c$LG5{rAUYM1j5*G@oVn9~ zizz{XH(nbw%f|wI=4rw^6mNIahQpB)OQy10^}ACdLPFc2@ldVi|v@1nWLND?)53O5|fg`RZW&XpF&s3@c-R?aad!$WoH6u0B|}zt)L($E^@U- zO#^fxu9}Zw7Xl~nG1FVM6DZSR0*t!4IyUeTrnp@?)Z)*!fhd3)&s(O+3D^#m#bAem zpf#*aiG_0S^ofpm@9O7j`VfLU0+{$x!u^}3!zp=XST0N@DZTp!7LEVJgqB1g{psNr za0uVmh3_9qah14@M_pi~vAZ#jc*&aSm$hCNDsuQ-zPe&*Ii#2=2gP+DP4=DY z_Y0lUsyE6yaV9)K)!oI6+*4|spx2at*30CAx~6-5kfJzQ`fN8$!lz%hz^J6GY?mVH zbYR^JZ(Pmj6@vy-&!`$5soyy-NqB^8cCT40&R@|6s@m+ZxPs=Bu77-+Os7+bsz4nA3DrJ8#{f98ZMaj-+BD;M+Jk?pgFcZIb}m9N z{ct9T)Kye&2>l^39O4Q2@b%sY?u#&O9PO4@t0c$NUXG}(DZJ<;_oe2~e==3Z1+`Zo zFrS3ns-c}ZognVBHbg#e+1JhC(Yq7==rSJQ8J~}%94(O#_-zJKwnBXihl#hUd9B_>+T& z7eHHPRC?5ONaUiCF7w|{J`bCWS7Q&xw-Sa={j-f)n5+I=9s;E#fBQB$`DDh<^mGiF zu-m_k+)dkBvBO(VMe2O4r^sf3;sk9K!xgXJU>|t9Vm8Ty;fl5pZzw z9j|}ZD}6}t;20^qrS?YVPuPRS<39d^y0#O1o_1P{tN0?OX!lc-ICcHI@2#$cY}_CY zev|xdFcRTQ_H)1fJ7S0*SpPs8e{d+9lR~IZ^~dKx!oxz?=Dp!fD`H=LH{EeC8C&z-zK$e=!5z8NL=4zx2{hl<5z*hEmO=b-7(k5H`bA~5gT30Sjy`@-_C zKM}^so9Ti1B;DovHByJkTK87cfbF16sk-G>`Q4-txyMkyQS$d}??|Aytz^;0GxvOs zPgH>h>K+`!HABVT{sYgzy3CF5ftv6hI-NRfgu613d|d1cg^jh+SK7WHWaDX~hlIJ3 z>%WxKT0|Db1N-a4r1oPKtF--^YbP=8Nw5CNt_ZnR{N(PXI>Cm$eqi@_IRmJ9#)~ZHK_UQ8mi}w^`+4$OihUGVz!kW^qxnCFo)-RIDbA&k-Y=+*xYv5y4^VQ9S)4W5Pe?_RjAX6lS6Nz#!Hry=+PKx2|o_H_3M`}Dq{Bl_PbP(qel~P@=m}VGW*pK96 zI@fVag{DZHi}>3}<(Hv<7cVfWiaVLWr@WWxk5}GDEbB<+Aj;(c>;p1qmyAIj+R!`@#jf$ zy4`q23L-72Zs4j?W+9lQD;CYIULt%;O3jPWg2a%Zs!5OW>5h1y{Qof!p&QxNt5=T( zd5fy&7=hyq;J8%86YBOdc$BbIFxJx>dUyTh`L z-oKa=OhRK9UPVRWS`o2x53bAv+py)o)kNL6 z9W1Dlk-g6Ht@-Z^#6%`9S9`909^EMj?9R^4IxssCY-hYzei^TLq7Cj>z$AJyaU5=z zl!xiWvz0U8kY$etrcp8mL;sYqGZD!Hs-U2N{A|^oEKA482v1T%cs%G@X9M?%lX)p$ zZoC7iYTPe8yxY0Jne|s)fCRe1mU=Vb1J_&WcIyP|x4$;VSVNC`M+e#oOA`#h>pyU6 z?7FeVpk`Hsu`~T3i<_4<5fu?RkhM;@LjKo6nX>pa%8dSdgPO9~Jze;5r>Tb1Xqh5q z&SEdTXevV@PT~!O6z|oypTk7Qq+BNF5IQ(8s18c=^0@sc8Gi|3e>VKCsaZ?6=rrck zl@oF5Bd0zH?@15PxSJIRroK4Wa?1o;An;p0#%ZJ^tI=(>AJ2OY0GP$E_3(+Zz4$AQ zW)QWl<4toIJ5TeF&gNXs>_rl}glkeG#GYbHHOv-G!%dJNoIKxn)FK$5&2Zv*AFic! z@2?sY&I*PSfZ8bU#c9fdIJQa_cQijnj39-+hS@+~e*5W3bj%A}%p9N@>*tCGOk+cF zlcSzI6j%Q|2e>QG3A<86w?cx6sBtLNWF6_YR?~C)IC6_10SNoZUHrCpp6f^*+*b8` zlx4ToZZuI0XW1W)24)92S)y0QZa);^NRTX6@gh8@P?^=#2dV9s4)Q@K+gnc{6|C}& zDLHr7nDOLrsH)L@Zy{C_2UrYdZ4V{|{c8&dRG;wY`u>w%$*p>PO_}3`Y21pk?8Wtq zGwIXTulf7AO2FkPyyh2TZXM1DJv>hI`}x`OzQI*MBc#=}jaua&czSkI2!s^rOci|V zFkp*Vbiz5vWa9HPFXMi=BV&n3?1?%8#1jq?p^3wAL`jgcF)7F4l<(H^!i=l-(OTDE zxf2p71^WRIExLf?ig0FRO$h~aA23s#L zuZPLkm>mDwBeIu*C7@n@_$oSDmdWY7*wI%aL73t~`Yu7YwE-hxAATmOi0dmB9|D5a zLsR7OQcA0`vN9m0L|5?qZ|jU+cx3_-K2!K$zDbJ$UinQy<9nd5ImWW5n^&=Gg>Gsh zY0u?m1e^c~Ug39M{{5q2L~ROq#c{eG8Oy#5h_q=#AJj2Yops|1C^nv0D1=fBOdfAG z%>=vl*+_w`&M7{qE#$xJJp_t>bSh7Mpc(RAvli9kk3{KgG5K@a-Ue{IbU{`umXrR3ra5Y7xiX42+Q%N&-0#`ae_ z#$Y6Wa++OPEDw@96Zz##PFo9sADepQe|hUy!Zzc2C(L`k9&=a8XFr+!hIS>D2{pdGP1SzwyaGLiH3j--P>U#TWw90t8{8Bt%m7Upspl#=*hS zhy|(XL6HOqBW}Og^tLX7 z+`b^L{O&oqjwbxDDTg2B;Yh2(fW>%S5Pg8^u1p*EFb z`(fbUM0`afawYt%VBfD&b3MNJ39~Ldc@SAuzsMiN%E}5{uUUBc7hc1IUE~t-Y9h@e7PC|sv$xGx=hZiMXNJxz5V(np%6u{n24iWX#!8t#>Ob$in<>dw96H)oGdTHnU zSM+BPss*5)Wz@+FkooMxxXZP1{2Nz7a6BB~-A_(c&OiM)UUNoa@J8FGxtr$)`9;|O z(Q?lq1Q+!E`}d?KemgC!{nB1JJ!B>6J@XGQp9NeQvtbM2n7F%v|IS=XWPVZY(>oq$ zf=}8O_x`KOxZoGnp=y24x}k6?gl_0dTF!M!T`={`Ii{GnT1jrG9gPh)R=RZG8lIR| z{ZJ6`x8n|y+lZuy${fuEDTAf`OP!tGySLXD}ATJO5UoZv|Xo3%7O~L63+kw}v)Ci=&tWx3bQJfL@5O18CbPlkR^IcKA zy1=^Vl-K-QBP?9^R`@;czcUw;Enbbyk@vJQB>BZ4?;DM%BUf^eZE+sOy>a){qCY6Y znYy;KGpch-zf=5|p#SoAV+ie8M5(Xg-{FoLx-wZC9IutT!(9rJ8}=!$!h%!J+vE2e z(sURwqCC35v?1>C1L)swfA^sr16{yj7-zbT6Rf26-JoEt%U?+|rQ zeBuGohE?@*!zR9)1P|3>KmJSgK*fOt>N>j}LJB`>o(G#Dduvx7@DY7};W7K;Yj|8O zGF<+gTuoIKe7Rf+LQG3-V1L^|E;F*}bQ-{kuHq}| ze_NwA7~US19sAZ)@a`g*zkl*ykv2v3tPrb4Og2#?k6Lc7@1I~+ew48N&03hW^1Cx+ zfk5Lr4-n=#HYg<7ka5i>2A@ZeJ60gl)IDX!!p zzfXZQ?GrT>JEKl7$SH!otzK6=0dIlqN)c23YLB&Krf9v-{@V8p+-e2`ujFR!^M%*; ze_7(Jh$QgoqwB!HbX=S+^wqO15O_TQ0-qX8f-|&SOuo3ZE{{9Jw5{}>MhY}|GBhO& zv48s_B=9aYQfa;d>~1Z$y^oUUaDer>7ve5+Gf?rIG4GZ!hRKERlRNgg_C{W_!3tsI2TWbX8f~MY)1Q`6Wj&JJ~*;ay_0@e zzx+mE-pu8{cEcVfBqsnm=jFU?H}xj@%CAx#NO>3 z_re3Rq%d1Y7VkKy{=S73&p;4^Praw6Y59VCP6M?!Kt7{v#DG#tz?E)`K95gH_mEvb z%$<~_mQ$ad?~&T=O0i0?`YSp?E3Dj?V>n+uTRHAXn`l!pH9Mr}^D1d@mkf+;(tV45 zH_yfs^kOGLXlN*0GU;O&{=awxd?&`{JPRr$z<1HcAO2K`K}92$wC}ky&>;L?#!(`w z68avZGvb728!vgw>;8Z8I@mLtI`?^u6R>sK4E7%=y)jpmE$fH!Dj*~(dy~-2A5Cm{ zl{1AZw`jaDmfvaB?jvKwz!GC}@-Dz|bFm1OaPw(ia#?>vF7Y5oh{NVbyD~cHB1KFn z9C@f~X*Wk3>sQH9#D~rLPslAd26@AzMh=_NkH_yTNXx6-AdbAb z{Ul89YPHslD?xAGzOlQ*aMYUl6#efCT~WI zOvyiewT=~l1W(_2cEd(8rDywOwjM-7P9!8GCL-1<9KXXO=6%!9=W++*l1L~gRSxLVd8K=A7&t52ql=J&BMQu{fa6y zXO_e>d?4X)xp2V8e3xIQGbq@+vo#&n>-_WreTTW0Yr?|YRPP43cDYACMQ(3t6(?_k zfgDOAU^-pew_f5U#WxRXB30wcfDS3;k~t@b@w^GG&<5n$Ku?tT(%bQH(@UHQGN)N|nfC~7?(etU`}XB)$>KY;s=bYGY#kD%i9fz= z2nN9l?UPMKYwn9bX*^xX8Y@%LNPFU>s#Ea1DaP%bSioqRWi9JS28suTdJycYQ+tW7 zrQ@@=13`HS*dVKaVgcem-45+buD{B;mUbY$YYULhxK)T{S?EB<8^YTP$}DA{(&)@S zS#<8S96y9K2!lG^VW-+CkfXJIH;Vo6wh)N}!08bM$I7KEW{F6tqEQ?H@(U zAqfi%KCe}2NUXALo;UN&k$rU0BLNC$24T_mcNY(a@lxR`kqNQ0z%8m>`&1ro40HX} z{{3YQ;2F9JnVTvDY<4)x+88i@MtXE6TBd7POk&QfKU-F&*C`isS(T_Q@}K)=zW#K@ zbXpcAkTT-T5k}Wj$dMZl7=GvlcCMt}U`#Oon1QdPq%>9J$rKTY8#OmlnNWBYwafhx zqFnym@okL#Xw>4SeRFejBnZzY$jbO)e^&&sHBgMP%Ygfi!9_3hp17=AwLBNFTimf0 zw6BHNXw19Jg_Ud6`5n#gMpqe%9!QB^_7wAYv8nrW94A{*t8XZu0UT&`ZHfkd(F{Px zD&NbRJP#RX<=+sEeGs2`9_*J2OlECpR;4uJie-d__m*(aaGE}HIo+3P{my@;a~9Y$ zHBXVJ83#&@o6{M+pE9^lI<4meLLFN_3rwgR4IRyp)~OF0n+#ORrcJ2_On9-78bWbG zuCO0esc*n1X3@p1?lN{qWS?l7J$^jbpeel{w~51*0CM+q9@9X=>%MF(ce~om(}?td zjkUmdUR@LOn-~6LX#=@a%rvj&>DFEoQscOvvC@&ZB5jVZ-;XzAshwx$;Qf@U41W=q zOSSjQGQV8Qi3*4DngNMIM&Cxm7z*-K`~Bl(TcEUxjQ1c=?)?wF8W1g;bAR%sM#LK( z_Op?=P%)Z+J!>vpN`By0$?B~Out%P}kCriDq@}In&fa_ZyKV+nLM0E?hfxuu%ciUz z>yAk}OydbWNl7{)#112j&qmw;*Uj&B;>|;Qwfc?5wIYIHH}s6Mve@5c5r+y)jK9i( z_}@uC(98g)==AGkVN?4>o@w=7x9qhW^ zB(b5%%4cHSV?3M?k&^py)j*LK16T^Ef4tb05-h-tyrjt$5!oo4spEfXFK7r_Gfv7#x$bsR7T zs;dqxzUg9v&GjsQGKTP*=B(;)be2aN+6>IUz+Hhw-n>^|`^xu*xvjGPaDoFh2W4-n z@Wji{5Y$m>@Vt7TE_QVQN4*vcfWv5VY-dT0SV=l=8LAEq1go*f zkjukaDV=3kMAX6GAf0QOQHwP^{Z^=#Lc)sh`QB)Ftl&31jABvq?8!3bt7#8vxB z53M{4{GR4Hl~;W3r}PgXSNOt477cO62Yj(HcK&30zsmWpvAplCtpp&mC{`2Ue*Bwu zF&UX1;w%`Bs1u%RtGPFl=&sHu@Q1nT`z={;5^c^^S~^?2-?<|F9RT*KQmfgF!7=wD@hytxbD;=9L6PZrK*1<4HMObNWehA62DtTy)q5H|57 z9dePuC!1;0MMRRl!S@VJ8qG=v^~aEU+}2Qx``h1LII!y{crP2ky*R;Cb;g|r<#ryo zju#s4dE?5CTIZKc*O4^3qWflsQ(voX>(*_JP7>Q&$%zCAIBTtKC^JUi@&l6u&t0hXMXjz_y!;r@?k|OU9aD%938^TZ>V? zqJmom_6dz4DBb4Cgs_Ef@}F%+cRCR%UMa9pi<-KHN;t#O@cA%(LO1Rb=h?5jiTs93 zPLR78p+3t>z4|j=<>2i4b`ketv}9Ax#B0)hn7@bFl;rDfP8p7u9XcEb!5*PLKB(s7wQC2kzI^@ae)|DhNDmSy1bOLid%iIap@24A(q2XI!z_hkl-$1T10 z+KKugG4-}@u8(P^S3PW4x>an;XWEF-R^gB{`t8EiP{ZtAzoZ!JRuMRS__-Gg#Qa3{<;l__CgsF+nfmFNi}p z>rV!Y6B@cC>1up)KvaEQiAvQF!D>GCb+WZsGHjDeWFz?WVAHP65aIA8u6j6H35XNYlyy8>;cWe3ekr};b;$9)0G`zsc9LNsQ&D?hvuHRpBxH)r-1t9|Stc*u<}Ol&2N+wPMom}d15_TA=Aprp zjN-X3*Af$7cDWMWp##kOH|t;c2Pa9Ml4-)o~+7P;&q8teF-l}(Jt zTGKOQqJTeT!L4d}Qw~O0aanA$Vn9Rocp-MO4l*HK)t%hcp@3k0%&_*wwpKD6ThM)R z8k}&7?)YS1ZYKMiy?mn>VXiuzX7$Ixf7EW8+C4K^)m&eLYl%#T=MC;YPvD&w#$MMf zQ=>`@rh&&r!@X&v%ZlLF42L_c=5dSU^uymKVB>5O?AouR3vGv@ei%Z|GX5v1GK2R* zi!!}?+-8>J$JH^fPu@)E6(}9$d&9-j51T^n-e0Ze%Q^)lxuex$IL^XJ&K2oi`wG}QVGk2a7vC4X?+o^z zsCK*7`EUfSuQA*K@Plsi;)2GrayQOG9OYF82Hc@6aNN5ulqs1Of-(iZQdBI^U5of^ zZg2g=Xtad7$hfYu6l~KDQ}EU;oIj(3nO#u9PDz=eO3(iax7OCmgT2p_7&^3q zg7aQ;Vpng*)kb6=sd5?%j5Dm|HczSChMo8HHq_L8R;BR5<~DVyU$8*Tk5}g0eW5x7 z%d)JFZ{(Y<#OTKLBA1fwLM*fH7Q~7Sc2Ne;mVWqt-*o<;| z^1@vo_KTYaMnO$7fbLL+qh#R$9bvnpJ$RAqG+z8h|} z3F5iwG*(sCn9Qbyg@t0&G}3fE0jGq3J!JmG2K&$urx^$z95) z7h?;4vE4W=v)uZ*Eg3M^6f~|0&T)2D;f+L_?M*21-I1pnK(pT$5l#QNlT`SidYw~o z{`)G)Asv#cue)Ax1RNWiRUQ(tQ(bzd-f2U4xlJK+)ZWBxdq#fp=A>+Qc%-tl(c)`t z$e2Ng;Rjvnbu7((;v4LF9Y1?0el9hi!g>G{^37{ z`^s-03Z5jlnD%#Mix19zkU_OS|86^_x4<0(*YbPN}mi-$L?Z4K(M|2&VV*n*ZYN_UqI?eKZi3!b)i z%n3dzUPMc-dc|q}TzvPy!VqsEWCZL(-eURDRG4+;Eu!LugSSI4Fq$Ji$Dp08`pfP_C5Yx~`YKcywlMG;$F z)R5!kVml_Wv6MSpeXjG#g?kJ0t_MEgbXlUN3k|JJ%N>|2xn8yN>>4qxh!?dGI}s|Y zDTKd^JCrRSN+%w%D_uf=Tj6wIV$c*g8D96jb^Kc#>5Fe-XxKC@!pIJw0^zu;`_yeb zhUEm-G*C=F+jW%cP(**b61fTmPn2WllBr4SWNdKe*P8VabZsh0-R|?DO=0x`4_QY) zR7sthW^*BofW7{Sak&S1JdiG?e=SfL24Y#w_)xrBVhGB-13q$>mFU|wd9Xqe-o3{6 zSn@@1@&^)M$rxb>UmFuC+pkio#T;mSnroMVZJ%nZ!uImi?%KsIX#@JU2VY(`kGb1A z7+1MEG)wd@)m^R|a2rXeviv$!emwcY(O|M*xV!9%tBzarBOG<4%gI9SW;Um_gth4=gznYzOFd)y8e+3APCkL)i-OI`;@7-mCJgE`js(M} z;~ZcW{{FMVVO)W>VZ}ILouF#lWGb%Couu}TI4kubUUclW@jEn6B_^v!Ym*(T*4HF9 zWhNKi8%sS~viSdBtnrq!-Dc5(G^XmR>DFx8jhWvR%*8!m*b*R8e1+`7{%FACAK`7 zzdy8TmBh?FVZ0vtw6npnWwM~XjF2fNvV#ZlGG z?FxHkXHN>JqrBYoPo$)zNC7|XrQfcqmEXWud~{j?La6@kbHG@W{xsa~l1=%eLly8B z4gCIH05&Y;6O2uFSopNqP|<$ml$N40^ikxw0`o<~ywS1(qKqQN!@?Ykl|bE4M?P+e zo$^Vs_+x)iuw?^>>`$&lOQOUkZ5>+OLnRA)FqgpDjW&q*WAe(_mAT6IKS9;iZBl8M z<@=Y%zcQUaSBdrs27bVK`c$)h6A1GYPS$y(FLRD5Yl8E3j0KyH08#8qLrsc_qlws; znMV%Zq8k+&T2kf%6ZO^2=AE9>?a587g%-={X}IS~P*I(NeCF9_9&`)|ok0iiIun zo+^odT0&Z4k;rn7I1v87=z!zKU(%gfB$(1mrRYeO$sbqM22Kq68z9wgdg8HBxp>_< zn9o%`f?sVO=IN#5jSX&CGODWlZfQ9A)njK2O{JutYwRZ?n0G_p&*uwpE`Md$iQxrd zoQfF^b8Ou)+3BO_3_K5y*~?<(BF@1l+@?Z6;^;U>qlB)cdro;rxOS1M{Az$s^9o5sXDCg8yD<=(pKI*0e zLk>@lo#&s0)^*Q+G)g}C0IErqfa9VbL*Qe=OT@&+N8m|GJF7jd83vY#SsuEv2s{Q> z>IpoubNs>D_5?|kXGAPgF@mb_9<%hjU;S0C8idI)a=F#lPLuQJ^7OnjJlH_Sks9JD zMl1td%YsWq3YWhc;E$H1<0P$YbSTqs`JKY%(}svsifz|h8BHguL82dBl+z0^YvWk8 zGy;7Z0v5_FJ2A$P0wIr)lD?cPR%cz>kde!=W%Ta^ih+Dh4UKdf7ip?rBz@%y2&>`6 zM#q{JXvW9ZlaSk1oD!n}kSmcDa2v6T^Y-dy+#fW^y>eS8_%<7tWXUp8U@s$^{JFfKMjDAvR z$YmVB;n3ofl!ro9RNT!TpQpcycXCR}$9k5>IPWDXEenQ58os?_weccrT+Bh5sLoiH zZ_7~%t(vT)ZTEO= zb0}@KaD{&IyK_sd8b$`Qz3%UA`nSo zn``!BdCeN!#^G;lK@G2ron*0jQhbdw)%m$2;}le@z~PSLnU-z@tL)^(p%P>OO^*Ff zNRR9oQ`W+x^+EU+3BpluwK77|B3=8QyT|$V;02bn_LF&3LhLA<#}{{)jE)}CiW%VEU~9)SW+=F%7U-iYlQ&q!#N zwI2{(h|Pi&<8_fqvT*}FLN^0CxN}#|3I9G_xmVg$gbn2ZdhbmGk7Q5Q2Tm*ox8NMo zv`iaZW|ZEOMyQga5fts?&T-eCCC9pS0mj7v0SDkD=*^MxurP@89v&Z#3q{FM!a_nr zb?KzMv`BBFOew>4!ft@A&(v-kWXny-j#egKef|#!+3>26Qq0 zv!~8ev4G`7Qk>V1TaMT-&ziqoY3IJp8_S*%^1j73D|=9&;tDZH^!LYFMmME4*Wj(S zRt~Q{aLb_O;wi4u&=}OYuj}Lw*j$@z*3>4&W{)O-oi@9NqdoU!=U%d|se&h?^$Ip# z)BY+(1+cwJz!yy4%l(aLC;T!~Ci>yAtXJb~b*yr&v7f{YCU8P|N1v~H`xmGsG)g)y z4%mv=cPd`s7a*#OR7f0lpD$ueP>w8qXj0J&*7xX+U!uat5QNk>zwU$0acn5p=$88L=jn_QCSYkTV;1~(yUem#0gB`FeqY98sf=>^@ z_MCdvylv~WL%y_%y_FE1)j;{Szj1+K7Lr_y=V+U zk6Tr;>XEqlEom~QGL!a+wOf(@ZWoxE<$^qHYl*H1a~kk^BLPn785%nQb$o;Cuz0h& za9LMx^bKEbPS%e8NM33Jr|1T|ELC(iE!FUci38xW_Y7kdHid#2ie+XZhP;2!Z;ZAM zB_cXKm)VrPK!SK|PY00Phwrpd+x0_Aa;}cDQvWKrwnQrqz##_gvHX2ja?#_{f#;bz`i>C^^ zTLDy;6@HZ~XQi7rph!mz9k!m;KchA)uMd`RK4WLK7)5Rl48m#l>b(#`WPsl<0j z-sFkSF6>Nk|LKnHtZ`W_NnxZP62&w)S(aBmmjMDKzF%G;3Y?FUbo?>b5;0j8Lhtc4 zr*8d5Y9>g@FFZaViw7c16VsHcy0u7M%6>cG1=s=Dtx?xMJSKIu9b6GU8$uSzf43Y3 zYq|U+IWfH;SM~*N1v`KJo!|yfLxTFS?oHsr3qvzeVndVV^%BWmW6re_S!2;g<|Oao z+N`m#*i!)R%i1~NO-xo{qpwL0ZrL7hli;S z3L0lQ_z}z`fdK39Mg~Zd*%mBdD;&5EXa~@H(!###L`ycr7gW`f)KRuqyHL3|uyy3h zSS^td#E&Knc$?dXs*{EnPYOp^-vjAc-h4z#XkbG&REC7;0>z^^Z}i8MxGKerEY z>l?(wReOlXEsNE5!DO&ZWyxY)gG#FSZs%fXuzA~XIAPVp-%yb2XLSV{1nH6{)5opg z(dZKckn}Q4Li-e=eUDs1Psg~5zdn1>ql(*(nn6)iD*OcVkwmKL(A{fix(JhcVB&}V zVt*Xb!{gzvV}dc446>(D=SzfCu7KB`oMjv6kPzSv&B>>HLSJP|wN`H;>oRw*tl#N) z*zZ-xwM7D*AIsBfgqOjY1Mp9aq$kRa^dZU_xw~KxP;|q(m+@e+YSn~`wEJzM|Ippb zzb@%;hB7iH4op9SqmX?j!KP2chsb79(mFossBO-Zj8~L}9L%R%Bw<`^X>hjkCY5SG z7lY!8I2mB#z)1o;*3U$G)3o0A&{0}#B;(zPd2`OF`Gt~8;0Re8nIseU z_yzlf$l+*-wT~_-cYk$^wTJ@~7i@u(CZs9FVkJCru<*yK8&>g+t*!JqCN6RH%8S-P zxH8+Cy#W?!;r?cLMC(^BtAt#xPNnwboI*xWw#T|IW^@3|q&QYY6Ehxoh@^URylR|T zne-Y6ugE^7p5bkRDWIh)?JH5V^ub82l-LuVjDr7UT^g`q4dB&mBFRWGL_C?hoeL(% zo}ocH5t7|1Mda}T!^{Qt9vmA2ep4)dQSZO>?Eq8}qRp&ZJ?-`Tnw+MG(eDswP(L*X3ahC2Ad0_wD^ff9hfzb%Jd`IXx5 zae@NMzBXJDwJS?7_%!TB^E$N8pvhOHDK$7YiOelTY`6KX8hK6YyT$tk*adwN>s^Kp zwM3wGVPhwKU*Yq-*BCs}l`l#Tej(NQ>jg*S0TN%D+GcF<14Ms6J`*yMY;W<-mMN&-K>((+P}+t+#0KPGrzjP zJ~)=Bcz%-K!L5ozIWqO(LM)l_9lVOc4*S65&DKM#TqsiWNG{(EZQw!bc>qLW`=>p-gVJ;T~aN2D_- z{>SZC=_F+%hNmH6ub%Ykih0&YWB!%sd%W5 zHC2%QMP~xJgt4>%bU>%6&uaDtSD?;Usm}ari0^fcMhi_)JZgb1g5j zFl4`FQ*%ROfYI}e7RIq^&^a>jZF23{WB`T>+VIxj%~A-|m=J7Va9FxXV^%UwccSZd zuWINc-g|d6G5;95*%{e;9S(=%yngpfy+7ao|M7S|Jb0-4+^_q-uIqVS&ufU880UDH*>(c)#lt2j zzvIEN>>$Y(PeALC-D?5JfH_j+O-KWGR)TKunsRYKLgk7eu4C{iF^hqSz-bx5^{z0h ze2+u>Iq0J4?)jIo)}V!!m)%)B;a;UfoJ>VRQ*22+ncpe9f4L``?v9PH&;5j{WF?S_C>Lq>nkChZB zjF8(*v0c(lU^ZI-)_uGZnnVRosrO4`YinzI-RSS-YwjYh3M`ch#(QMNw*)~Et7Qpy z{d<3$4FUAKILq9cCZpjvKG#yD%-juhMj>7xIO&;c>_7qJ%Ae8Z^m)g!taK#YOW3B0 zKKSMOd?~G4h}lrZbtPk)n*iOC1~mDhASGZ@N{G|dF|Q^@1ljhe=>;wusA&NvY*w%~ zl+R6B^1yZiF)YN>0ms%}qz-^U-HVyiN3R9k1q4)XgDj#qY4CE0)52%evvrrOc898^ z*^)XFR?W%g0@?|6Mxo1ZBp%(XNv_RD-<#b^?-Fs+NL^EUW=iV|+Vy*F%;rBz~pN7%-698U-VMfGEVnmEz7fL1p)-5sLT zL;Iz>FCLM$p$c}g^tbkGK1G$IALq1Gd|We@&TtW!?4C7x4l*=4oF&&sr0Hu`x<5!m zhX&&Iyjr?AkNXU_5P_b^Q3U9sy#f6ZF@2C96$>1k*E-E%DjwvA{VL0PdU~suN~DZo zm{T!>sRdp`Ldpp9olrH@(J$QyGq!?#o1bUo=XP2OEuT3`XzI>s^0P{manUaE4pI%! zclQq;lbT;nx7v3tR9U)G39h?ryrxzd0xq4KX7nO?piJZbzT_CU&O=T(Vt;>jm?MgC z2vUL#*`UcMsx%w#vvjdamHhmN!(y-hr~byCA-*iCD};#l+bq;gkwQ0oN=AyOf@8ow>Pj<*A~2*dyjK}eYdN);%!t1 z6Y=|cuEv-|5BhA?n2Db@4s%y~(%Wse4&JXw=HiO48%c6LB~Z0SL1(k^9y?ax%oj~l zf7(`iAYLdPRq*ztFC z7VtAb@s{as%&Y;&WnyYl+6Wm$ru*u!MKIg_@01od-iQft0rMjIj8e7P9eKvFnx_X5 zd%pDg-|8<>T2Jdqw>AII+fe?CgP+fL(m0&U??QL8YzSjV{SFi^vW~;wN@or_(q<0Y zRt~L}#JRcHOvm$CB)T1;;7U>m%)QYBLTR)KTARw%zoDxgssu5#v{UEVIa<>{8dtkm zXgbCGp$tfue+}#SD-PgiNT{Zu^YA9;4BnM(wZ9-biRo_7pN}=aaimjYgC=;9@g%6< zxol5sT_$<8{LiJ6{l1+sV)Z_QdbsfEAEMw!5*zz6)Yop?T0DMtR_~wfta)E6_G@k# zZRP11D}$ir<`IQ`<(kGfAS?O-DzCyuzBq6dxGTNNTK?r^?zT30mLY!kQ=o~Hv*k^w zvq!LBjW=zzIi%UF@?!g9vt1CqdwV(-2LYy2=E@Z?B}JDyVkluHtzGsWuI1W5svX~K z&?UJ45$R7g>&}SFnLnmw09R2tUgmr_w6mM9C}8GvQX>nL&5R#xBqnp~Se(I>R42`T zqZe9p6G(VzNB3QD><8+y%{e%6)sZDRXTR|MI zM#eZmao-~_`N|>Yf;a;7yvd_auTG#B?Vz5D1AHx=zpVUFe7*hME z+>KH5h1In8hsVhrstc>y0Q!FHR)hzgl+*Q&5hU9BVJlNGRkXiS&06eOBV^dz3;4d5 zeYX%$62dNOprZV$px~#h1RH?_E%oD6y;J;pF%~y8M)8pQ0olYKj6 zE+hd|7oY3ot=j9ZZ))^CCPADL6Jw%)F@A{*coMApcA$7fZ{T@3;WOQ352F~q6`Mgi z$RI6$8)a`Aaxy<8Bc;{wlDA%*%(msBh*xy$L-cBJvQ8hj#FCyT^%+Phw1~PaqyDou^JR0rxDkSrmAdjeYDFDZ`E z)G3>XtpaSPDlydd$RGHg;#4|4{aP5c_Om z2u5xgnhnA)K%8iU==}AxPxZCYC)lyOlj9as#`5hZ=<6<&DB%i_XCnt5=pjh?iusH$ z>)E`@HNZcAG&RW3Ys@`Ci{;8PNzE-ZsPw$~Wa!cP$ye+X6;9ceE}ah+3VY7Mx}#0x zbqYa}eO*FceiY2jNS&2cH9Y}(;U<^^cWC5Ob&)dZedvZA9HewU3R;gRQ)}hUdf+~Q zS_^4ds*W1T#bxS?%RH&<739q*n<6o|mV;*|1s>ly-Biu<2*{!!0#{_234&9byvn0* z5=>{95Zfb{(?h_Jk#ocR$FZ78O*UTOxld~0UF!kyGM|nH%B*qf)Jy}N!uT9NGeM19 z-@=&Y0yGGo_dw!FD>juk%P$6$qJkj}TwLBoefi;N-$9LAeV|)|-ET&culW9Sb_pc_ zp{cXI0>I0Jm_i$nSvGnYeLSSj{ccVS2wyL&0x~&5v;3Itc82 z5lIAkfn~wcY-bQB$G!ufWt%qO;P%&2B_R5UKwYxMemIaFm)qF1rA zc>gEihb=jBtsXCi0T%J37s&kt*3$s7|6)L(%UiY)6axuk{6RWIS8^+u;)6!R?Sgap z9|6<0bx~AgVi|*;zL@2x>Pbt2Bz*uv4x-`{F)XatTs`S>unZ#P^ZiyjpfL_q2z^fqgR-fbOcG=Y$q>ozkw1T6dH8-)&ww+z?E0 zR|rV(9bi6zpX3Ub>PrPK!{X>e$C66qCXAeFm)Y+lX8n2Olt7PNs*1^si)j!QmFV#t z0P2fyf$N^!dyTot&`Ew5{i5u<8D`8U`qs(KqaWq5iOF3x2!-z65-|HsyYz(MAKZ?< zCpQR;E)wn%s|&q(LVm0Ab>gdmCFJeKwVTnv@Js%!At;I=A>h=l=p^&<4;Boc{$@h< z38v`3&2wJtka@M}GS%9!+SpJ}sdtoYzMevVbnH+d_eMxN@~~ zZq@k)7V5f8u!yAX2qF3qjS7g%n$JuGrMhQF!&S^7(%Y{rP*w2FWj(v_J{+Hg*}wdWOd~pHQ19&n3RWeljK9W%sz&Y3Tm3 zR`>6YR54%qBHGa)2xbs`9cs_EsNHxsfraEgZ)?vrtooeA0sPKJK7an){ngtV@{SBa zkO6ORr1_Xqp+`a0e}sC*_y(|RKS13ikmHp3C^XkE@&wjbGWrt^INg^9lDz#B;bHiW zkK4{|cg08b!yHFSgPca5)vF&gqCgeu+c82%&FeM^Bb}GUxLy-zo)}N;#U?sJ2?G2BNe*9u_7kE5JeY!it=f`A_4gV3} z`M!HXZy#gN-wS!HvHRqpCHUmjiM;rVvpkC!voImG%OFVN3k(QG@X%e``VJSJ@Z7tb z*Onlf>z^D+&$0!4`IE$;2-NSO9HQWd+UFW(r;4hh;(j^p4H-~6OE!HQp^96v?{9Zt z;@!ZcccV%C2s6FMP#qvo4kG6C04A>XILt>JW}%0oE&HM5f6 zYLD!;My>CW+j<~=Wzev{aYtx2ZNw|ptTFV(4;9`6Tmbz6K1)fv4qPXa2mtoPt&c?P zhmO+*o8uP3ykL6E$il00@TDf6tOW7fmo?Oz_6GU^+5J=c22bWyuH#aNj!tT-^IHrJ zu{aqTYw@q;&$xDE*_kl50Jb*dp`(-^p={z}`rqECTi~3 z>0~A7L6X)=L5p#~$V}gxazgGT7$3`?a)zen>?TvAuQ+KAIAJ-s_v}O6@`h9n-sZk> z`3{IJeb2qu9w=P*@q>iC`5wea`KxCxrx{>(4{5P+!cPg|pn~;n@DiZ0Y>;k5mnKeS z!LIfT4{Lgd=MeysR5YiQKCeNhUQ;Os1kAymg6R!u?j%LF z4orCszIq_n52ulpes{(QN|zirdtBsc{9^Z72Ycb2ht?G^opkT_#|4$wa9`)8k3ilU z%ntAi`nakS1r10;#k^{-ZGOD&Z2|k=p40hRh5D7(&JG#Cty|ECOvwsSHkkSa)36$4 z?;v#%@D(=Raw(HP5s>#4Bm?f~n1@ebH}2tv#7-0l-i^H#H{PC|F@xeNS+Yw{F-&wH z07)bj8MaE6`|6NoqKM~`4%X> zKFl&7g1$Z3HB>lxn$J`P`6GSb6CE6_^NA1V%=*`5O!zP$a7Vq)IwJAki~XBLf=4TF zPYSL}>4nOGZ`fyHChq)jy-f{PKFp6$plHB2=;|>%Z^%)ecVue(*mf>EH_uO^+_zm? zJATFa9SF~tFwR#&0xO{LLf~@}s_xvCPU8TwIJgBs%FFzjm`u?1699RTui;O$rrR{# z1^MqMl5&6)G%@_k*$U5Kxq84!AdtbZ!@8FslBML}<`(Jr zenXrC6bFJP=R^FMBg7P?Pww-!a%G@kJH_zezKvuWU0>m1uyy}#Vf<$>u?Vzo3}@O% z1JR`B?~Tx2)Oa|{DQ_)y9=oY%haj!80GNHw3~qazgU-{|q+Bl~H94J!a%8UR?XsZ@ z0*ZyQugyru`V9b(0OrJOKISfi89bSVR zQy<+i_1XY}4>|D%X_`IKZUPz6=TDb)t1mC9eg(Z=tv zq@|r37AQM6A%H%GaH3szv1L^ku~H%5_V*fv$UvHl*yN4iaqWa69T2G8J2f3kxc7UE zOia@p0YNu_q-IbT%RwOi*|V|&)e5B-u>4=&n@`|WzH}BK4?33IPpXJg%`b=dr_`hU z8JibW_3&#uIN_#D&hX<)x(__jUT&lIH$!txEC@cXv$7yB&Rgu){M`9a`*PH} zRcU)pMWI2O?x;?hzR{WdzKt^;_pVGJAKKd)F$h;q=Vw$MP1XSd<;Mu;EU5ffyKIg+ z&n-Nb?h-ERN7(fix`htopPIba?0Gd^y(4EHvfF_KU<4RpN0PgVxt%7Yo99X*Pe|zR z?ytK&5qaZ$0KSS$3ZNS$$k}y(2(rCl=cuYZg{9L?KVgs~{?5adxS))Upm?LDo||`H zV)$`FF3icFmxcQshXX*1k*w3O+NjBR-AuE70=UYM*7>t|I-oix=bzDwp2*RoIwBp@r&vZukG; zyi-2zdyWJ3+E?{%?>e2Ivk`fAn&Ho(KhGSVE4C-zxM-!j01b~mTr>J|5={PrZHOgO zw@ND3=z(J7D>&C7aw{zT>GHhL2BmUX0GLt^=31RRPSnjoUO9LYzh_yegyPoAKhAQE z>#~O27dR4&LdQiak6={9_{LN}Z>;kyVYKH^d^*!`JVSXJlx#&r4>VnP$zb{XoTb=> zZsLvh>keP3fkLTIDdpf-@(ADfq4=@X=&n>dyU0%dwD{zsjCWc;r`-e~X$Q3NTz_TJ zOXG|LMQQIjGXY3o5tBm9>k6y<6XNO<=9H@IXF;63rzsC=-VuS*$E{|L_i;lZmHOD< zY92;>4spdeRn4L6pY4oUKZG<~+8U-q7ZvNOtW0i*6Q?H`9#U3M*k#4J;ek(MwF02x zUo1wgq9o6XG#W^mxl>pAD)Ll-V5BNsdVQ&+QS0+K+?H-gIBJ-ccB1=M_hxB6qcf`C zJ?!q!J4`kLhAMry4&a_0}up{CFevcjBl|N(uDM^N5#@&-nQt2>z*U}eJGi}m5f}l|IRVj-Q;a>wcLpK5RRWJ> zysdd$)Nv0tS?b~bw1=gvz3L_ZAIdDDPj)y|bp1;LE`!av!rODs-tlc}J#?erTgXRX z$@ph%*~_wr^bQYHM7<7=Q=45v|Hk7T=mDpW@OwRy3A_v`ou@JX5h!VI*e((v*5Aq3 zVYfB4<&^Dq5%^?~)NcojqK`(VXP$`#w+&VhQOn%;4pCkz;NEH6-FPHTQ+7I&JE1+Ozq-g43AEZV>ceQ^9PCx zZG@OlEF~!Lq@5dttlr%+gNjRyMwJdJU(6W_KpuVnd{3Yle(-p#6erIRc${l&qx$HA z89&sp=rT7MJ=DuTL1<5{)wtUfpPA|Gr6Q2T*=%2RFm@jyo@`@^*{5{lFPgv>84|pv z%y{|cVNz&`9C*cUely>-PRL)lHVErAKPO!NQ3<&l5(>Vp(MuJnrOf^4qpIa!o3D7( z1bjn#Vv$#or|s7Hct5D@%;@48mM%ISY7>7@ft8f?q~{s)@BqGiupoK1BAg?PyaDQ1 z`YT8{0Vz{zBwJ={I4)#ny{RP{K1dqzAaQN_aaFC%Z>OZ|^VhhautjDavGtsQwx@WH zr|1UKk^+X~S*RjCY_HN!=Jx>b6J8`Q(l4y|mc<6jnkHVng^Wk(A13-;AhawATsmmE#H%|8h}f1frs2x@Fwa_|ea+$tdG2Pz{7 z!ox^w^>^Cv4e{Xo7EQ7bxCe8U+LZG<_e$RnR?p3t?s^1Mb!ieB z#@45r*PTc_yjh#P=O8Zogo+>1#|a2nJvhOjIqKK1U&6P)O%5s~M;99O<|Y9zomWTL z666lK^QW`)cXV_^Y05yQZH3IRCW%25BHAM$c0>w`x!jh^15Zp6xYb!LoQ zr+RukTw0X2mxN%K0%=8|JHiaA3pg5+GMfze%9o5^#upx0M?G9$+P^DTx7~qq9$Qoi zV$o)yy zuUq>3c{_q+HA5OhdN*@*RkxRuD>Bi{Ttv_hyaaB;XhB%mJ2Cb{yL;{Zu@l{N?!GKE7es6_9J{9 zO(tmc0ra2;@oC%SS-8|D=omQ$-Dj>S)Utkthh{ovD3I%k}HoranSepC_yco2Q8 zY{tAuPIhD{X`KbhQIr%!t+GeH%L%q&p z3P%<-S0YY2Emjc~Gb?!su85}h_qdu5XN2XJUM}X1k^!GbwuUPT(b$Ez#LkG6KEWQB z7R&IF4srHe$g2R-SB;inW9T{@+W+~wi7VQd?}7||zi!&V^~o0kM^aby7YE_-B63^d zf_uo8#&C77HBautt_YH%v6!Q>H?}(0@4pv>cM6_7dHJ)5JdyV0Phi!)vz}dv{*n;t zf(+#Hdr=f8DbJqbMez)(n>@QT+amJ7g&w6vZ-vG^H1v~aZqG~u!1D(O+jVAG0EQ*aIsr*bsBdbD`)i^FNJ z&B@yxqPFCRGT#}@dmu-{0vp47xk(`xNM6E=7QZ5{tg6}#zFrd8Pb_bFg7XP{FsYP8 zbvWqG6#jfg*4gvY9!gJxJ3l2UjP}+#QMB(*(?Y&Q4PO`EknE&Cb~Yb@lCbk;-KY)n zzbjS~W5KZ3FV%y>S#$9Sqi$FIBCw`GfPDP|G=|y32VV-g@a1D&@%_oAbB@cAUx#aZ zlAPTJ{iz#Qda8(aNZE&0q+8r3&z_Ln)b=5a%U|OEcc3h1f&8?{b8ErEbilrun}mh3 z$1o^$-XzIiH|iGoJA`w`o|?w3m*NX|sd$`Mt+f*!hyJvQ2fS*&!SYn^On-M|pHGlu z4SC5bM7f6BAkUhGuN*w`97LLkbCx=p@K5RL2p>YpDtf{WTD|d3ucb6iVZ-*DRtoEA zCC5(x)&e=giR_id>5bE^l%Mxx>0@FskpCD4oq@%-Fg$8IcdRwkfn;DsjoX(v;mt3d z_4Mnf#Ft4x!bY!7Hz?RRMq9;5FzugD(sbt4up~6j?-or+ch~y_PqrM2hhTToJjR_~ z)E1idgt7EW>G*9%Q^K;o_#uFjX!V2pwfpgi>}J&p_^QlZki!@#dkvR`p?bckC`J*g z=%3PkFT3HAX2Q+dShHUbb1?ZcK8U7oaufLTCB#1W{=~k0Jabgv>q|H+GU=f-y|{p4 zwN|AE+YbCgx=7vlXE?@gkXW9PaqbO#GB=4$o0FkNT#EI?aLVd2(qnPK$Yh%YD%v(mdwn}bgsxyIBI^)tY?&G zi^2JfClZ@4b{xFjyTY?D61w@*ez2@5rWLpG#34id?>>oPg{`4F-l`7Lg@D@Hc}On} zx%BO4MsLYosLGACJ-d?ifZ35r^t*}wde>AAWO*J-X%jvD+gL9`u`r=kP zyeJ%FqqKfz8e_3K(M1RmB?gIYi{W7Z<THP2ihue0mbpu5n(x_l|e1tw(q!#m5lmef6ktqIb${ zV+ee#XRU}_dDDUiV@opHZ@EbQ<9qIZJMDsZDkW0^t3#j`S)G#>N^ZBs8k+FJhAfu< z%u!$%dyP3*_+jUvCf-%{x#MyDAK?#iPfE<(@Q0H7;a125eD%I(+!x1f;Sy`e<9>nm zQH4czZDQmW7^n>jL)@P@aAuAF$;I7JZE5a8~AJI5CNDqyf$gjloKR7C?OPt9yeH}n5 zNF8Vhmd%1O>T4EZD&0%Dt7YWNImmEV{7QF(dy!>q5k>Kh&Xy8hcBMUvVV~Xn8O&%{ z&q=JCYw#KlwM8%cu-rNadu(P~i3bM<_a{3!J*;vZhR6dln6#eW0^0kN)Vv3!bqM`w z{@j*eyzz=743dgFPY`Cx3|>ata;;_hQ3RJd+kU}~p~aphRx`03B>g4*~f%hUV+#D9rYRbsGD?jkB^$3XcgB|3N1L& zrmk9&Dg450mAd=Q_p?gIy5Zx7vRL?*rpNq76_rysFo)z)tp0B;7lSb9G5wX1vC9Lc z5Q8tb-alolVNWFsxO_=12o}X(>@Mwz1mkYh1##(qQwN=7VKz?61kay8A9(94Ky(4V zq6qd2+4a20Z0QRrmp6C?4;%U?@MatfXnkj&U6bP_&2Ny}BF%4{QhNx*Tabik9Y-~Z z@0WV6XD}aI(%pN}oW$X~Qo_R#+1$@J8(31?zM`#e`#(0f<-AZ^={^NgH#lc?oi(Mu zMk|#KR^Q;V@?&(sh5)D;-fu)rx%gXZ1&5)MR+Mhssy+W>V%S|PRNyTAd}74<(#J>H zR(1BfM%eIv0+ngHH6(i`?-%_4!6PpK*0X)79SX0X$`lv_q>9(E2kkkP;?c@rW2E^Q zs<;`9dg|lDMNECFrD3jTM^Mn-C$44}9d9Kc z#>*k&e#25;D^%82^1d@Yt{Y91MbEu0C}-;HR4+IaCeZ`l?)Q8M2~&E^FvJ?EBJJ(% zz1>tCW-E~FB}DI}z#+fUo+=kQME^=eH>^%V8w)dh*ugPFdhMUi3R2Cg}Zak4!k_8YW(JcR-)hY8C zXja}R7@%Q0&IzQTk@M|)2ViZDNCDRLNI)*lH%SDa^2TG4;%jE4n`8`aQAA$0SPH2@ z)2eWZuP26+uGq+m8F0fZn)X^|bNe z#f{qYZS!(CdBdM$N2(JH_a^b#R2=>yVf%JI_ieRFB{w&|o9txwMrVxv+n78*aXFGb z>Rkj2yq-ED<)A46T9CL^$iPynv`FoEhUM10@J+UZ@+*@_gyboQ>HY9CiwTUo7OM=w zd~$N)1@6U8H#Zu(wGLa_(Esx%h@*pmm5Y9OX@CY`3kPYPQx@z8yAgtm(+agDU%4?c zy8pR4SYbu8vY?JX6HgVq7|f=?w(%`m-C+a@E{euXo>XrGmkmFGzktI*rj*8D z)O|CHKXEzH{~iS+6)%ybRD|JRQ6j<+u_+=SgnJP%K+4$st+~XCVcAjI9e5`RYq$n{ zzy!X9Nv7>T4}}BZpSj9G9|(4ei-}Du<_IZw+CB`?fd$w^;=j8?vlp(#JOWiHaXJjB0Q00RHJ@sG6N#y^H7t^&V} z;VrDI4?75G$q5W9mV=J2iP24NHJy&d|HWHva>FaS#3AO?+ohh1__FMx;?`f{HG3v0 ztiO^Wanb>U4m9eLhoc_2B(ca@YdnHMB*~aYO+AE(&qh@?WukLbf_y z>*3?Xt-lxr?#}y%kTv+l8;!q?Hq8XSU+1E8x~o@9$)zO2z9K#(t`vPDri`mKhv|sh z{KREcy`#pnV>cTT7dm7M9B@9qJRt3lfo(C`CNkIq@>|2<(yn!AmVN?ST zbX_`JjtWa3&N*U{K7FYX8})*D#2@KBae` zhKS~s!r%SrXdhCsv~sF}7?ocyS?afya6%rDBu6g^b2j#TOGp^1zrMR}|70Z>CeYq- z1o|-=FBKlu{@;pm@QQJ_^!&hzi;0Z_Ho){x3O1KQ#TYk=rAt9`YKC0Y^}8GWIN{QW znYJyVTrmNvl!L=YS1G8BAxGmMUPi+Q7yb0XfG`l+L1NQVSbe^BICYrD;^(rke{jWCEZOtVv3xFze!=Z&(7}!)EcN;v0Dbit?RJ6bOr;N$ z=nk8}H<kCEE+IK3z<+3mkn4q!O7TMWpKShWWWM)X*)m6k%3luF6c>zOsFccvfLWf zH+mNkh!H@vR#~oe=ek}W3!71z$Dlj0c(%S|sJr>rvw!x;oCek+8f8s!U{DmfHcNpO z9>(IKOMfJwv?ey`V2ysSx2Npeh_x#bMh)Ngdj$al;5~R7Ac5R2?*f{hI|?{*$0qU- zY$6}ME%OGh^zA^z9zJUs-?a4ni8cw_{cYED*8x{bWg!Fn9)n;E9@B+t;#k}-2_j@# zg#b%R(5_SJAOtfgFCBZc`n<&z6)%nOIu@*yo!a% zpLg#36KBN$01W{b;qWN`Tp(T#jh%;Zp_zpS64lvBVY2B#UK)p`B4Oo)IO3Z&D6<3S zfF?ZdeNEnzE{}#gyuv)>;z6V{!#bx)` zY;hL*f(WVD*D9A4$WbRKF2vf;MoZVdhfWbWhr{+Db5@M^A4wrFReuWWimA4qp`GgoL2`W4WPUL5A=y3Y3P z%G?8lLUhqo@wJW8VDT`j&%YY7xh51NpVYlsrk_i4J|pLO(}(b8_>%U2M`$iVRDc-n zQiOdJbroQ%*vhN{!{pL~N|cfGooK_jTJCA3g_qs4c#6a&_{&$OoSQr_+-O^mKP=Fu zGObEx`7Qyu{nHTGNj(XSX*NPtAILL(0%8Jh)dQh+rtra({;{W2=f4W?Qr3qHi*G6B zOEj7%nw^sPy^@05$lOCjAI)?%B%&#cZ~nC|=g1r!9W@C8T0iUc%T*ne z)&u$n>Ue3FN|hv+VtA+WW)odO-sdtDcHfJ7s&|YCPfWaVHpTGN46V7Lx@feE#Od%0XwiZy40plD%{xl+K04*se zw@X4&*si2Z_0+FU&1AstR)7!Th(fdaOlsWh`d!y=+3m!QC$Zlkg8gnz!}_B7`+wSz z&kD?6{zPnE3uo~Tv8mLP%RaNt2hcCJBq=0T>%MW~Q@Tpt2pPP1?KcywH>in5@ zx+5;xu-ltFfo5vLU;2>r$-KCHjwGR&1XZ0YNyrXXAUK!FLM_7mV&^;;X^*YH(FLRr z`0Jjg7wiq2bisa`CG%o9i)o1`uG?oFjU_Zrv1S^ipz$G-lc^X@~6*)#%nn+RbgksJfl{w=k31(q>7a!PCMp5YY{+Neh~mo zG-3dd!0cy`F!nWR?=9f_KP$X?Lz&cLGm_ohy-|u!VhS1HG~e7~xKpYOh=GmiiU;nu zrZ5tWfan3kp-q_vO)}vY6a$19Q6UL0r znJ+iSHN-&w@vDEZ0V%~?(XBr|jz&vrBNLOngULxtH(Rp&U*rMY42n;05F11xh?k;n_DX2$4|vWIkXnbwfC z=ReH=(O~a;VEgVO?>qsP*#eOC9Y<_9Yt<6X}X{PyF7UXIA$f)>NR5P&4G_Ygq(9TwwQH*P>Rq>3T4I+t2X(b5ogXBAfNf!xiF#Gilm zp2h{&D4k!SkKz-SBa%F-ZoVN$7GX2o=(>vkE^j)BDSGXw?^%RS9F)d_4}PN+6MlI8*Uk7a28CZ)Gp*EK)`n5i z){aq=0SFSO-;sw$nAvJU-$S-cW?RSc7kjEBvWDr1zxb1J7i;!i+3PQwb=)www?7TZ zE~~u)vO>#55eLZW;)F(f0KFf8@$p)~llV{nO7K_Nq-+S^h%QV_CnXLi)p*Pq&`s!d zK2msiR;Hk_rO8`kqe_jfTmmv|$MMo0ll}mI)PO4!ikVd(ZThhi&4ZwK?tD-}noj}v zBJ?jH-%VS|=t)HuTk?J1XaDUjd_5p1kPZi6y#F6$lLeRQbj4hsr=hX z4tXkX2d5DeLMcAYTeYm|u(XvG5JpW}hcOs4#s8g#ihK%@hVz|kL=nfiBqJ{*E*WhC zht3mi$P3a(O5JiDq$Syu9p^HY&9~<#H89D8 zJm84@%TaL_BZ+qy8+T3_pG7Q%z80hnjN;j>S=&WZWF48PDD%55lVuC0%#r5(+S;WH zS7!HEzmn~)Ih`gE`faPRjPe^t%g=F ztpGVW=Cj5ZkpghCf~`ar0+j@A=?3(j@7*pq?|9)n*B4EQTA1xj<+|(Y72?m7F%&&& zdO44owDBPT(8~RO=dT-K4#Ja@^4_0v$O3kn73p6$s?mCmVDUZ+Xl@QcpR6R3B$=am z%>`r9r2Z79Q#RNK?>~lwk^nQlR=Hr-ji$Ss3ltbmB)x@0{VzHL-rxVO(++@Yr@Iu2 zTEX)_9sVM>cX$|xuqz~Y8F-(n;KLAfi*63M7mh&gsPR>N0pd9h!0bm%nA?Lr zS#iEmG|wQd^BSDMk0k?G>S-uE$vtKEF8Dq}%vLD07zK4RLoS?%F1^oZZI$0W->7Z# z?v&|a`u#UD=_>i~`kzBGaPj!mYX5g?3RC4$5EV*j0sV)>H#+$G6!ci=6`)85LWR=FCp-NUff`;2zG9nU6F~ z;3ZyE*>*LvUgae+uMf}aV}V*?DCM>{o31+Sx~6+sz;TI(VmIpDrN3z+BUj`oGGgLP z>h9~MP}Pw#YwzfGP8wSkz`V#}--6}7S9yZvb{;SX?6PM_KuYpbi~*=teZr-ga2QqIz{QrEyZ@>eN*qmy;N@FCBbRNEeeoTmQyrX;+ zCkaJ&vOIbc^2BD6_H+Mrcl?Nt7O{xz9R_L0ZPV_u!sz+TKbXmhK)0QWoe-_HwtKJ@@7=L+ z+K8hhf=4vbdg3GqGN<;v-SMIzvX=Z`WUa_91Yf89^#`G(f-Eq>odB^p-Eqx}ENk#&MxJ+%~Ad2-*`1LNT>2INPw?*V3&kE;tt?rQyBw? zI+xJD04GTz1$7~KMnfpkPRW>f%n|0YCML@ODe`10;^DXX-|Hb*IE%_Vi#Pn9@#ufA z_8NY*1U%VseqYrSm?%>F@`laz+f?+2cIE4Jg6 z_VTcx|DSEA`g!R%RS$2dSRM|9VQClsW-G<~=j5T`pTbu-x6O`R z98b;}`rPM(2={YiytrqX+uh65f?%XiPp`;4CcMT*E*dQJ+if9^D>c_Dk8A(cE<#r=&!& z_`Z01=&MEE+2@yr!|#El=yM}v>i=?w^2E_FLPy(*4A9XmCNy>cBWdx3U>1RylsItO z4V8T$z3W-qqq*H`@}lYpfh=>C!tieKhoMGUi)EpWDr;yIL&fy};Y&l|)f^QE*k~4C zH>y`Iu%#S)z)YUqWO%el*Z)ME#p{1_8-^~6UF;kBTW zMQ!eXQuzkR#}j{qb(y9^Y!X7&T}}-4$%4w@w=;w+>Z%uifR9OoQ>P?0d9xpcwa>7kTv2U zT-F?3`Q`7xOR!gS@j>7In>_h){j#@@(ynYh;nB~}+N6qO(JO1xA z@59Pxc#&I~I64slNR?#hB-4XE>EFU@lUB*D)tu%uEa))B#eJ@ZOX0hIulfnDQz-y8 z`CX@(O%_VC{Ogh&ot``jlDL%R!f>-8yq~oLGxBO?+tQb5%k@a9zTs!+=NOwSVH-cR zqFo^jHeXDA_!rx$NzdP;>{-j5w3QUrR<;}=u2|FBJ;D#v{SK@Z6mjeV7_kFmWt95$ zeGaF{IU?U>?W`jzrG_9=9}yN*LKyzz))PLE+)_jc#4Rd$yFGol;NIk(qO1$5VXR)+ zxF7%f4=Q!NzR>DVXUB&nUT&>Nyf+5QRF+Z`X-bB*7=`|Go5D1&h~ zflKLw??kpiRm0h3|1GvySC2^#kcFz^5{79KKlq@`(leBa=_4CgV9sSHr{RIJ^KwR_ zY??M}-x^=MD+9`v@I3jue=OCn0kxno#6i>b(XKk_XTp_LpI}X*UA<#* zsgvq@yKTe_dTh>q1aeae@8yur08S(Q^8kXkP_ty48V$pX#y9)FQa~E7P7}GP_CbCm zc2dQxTeW(-~Y6}im24*XOC8ySfH*HMEnW3 z4CXp8iK(Nk<^D$g0kUW`8PXn2kdcDk-H@P0?G8?|YVlIFb?a>QunCx%B9TzsqQQ~HD!UO7zq^V!v9jho_FUob&Hxi ztU1nNOK)a!gkb-K4V^QVX05*>-^i|{b`hhvQLyj`E1vAnj0fbqqO%r z6Q;X1x0dL~GqMv%8QindZ4CZ%7pYQW~ z9)I*#Gjref-q(4Z*E#1c&rE0-_(4;_M(V7rgH_7H;ps1s%GBmU z{4a|X##j#XUF2n({v?ZUUAP5k>+)^F)7n-npbV3jAlY8V3*W=fwroDS$c&r$>8aH` zH+irV{RG3^F3oW2&E%5hXgMH9>$WlqX76Cm+iFmFC-DToTa`AcuN9S!SB+BT-IA#3P)JW1m~Cuwjs`Ep(wDXE4oYmt*aU z!Naz^lM}B)JFp7ejro7MU9#cI>wUoi{lylR2~s)3M!6a=_W~ITXCPd@U9W)qA5(mdOf zd3PntGPJyRX<9cgX?(9~TZB5FdEHW~gkJXY51}?s4ZT_VEdwOwD{T2E-B>oC8|_ZwsPNj=-q(-kwy%xX2K0~H z{*+W`-)V`7@c#Iuaef=?RR2O&x>W0A^xSwh5MsjTz(DVG-EoD@asu<>72A_h<39_# zawWVU<9t{r*e^u-5Q#SUI6dV#p$NYEGyiowT>>d*or=Ps!H$-3={bB|An$GPkP5F1 zTnu=ktmF|6E*>ZQvk^~DX(k!N`tiLut*?3FZhs$NUEa4ccDw66-~P;x+0b|<!ZN7Z%A`>2tN#CdoG>((QR~IV_Gj^Yh%!HdA~4C3jOXaqb6Ou z21T~Wmi9F6(_K0@KR@JDTh3-4mv2=T7&ML<+$4;b9SAtv*Uu`0>;VVZHB{4?aIl3J zL(rMfk?1V@l)fy{J5DhVlj&cWKJCcrpOAad(7mC6#%|Sn$VwMjtx6RDx1zbQ|Ngg8N&B56DGhu;dYg$Z{=YmCNn+?ceDclp65c_RnKs4*vefnhudSlrCy6-96vSB4_sFAj# zftzECwmNEOtED^NUt{ZDjT7^g>k1w<=af>+0)%NA;IPq6qx&ya7+QAu=pk8t>KTm` zEBj9J*2t|-(h)xc>Us*jHs)w9qmA>8@u21UqzKk*Ei#0kCeW6o z-2Q+Tvt25IUkb}-_LgD1_FUJ!U8@8OC^9(~Kd*0#zr*8IQkD)6Keb(XFai5*DYf~` z@U?-{)9X&BTf!^&@^rjmvea#9OE~m(D>qfM?CFT9Q4RxqhO0sA7S)=--^*Q=kNh7Y zq%2mu_d_#23d`+v`Ol263CZ<;D%D8Njj6L4T`S*^{!lPL@pXSm>2;~Da- zBX97TS{}exvSva@J5FJVCM$j4WDQuME`vTw>PWS0!;J7R+Kq zVUy6%#n5f7EV(}J#FhDpts;>=d6ow!yhJj8j>MJ@Wr_?x30buuutIG97L1A*QFT$c ziC5rBS;#qj=~yP-yWm-p(?llTwDuhS^f&<(9vA9@UhMH2-Fe_YAG$NvK6X{!mvPK~ zuEA&PA}meylmaIbbJXDOzuIn8cJNCV{tUA<$Vb?57JyAM`*GpEfMmFq>)6$E(9e1@W`l|R%-&}38#bl~levA#fx2wiBk^)mPj?<=S&|gv zQO)4*91$n08@W%2b|QxEiO0KxABAZC{^4BX^6r>Jm?{!`ZId9jjz<%pl(G5l));*`UU3KfnuXSDj2aP>{ zRIB$9pm7lj3*Xg)c1eG!cb+XGt&#?7yJ@C)(Ik)^OZ5><4u$VLCqZ#q2NMCt5 z6$|VN(RWM;5!JV?-h<JkEZ(SZF zC(6J+>A6Am9H7OlOFq6S62-2&z^Np=#xXsOq0WUKr zY_+Ob|CQd1*!Hirj5rn*=_bM5_zKmq6lG zn*&_=x%?ATxZ8ZTzd%biKY_qyNC#ZQ1vX+vc48N>aJXEjs{Y*3Op`Q7-oz8jyAh>d zNt_qvn`>q9aO~7xm{z`ree%lJ3YHCyC`q`-jUVCn*&NIml!uuMNm|~u3#AV?6kC+B z?qrT?xu2^mobSlzb&m(8jttB^je0mx;TT8}`_w(F11IKz83NLj@OmYDpCU^u?fD{) z&=$ptwVw#uohPb2_PrFX;X^I=MVXPDpqTuYhRa>f-=wy$y3)40-;#EUDYB1~V9t%$ z^^<7Zbs0{eB93Pcy)96%XsAi2^k`Gmnypd-&x4v9rAq<>a(pG|J#+Q>E$FvMLmy7T z5_06W=*ASUyPRfgCeiPIe{b47Hjqpb`9Xyl@$6*ntH@SV^bgH&Fk3L9L=6VQb)Uqa z33u#>ecDo&bK(h1WqSH)b_Th#Tvk&%$NXC@_pg5f-Ma#7q;&0QgtsFO~`V&{1b zbSP*X)jgLtd@9XdZ#2_BX4{X~pS8okF7c1xUhEV9>PZco>W-qz7YMD`+kCGULdK|^ zE7VwQ-at{%&fv`a+b&h`TjzxsyQX05UB~a0cuU-}{*%jR48J+yGWyl3Kdz5}U>;lE zgkba*yI5>xqIPz*Y!-P$#_mhHB!0Fpnv{$k-$xxjLAc`XdmHd1k$V@2QlblfJPrly z*~-4HVCq+?9vha>&I6aRGyq2VUon^L1a)g`-Xm*@bl2|hi2b|UmVYW|b+Gy?!aS-p z86a}Jep6Mf>>}n^*Oca@Xz}kxh)Y&pX$^CFAmi#$YVf57X^}uQD!IQSN&int=D> zJ>_|au3Be?hmPKK)1^JQ(O29eTf`>-x^jF2xYK6j_9d_qFkWHIan5=7EmDvZoQWz5 zZGb<{szHc9Nf@om)K_<=FuLR<&?5RKo3LONFQZ@?dyjemAe4$yDrnD zglU#XYo6|~L+YpF#?deK6S{8A*Ou;9G`cdC4S0U74EW18bc5~4>)<*}?Z!1Y)j;Ot zosEP!pc$O^wud(={WG%hY07IE^SwS-fGbvpP?;l8>H$;}urY2JF$u#$q}E*ZG%fR# z`p{xslcvG)kBS~B*^z6zVT@e}imYcz_8PRzM4GS52#ms5Jg9z~ME+uke`(Tq1w3_6 zxUa{HerS7!Wq&y(<9yyN@P^PrQT+6ij_qW3^Q)I53iIFCJE?MVyGLID!f?QHUi1tq z0)RNIMGO$2>S%3MlBc09l!6_(ECxXTU>$KjWdZX^3R~@3!SB zah5Za2$63;#y!Y}(wg1#shMePQTzfQfXyJ-Tf`R05KYcyvo8UW9-IWGWnzxR6Vj8_la;*-z5vWuwUe7@sKr#Tr51d z2PWn5h@|?QU3>k=s{pZ9+(}oye zc*95N_iLmtmu}H-t$smi49Y&ovX}@mKYt2*?C-i3Lh4*#q5YDg1Mh`j9ovRDf9&& zp_UMQh`|pC!|=}1uWoMK5RAjdTg3pXPCsYmRkWW}^m&)u-*c_st~gcss(`haA)xVw zAf=;s>$`Gq_`A}^MjY_BnCjktBNHY1*gzh(i0BFZ{Vg^F?Pbf`8_clvdZ)5(J4EWzAP}Ba5zX=S(2{gDugTQ3`%!q`h7kYSnwC`zEWeuFlODKiityMaM9u{Z%E@@y1jmZA#ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba55c6dabc3aac36f33d859266c18fa0d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5680 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 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa40fb3d1e0710331a48de5d256da3f275d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 520 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 diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/src/serious_python/example/flet_ffi_example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cfddf3d9dade342351e627a0a75609fb46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 2cadea52..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = flet_example - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig b/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements b/src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index 9f56413f..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist b/src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift b/src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb2..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements b/src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements deleted file mode 100644 index e89b7f32..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift b/src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 5418c9f5..00000000 --- a/src/serious_python/example/flet_ffi_example/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import FlutterMacOS -import Cocoa -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/src/serious_python/example/flet_ffi_example/pubspec.lock b/src/serious_python/example/flet_ffi_example/pubspec.lock deleted file mode 100644 index 427dbdd5..00000000 --- a/src/serious_python/example/flet_ffi_example/pubspec.lock +++ /dev/null @@ -1,1201 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - archive: - dependency: transitive - description: - name: archive - sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff - url: "https://pub.dev" - source: hosted - version: "4.0.9" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 - url: "https://pub.dev" - source: hosted - version: "2.13.1" - battery_plus: - dependency: transitive - description: - name: battery_plus - sha256: ad16fcb55b7384be6b4bbc763d5e2031ac7ea62b2d9b6b661490c7b9741155bf - url: "https://pub.dev" - source: hosted - version: "7.0.0" - battery_plus_platform_interface: - dependency: transitive - description: - name: battery_plus_platform_interface - sha256: e8342c0f32de4b1dfd0223114b6785e48e579bfc398da9471c9179b907fa4910 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b - url: "https://pub.dev" - source: hosted - version: "1.4.1" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - code_assets: - dependency: transitive - description: - name: code_assets - sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - connectivity_plus: - dependency: transitive - description: - name: connectivity_plus - sha256: "62ffa266d9a23b79fb3fcbc206afc00bb979417ba57b1324c546b5aab95ba057" - url: "https://pub.dev" - source: hosted - version: "7.1.1" - connectivity_plus_platform_interface: - dependency: transitive - description: - name: connectivity_plus_platform_interface - sha256: "3c09627c536d22fd24691a905cdd8b14520de69da52c7a97499c8be5284a32ed" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.dev" - source: hosted - version: "0.3.5+2" - crypto: - dependency: transitive - description: - name: crypto - sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" - source: hosted - version: "3.0.7" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" - url: "https://pub.dev" - source: hosted - version: "1.0.9" - dbus: - dependency: transitive - description: - name: dbus - sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 - url: "https://pub.dev" - source: hosted - version: "0.7.12" - device_info_plus: - dependency: transitive - description: - name: device_info_plus - sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd - url: "https://pub.dev" - source: hosted - version: "12.4.0" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.dev" - source: hosted - version: "7.0.3" - equatable: - dependency: transitive - description: - name: equatable - sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" - url: "https://pub.dev" - source: hosted - version: "2.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - file_picker: - dependency: transitive - description: - name: file_picker - sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343" - url: "https://pub.dev" - source: hosted - version: "10.3.10" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flet: - dependency: "direct main" - description: - path: "packages/flet" - ref: dart-bridge - resolved-ref: "33b3b972373fb3f268fe7acc84876b87dbb9a31c" - url: "https://github.com/flet-dev/flet.git" - source: git - version: "0.85.3" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_highlight: - dependency: transitive - description: - name: flutter_highlight - sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" - url: "https://pub.dev" - source: hosted - version: "0.7.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_markdown_plus: - dependency: transitive - description: - name: flutter_markdown_plus - sha256: "039177906850278e8fb1cd364115ee0a46281135932fa8ecea8455522166d2de" - url: "https://pub.dev" - source: hosted - version: "1.0.7" - flutter_markdown_plus_latex: - dependency: transitive - description: - name: flutter_markdown_plus_latex - sha256: "2e7698b291f0657ca445efab730bb25a8c5851037e882cb7bf47d16a5c218de7" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - flutter_math_fork: - dependency: transitive - description: - name: flutter_math_fork - sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407" - url: "https://pub.dev" - source: hosted - version: "0.7.4" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" - url: "https://pub.dev" - source: hosted - version: "2.0.35" - flutter_svg: - dependency: transitive - description: - name: flutter_svg - sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - highlight: - dependency: transitive - description: - name: highlight - sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" - url: "https://pub.dev" - source: hosted - version: "0.7.0" - hooks: - dependency: transitive - description: - name: hooks - sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - http: - dependency: transitive - description: - name: http - sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - intl: - dependency: transitive - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - jni: - dependency: transitive - description: - name: jni - sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f - url: "https://pub.dev" - source: hosted - version: "1.0.0" - jni_flutter: - dependency: transitive - description: - name: jni_flutter - sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" - url: "https://pub.dev" - source: hosted - version: "4.12.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - markdown: - dependency: transitive - description: - name: markdown - sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 - url: "https://pub.dev" - source: hosted - version: "7.3.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 - url: "https://pub.dev" - source: hosted - version: "0.12.19" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" - url: "https://pub.dev" - source: hosted - version: "0.13.0" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - msgpack_dart: - dependency: "direct main" - description: - name: msgpack_dart - sha256: c2d235ed01f364719b5296aecf43ac330f0d7bc865fa134d0d7910a40454dffb - url: "https://pub.dev" - source: hosted - version: "1.0.1" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - nm: - dependency: transitive - description: - name: nm - sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" - url: "https://pub.dev" - source: hosted - version: "9.4.1" - package_config: - dependency: transitive - description: - name: package_config - sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.dev" - source: hosted - version: "2.2.0" - package_info_plus: - dependency: "direct main" - description: - name: package_info_plus - sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20" - url: "https://pub.dev" - source: hosted - version: "9.0.1" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - pasteboard: - dependency: transitive - description: - name: pasteboard - sha256: "9ff73ada33f79a59ff91f6c01881fd4ed0a0031cfc4ae2d86c0384471525fca1" - url: "https://pub.dev" - source: hosted - version: "0.4.0" - path: - dependency: "direct main" - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" - url: "https://pub.dev" - source: hosted - version: "2.3.1" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.dev" - source: hosted - version: "2.6.0" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - posix: - dependency: transitive - description: - name: posix - sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" - url: "https://pub.dev" - source: hosted - version: "6.5.0" - process: - dependency: transitive - description: - name: process - sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 - url: "https://pub.dev" - source: hosted - version: "5.0.5" - provider: - dependency: transitive - description: - name: provider - sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.dev" - source: hosted - version: "6.1.5+1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - record_use: - dependency: transitive - description: - name: record_use - sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - screen_brightness: - dependency: transitive - description: - name: screen_brightness - sha256: "7ea1c037422f007f022dcff3ee955bf8e61a474d5426b29be9290fd976c3e46b" - url: "https://pub.dev" - source: hosted - version: "2.1.9" - screen_brightness_android: - dependency: transitive - description: - name: screen_brightness_android - sha256: "0e4b0a07d5f730b91a8780d8436f3a92be8a8cc2066032ed88b93c8fa153fadf" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - screen_brightness_ios: - dependency: transitive - description: - name: screen_brightness_ios - sha256: "0792d8f98852558f831b4b75241c46047b884598b3f4d982b37dc2dd43e2b2e1" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - screen_brightness_macos: - dependency: transitive - description: - name: screen_brightness_macos - sha256: "278712cf5288db57bd335968cbfb2ec5441028f1ee2fcbdc8d1582d8210a3442" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - screen_brightness_ohos: - dependency: transitive - description: - name: screen_brightness_ohos - sha256: "33f495741d5aa53104d3f5875dcb4b6a119f29ef595be17129ee03a5b78e76a9" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - screen_brightness_platform_interface: - dependency: transitive - description: - name: screen_brightness_platform_interface - sha256: "59d50850d6735d677780fc7359c8e997d0ff6df91c8465161c9e617a7b0a11d8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - screen_brightness_windows: - dependency: transitive - description: - name: screen_brightness_windows - sha256: "121f9dd6d62585bfb4e468c2170804ce4f2a2303ae6b2efc3a065c94937505d7" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - screen_retriever: - dependency: transitive - description: - name: screen_retriever - sha256: "42cc3b402a0f67d2455a0d067553d0f13453f6a008d98eababf8b63958d506bd" - url: "https://pub.dev" - source: hosted - version: "0.2.1" - screen_retriever_linux: - dependency: transitive - description: - name: screen_retriever_linux - sha256: "2a476f1a5538065bc5badf376cfdc83d6ecf07d77eb2391b9c2bff5a76970048" - url: "https://pub.dev" - source: hosted - version: "0.2.1" - screen_retriever_macos: - dependency: transitive - description: - name: screen_retriever_macos - sha256: b5abb900fcb86614ff10b738b34e37b9e1d03b0447280668e2bc8a98bdc7bd59 - url: "https://pub.dev" - source: hosted - version: "0.2.1" - screen_retriever_platform_interface: - dependency: transitive - description: - name: screen_retriever_platform_interface - sha256: "3af22d926bedf20c2caa308eea376776451a3af125919ce072e56525fded8901" - url: "https://pub.dev" - source: hosted - version: "0.2.1" - screen_retriever_windows: - dependency: transitive - description: - name: screen_retriever_windows - sha256: c44b38a4c4bab34af259180a70a4eee1e29384e7b82e627c9faa68afcdab2e73 - url: "https://pub.dev" - source: hosted - version: "0.2.1" - screenshot: - dependency: transitive - description: - name: screenshot - sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sensors_plus: - dependency: transitive - description: - name: sensors_plus - sha256: "56e8cd4260d9ed8e00ecd8da5d9fdc8a1b2ec12345a750dfa51ff83fcf12e3fa" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - sensors_plus_platform_interface: - dependency: transitive - description: - name: sensors_plus_platform_interface - sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - serious_python: - dependency: "direct main" - description: - path: "../.." - relative: true - source: path - version: "2.0.0" - serious_python_android: - dependency: transitive - description: - path: "../../../serious_python_android" - relative: true - source: path - version: "2.0.0" - serious_python_darwin: - dependency: transitive - description: - path: "../../../serious_python_darwin" - relative: true - source: path - version: "2.0.0" - serious_python_linux: - dependency: transitive - description: - path: "../../../serious_python_linux" - relative: true - source: path - version: "2.0.0" - serious_python_platform_interface: - dependency: transitive - description: - path: "../../../serious_python_platform_interface" - relative: true - source: path - version: "2.0.0" - serious_python_windows: - dependency: transitive - description: - path: "../../../serious_python_windows" - relative: true - source: path - version: "2.0.0" - share_plus: - dependency: transitive - description: - name: share_plus - sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa" - url: "https://pub.dev" - source: hosted - version: "12.0.2" - share_plus_platform_interface: - dependency: transitive - description: - name: share_plus_platform_interface - sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - shared_preferences: - dependency: transitive - description: - name: shared_preferences - sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf - url: "https://pub.dev" - source: hosted - version: "2.5.5" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 - url: "https://pub.dev" - source: hosted - version: "2.4.23" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.dev" - source: hosted - version: "2.5.6" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" - source: hosted - version: "2.4.3" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shimmer: - dependency: transitive - description: - name: shimmer - sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.dev" - source: hosted - version: "1.10.2" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" - url: "https://pub.dev" - source: hosted - version: "0.7.10" - toml: - dependency: transitive - description: - name: toml - sha256: "9968de24e45b632bf1a654fe1ac7b6fe5261c349243df83fd262397799c45a2d" - url: "https://pub.dev" - source: hosted - version: "0.15.0" - tuple: - dependency: transitive - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - upower: - dependency: transitive - description: - name: upower - sha256: cf042403154751180affa1d15614db7fa50234bc2373cd21c3db666c38543ebf - url: "https://pub.dev" - source: hosted - version: "0.7.0" - url_launcher: - dependency: transitive - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" - url: "https://pub.dev" - source: hosted - version: "6.3.30" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" - url: "https://pub.dev" - source: hosted - version: "6.4.1" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" - url: "https://pub.dev" - source: hosted - version: "2.4.3" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - uuid: - dependency: transitive - description: - name: uuid - sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" - url: "https://pub.dev" - source: hosted - version: "4.5.3" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "7ee12e6dffe0fc8e755179d6d91b3b34f5924223fc104d85572ef9180d73d172" - url: "https://pub.dev" - source: hosted - version: "1.2.5" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" - url: "https://pub.dev" - source: hosted - version: "15.2.0" - wakelock_plus: - dependency: transitive - description: - name: wakelock_plus - sha256: ddf3db70eaa10c37558ff817519b85d527dbd21034fd5d8e1c2e85f31588f1c1 - url: "https://pub.dev" - source: hosted - version: "1.5.2" - wakelock_plus_platform_interface: - dependency: transitive - description: - name: wakelock_plus_platform_interface - sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b - url: "https://pub.dev" - source: hosted - version: "1.5.1" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - win32: - dependency: transitive - description: - name: win32 - sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.dev" - source: hosted - version: "5.15.0" - win32_registry: - dependency: transitive - description: - name: win32_registry - sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - window_manager: - dependency: transitive - description: - name: window_manager - sha256: "7eb6d6c4164ec08e1bf978d6e733f3cebe792e2a23fb07cbca25c2872bfdbdcd" - url: "https://pub.dev" - source: hosted - version: "0.5.1" - window_to_front: - dependency: transitive - description: - name: window_to_front - sha256: "14fad8984db4415e2eeb30b04bb77140b180e260d6cb66b26de126a8657a9241" - url: "https://pub.dev" - source: hosted - version: "0.0.4" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" diff --git a/src/serious_python/example/flet_ffi_example/pubspec.yaml b/src/serious_python/example/flet_ffi_example/pubspec.yaml deleted file mode 100644 index c6f51e1b..00000000 --- a/src/serious_python/example/flet_ffi_example/pubspec.yaml +++ /dev/null @@ -1,81 +0,0 @@ -name: flet_ffi_example -description: Flet counter example exercising the in-process dart_bridge transport (instead of the Unix socket). -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 - -environment: - sdk: ">=3.0.3 <4.0.0" - flutter: ">=3.7.0" - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - flutter_web_plugins: - sdk: flutter - - serious_python: - path: ../../ - - flet: - git: - url: https://github.com/flet-dev/flet.git - ref: dart-bridge - path: packages/flet - - path: ^1.8.3 - path_provider: ^2.1.4 - package_info_plus: ^9.0.0 - # msgpack_dart is the wire format Flet uses. _DartBridgeBackendChannel - # (in lib/main.dart) encodes outbound frames before handing them to - # PythonBridge.send. - msgpack_dart: ^1.0.1 - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^2.0.0 - integration_test: - sdk: flutter - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - uses-material-design: true - - assets: - - app/app.zip - - app/app.zip.hash \ No newline at end of file diff --git a/src/serious_python/example/flet_ffi_example/test/widget_test.dart b/src/serious_python/example/flet_ffi_example/test/widget_test.dart deleted file mode 100644 index 49c1e76c..00000000 --- a/src/serious_python/example/flet_ffi_example/test/widget_test.dart +++ /dev/null @@ -1,10 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -void main() { - // todo -} diff --git a/src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart b/src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart deleted file mode 100644 index b38629cc..00000000 --- a/src/serious_python/example/flet_ffi_example/test_driver/integration_test.dart +++ /dev/null @@ -1,3 +0,0 @@ -import 'package:integration_test/integration_test_driver.dart'; - -Future main() => integrationDriver(); diff --git a/src/serious_python/example/flet_ffi_example/web/favicon.png b/src/serious_python/example/flet_ffi_example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-192.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-512.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-192.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76e525556d5d89141648c724331630325d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! diff --git a/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-512.png b/src/serious_python/example/flet_ffi_example/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c56691fbdb0b7efa65097c7cc1edac12a6d3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20998 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 MPgg&ebxsLQ025IeI{*Lx diff --git a/src/serious_python/example/flet_ffi_example/web/index.html b/src/serious_python/example/flet_ffi_example/web/index.html deleted file mode 100644 index 41f4ced7..00000000 --- a/src/serious_python/example/flet_ffi_example/web/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - flet_example - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/web/manifest.json b/src/serious_python/example/flet_ffi_example/web/manifest.json deleted file mode 100644 index 58b0e920..00000000 --- a/src/serious_python/example/flet_ffi_example/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "flet_example", - "short_name": "flet_example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/src/serious_python/example/flet_ffi_example/windows/.gitignore b/src/serious_python/example/flet_ffi_example/windows/.gitignore deleted file mode 100644 index d492d0d9..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt deleted file mode 100644 index cee1b1bd..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/CMakeLists.txt +++ /dev/null @@ -1,102 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(flet_example LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "flet_example") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(VERSION 3.14...3.25) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt deleted file mode 100644 index 903f4899..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# Set fallback configurations for older versions of the flutter tool. -if (NOT DEFINED FLUTTER_TARGET_PLATFORM) - set(FLUTTER_TARGET_PLATFORM "windows-x64") -endif() - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - ${FLUTTER_TARGET_PLATFORM} $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 5280993c..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,41 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - BatteryPlusWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin")); - ConnectivityPlusWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); - PasteboardPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("PasteboardPlugin")); - ScreenBrightnessWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); - ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); - SeriousPythonWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SeriousPythonWindowsPluginCApi")); - SharePlusWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); - UrlLauncherWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("UrlLauncherWindows")); - WindowManagerPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("WindowManagerPlugin")); - WindowToFrontPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("WindowToFrontPlugin")); -} diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake deleted file mode 100644 index ec8b95fd..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,34 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - battery_plus - connectivity_plus - pasteboard - screen_brightness_windows - screen_retriever_windows - serious_python_windows - share_plus - url_launcher_windows - window_manager - window_to_front -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST - jni -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt b/src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt deleted file mode 100644 index 394917c0..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc b/src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc deleted file mode 100644 index 320618d6..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "flet_example" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "flet_example" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "flet_example.exe" "\0" - VALUE "ProductName", "flet_example" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp deleted file mode 100644 index 955ee303..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - // Flutter can complete the first frame before the "show window" callback is - // registered. The following call ensures a frame is pending to ensure the - // window is shown. It is a no-op if the first frame hasn't completed yet. - flutter_controller_->ForceRedraw(); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h b/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652f..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/main.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/main.cpp deleted file mode 100644 index ea917ad4..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"flet_example", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/resource.h b/src/serious_python/example/flet_ffi_example/windows/runner/resource.h deleted file mode 100644 index 66a65d1e..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/resources/app_icon.ico b/src/serious_python/example/flet_ffi_example/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20caf6370ebb9253ad831cc31de4a9c965f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33772 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 diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest b/src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest deleted file mode 100644 index a42ea768..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,20 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - - - - - - - diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp deleted file mode 100644 index b2b08734..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/utils.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/utils.h b/src/serious_python/example/flet_ffi_example/windows/runner/utils.h deleted file mode 100644 index 3879d547..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp b/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp deleted file mode 100644 index 60608d0f..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} diff --git a/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h b/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h deleted file mode 100644 index e901dde6..00000000 --- a/src/serious_python/example/flet_ffi_example/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ From b4eee25e9905fc6802245170194d98eee218342c Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 13:21:32 -0700 Subject: [PATCH 097/114] bridge_example: README covers two-channel design + perf/memory baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the old single-bridge echo description with: * The actual current shape — two PythonBridge channels (JSON control + raw echo) and what each is used for. * Doc-grade descriptions of the three integration tests so a reader knows what each covers before opening the .dart file. * The 2026-06-12 macOS / M2 Pro perf and memory baseline (throughput table, memory deltas, narrative on what the numbers mean). Keeping perf numbers next to the tests that produce them means there's one place to look when the next libdart_bridge or serious-python bump changes the baseline. --- .../example/bridge_example/README.md | 116 ++++++++++++++---- 1 file changed, 94 insertions(+), 22 deletions(-) diff --git a/src/serious_python/example/bridge_example/README.md b/src/serious_python/example/bridge_example/README.md index a330a0a4..9acff260 100644 --- a/src/serious_python/example/bridge_example/README.md +++ b/src/serious_python/example/bridge_example/README.md @@ -1,15 +1,19 @@ # bridge_example -Minimal Flutter app exercising [`PythonBridge`](../../lib/bridge.dart) — -the in-process byte transport between Dart and the embedded CPython -runtime. Sends bytes from Dart to Python via `bridge.send()`, and Python -echoes them back through `dart_bridge.send_bytes()`. No Flet, no msgpack, -no protocol layer — the smallest possible end-to-end demonstration of the -transport. +Direct exercise of [`PythonBridge`](../../lib/bridge.dart) — the in-process byte transport between Dart and the embedded CPython runtime. No Flet, no MsgPack, no protocol layer beyond what this example draws itself. Used as the CI gate for the `serious_python` repo and as the perf / leak baseline for every change to `libdart_bridge`. -## Build the Python app bundle +## What it does + +Two independent `PythonBridge` channels open at startup; Python registers a handler per channel: -Before running, package the Python source into `app/app.zip`: +| Channel | Env var carrying the Dart-side native port to Python | Wire format | Purpose | +|---------|------------------------------------------------------|----------------------------------------------|------------------------------------------| +| Control | `BRIDGE_EXAMPLE_CONTROL_PORT` | UTF-8 JSON, `{"op": …}` ↔ `{"event": …}` | Interactivity (counter, version), memory snapshots | +| Echo | `BRIDGE_EXAMPLE_ECHO_PORT` | Raw bytes — Python echoes the frame verbatim | Throughput timing, memory hammer loop | + +Separating channels means the throughput / memory hot path is just `bridge.send` → `dart_bridge.send_bytes` echo back, with zero framing tax on either side. The JSON dispatcher only runs for tiny control messages where the encoding cost is irrelevant. + +## Build the Python app bundle ```sh # From this directory: @@ -17,11 +21,7 @@ dart run serious_python:main package app/src --platform Darwin \ --python-version 3.14 ``` -Substitute `Darwin` with `Linux`, `Windows`, or `Android` for those -targets (each platform plugin's CMake/Gradle pipeline downloads the -prebuilt `dart_bridge` native binary from -[flet-dev/dart-bridge](https://github.com/flet-dev/dart-bridge) at build -time — no `--bridge` flag, no PyPI wheel). +Substitute `Darwin` with `Linux`, `Windows`, `iOS`, or `Android`. Each platform plugin's CMake / Gradle pipeline downloads the prebuilt `dart_bridge` native binary from [flet-dev/dart-bridge](https://github.com/flet-dev/dart-bridge) at build time — no `--bridge` flag, no PyPI wheel. ## Run @@ -29,13 +29,85 @@ time — no `--bridge` flag, no PyPI wheel). flutter run -d macos # or -d linux / windows / ``` -How it works: +Tap `+` / `−` to send `{"op": "inc"}` / `{"op": "dec"}` on the control channel; the displayed counter updates from the Python-side `{"event": "count", "value": …}` response. The version banner is populated by an analogous `{"op": "version"}` round-trip on `initState`. + +## Integration tests + +Three tests under [`integration_test/`](integration_test/): + +| Test | What it covers | +|----------------------------|------------------------------------------------------------------------------------------------------| +| `interactivity_test.dart` | Counter +/-, version banner. Asserts UI text via Flutter widget keys; matches `EXPECTED_PYTHON_VERSION` if supplied via `--dart-define`. | +| `throughput_test.dart` | Size sweep 1 KB → 16 MB, 100 round-trips each. Logs min/p50/p95/mean + MB/s. Floor assertion at ≥ 1 MB. | +| `memory_test.dart` | 1 000 × 1 MB echo round-trips (~2 GB total). Snapshots Python `tracemalloc` + RSS before/after. Asserts `traced_delta < 5 MB`. | + +```sh +# After `dart run serious_python:main package …`: +flutter test integration_test/throughput_test.dart -d macos +flutter test integration_test/memory_test.dart -d macos +flutter test integration_test/interactivity_test.dart -d macos \ + --dart-define=EXPECTED_PYTHON_VERSION=3.14 +``` + +--- + +# Performance & memory baseline + +> Measured 2026-06-12 on the bridge_example integration tests. Re-running these is the canonical way to refresh the numbers after any `libdart_bridge` / `serious-python` bump. + +## Test environment + +| | | +|----------------|----------------------------------------------------------| +| Hardware | MacBook Pro M2 Pro, 32 GB | +| OS | macOS 26.5 | +| Python | CPython 3.14.6 (embedded via `libdart_bridge`) | +| Flutter | 3.41.7, Debug build | +| Test harness | `bridge_example/integration_test/` (`flutter test integration_test`) | + +## Throughput + +Methodology — round-trip = `Dart.send(N bytes) → Python echo handler → Dart receives N bytes back`. Throughput counted as `(2 × N) / mean_seconds` since both directions cross the bridge. Payload is `Random()`-seeded so each iteration is unique. 100 iterations per size. + +| Payload | min | p50 | p95 | mean | Throughput | +|--------:|--------:|--------:|--------:|--------:|---------------:| +| 1 KB | 0.08 ms | 0.08 ms | 0.11 ms | 0.08 ms | 23 MB/s | +| 64 KB | 0.07 ms | 0.09 ms | 0.12 ms | 0.09 ms | 1.3 GB/s | +| 256 KB | 0.11 ms | 0.16 ms | 0.33 ms | 0.21 ms | 2.4 GB/s | +| 1 MB | 0.24 ms | 0.31 ms | 0.84 ms | 0.45 ms | **4.5 GB/s** | +| 4 MB | 0.82 ms | 1.01 ms | 3.83 ms | 1.55 ms | 5.2 GB/s | +| 16 MB | 2.45 ms | 3.32 ms | 9.12 ms | 4.45 ms | **7.2 GB/s** | + +### What the curve says + +- **Below ~64 KB the transport is call-overhead-bound.** Every round-trip pays a fixed ~80 µs floor (Dart isolate scheduling + Python GIL acquisition + two `bridge.send_bytes` calls). At 1 KB this overhead swamps the byte work — 23 MB/s is the *call rate*, not the *memory rate*. +- **At 64 KB → 16 MB it scales linearly with payload size.** Throughput goes from 1.3 GB/s to 7.2 GB/s as the per-byte cost (memory copy + Dart Native API marshalling) dominates the fixed per-call cost. +- **7.2 GB/s at 16 MB is within an order of magnitude of M2 Pro's main-memory bandwidth ceiling** (~200 GB/s theoretical, ~50 GB/s achievable for non-tuned `memcpy`). Practically: the bridge is memory-copy-bound, which is the best you can do without a true zero-copy shared-buffer scheme. + +For comparison: a Unix-domain socket transport on the same hardware tops out near 1 GB/s for similar-sized payloads, because every byte traverses the kernel. + +## Memory + +Methodology — 1 000 × 1 MB echo round-trips (~2 GB of bytes crossing the bridge total). Python heap measured via `tracemalloc.get_traced_memory()` (load-bearing leak signal — unit-stable, byte-accurate). RSS measured via `resource.getrusage(RUSAGE_SELF).ru_maxrss` on the Python side and `ProcessInfo.currentRss` on the Dart side (informational only — page residency, not retention). + +| Metric | Before | After | Delta | +|-------------------------------------|----------:|----------:|--------------------------------------------:| +| Python heap (`tracemalloc`) | 10 179 B | 10 179 B | **0 B** | +| Python RSS (`ru_maxrss`) | 350 MB | 457 MB | +112 MB | +| Dart RSS (`ProcessInfo.currentRss`) | 1 232 MB | 1 239 MB | +7 MB | +| Python `tracemalloc` peak | 11 446 B | 1.0 MB | +~1 MB (per-iteration buffer; reclaimed) | + +### What the deltas say + +- **`traced_delta = 0 B` after 2 GB of throughput.** This is the only number that matters for "does the bridge leak?" — Python's heap accounting is exact down to the byte. Zero growth means **the bridge does not retain a single byte** of the data it transports. +- **`traced_peak` rose to ~1 MB** — exactly the size of one in-flight payload, then reclaimed. The bridge holds at most one frame's worth of bytes per direction. +- **RSS growth (Python +112 MB, Dart +7 MB) is OS-level page residency**, not retention. macOS keeps recently-faulted-in pages mapped for performance; the kernel will release them under pressure. This is normal behaviour for any process that has briefly touched a lot of memory, and is decoupled from actual ownership of bytes. + +## Bottom line -1. Dart creates a `PythonBridge`; its `port` (a `ReceivePort.sendPort.nativePort`) - is exported to Python via the `BRIDGE_EXAMPLE_PORT` env var passed to - `SeriousPython.run()`. -2. Python reads the env var, registers a handler keyed on that port via - `dart_bridge.set_enqueue_handler_func(port, handler)`, and echoes any - incoming frame with a `b"echo: "` prefix using `dart_bridge.send_bytes(port, ...)`. -3. Dart's `bridge.send()` returns `false` until the Python-side handler - is registered; the example retries briefly to cover that startup race. +| Concern | Result | +|---------------------------------------------|-----------------------------------------------------------------| +| Speed at typical Flet message size (~KB) | ~80 µs per round-trip (~12 000 messages/sec round-trip rate) | +| Speed at "moving files / images" sizes (MB) | **4.5 GB/s at 1 MB, 7.2 GB/s at 16 MB** — memory-bandwidth class | +| Leaks? | **None. 2 GB moved, Python heap unchanged.** | +| Bytes retained per round-trip | Zero (peak ≤ 1 MB during one frame, then reclaimed) | From 5c7c940e5ae20c3c414ed19e4b00f25beee9c40f Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 13:25:44 -0700 Subject: [PATCH 098/114] ci(bridge_example): invoke each integration test file separately MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI run 27440632153 caught this: `flutter test integration_test` over the whole directory passes the first file then trips "Error waiting for a debug connection: The log reader stopped unexpectedly, or never started" / "Unable to start the app on the device" on every subsequent file. Local runs worked because I'd been invoking each file separately by habit. In CI we relied on the directory-wide form, which reuses one Dart VM session across files — bridge_example's per-test `SeriousPython.run()` + two `PythonBridge` instance creation + Python process spawn isn't a clean enough teardown for the next file's `runApp()` to take over the VM. Spawning a fresh `flutter test` process per file sidesteps the issue entirely. Applied uniformly to all five matrices: macOS, iOS, Android, Windows, Linux. Each now runs three explicit invocations: interactivity_test, throughput_test, memory_test. Affected runs: macOS×3, iOS×3, Android×3, Linux ARM×3 (and likely Linux AMD64 / Windows on a longer iteration count — the failure order was platform-dependent based on file-traversal order). --- .github/workflows/ci.yml | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d22e4368..76fca796 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,7 +61,15 @@ jobs: working-directory: "src/serious_python/example/bridge_example" run: | dart run serious_python:main package app/src --platform Darwin --python-version ${{ matrix.python_version }} - flutter test integration_test -d macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + # Each test file is invoked separately. `flutter test integration_test` + # over the directory reuses one VM session, but the second file's + # `runApp()` then trips "Unable to start the app on the device" — + # the spawn-then-teardown of bridge_example's embedded Python + + # PythonBridge ports isn't clean enough for VM reuse. One process + # per file sidesteps the issue. + flutter test integration_test/interactivity_test.dart -d macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flutter test integration_test/throughput_test.dart -d macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flutter test integration_test/memory_test.dart -d macos --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} bridge_example_ios: name: Test Bridge example on iOS (Python ${{ matrix.python_version }}) @@ -116,8 +124,11 @@ jobs: # time) when iOS-specific site-packages subdirs exist. Empty # --requirements skips that branch and the build fails. dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements certifi - echo "[$(ts)] >>> flutter test integration_test" - flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + echo "[$(ts)] >>> flutter test integration_test (per-file)" + # See macOS job for why each file runs as a separate invocation. + flutter test integration_test/interactivity_test.dart --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flutter test integration_test/throughput_test.dart --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flutter test integration_test/memory_test.dart --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} echo "[$(ts)] >>> done" bridge_example_android: @@ -191,7 +202,12 @@ jobs: sdkmanager --list_installed script: | cd src/serious_python/example/bridge_example && dart run serious_python:main package app/src --platform Android --python-version ${{ matrix.python_version }} - cd src/serious_python/example/bridge_example && flutter test integration_test --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + # Per-file: `flutter test integration_test` (whole dir) reuses one + # VM session and the second file fails to start the app. See + # bridge_example_macos for the discovery. + cd src/serious_python/example/bridge_example && flutter test integration_test/interactivity_test.dart --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + cd src/serious_python/example/bridge_example && flutter test integration_test/throughput_test.dart --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + cd src/serious_python/example/bridge_example && flutter test integration_test/memory_test.dart --device-id emulator-${{ env.EMULATOR_PORT }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} - name: Diagnostics on failure if: failure() @@ -251,7 +267,12 @@ jobs: # (default PowerShell shell on windows runners eats the failure when # piping into tail). set -o pipefail - flutter test integration_test -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + # Per-file: `flutter test integration_test` (whole dir) reuses one + # VM session and the second file fails to start the app. See + # bridge_example_macos for the discovery. + flutter test integration_test/interactivity_test.dart -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + flutter test integration_test/throughput_test.dart -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + flutter test integration_test/memory_test.dart -d windows --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - name: Diagnostics on failure if: failure() @@ -342,7 +363,12 @@ jobs: --platform Linux \ --python-version ${{ matrix.python_version }} set -o pipefail - xvfb-run flutter test integration_test -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + # Per-file: `flutter test integration_test` (whole dir) reuses one + # VM session and the second file fails to start the app. See + # bridge_example_macos for the discovery. + xvfb-run flutter test integration_test/interactivity_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + xvfb-run flutter test integration_test/throughput_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + xvfb-run flutter test integration_test/memory_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - name: Diagnostics on failure if: failure() From abca89280df6552c0d498f1cc6355332a7a7492c Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 13:39:34 -0700 Subject: [PATCH 099/114] ci(linux): share a single Xvfb across the three test invocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 27441055242 had 3-of-6 Linux jobs fail with "xvfb-run: error: Xvfb failed to start" on the second or third flutter test invocation. The pattern was randomly distributed across python versions (3.12, 3.13, 3.14) and arches (AMD64, ARM64) — the signature of a display-number race when xvfb-run is called back to back: the previous Xvfb hadn't fully released its display before the next xvfb-run tried to claim one. Start one Xvfb on :99 at the top of the test step (with a kill-on-EXIT trap), then run all three test files against the same DISPLAY. Also bumped the post-startup settle from "none" to a fixed 1-second sleep before the first flutter test runs (no xdpyinfo on the runner to do a proper readiness check, and 1s is plenty for Xvfb to start listening). --- .github/workflows/ci.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76fca796..9dac6a39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -363,12 +363,27 @@ jobs: --platform Linux \ --python-version ${{ matrix.python_version }} set -o pipefail + + # Three back-to-back `xvfb-run` invocations race for display + # numbers — the second/third sometimes trips "Xvfb failed to + # start" because the previous Xvfb's display isn't released yet + # (3-of-6 Linux jobs in run 27441055242 hit this). Start one + # Xvfb up front, share DISPLAY across all three test runs. + Xvfb :99 -screen 0 1280x1024x24 >/tmp/xvfb.log 2>&1 & + XVFB_PID=$! + export DISPLAY=:99 + trap 'kill $XVFB_PID 2>/dev/null || true' EXIT + # Brief settle so Xvfb is accepting connections before flutter + # test tries to open the window. xdpyinfo isn't in the ubuntu + # runner's default toolchain; a fixed sleep is sufficient. + sleep 1 + # Per-file: `flutter test integration_test` (whole dir) reuses one # VM session and the second file fails to start the app. See # bridge_example_macos for the discovery. - xvfb-run flutter test integration_test/interactivity_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - xvfb-run flutter test integration_test/throughput_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - xvfb-run flutter test integration_test/memory_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + flutter test integration_test/interactivity_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + flutter test integration_test/throughput_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 + flutter test integration_test/memory_test.dart -d linux --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} -v 2>&1 | tail -300 - name: Diagnostics on failure if: failure() From 5729e4925eac1a849eaa30a9b486136ccd2e8ba8 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Fri, 12 Jun 2026 20:46:48 -0700 Subject: [PATCH 100/114] Add docs for dedicated data channels Add comprehensive documentation (docs/dedicated-data-channels.md) for the new DataChannel feature implemented in Flet 0.86.0. The doc explains the problem, architecture, public Python/Dart APIs, cross-mode transport choices, muxed wire format, backpressure pattern, concurrency considerations, empirical performance baselines, and known limitations, and links to implementation files and examples. --- docs/dedicated-data-channels.md | 376 ++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 docs/dedicated-data-channels.md diff --git a/docs/dedicated-data-channels.md b/docs/dedicated-data-channels.md new file mode 100644 index 00000000..aab40476 --- /dev/null +++ b/docs/dedicated-data-channels.md @@ -0,0 +1,376 @@ +# Dedicated data channels for Flet widgets + +> **Status:** implemented in Flet 0.86.0. +> Implementation lives in +> [`packages/flet/lib/src/transport/data_channel.dart`](https://github.com/flet-dev/flet/blob/main/packages/flet/lib/src/transport/data_channel.dart) +> (Dart abstract API), +> [`packages/flet/lib/src/transport/protocol_muxed_data_channel.dart`](https://github.com/flet-dev/flet/blob/main/packages/flet/lib/src/transport/protocol_muxed_data_channel.dart) +> (cross-mode muxed fallback), and +> [`sdk/python/packages/flet/src/flet/data_channel.py`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet/src/flet/data_channel.py) +> (Python). First production consumer is +> [`flet-charts.MatplotlibChartCanvas`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py). +> Empirical baseline: this repo's +> [`bridge_example`](../src/serious_python/example/bridge_example/README.md). + +## Problem + +Flet's main control protocol carries widget state and events over a single +MsgPack-framed channel. Every byte — including bulk payloads like image +frames or audio buffers — pays the protocol cost: + +- Python: `msgpack.packb(big_bytes_field)` allocates a fresh buffer and + serializes into it. +- Dart: the streaming MsgPack decoder allocates another `Uint8List`, + decodes the ext, copies again. + +End-to-end throughput tops out around ~1 GB/s with several allocations +per frame. Fine for widget state diffs (tens of bytes per event). Not +fine for: + +- A chart / image widget receiving large bitmaps from Python (1080p RGBA + at 60 fps = 480 MB/s). +- A camera widget pushing frames from Dart into Python for ML inference. +- A microphone widget streaming PCM to a Python signal-processing + pipeline. + +`DataChannel` gives such widgets a dedicated byte channel alongside the +protocol — control flows still ride the protocol, bulk bytes bypass +MsgPack entirely. + +## What's available today + +`libdart_bridge` already supports an arbitrary number of independent +port↔handler pairs per process. The `flet build` template uses two +`PythonBridge` instances internally (one for the Flet protocol, one for +exit-code transmission). [`bridge_example`](../src/serious_python/example/bridge_example/) +opens two channels (JSON control + raw bytes echo) and round-trips +~16 MB payloads at **7 GiB/s** on M2 Pro — see +[bridge_example/README.md → Performance & memory baseline](../src/serious_python/example/bridge_example/README.md#performance--memory-baseline). + +A widget gets the same headroom: open a dedicated channel via `flet`'s +`DataChannel` API, ship raw bytes, never touch MsgPack on the hot path. + +## Architecture + +``` + package:flet (no Python deps, no transport deps) + ┌──────────────────────────────────────────────────────────────────┐ + │ abstract DataChannel { id, messages, send, close } │ + │ abstract DataChannelFactory { open() } │ + │ FletApp(dataChannelFactory: …) │ + │ FletBackend.openDataChannel() │ + │ │ + │ DEFAULT (built-in) ProtocolMuxedDataChannelFactory: │ + │ – muxes bytes over the existing FletBackendChannel │ + │ – works on every transport (UDS, TCP, WebSocket, postMessage) │ + │ – activated when no faster factory was injected │ + └──────────────────────────────────────────────────────────────────┘ + ▲ ▲ + │ injected by │ used by every non-embedded mode: + │ flet build template │ - dev (UDS/TCP socket) + │ │ - web with Pyodide (postMessage + Transferable) + │ │ - web with Python server (WebSocket) + ┌──────────────────────────────┐ ┌──────────────────────────────────────────────────────┐ + │ _PythonBridgeDataChannel │ │ DEFAULT (built-in) ProtocolMuxedDataChannel impl │ + │ wraps PythonBridge directly │ │ rides the active FletBackendChannel using the wire │ + │ (4–7 GiB/s) │ │ format below. Zero-copy on postMessage via │ + └──────────────────────────────┘ │ Transferable ArrayBuffer on that transport. │ + └──────────────────────────────────────────────────────┘ + ▲ uses + ┌─────────────────────────────────────────────────────────────────┐ + │ Extension widget (3rd-party) — imports only `package:flet` │ + │ Dart: final ch = FletBackend.of(context).openDataChannel(); │ + │ ch.send(bytes); ch.messages.listen(...) │ + │ Python: on_data_channel_open handler ↓ │ + │ self._channel = self.get_data_channel(e.channel_id) │ + └─────────────────────────────────────────────────────────────────┘ +``` + +Key shape decisions that fell out of implementation: + +1. **`flet` stays Python-independent.** Widget code on either side imports + only `package:flet` / `flet`. The `serious_python` dependency lives in + the `flet build` template's `native_runtime.dart`, behind a conditional + import. Web builds don't pull it in at all. +2. **Allocator: Dart side, always.** `FletBackend.of(context).openDataChannel()` + mints the id (a Dart native port in embedded mode, a monotonic u32 in + muxed mode). Python never allocates a channel — it only attaches to + ones Dart has already opened. +3. **Handshake: control event, not a property.** When the Dart widget + opens a channel it fires `data_channel_open` (a normal Flet control + event) carrying `{channel_name, channel_id}`. Python receives this via + the standard event handler and calls `self.get_data_channel(channel_id)` + to attach. No polling, no exception, no race window. A widget that + opens N channels fires N events with distinct `channel_name` values + for handler-side dispatch. +4. **Cross-mode.** Same widget code runs in four modes; only the + transport changes (see *Cross-mode operation* below). + +## Public API + +### Python side + +```python +import flet as ft +from typing import Optional + +@ft.control("MyImageChart") +class MyImageChart(ft.LayoutControl): + on_data_channel_open: Optional[ + ft.EventHandler[ft.DataChannelOpenEvent] + ] = None + + def init(self) -> None: + self._frames: Optional[ft.DataChannel] = None + if self.on_data_channel_open is None: + self.on_data_channel_open = self._capture_channel + + def _capture_channel(self, e: ft.DataChannelOpenEvent) -> None: + # Single-channel widget — no need to dispatch on e.channel_name. + # Multi-channel widgets `match e.channel_name:` here. + self._frames = self.get_data_channel(e.channel_id) + # Optional inbound handler: + self._frames.on_bytes(self._on_frame_from_dart) + + def push_frame(self, rgba_bytes: bytes) -> None: + if self._frames is not None: + self._frames.send(rgba_bytes) + + def _on_frame_from_dart(self, payload: bytes) -> None: + # called from the transport's delivery thread — push to a queue, + # don't block here + ... +``` + +### Dart side + +```dart +import 'package:flet/flet.dart'; +// No imports of `serious_python` or `dart_bridge`. + +class MyImageChartState extends State { + late final DataChannel _frames; + StreamSubscription? _sub; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (_frames != null) return; // initialize lazily, once + _frames = FletBackend.of(context).openDataChannel(); + _sub = _frames.messages.listen(_onFrameFromPython); + // Announce the channel to Python. + widget.control.triggerEvent("data_channel_open", { + "channel_name": "frames", + "channel_id": _frames.id, + }); + } + + void _onFrameFromPython(Uint8List bytes) { + // Hand to a Texture, dart:ui.Image.fromPixels, etc. + } + + @override + void dispose() { + _sub?.cancel(); + _frames.close(); + super.dispose(); + } +} +``` + +The `data_channel_open` event name is a **Flet convention, not framework- +intercepted** — the framework provides `Control.get_data_channel(id)` and +`FletBackend.openDataChannel()`; the widget wires the event on both ends. + +## Cross-mode operation + +Flet runs Python in different processes depending on deployment. Each +mode picks its own data-channel transport; the widget API is identical: + +| Mode | Flet protocol transport | DataChannel transport | Performance | +|------|------------------------|----------------------|-------------| +| **Embedded native** (`flet build` apk/macos/ios/...) | dart_bridge FFI | Dedicated `PythonBridge` per channel | 4–7 GiB/s (memory-copy bound) | +| **Web with Pyodide** | `postMessage` | Muxed over postMessage, Transferable ArrayBuffer | ~memory-bandwidth, zero-copy | +| **`flet run` dev mode** | UDS / TCP socket | Muxed over the protocol socket | ~hundreds of MB/s | +| **Web with Python server** | WebSocket | Muxed over WebSocket | ~hundreds of MB/s | + +Embedded native gets dedicated bridges because the FFI runtime supports +them natively at zero overhead. The other three modes share the built-in +`ProtocolMuxedDataChannelFactory` — channel frames ride the same byte +transport as the Flet protocol, with a 1-byte type discriminator to +disambiguate. + +## Wire format (muxed fallback) + +``` +type 0x00 → legacy Flet protocol frame (msgpack array [ClientAction, body]) +type 0x01 → raw DataChannel frame: [channel_id:u32 LE][raw payload bytes] +``` + +- **Message-oriented transports** (WebSocket, postMessage, dart_bridge): + each `send` is one packet of shape `[type:u8][payload]`. 5 bytes of + overhead per data-channel frame. +- **Stream-oriented transports** (UDS, TCP): each packet is prefixed + with `[length:u32 LE]` so the receiver can re-frame. 9 bytes of + overhead per data-channel frame. + +Under 1% overhead at any payload size that motivates a dedicated channel +(≥ 1 KB). + +**Channel-id allocation.** Embedded mode uses the Dart native port (64-bit, +allocated by `RawReceivePort`). Muxed mode uses a session-scoped +monotonic 32-bit counter — 0 reserved as "unallocated," ids never recycled +within a session. At 1 alloc/μs the u32 space lasts ~1 hour; real apps +open single-digit channels. The public `DataChannel.id : int` API is +64-bit; the u32 truncation is an internal contract of the muxed wire +format only. + +**Compatibility.** This wire format is **not backwards-compatible** with +pre-0.86 Flet servers/clients. Mixed-version `flet run` setups fail at +the first packet decode. See the Flet 0.86 breaking-change guide: +[Flet protocol framing upgraded for DataChannel support](https://flet.dev/docs/updates/breaking-changes/data-channel-protocol-upgrade). + +## Backpressure pattern (WebAgg-style) + +`DataChannel.send` is **synchronous fire-and-forget** on the Python side. +For producers that can outpace the consumer (camera streams, animation +loops, interactive matplotlib drags), the widget must implement explicit +backpressure — otherwise frames pile up in the Dart-side queue and replay +in a burst. + +The canonical pattern is a 1-byte ack from Dart after each frame paints, +mirroring matplotlib WebAgg's `img.onload` → `waiting=false` flow: + +**Dart side**, after the apply chain resolves: +```dart +_enqueue(() => applyFull(payload)).whenComplete(() { + _channel?.send(Uint8List.fromList([0xFF])); // ack +}); +``` + +**Python side** registers a callback for inbound bytes that observes the +ack and clears the producer-side `_waiting` flag. Matplotlib's existing +draw-request gate (`if not self._waiting: send(draw_request)`) then +naturally rate-limits to one frame in flight. + +Reference: [`flet-charts/matplotlib_chart_canvas`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py) ++ [`matplotlib_chart_canvas.dart`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart). +The Python side exposes `canvas.set_on_frame_applied(callback)` for +producer widgets like `MatplotlibChart` to chain onto. + +## Concurrency model + +### Python side — GIL-bound + +`channel.on_bytes(handler)` fires the handler synchronously under the GIL +on whatever OS thread the transport delivered from (dart_bridge thread in +embedded mode, asyncio loop in muxed mode). Heavy work in the handler +starves Python; the right pattern is enqueue-then-process with a bounded +queue + worker pool: + +```python +def did_mount(self): + self._queue = queue.Queue(maxsize=4) # bounded → drop policy + self._pool = ThreadPoolExecutor(max_workers=4) + self._frames.on_bytes(self._enqueue) + threading.Thread(target=self._pump, daemon=True).start() + +def _enqueue(self, payload): + try: self._queue.put_nowait(payload) + except queue.Full: pass # drop overflow + +def _pump(self): + while True: + payload = self._queue.get() + self._pool.submit(self._decode_and_reply, payload) +``` + +Real parallelism comes from C extensions that **release the GIL during +their work** — NumPy, PyTorch, Pillow, cryptography. Pure-Python CPU work +serialises on the GIL; for that, use `multiprocessing` or +PEP 684 subinterpreters. + +### Dart side — Isolate scope + +**`FletBackend.of(context).openDataChannel()` is main-Isolate only.** +`BuildContext` is part of Flutter's widget tree, which lives on the main +Isolate. The `PythonBridge` it constructs has its `RawReceivePort` on the +main Isolate. + +For worker-Isolate parallelism (e.g. a video decoder offloading texture +upload from the UI thread), the worker has to construct its **own** +`PythonBridge` directly — bypassing the framework helper, importing +`package:serious_python/bridge.dart` in the worker's entry-point file — +and ship its port back to main via `SendPort` for the +`data_channel_open` event fire. + +| Operation | Safe? | +|-----------|-------| +| `FletBackend.of(context).openDataChannel()` from a worker Isolate | ✗ BuildContext is main-Isolate only | +| Multiple `PythonBridge` instances across Isolates (worker constructs its own) | ✓ libdart_bridge multiplexes | +| One `PythonBridge` instance used from multiple Isolates | ✗ `RawReceivePort` is single-Isolate | +| Python `dart_bridge.send_bytes(port, ...)` from worker threads | ✓ serialised internally | +| Python handler running concurrently for one port | ✗ GIL — one in-flight handler per port | + +Non-embedded modes are single-Isolate by design — the muxed channel +registry lives in `FletBackend` on the main Isolate. Workers there ship +payloads via `TransferableTypedData` from/to main rather than opening +channels themselves. + +## Empirical baseline + +Measured 2026-06-12 on M2 Pro / macOS 26.5 / Flutter Debug build via +[`bridge_example`](../src/serious_python/example/bridge_example/README.md). +These are the `PythonBridge` numbers — they apply directly to embedded +native mode. Muxed-fallback throughput on dev/web transports is +transport-bound (sockets ~hundreds of MB/s; postMessage Transferable +~memory-bandwidth at large payloads). + +| Payload | Mean round-trip | Throughput | +|--------:|----------------:|-----------:| +| 1 KB | 0.08 ms | 23 MB/s | +| 64 KB | 0.09 ms | 1.3 GB/s | +| 1 MB | 0.45 ms | **4.5 GB/s** | +| 16 MB | 4.45 ms | **7.2 GB/s** | + +Memory: 1000 × 1 MB hammer loop (2 GB through the bridge) grows Python's +`tracemalloc` heap by **0 bytes**. Peak in-flight is one frame's worth. + +For a real-widget reference, the matplotlib pilot at a 3D figure with +heavy surface + contour layers measures ~15 fps at ~200 KB PNG/frame; +the bottleneck is matplotlib's mplot3d render (~53 ms/frame), not the +DataChannel (which runs at ~3 MB/s here against a ~4500 MB/s budget). + +## Known limitations / not in this release + +- **No built-in backpressure knob.** Per-channel queue depth or + "latest frame only" mode is the widget author's responsibility (see + *Backpressure pattern* above). A framework-level + `channel.queue_depth` knob is a future addition. +- **No discovery / introspection.** No "how many channels are open" or + "queue depth per channel" debug surface yet. +- **No Pyodide-dedicated MessageChannels.** v1 muxes through one + `postMessage` transport with Transferable for zero-copy outbound. If + head-of-line blocking on Pyodide becomes a visible issue, a v2 PR can + inject a per-channel `MessageChannel` factory through the same + `DataChannelFactory` injection point — no widget API changes. +- **No Python-initiated channel opens.** Dart is the always-allocator. + Reversing direction (Python wants a channel before any Dart widget has + asked) is a v2 question. +- **True zero-copy shared memory** (mmap + offset handoff) — the bridge + still does one `memcpy` per direction. Eliminating it requires + lifetime/ownership coordination between Dart's GC and CPython's + refcounting that's out of scope here. The 4–7 GiB/s ceiling is plenty + for the foreseeable use cases. + +## References + +- [`bridge_example`](../src/serious_python/example/bridge_example/) — + empirical baseline + reproducible test suite. Throughput and memory + numbers above come from its `throughput_test.dart` and `memory_test.dart`. +- [Flet 0.86 breaking-change guide](https://flet.dev/docs/updates/breaking-changes/data-channel-protocol-upgrade) + — wire format change details for anyone speaking the Flet protocol + outside the bundled CLI/runtime. +- [`matplotlib_chart_canvas.py`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py) + + [`matplotlib_chart_canvas.dart`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart) + — first production widget using DataChannel end-to-end, with backpressure ack. From fc0f486161441354289301c24c16c5df7d31132b Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sat, 13 Jun 2026 10:35:42 -0700 Subject: [PATCH 101/114] ci: silence the two Node 20 deprecation warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 27456825168 emitted Node 20 warnings for two actions: - gradle/actions/setup-gradle@v3: bumped to @v5. v5 is the last fully MIT-licensed major (v6 split the caching code into a separate gradle-actions-caching component under proprietary Terms of Use) and is on Node 24. The bump should also resolve the 'Cache service responded with 400' restore failures, which were the v3 caching code hitting the new GitHub Actions Cache v2 backend. - futureware-tech/simulator-action@v5: upstream still ships node20 in action.yml and there is no Node 24 release. Set the workflow-level FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 env to make the runner execute node20-declared JS actions on Node 24 (documented opt-in from the Node 20 deprecation notice). Leaving the windows-latest NOTICEs in place — those are informational (latest is moving to windows-2025-vs2026 on 2026-06-15, no action needed). --- .github/workflows/ci.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9dac6a39..ecf96d57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,11 @@ env: SCRIPTS: "${{ github.workspace }}/.github/scripts" SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" UV_PYTHON: "3.12" + # futureware-tech/simulator-action upstream still declares node20 in + # action.yml (no Node 24 release as of v5). Force the runner to execute + # node20-declared JS actions on Node 24 so we don't trip the deprecation + # warning that becomes a hard error on 2026-09-16. + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" # Pin flet so the Python side matches the Dart-side flet version. With # `--only-binary :all:`, pip would otherwise silently downgrade to an # older flet whose transitive deps (e.g. msgpack) have wheels for the @@ -171,7 +176,11 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + # Stay on v5 — v6 moved the caching component to a separate + # `gradle-actions-caching` library under proprietary commercial + # Terms of Use (https://blog.gradle.org/github-actions-for-gradle-v6). + # v5 was the last fully MIT-licensed major and is on Node 24. + uses: gradle/actions/setup-gradle@v5 - name: AVD cache uses: actions/cache@v5 From 212efe71f0ffb840ace614d1ba2a203e20b7b49d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sat, 13 Jun 2026 10:37:43 -0700 Subject: [PATCH 102/114] ci: pin Windows runner to windows-2025-vs2026 CI was emitting `windows-latest requests are being redirected to windows-2025-vs2026 by June 15, 2026` NOTICE on every Windows job. Pin explicitly to the destination image instead of relying on the alias so the runner image can't shift under us silently. --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ecf96d57..59186092 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -238,7 +238,10 @@ jobs: bridge_example_windows: name: Test Bridge example on Windows (Python ${{ matrix.python_version }}) - runs-on: windows-latest + # Explicit pin instead of `windows-latest` to avoid silent image moves. + # `windows-2025-vs2026` is what GitHub redirects `windows-latest` to + # starting 2026-06-15 (Server 2025 + VS 2026). + runs-on: windows-2025-vs2026 strategy: fail-fast: false matrix: From 91bd28fa2f5bf8618e0aa9ceac37cfaa362147da Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sat, 13 Jun 2026 10:53:30 -0700 Subject: [PATCH 103/114] remove scaffold getPlatformVersion across all platform plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `getPlatformVersion` was the example method from `flutter create --template=plugin` — a sanity-check that returns a string like "macOS 14.5.0". Nothing in this workspace nor flet itself ever called `SeriousPython.getPlatformVersion()`; the only consumers were the scaffold-generated plugin tests for Linux and Windows. Drop it everywhere before the dart-bridge release. Touches all six packages: - Top-level facade + platform-interface + method-channel impl: drop the declaration / forwarding wrapper. - Linux & Windows Dart impls: drop the override and the now-unused `methodChannel` field; trim the corresponding flutter/services and flutter/foundation imports. - Linux native plugin (C): drop the `get_platform_version()` function, collapse the method-call handler to a `NotImplemented` stub, and remove the now-orphan ``, ``, and `_plugin_private.h` includes. Delete `_plugin_private.h` (only ever declared this function) and `linux/test/` (only tested this function; not referenced by CMakeLists). - Windows native plugin (C++): same shape — drop the case, the `` + `` includes, and the entire `windows/test/` scaffold. - Darwin Swift: drop the `getPlatformVersion` case; the `getResourcePath` case stays. Tighten the file docstring accordingly. - Android Java: drop the `getPlatformVersion` if-arm; `getAppVersion` / `getNativeLibraryDir` stay. flutter analyze: clean across all six packages (the 6 remaining warnings are pre-existing path-dep / missing-asset notes from local dev setup, unrelated to this change). Technically a public API break — `SeriousPython.getPlatformVersion()` is part of the published Dart API — but folded in here with the dart-bridge wire-format break already in flight. --- src/serious_python/lib/serious_python.dart | 5 --- .../serious_python_android/AndroidPlugin.java | 4 +- .../lib/serious_python_android.dart | 4 -- .../darwin/Classes/SeriousPythonPlugin.swift | 13 ++---- .../lib/serious_python_darwin.dart | 4 -- .../lib/serious_python_linux.dart | 12 ------ .../linux/serious_python_linux_plugin.cc | 32 ++------------ .../serious_python_linux_plugin_private.h | 10 ----- .../test/serious_python_linux_plugin_test.cc | 31 ------------- .../serious_python_platform_interface.dart | 4 -- .../src/method_channel_serious_python.dart | 5 --- .../lib/serious_python_windows.dart | 12 ------ .../windows/serious_python_windows_plugin.cpp | 31 ++----------- .../serious_python_windows_plugin_test.cpp | 43 ------------------- 14 files changed, 11 insertions(+), 199 deletions(-) delete mode 100644 src/serious_python_linux/linux/serious_python_linux_plugin_private.h delete mode 100644 src/serious_python_linux/linux/test/serious_python_linux_plugin_test.cc delete mode 100644 src/serious_python_windows/windows/test/serious_python_windows_plugin_test.cpp diff --git a/src/serious_python/lib/serious_python.dart b/src/serious_python/lib/serious_python.dart index 722d87fa..1cf29d41 100644 --- a/src/serious_python/lib/serious_python.dart +++ b/src/serious_python/lib/serious_python.dart @@ -9,11 +9,6 @@ export 'package:serious_python_platform_interface/src/utils.dart'; class SeriousPython { SeriousPython._(); - /// Returns the current name and version of the operating system. - static Future getPlatformVersion() { - return SeriousPythonPlatform.instance.getPlatformVersion(); - } - /// Runs Python program from an asset. /// /// [assetPath] is the path to an asset which is a zip archive diff --git a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java index 1705b962..de434d49 100644 --- a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java +++ b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java @@ -58,9 +58,7 @@ public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBi @Override public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { - if (call.method.equals("getPlatformVersion")) { - result.success("Android " + android.os.Build.VERSION.RELEASE); - } else if (call.method.equals("getAppVersion")) { + if (call.method.equals("getAppVersion")) { try { String packageName = context.getPackageName(); android.content.pm.PackageManager pm = context.getPackageManager(); diff --git a/src/serious_python_android/lib/serious_python_android.dart b/src/serious_python_android/lib/serious_python_android.dart index 5cde9748..a7947bc5 100644 --- a/src/serious_python_android/lib/serious_python_android.dart +++ b/src/serious_python_android/lib/serious_python_android.dart @@ -26,10 +26,6 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { SeriousPythonPlatform.instance = SeriousPythonAndroid(); } - @override - Future getPlatformVersion() => - methodChannel.invokeMethod('getPlatformVersion'); - @override Future run(String appPath, {String? script, diff --git a/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift b/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift index 8305c55e..07224c3d 100644 --- a/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift +++ b/src/serious_python_darwin/darwin/Classes/SeriousPythonPlugin.swift @@ -16,9 +16,9 @@ private func _sp_init_keepalive(_ data: UnsafeMutableRawPointer?) -> Int @_silgen_name("DartBridge_EnqueueMessage") private func _sp_enqueue_keepalive(_ data: UnsafePointer?, _ len: Int) -/// Thin Flutter plugin: surfaces the python.bundle resource path to Dart and -/// exposes the standard `getPlatformVersion`. All Python lifecycle now lives -/// in `serious_python_run` (dart_bridge.xcframework), invoked from Dart. +/// Thin Flutter plugin: surfaces the python.bundle resource path to Dart. +/// All Python lifecycle now lives in `serious_python_run` +/// (dart_bridge.xcframework), invoked from Dart. public class SeriousPythonPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { @@ -44,13 +44,6 @@ public class SeriousPythonPlugin: NSObject, FlutterPlugin { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { - case "getPlatformVersion": - #if os(iOS) - result("iOS " + UIDevice.current.systemVersion) - #else - result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString) - #endif - case "getResourcePath": // The python.bundle that prepare_{ios,macos}.sh assembles ends up // inside this plugin's framework bundle as a Resources subbundle. diff --git a/src/serious_python_darwin/lib/serious_python_darwin.dart b/src/serious_python_darwin/lib/serious_python_darwin.dart index 3a509b5c..bc68da36 100644 --- a/src/serious_python_darwin/lib/serious_python_darwin.dart +++ b/src/serious_python_darwin/lib/serious_python_darwin.dart @@ -17,10 +17,6 @@ class SeriousPythonDarwin extends SeriousPythonPlatform { SeriousPythonPlatform.instance = SeriousPythonDarwin(); } - @override - Future getPlatformVersion() => - methodChannel.invokeMethod('getPlatformVersion'); - @override Future run(String appPath, {String? script, diff --git a/src/serious_python_linux/lib/serious_python_linux.dart b/src/serious_python_linux/lib/serious_python_linux.dart index 361ccc08..fee2ac94 100644 --- a/src/serious_python_linux/lib/serious_python_linux.dart +++ b/src/serious_python_linux/lib/serious_python_linux.dart @@ -1,7 +1,5 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:path/path.dart' as p; import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; @@ -20,20 +18,10 @@ import 'package:serious_python_platform_interface/serious_python_platform_interf /// doesn't have a compile-time constant for it). /// 3. Hands env + sys.path to `serious_python_run` in a single FFI call. class SeriousPythonLinux extends SeriousPythonPlatform { - @visibleForTesting - final methodChannel = const MethodChannel('serious_python_linux'); - static void registerWith() { SeriousPythonPlatform.instance = SeriousPythonLinux(); } - @override - Future getPlatformVersion() async { - final version = - await methodChannel.invokeMethod('getPlatformVersion'); - return '$version ${Platform.resolvedExecutable}'; - } - @override Future run(String appPath, {String? script, diff --git a/src/serious_python_linux/linux/serious_python_linux_plugin.cc b/src/serious_python_linux/linux/serious_python_linux_plugin.cc index 4c1c75c7..e96f9191 100644 --- a/src/serious_python_linux/linux/serious_python_linux_plugin.cc +++ b/src/serious_python_linux/linux/serious_python_linux_plugin.cc @@ -2,14 +2,9 @@ #include #include -#include -#include - -#include "serious_python_linux_plugin_private.h" - -// Thin Flutter plugin: only surfaces the OS version. Python lifecycle now -// lives in libdart_bridge.so, invoked from Dart via FFI. +// Plugin-registration shell only — all method calls return NotImplemented. +// Python lifecycle lives in libdart_bridge.so, invoked from Dart via FFI. #define SERIOUS_PYTHON_LINUX_PLUGIN(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), serious_python_linux_plugin_get_type(), \ @@ -26,30 +21,11 @@ static void serious_python_linux_plugin_handle_method_call( SeriousPythonLinuxPlugin *self, FlMethodCall *method_call) { - g_autoptr(FlMethodResponse) response = nullptr; - const gchar *method = fl_method_call_get_name(method_call); - - if (strcmp(method, "getPlatformVersion") == 0) - { - response = get_platform_version(); - } - else - { - response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); - } - + g_autoptr(FlMethodResponse) response = + FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); fl_method_call_respond(method_call, response, nullptr); } -FlMethodResponse *get_platform_version() -{ - struct utsname uname_data = {}; - uname(&uname_data); - g_autofree gchar *version = g_strdup_printf("Linux %s", uname_data.version); - g_autoptr(FlValue) result = fl_value_new_string(version); - return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); -} - static void serious_python_linux_plugin_dispose(GObject *object) { G_OBJECT_CLASS(serious_python_linux_plugin_parent_class)->dispose(object); diff --git a/src/serious_python_linux/linux/serious_python_linux_plugin_private.h b/src/serious_python_linux/linux/serious_python_linux_plugin_private.h deleted file mode 100644 index 8bbd6ab9..00000000 --- a/src/serious_python_linux/linux/serious_python_linux_plugin_private.h +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include "include/serious_python_linux/serious_python_linux_plugin.h" - -// This file exposes some plugin internals for unit testing. See -// https://github.com/flutter/flutter/issues/88724 for current limitations -// in the unit-testable API. - -// Handles the getPlatformVersion method call. -FlMethodResponse *get_platform_version(); diff --git a/src/serious_python_linux/linux/test/serious_python_linux_plugin_test.cc b/src/serious_python_linux/linux/test/serious_python_linux_plugin_test.cc deleted file mode 100644 index f1a15537..00000000 --- a/src/serious_python_linux/linux/test/serious_python_linux_plugin_test.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -#include "include/serious_python_linux/serious_python_linux_plugin.h" -#include "serious_python_linux_plugin_private.h" - -// This demonstrates a simple unit test of the C portion of this plugin's -// implementation. -// -// Once you have built the plugin's example app, you can run these tests -// from the command line. For instance, for a plugin called my_plugin -// built for x64 debug, run: -// $ build/linux/x64/debug/plugins/my_plugin/my_plugin_test - -namespace serious_python_linux { -namespace test { - -TEST(SeriousPythonLinuxPlugin, GetPlatformVersion) { - g_autoptr(FlMethodResponse) response = get_platform_version(); - ASSERT_NE(response, nullptr); - ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - FlValue* result = fl_method_success_response_get_result( - FL_METHOD_SUCCESS_RESPONSE(response)); - ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_STRING); - // The full string varies, so just validate that it has the right format. - EXPECT_THAT(fl_value_get_string(result), testing::StartsWith("Linux ")); -} - -} // namespace test -} // namespace serious_python_linux diff --git a/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart b/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart index a1ac3e77..4c0a78f5 100644 --- a/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart +++ b/src/serious_python_platform_interface/lib/serious_python_platform_interface.dart @@ -26,10 +26,6 @@ abstract class SeriousPythonPlatform extends PlatformInterface { _instance = instance; } - Future getPlatformVersion() { - throw UnimplementedError('platformVersion() has not been implemented.'); - } - Future run(String appPath, {String? script, List? modulePaths, diff --git a/src/serious_python_platform_interface/lib/src/method_channel_serious_python.dart b/src/serious_python_platform_interface/lib/src/method_channel_serious_python.dart index 191cd349..64f3b100 100644 --- a/src/serious_python_platform_interface/lib/src/method_channel_serious_python.dart +++ b/src/serious_python_platform_interface/lib/src/method_channel_serious_python.dart @@ -9,11 +9,6 @@ class MethodChannelSeriousPython extends SeriousPythonPlatform { @visibleForTesting final methodChannel = const MethodChannel('serious_python'); - @override - Future getPlatformVersion() { - return methodChannel.invokeMethod('getPlatformVersion'); - } - @override Future run(String appPath, {String? script, diff --git a/src/serious_python_windows/lib/serious_python_windows.dart b/src/serious_python_windows/lib/serious_python_windows.dart index b6890224..a7553bb2 100644 --- a/src/serious_python_windows/lib/serious_python_windows.dart +++ b/src/serious_python_windows/lib/serious_python_windows.dart @@ -1,7 +1,5 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:path/path.dart' as p; import 'package:serious_python_platform_interface/serious_python_platform_interface.dart'; @@ -17,20 +15,10 @@ import 'package:serious_python_platform_interface/serious_python_platform_interf /// runner .exe directory, where the bundled CPython lives) and dispatches a /// single FFI call to `serious_python_run`. class SeriousPythonWindows extends SeriousPythonPlatform { - @visibleForTesting - final methodChannel = const MethodChannel('serious_python_windows'); - static void registerWith() { SeriousPythonPlatform.instance = SeriousPythonWindows(); } - @override - Future getPlatformVersion() async { - final version = - await methodChannel.invokeMethod('getPlatformVersion'); - return '$version ${Platform.resolvedExecutable}'; - } - @override Future run(String appPath, {String? script, diff --git a/src/serious_python_windows/windows/serious_python_windows_plugin.cpp b/src/serious_python_windows/windows/serious_python_windows_plugin.cpp index 4f88ae68..62f9a489 100644 --- a/src/serious_python_windows/windows/serious_python_windows_plugin.cpp +++ b/src/serious_python_windows/windows/serious_python_windows_plugin.cpp @@ -3,14 +3,11 @@ // This must be included before many other Windows headers. #include -#include - #include #include #include #include -#include namespace serious_python_windows { @@ -39,35 +36,13 @@ namespace serious_python_windows SeriousPythonWindowsPlugin::~SeriousPythonWindowsPlugin() {} - // Thin Flutter plugin: only surfaces the OS version. Python lifecycle now - // lives in dart_bridge[_d].dll, invoked from Dart via FFI. + // Plugin-registration shell only — all method calls return NotImplemented. + // Python lifecycle lives in dart_bridge[_d].dll, invoked from Dart via FFI. void SeriousPythonWindowsPlugin::HandleMethodCall( const flutter::MethodCall &method_call, std::unique_ptr> result) { - if (method_call.method_name().compare("getPlatformVersion") == 0) - { - std::ostringstream version_stream; - version_stream << "Windows "; - if (IsWindows10OrGreater()) - { - version_stream << "10+"; - } - else if (IsWindows8OrGreater()) - { - version_stream << "8"; - } - else if (IsWindows7OrGreater()) - { - version_stream << "7"; - } - - result->Success(flutter::EncodableValue(version_stream.str())); - } - else - { - result->NotImplemented(); - } + result->NotImplemented(); } } // namespace serious_python_windows diff --git a/src/serious_python_windows/windows/test/serious_python_windows_plugin_test.cpp b/src/serious_python_windows/windows/test/serious_python_windows_plugin_test.cpp deleted file mode 100644 index a5414da6..00000000 --- a/src/serious_python_windows/windows/test/serious_python_windows_plugin_test.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "serious_python_windows_plugin.h" - -namespace serious_python_windows { -namespace test { - -namespace { - -using flutter::EncodableMap; -using flutter::EncodableValue; -using flutter::MethodCall; -using flutter::MethodResultFunctions; - -} // namespace - -TEST(SeriousPythonWindowsPlugin, GetPlatformVersion) { - SeriousPythonWindowsPlugin plugin; - // Save the reply value from the success callback. - std::string result_string; - plugin.HandleMethodCall( - MethodCall("getPlatformVersion", std::make_unique()), - std::make_unique>( - [&result_string](const EncodableValue* result) { - result_string = std::get(*result); - }, - nullptr, nullptr)); - - // Since the exact string varies by host, just ensure that it's a string - // with the expected format. - EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0); -} - -} // namespace test -} // namespace serious_python_windows From 3d9c505746d4b6374ff8329af50c75f569de08e4 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sun, 14 Jun 2026 14:38:02 -0700 Subject: [PATCH 104/114] Centralize Python runtime versions via a date-keyed manifest Replace the ~6 independently hardcoded copies of the Python/Pyodide/ dart_bridge versions with a single source of truth: python-build's date-keyed manifest.json. serious_python pins one release date and commits generated snapshots of it; native builds read the committed snapshots offline, and CI guards against drift. - bin/gen_version_tables.dart: fetch python-build's manifest for the pinned pythonReleaseDate (or --release-date / --manifest) and write the committed snapshots: lib/src/python_versions.dart + a python_versions.properties in each native package. - lib/src/python_versions.dart (generated): the canonical table, moved out of package_command.dart; imported by package/version/configure commands. - Native configs (Android build.gradle, Darwin podspec, Linux/Windows CMakeLists) read the committed table with one layered resolution: SERIOUS_PYTHON_VERSION -> table -> per-field escape hatch -> error on unknown. - prepare_ios.sh/prepare_macos.sh take dart_bridge_version as a 4th arg from the table (drift unified to 1.2.3) instead of a hardcoded default. - New `configure` command stages the embedded Darwin interpreter for the selected version; `package` calls it so a version switch takes effect on a bare rebuild (no `rm -rf Pods`). - CI: "Version tables in sync with manifest" drift-check; drop the now- redundant resolve-python-vars action; key the flet cache on the snapshot. - Tests: run_example version_test (numpy ABI canary + version assertion via a main.py probe) and a gated python-version-switching workflow (sequential 3.12->3.13->3.14->3.12 on one VM, macOS + iOS). - Docs: CONTRIBUTING "Python runtime versions" bump flow; README manifest model + `configure`. --- .../actions/resolve-python-vars/action.yml | 50 ------ .github/workflows/ci.yml | 57 +++--- .../workflows/python-version-switching.yml | 99 ++++++++++ CONTRIBUTING.md | 29 +++ src/serious_python/README.md | 42 +++-- src/serious_python/bin/configure_command.dart | 62 +++++++ .../bin/gen_version_tables.dart | 170 ++++++++++++++++++ src/serious_python/bin/main.dart | 2 + src/serious_python/bin/package_command.dart | 141 +++++++-------- src/serious_python/bin/version_command.dart | 10 +- .../example/run_example/app/app.zip.hash | 2 +- .../example/run_example/app/src/main.py | 12 ++ .../integration_test/version_test.dart | 46 +++++ .../lib/src/python_versions.dart | 55 ++++++ .../android/build.gradle | 18 +- .../android/python_versions.properties | 8 + .../darwin/prepare_ios.sh | 8 +- .../darwin/prepare_macos.sh | 7 +- .../darwin/python_versions.properties | 8 + .../darwin/serious_python_darwin.podspec | 23 ++- src/serious_python_linux/linux/CMakeLists.txt | 27 ++- .../linux/python_versions.properties | 8 + .../windows/CMakeLists.txt | 27 ++- .../windows/python_versions.properties | 8 + 24 files changed, 727 insertions(+), 192 deletions(-) delete mode 100644 .github/actions/resolve-python-vars/action.yml create mode 100644 .github/workflows/python-version-switching.yml create mode 100644 src/serious_python/bin/configure_command.dart create mode 100644 src/serious_python/bin/gen_version_tables.dart create mode 100644 src/serious_python/example/run_example/integration_test/version_test.dart create mode 100644 src/serious_python/lib/src/python_versions.dart create mode 100644 src/serious_python_android/android/python_versions.properties create mode 100644 src/serious_python_darwin/darwin/python_versions.properties create mode 100644 src/serious_python_linux/linux/python_versions.properties create mode 100644 src/serious_python_windows/windows/python_versions.properties diff --git a/.github/actions/resolve-python-vars/action.yml b/.github/actions/resolve-python-vars/action.yml deleted file mode 100644 index daa76eb0..00000000 --- a/.github/actions/resolve-python-vars/action.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Resolve serious_python Python-version vars -description: | - Derive `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` for - the current `SERIOUS_PYTHON_VERSION` from `dart run serious_python:main - version --json` and export them to `$GITHUB_ENV` so subsequent steps — - including the platform plugin build scripts (Android `build.gradle`, - Darwin `prepare_{ios,macos}.sh`, Linux/Windows `CMakeLists.txt`) — pick - up the registry-correct values without having to hand-maintain a lookup - table in the workflow. - - Requires Flutter to be on PATH and `SERIOUS_PYTHON_VERSION` to be set in - env (typically by the caller's `env:` block, keyed off - `matrix.python_version`). - -runs: - using: composite - steps: - - name: Resolve full version + python-build date - shell: bash - working-directory: src/serious_python - run: | - set -euo pipefail - if [[ -z "${SERIOUS_PYTHON_VERSION:-}" ]]; then - echo "::error::SERIOUS_PYTHON_VERSION is not set in env." - exit 1 - fi - flutter pub get >/dev/null - # `dart run` writes mixed noise to stdout on a cold cache — - # "Building package executable...", "Running build hooks..." — and - # the build-hook line gets joined to our JSON's opening `{` with no - # newline, so line-based sed patterns like `^{` miss everything. - # Strip from the byte-level first `{` forward instead. stderr is - # captured alongside stdout so any genuine dart error is visible. - raw=$(dart run serious_python:main version --json 2>&1) - if [[ "$raw" != *"{"* ]]; then - echo "::error::dart run produced no JSON for SERIOUS_PYTHON_VERSION=${SERIOUS_PYTHON_VERSION}" - printf '%s\n' "$raw" - exit 1 - fi - json="{${raw#*\{}" - full=$(printf '%s\n' "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".standalone_version") - date=$(printf '%s\n' "$json" | jq -r ".python_releases.\"${SERIOUS_PYTHON_VERSION}\".python_build_release_date") - if [[ -z "$full" || "$full" == "null" || -z "$date" || "$date" == "null" ]]; then - echo "::error::serious_python:main version --json did not return values for SERIOUS_PYTHON_VERSION=${SERIOUS_PYTHON_VERSION}" - printf '%s\n' "$json" - exit 1 - fi - echo "SERIOUS_PYTHON_FULL_VERSION=$full" >> "$GITHUB_ENV" - echo "SERIOUS_PYTHON_BUILD_DATE=$date" >> "$GITHUB_ENV" - echo "Resolved Python $SERIOUS_PYTHON_VERSION: full=$full, python-build date=$date" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59186092..715698bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,38 @@ env: FLET_VERSION: "0.85.3" jobs: + version_tables_in_sync: + name: Version tables in sync with manifest + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Regenerate version tables and check for drift + working-directory: src/serious_python + run: | + set -euo pipefail + flutter pub get >/dev/null + dart run serious_python:gen_version_tables + if ! git diff --quiet; then + echo "::error::Generated Python version tables are out of date." + echo "The committed lib/src/python_versions.dart and the four" + echo "python_versions.properties must match python-build's" + echo "manifest.json for the pinned pythonReleaseDate. To fix: edit" + echo "python-build's manifest.json + cut a release, bump" + echo "pythonReleaseDate, then run" + echo " (cd src/serious_python && dart run serious_python:gen_version_tables)" + echo "and commit the regenerated files." + git --no-pager diff + exit 1 + fi + bridge_example_macos: name: Test Bridge example on macOS (Python ${{ matrix.python_version }}) runs-on: macos-26 @@ -50,14 +82,11 @@ jobs: path: '.fvmrc' cache: true - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - name: Cache flet downloads uses: actions/cache@v5 with: path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/lib/src/python_versions.dart', 'src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} restore-keys: | flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- @@ -96,14 +125,11 @@ jobs: path: '.fvmrc' cache: true - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - name: Cache flet downloads uses: actions/cache@v5 with: path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/lib/src/python_versions.dart', 'src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} restore-keys: | flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- @@ -157,14 +183,11 @@ jobs: path: '.fvmrc' cache: true - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - name: Cache flet downloads uses: actions/cache@v5 with: path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/lib/src/python_versions.dart', 'src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} restore-keys: | flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- @@ -258,14 +281,11 @@ jobs: path: '.fvmrc' cache: true - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - name: Cache flet downloads uses: actions/cache@v5 with: path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/lib/src/python_versions.dart', 'src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} restore-keys: | flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- @@ -339,14 +359,11 @@ jobs: channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} cache: true - - name: Resolve Python version vars - uses: ./.github/actions/resolve-python-vars - - name: Cache flet downloads uses: actions/cache@v5 with: path: ~/.flet/cache - key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} + key: flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}-${{ hashFiles('src/serious_python/lib/src/python_versions.dart', 'src/serious_python/bin/package_command.dart', 'src/serious_python_android/android/build.gradle', 'src/serious_python_darwin/darwin/prepare_macos.sh', 'src/serious_python_darwin/darwin/prepare_ios.sh', 'src/serious_python_windows/windows/CMakeLists.txt', 'src/serious_python_linux/linux/CMakeLists.txt') }} restore-keys: | flet-cache-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python_version }}- flet-cache-${{ runner.os }}-${{ runner.arch }}- diff --git a/.github/workflows/python-version-switching.yml b/.github/workflows/python-version-switching.yml new file mode 100644 index 00000000..f77f3bd2 --- /dev/null +++ b/.github/workflows/python-version-switching.yml @@ -0,0 +1,99 @@ +name: Python version switching + +# Regression guard for switching the embedded Python version on a single +# machine: the matrix CI (one VM per version) can't catch a stale runtime left +# over from a previous version, so this job builds run_example for several +# versions *sequentially on the same runner* (including a downgrade) and asserts +# the running interpreter — and its numpy wheel — match each requested version. +# +# Gated (heavy: per-version package + build) — runs on PRs that touch the +# version/darwin machinery, manually, and nightly. +on: + workflow_dispatch: + schedule: + - cron: "0 6 * * *" + pull_request: + paths: + - "src/serious_python_darwin/**" + - "src/serious_python/lib/src/python_versions.dart" + - "src/serious_python/bin/**" + - "src/serious_python/example/run_example/**" + - ".github/workflows/python-version-switching.yml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + switch_macos: + name: Switch Python versions on macOS + runs-on: macos-26 + timeout-minutes: 40 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: ".fvmrc" + cache: true + + - name: Package + run version_test for each Python (same VM) + working-directory: src/serious_python/example/run_example + run: | + set -euo pipefail + export SERIOUS_PYTHON_SITE_PACKAGES="$(pwd)/build/site-packages" + flutter pub get + for v in 3.12 3.13 3.14 3.12; do + echo "::group::Python $v" + export SERIOUS_PYTHON_VERSION=$v + # NOTE: no `rm -rf Pods` — package stages the interpreter so a bare + # repackage + rebuild switches versions on its own. + dart run serious_python:main package app/src \ + --platform Darwin --python-version "$v" -r -r -r app/src/requirements.txt + flutter test integration_test/version_test.dart -d macos \ + --dart-define=EXPECTED_PYTHON_VERSION="$v" + echo "::endgroup::" + done + + switch_ios: + name: Switch Python versions on iOS + runs-on: macos-26 + timeout-minutes: 50 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: ".fvmrc" + cache: true + + - name: Setup iOS Simulator + id: simulator + uses: futureware-tech/simulator-action@v5 + with: + model: "iPhone 17 Pro Max" + os: "iOS" + os_version: "26.5" + shutdown_after_job: true + wait_for_boot: true + + - name: Package + run version_test for each Python (same VM) + working-directory: src/serious_python/example/run_example + run: | + set -euo pipefail + export SERIOUS_PYTHON_SITE_PACKAGES="$(pwd)/build/site-packages" + flutter pub get + for v in 3.12 3.13 3.14 3.12; do + echo "::group::Python $v" + export SERIOUS_PYTHON_VERSION=$v + dart run serious_python:main package app/src \ + --platform iOS --python-version "$v" -r -r -r app/src/requirements.txt + flutter test integration_test/version_test.dart \ + -d ${{ steps.simulator.outputs.udid }} \ + --dart-define=EXPECTED_PYTHON_VERSION="$v" + echo "::endgroup::" + done diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 327284e8..5079aed6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,35 @@ Bump `serious_python` dependency version with `flutter pub get` in example lock Update `CHANGELOG.md`. +## Python runtime versions + +The supported Python versions, their CPython / Pyodide / dart_bridge details, and +which versions get built are all defined in a single source of truth: the +**`manifest.json`** in [`flet-dev/python-build`](https://github.com/flet-dev/python-build), +published as an asset on each date-keyed (`YYYYMMDD`) release. + +serious_python pins one release date (`pythonReleaseDate`) and commits generated +snapshots of that manifest — **never hand-edit these**: + +* `src/serious_python/lib/src/python_versions.dart` — read by the CLI commands +* `python_versions.properties` in each platform package — read by the + Android / Darwin / Linux / Windows build configs + +To add or bump a Python / Pyodide / dart_bridge version: + +1. Edit `manifest.json` in python-build and cut a new release (run the **Build + Python Packages** workflow with a `YYYYMMDD` `release_date`). +2. Regenerate the snapshots from the new release: + + ``` + cd src/serious_python + dart run serious_python:gen_version_tables --release-date + ``` + + (Omit `--release-date` to re-fetch the currently pinned release.) +3. Commit the regenerated `python_versions.dart` and `python_versions.properties` + files. CI's **Version tables in sync with manifest** job fails if they drift. + ## Getting token for automatic publishing to pub.dev Token locations on different OSes: https://stackoverflow.com/a/70487480/1435891 diff --git a/src/serious_python/README.md b/src/serious_python/README.md index 8d913b1e..10090f4d 100644 --- a/src/serious_python/README.md +++ b/src/serious_python/README.md @@ -34,19 +34,21 @@ The default is the latest stable row (currently **3.14**) when neither applied to `[project].requires-python` in your `pyproject.toml`, so most users never need to touch this flag directly. -`SERIOUS_PYTHON_VERSION` (short, e.g. `3.14`) is the only input most users -need to set. When `flet build` invokes the platform plugins it also exports -`SERIOUS_PYTHON_FULL_VERSION` (e.g. `3.14.6`) and `SERIOUS_PYTHON_BUILD_DATE` -(e.g. `20260611` — the `flet-dev/python-build` release tag); the plugin build -scripts pick them up automatically and combine them into the -`…//python-*--*` download URLs. - -Source of truth: the `_pythonReleases` map in -[`bin/package_command.dart`](bin/package_command.dart) (Dart side) and -`flet_cli/utils/python_versions.py` (Python side). Adding a new short version -means appending a row to both. Pre-release CPython lines (e.g. 3.15) can be -listed with `prerelease: true` so they're opt-in via explicit -`--python-version 3.15` (or `requires-python = "==3.15.*"`) without becoming +`SERIOUS_PYTHON_VERSION` (short, e.g. `3.14`) is the only input you set — the +full version, python-build release date, Pyodide version/tag, and dart_bridge +version all derive from it. (`SERIOUS_PYTHON_FULL_VERSION`, +`SERIOUS_PYTHON_BUILD_DATE`, `DART_BRIDGE_VERSION` exist as rarely-needed escape +hatches.) A single `export SERIOUS_PYTHON_VERSION=3.13` covers both the +packaging phase and the later Flutter build. + +Source of truth: the date-keyed `manifest.json` published by +[`flet-dev/python-build`](https://github.com/flet-dev/python-build). +serious_python pins one release and commits generated snapshots of it — +`lib/src/python_versions.dart` (used by the CLI) and a `python_versions.properties` +in each platform package (read by the native build configs). To bump versions +see [CONTRIBUTING.md](CONTRIBUTING.md); never hand-edit the generated files. +Pre-release CPython lines are marked `prerelease: true`, so they're opt-in via +explicit `--python-version` (or `requires-python = "==3.15.*"`) without becoming the auto-resolved default. ## Usage @@ -149,6 +151,20 @@ read by each platform plugin's build script (`build.gradle`, the phase and the Flutter build phase. See the [Python versions](#python-versions) table above for the matching CPython and Pyodide releases. +#### Running a script without packaging (`configure`) + +The `package` command stages the embedded Darwin (iOS/macOS) runtime for the +selected version automatically. For the bare "run a Python script" flow where +you skip `package`, stage it yourself with `configure`, then build: + +``` +export SERIOUS_PYTHON_VERSION=3.13 +dart run serious_python:main configure --platform Darwin # or iOS +``` + +Android, Linux and Windows download the runtime during their native build, so +`configure` is a no-op there. + #### Installing requirements Python app dependencies are installed with the `--requirements` option (alias `-r`). The value is passed verbatim to `pip`, so any flag pip accepts works. Pass each dependency as its own option to support specifiers that contain commas: diff --git a/src/serious_python/bin/configure_command.dart b/src/serious_python/bin/configure_command.dart new file mode 100644 index 00000000..6618b9b5 --- /dev/null +++ b/src/serious_python/bin/configure_command.dart @@ -0,0 +1,62 @@ +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:serious_python/src/python_versions.dart'; + +import 'package_command.dart' show stageDarwinRuntime, sitePackagesEnvironmentVariable; + +/// `configure` subcommand: stages the embedded Python runtime for a platform and +/// version without packaging an app. Useful when running a bare Python script +/// (no `package` step) and to make a version switch take effect on a rebuild. +/// +/// Only Darwin (iOS/macOS) needs explicit staging — the Android/Linux/Windows +/// native builds download the runtime themselves from the version table. +class ConfigureCommand extends Command { + @override + final name = "configure"; + + @override + final description = + "Stage the embedded Python runtime for a platform/version (Darwin)."; + + ConfigureCommand() { + argParser.addOption('platform', + abbr: "p", + allowed: ["iOS", "Android", "Emscripten", "Windows", "Linux", "Darwin"], + mandatory: true, + help: "Platform to stage the runtime for, e.g. 'iOS' or 'Darwin'."); + argParser.addOption('python-version', + allowed: pythonReleases.keys.toList(), + help: "Short Python version to stage (e.g. 3.13). Defaults to " + "\$$pythonVersionEnvironmentVariable env var or " + "'$defaultPythonVersion'."); + } + + @override + Future run() async { + final platform = argResults!['platform'] as String; + final shortVersion = (argResults!['python-version'] as String?) ?? + Platform.environment[pythonVersionEnvironmentVariable] ?? + defaultPythonVersion; + + if (platform != "iOS" && platform != "Darwin") { + stdout.writeln("configure: nothing to stage for $platform — its native " + "build downloads the runtime from python_versions.properties."); + return; + } + + final sitePackagesRoot = + Platform.environment[sitePackagesEnvironmentVariable]; + if (sitePackagesRoot == null || sitePackagesRoot.trim().isEmpty) { + stderr.writeln("serious_python: set $sitePackagesEnvironmentVariable to " + "the app's site-packages directory before running configure."); + exit(2); + } + + await stageDarwinRuntime( + platform: platform, + shortVersion: shortVersion, + sitePackagesRoot: sitePackagesRoot, + ); + } +} diff --git a/src/serious_python/bin/gen_version_tables.dart b/src/serious_python/bin/gen_version_tables.dart new file mode 100644 index 00000000..d4dc43af --- /dev/null +++ b/src/serious_python/bin/gen_version_tables.dart @@ -0,0 +1,170 @@ +// Generates the committed Python-version snapshots from python-build's +// date-keyed manifest.json (the single source of truth): +// +// * lib/src/python_versions.dart — Dart consts for the CLI commands +// * /python_versions.properties — KEY=VALUE tables the +// Android/Darwin/Linux/Windows build configs read at build time +// +// Usage (run from the serious_python package dir): +// dart run serious_python:gen_version_tables # re-fetch the pinned release +// dart run serious_python:gen_version_tables --release-date 20260615 +// dart run serious_python:gen_version_tables --manifest path/to/manifest.json +// +// CI runs the no-arg form and `git diff --exit-code`s the result to guard drift. +import 'dart:convert'; +import 'dart:io'; + +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as p; + +const _releaseUrlBase = + 'https://github.com/flet-dev/python-build/releases/download'; +const _generatedDartFile = 'lib/src/python_versions.dart'; + +// Native packages (siblings under src/) that read python_versions.properties. +const _nativePackageDirs = [ + '../serious_python_android/android', + '../serious_python_darwin/darwin', + '../serious_python_linux/linux', + '../serious_python_windows/windows', +]; + +Future main(List args) async { + String? releaseDate; + String? manifestPath; + for (var i = 0; i < args.length; i++) { + switch (args[i]) { + case '--release-date': + releaseDate = args[++i]; + break; + case '--manifest': + manifestPath = args[++i]; + break; + default: + stderr.writeln('Unknown argument: ${args[i]}'); + exit(2); + } + } + + final Map manifest; + if (manifestPath != null) { + manifest = jsonDecode(await File(manifestPath).readAsString()) + as Map; + } else { + releaseDate ??= _readPinnedReleaseDate(); + if (releaseDate == null) { + stderr.writeln('Pass --release-date YYYYMMDD (or --manifest PATH) — no ' + 'pinned release found in $_generatedDartFile.'); + exit(2); + } + final url = '$_releaseUrlBase/$releaseDate/manifest.json'; + final resp = await http.get(Uri.parse(url)); + if (resp.statusCode != 200) { + stderr.writeln('Failed to fetch $url (HTTP ${resp.statusCode}).'); + exit(1); + } + manifest = jsonDecode(resp.body) as Map; + } + + final release = (manifest['release'] ?? releaseDate) as String?; + if (release == null) { + stderr.writeln('Manifest has no "release" field; pass --release-date.'); + exit(2); + } + final defaultPython = manifest['default_python_version'] as String; + final dartBridge = manifest['dart_bridge_version'] as String; + final pythons = (manifest['pythons'] as Map).cast(); + final shorts = pythons.keys.toList()..sort(); + + await File(_generatedDartFile) + .writeAsString(_dartFile(release, defaultPython, dartBridge, pythons, shorts)); + + final props = _propertiesFile(release, defaultPython, dartBridge, pythons, shorts); + for (final dir in _nativePackageDirs) { + await File(p.join(dir, 'python_versions.properties')).writeAsString(props); + } + + stdout.writeln( + 'Generated version tables for release $release (${shorts.join(", ")}).'); +} + +String? _readPinnedReleaseDate() { + final f = File(_generatedDartFile); + if (!f.existsSync()) return null; + final m = RegExp(r'''pythonReleaseDate\s*=\s*["'](\d+)["']''') + .firstMatch(f.readAsStringSync()); + return m?.group(1); +} + +String _genHeader(String release) => ''' +// GENERATED by `dart run serious_python:gen_version_tables` from python-build's +// manifest.json (release $release). Do not edit by hand — edit python-build's +// manifest.json, cut a release, bump `pythonReleaseDate`, and regenerate. +'''; + +String _dartFile(String release, String defaultPython, String dartBridge, + Map pythons, List shorts) { + final b = StringBuffer(_genHeader(release)) + ..writeln() + ..writeln('const pythonVersionEnvironmentVariable = "SERIOUS_PYTHON_VERSION";') + ..writeln( + 'const pythonFullVersionEnvironmentVariable = "SERIOUS_PYTHON_FULL_VERSION";') + ..writeln( + 'const pythonDistReleaseEnvironmentVariable = "SERIOUS_PYTHON_DIST_RELEASE";') + ..writeln( + 'const pythonBuildDateEnvironmentVariable = "SERIOUS_PYTHON_BUILD_DATE";') + ..writeln( + 'const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION";') + ..writeln('const dartBridgeVersionEnvironmentVariable = "DART_BRIDGE_VERSION";') + ..writeln() + ..writeln('/// python-build release the bundled runtimes come from (YYYYMMDD).') + ..writeln('const pythonReleaseDate = "$release";') + ..writeln('const dartBridgeVersion = "$dartBridge";') + ..writeln('const defaultPythonVersion = "$defaultPython";') + ..writeln() + ..writeln('class PythonRelease {') + ..writeln(' const PythonRelease({') + ..writeln(' required this.standaloneVersion,') + ..writeln(' required this.standaloneReleaseDate,') + ..writeln(' required this.pyodideVersion,') + ..writeln(' required this.pyodidePlatformTag,') + ..writeln(' required this.prerelease,') + ..writeln(' });') + ..writeln() + ..writeln(' final String standaloneVersion;') + ..writeln(' final String standaloneReleaseDate;') + ..writeln(' final String pyodideVersion;') + ..writeln(' final String pyodidePlatformTag;') + ..writeln(' final bool prerelease;') + ..writeln('}') + ..writeln() + ..writeln('const pythonReleases = {'); + for (final s in shorts) { + final r = pythons[s] as Map; + b + ..writeln(' "$s": PythonRelease(') + ..writeln(' standaloneVersion: "${r['full_version']}",') + ..writeln(' standaloneReleaseDate: "${r['standalone_release_date']}",') + ..writeln(' pyodideVersion: "${r['pyodide_version']}",') + ..writeln(' pyodidePlatformTag: "${r['pyodide_platform_tag']}",') + ..writeln(' prerelease: ${r['prerelease'] == true},') + ..writeln(' ),'); + } + b.writeln('};'); + return b.toString(); +} + +String _propertiesFile(String release, String defaultPython, String dartBridge, + Map pythons, List shorts) { + final b = StringBuffer() + ..writeln('# GENERATED by `dart run serious_python:gen_version_tables` from') + ..writeln('# python-build manifest.json (release $release). Do not edit by hand.') + ..writeln('default_python_version=$defaultPython') + ..writeln('dart_bridge_version=$dartBridge') + ..writeln('python_build_release_date=$release'); + for (final s in shorts) { + final r = pythons[s] as Map; + b.writeln('$s.full_version=${r['full_version']}'); + } + return b.toString(); +} diff --git a/src/serious_python/bin/main.dart b/src/serious_python/bin/main.dart index 7e03cff1..372dab98 100644 --- a/src/serious_python/bin/main.dart +++ b/src/serious_python/bin/main.dart @@ -1,5 +1,6 @@ import 'package:args/command_runner.dart'; +import 'configure_command.dart'; import 'package_command.dart'; import 'version_command.dart'; @@ -7,6 +8,7 @@ void main(List arguments) async { var runner = CommandRunner("dart run serious_python:main", "A tool for packaging Python apps to work with serious_python package.") ..addCommand(PackageCommand()) + ..addCommand(ConfigureCommand()) ..addCommand(VersionCommand()); await runner.run(arguments); diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index 70d78eea..baf4607c 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -9,6 +9,7 @@ import 'package:glob/list_local_fs.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; import 'package:shelf/shelf.dart'; +import 'package:serious_python/src/python_versions.dart'; import 'package:shelf/shelf_io.dart' as shelf_io; import 'macos_utils.dart' as macos_utils; @@ -24,83 +25,62 @@ const flutterPackagesFlutterEnvironmentVariable = const allowSourceDistrosEnvironmentVariable = "SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS"; -const pythonVersionEnvironmentVariable = "SERIOUS_PYTHON_VERSION"; -const pythonFullVersionEnvironmentVariable = "SERIOUS_PYTHON_FULL_VERSION"; -const pythonDistReleaseEnvironmentVariable = "SERIOUS_PYTHON_DIST_RELEASE"; -const pythonBuildDateEnvironmentVariable = "SERIOUS_PYTHON_BUILD_DATE"; -const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION"; - -const defaultPythonVersion = "3.14"; - -class PythonRelease { - const PythonRelease({ - required this.standaloneVersion, - required this.standaloneReleaseDate, - required this.pythonBuildReleaseDate, - required this.pyodideVersion, - required this.pyodidePlatformTag, - required this.prerelease, - }); - - final String standaloneVersion; - final String standaloneReleaseDate; - - // Release date tag of the matching `flet-dev/python-build` release - // (e.g. "20260611"). Combined with `standaloneVersion` to construct the - // platform-plugin download URLs. - final String pythonBuildReleaseDate; - - final String pyodideVersion; - final String pyodidePlatformTag; - - // When true, this release is supported by `--python-version` but is not - // picked automatically by the default or by `[project].requires-python` - // resolution on the Flet CLI side. Use for beta CPython lines. - final bool prerelease; +// Python runtime version data — `defaultPythonVersion`, `pythonReleases`, the +// `*EnvironmentVariable` names, `dartBridgeVersion`, `pythonReleaseDate` — lives +// in the generated `lib/src/python_versions.dart` (imported above). It is a +// snapshot of python-build's manifest.json; regenerate with +// `dart run serious_python:gen_version_tables`. + +/// Stages the embedded Darwin (iOS/macOS) Python runtime for [shortVersion] by +/// running the plugin's version-aware prepare script through the `.pod` symlink +/// in [sitePackagesRoot]. This is what makes a version switch take effect on a +/// bare rebuild (no `pod install` re-run needed). No-op for non-Darwin platforms, +/// whose native build stages the runtime itself. Returns false if skipped. Used +/// by both the `package` and `configure` commands. +Future stageDarwinRuntime({ + required String platform, + required String shortVersion, + required String sitePackagesRoot, +}) async { + final script = platform == "iOS" + ? "prepare_ios.sh" + : platform == "Darwin" + ? "prepare_macos.sh" + : null; + if (script == null) return false; + final release = pythonReleases[shortVersion]; + if (release == null) { + stderr.writeln("serious_python: unknown Python version '$shortVersion'. " + "Supported: ${pythonReleases.keys.join(", ")}"); + exit(2); + } + final fullVersion = + Platform.environment[pythonFullVersionEnvironmentVariable] ?? + release.standaloneVersion; + final buildDate = Platform.environment[pythonBuildDateEnvironmentVariable] ?? + pythonReleaseDate; + final bridge = Platform.environment[dartBridgeVersionEnvironmentVariable] ?? + dartBridgeVersion; + final sh = File(path.join(sitePackagesRoot, ".pod", script)); + if (!await sh.exists()) { + stdout.writeln("serious_python: $script not found under " + "$sitePackagesRoot/.pod — build the app once so CocoaPods creates the " + "plugin symlink, then re-run."); + return false; + } + stdout.writeln( + "Staging $platform Python $shortVersion (CPython $fullVersion) runtime..."); + final process = await Process.start( + "/bin/sh", [sh.path, shortVersion, fullVersion, buildDate, bridge], + mode: ProcessStartMode.inheritStdio); + final code = await process.exitCode; + if (code != 0) { + stderr.writeln("serious_python: $script failed (exit $code)."); + exit(code); + } + return true; } -// Source of truth for the Python <-> CPython standalone <-> Pyodide mapping. -// Mirror any change here in flet-cli's python_versions.py. -const pythonReleases = { - "3.12": PythonRelease( - standaloneVersion: "3.12.13", - standaloneReleaseDate: "20260610", - pythonBuildReleaseDate: "20260611", - pyodideVersion: "0.27.7", - pyodidePlatformTag: "pyodide-2024.0-wasm32", - prerelease: false, - ), - "3.13": PythonRelease( - standaloneVersion: "3.13.14", - standaloneReleaseDate: "20260610", - pythonBuildReleaseDate: "20260611", - pyodideVersion: "0.29.4", - pyodidePlatformTag: "pyemscripten-2025.0-wasm32", - prerelease: false, - ), - "3.14": PythonRelease( - standaloneVersion: "3.14.6", - standaloneReleaseDate: "20260610", - pythonBuildReleaseDate: "20260611", - pyodideVersion: "314.0.0", - pyodidePlatformTag: "pyemscripten-2026.0-wasm32", - prerelease: false, - ), - // Add future pre-release CPython lines by setting `prerelease: true`. They - // become opt-in via `--python-version 3.15` (or an explicit - // `requires-python = "==3.15.*"` on the Flet CLI side) without becoming - // the default or matching open-ended `requires-python` specifiers. - // - // "3.15": PythonRelease( - // standaloneVersion: "3.15.0", - // standaloneReleaseDate: "...", - // pythonBuildReleaseDate: "...", - // pyodideVersion: "...", - // pyodidePlatformTag: "...", - // prerelease: true, - // ), -}; - const platforms = { "iOS": { "iphoneos.arm64": {"tag": "ios-13.0-arm64-iphoneos", "mac_ver": ""}, @@ -293,9 +273,6 @@ class PackageCommand extends Command { standaloneReleaseDate: Platform.environment[pythonDistReleaseEnvironmentVariable] ?? baseRelease.standaloneReleaseDate, - pythonBuildReleaseDate: - Platform.environment[pythonBuildDateEnvironmentVariable] ?? - baseRelease.pythonBuildReleaseDate, pyodideVersion: Platform.environment[pyodideVersionEnvironmentVariable] ?? baseRelease.pyodideVersion, @@ -574,6 +551,14 @@ class PackageCommand extends Command { _verbose); } + // Stage the embedded Darwin interpreter for the selected version so the + // build uses it without `pod install` having to re-run prepare. + await stageDarwinRuntime( + platform: platform, + shortVersion: _pythonShortVersion, + sitePackagesRoot: sitePackagesRoot, + ); + // synchronize pod var syncSh = File(path.join(sitePackagesRoot, ".pod", "sync_site_packages.sh")); diff --git a/src/serious_python/bin/version_command.dart b/src/serious_python/bin/version_command.dart index 2801316c..1770737b 100644 --- a/src/serious_python/bin/version_command.dart +++ b/src/serious_python/bin/version_command.dart @@ -3,13 +3,12 @@ import 'dart:io'; import 'package:args/command_runner.dart'; import 'package:package_config/package_config.dart'; - -import 'package_command.dart'; +import 'package:serious_python/src/python_versions.dart'; /// `version` subcommand: prints the serious_python package version, the /// default Python version, and the supported-Python matrix sourced from -/// [pythonReleases] in `package_command.dart`. With `--json`, emits a -/// machine-readable document for CI / tooling consumption. +/// [pythonReleases] in the generated `lib/src/python_versions.dart`. With +/// `--json`, emits a machine-readable document for CI / tooling consumption. class VersionCommand extends Command { @override final name = "version"; @@ -34,13 +33,14 @@ class VersionCommand extends Command { if (jsonMode) { final doc = { "serious_python_version": version, + "python_build_release_date": pythonReleaseDate, "default_python_version": defaultPythonVersion, + "dart_bridge_version": dartBridgeVersion, "python_releases": { for (final entry in pythonReleases.entries) entry.key: { "standalone_version": entry.value.standaloneVersion, "standalone_release_date": entry.value.standaloneReleaseDate, - "python_build_release_date": entry.value.pythonBuildReleaseDate, "pyodide_version": entry.value.pyodideVersion, "pyodide_platform_tag": entry.value.pyodidePlatformTag, "prerelease": entry.value.prerelease, diff --git a/src/serious_python/example/run_example/app/app.zip.hash b/src/serious_python/example/run_example/app/app.zip.hash index 615dadf3..9377386a 100644 --- a/src/serious_python/example/run_example/app/app.zip.hash +++ b/src/serious_python/example/run_example/app/app.zip.hash @@ -1 +1 @@ -2b009202b20832851c62f09fd3dc603131d9efa45da27efb94eb21b32da28ed0 \ No newline at end of file +9ad98bb4d417761b6ef015d8603109a1b20c4c20798c41e7fb05c356062c4743 \ No newline at end of file diff --git a/src/serious_python/example/run_example/app/src/main.py b/src/serious_python/example/run_example/app/src/main.py index a08b287d..ddaf0816 100644 --- a/src/serious_python/example/run_example/app/src/main.py +++ b/src/serious_python/example/run_example/app/src/main.py @@ -10,6 +10,18 @@ _imp.extension_suffixes() +# Version probe for the version-switching integration test: when +# PYTHON_VERSION_FILENAME is set, import numpy (a native-extension ABI canary — +# a wrong interpreter for the packaged cp wheels fails this import) and +# write the running interpreter's short version, then exit. +_version_file = os.getenv("PYTHON_VERSION_FILENAME") +if _version_file: + import numpy # noqa: F401 + + with open(_version_file, "w") as _vf: + _vf.write(f"{sys.version_info.major}.{sys.version_info.minor}") + sys.exit(0) + print("HELLO!") print("sys.path:", sys.path) diff --git a/src/serious_python/example/run_example/integration_test/version_test.dart b/src/serious_python/example/run_example/integration_test/version_test.dart new file mode 100644 index 00000000..bfca3b25 --- /dev/null +++ b/src/serious_python/example/run_example/integration_test/version_test.dart @@ -0,0 +1,46 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:path/path.dart' as p; +import 'package:serious_python/serious_python.dart'; + +/// Asserts the embedded Python runtime is the version we asked for. Pass the +/// expected short version via `--dart-define=EXPECTED_PYTHON_VERSION=3.x`. +/// +/// The packaged app (app/src/main.py) imports numpy when `PYTHON_VERSION_FILENAME` +/// is set — a native-extension ABI canary that fails if the bundled interpreter +/// doesn't match the packaged cp wheels — then writes its short version to +/// that file. This is the regression guard for switching Python versions on one +/// machine (see .github/workflows/python-version-switching.yml). +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('embedded Python matches EXPECTED_PYTHON_VERSION', (tester) async { + const expected = String.fromEnvironment('EXPECTED_PYTHON_VERSION'); + expect(expected, isNotEmpty, + reason: 'pass --dart-define=EXPECTED_PYTHON_VERSION=3.x'); + + final tempDir = await Directory.systemTemp.createTemp('version_test'); + final versionFile = p.join(tempDir.path, 'pyversion.txt'); + + unawaited(SeriousPython.run('app/app.zip', + environmentVariables: {'PYTHON_VERSION_FILENAME': versionFile}, + sync: false)); + + String? actual; + for (var i = 0; i < 60; i++) { + await tester.pump(const Duration(seconds: 1)); + final f = File(versionFile); + if (await f.exists()) { + actual = (await f.readAsString()).trim(); + if (actual.isNotEmpty) break; + } + } + + expect(actual, expected, + reason: 'the embedded interpreter (and its numpy wheel) should be the ' + 'requested Python version'); + }); +} diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart new file mode 100644 index 00000000..d4848523 --- /dev/null +++ b/src/serious_python/lib/src/python_versions.dart @@ -0,0 +1,55 @@ +// GENERATED by `dart run serious_python:gen_version_tables` from python-build's +// manifest.json (release 20260614). Do not edit by hand — edit python-build's +// manifest.json, cut a release, bump `pythonReleaseDate`, and regenerate. + +const pythonVersionEnvironmentVariable = "SERIOUS_PYTHON_VERSION"; +const pythonFullVersionEnvironmentVariable = "SERIOUS_PYTHON_FULL_VERSION"; +const pythonDistReleaseEnvironmentVariable = "SERIOUS_PYTHON_DIST_RELEASE"; +const pythonBuildDateEnvironmentVariable = "SERIOUS_PYTHON_BUILD_DATE"; +const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION"; +const dartBridgeVersionEnvironmentVariable = "DART_BRIDGE_VERSION"; + +/// python-build release the bundled runtimes come from (YYYYMMDD). +const pythonReleaseDate = "20260614"; +const dartBridgeVersion = "1.2.3"; +const defaultPythonVersion = "3.14"; + +class PythonRelease { + const PythonRelease({ + required this.standaloneVersion, + required this.standaloneReleaseDate, + required this.pyodideVersion, + required this.pyodidePlatformTag, + required this.prerelease, + }); + + final String standaloneVersion; + final String standaloneReleaseDate; + final String pyodideVersion; + final String pyodidePlatformTag; + final bool prerelease; +} + +const pythonReleases = { + "3.12": PythonRelease( + standaloneVersion: "3.12.13", + standaloneReleaseDate: "20260610", + pyodideVersion: "0.27.7", + pyodidePlatformTag: "pyodide-2024.0-wasm32", + prerelease: false, + ), + "3.13": PythonRelease( + standaloneVersion: "3.13.14", + standaloneReleaseDate: "20260610", + pyodideVersion: "0.29.4", + pyodidePlatformTag: "pyemscripten-2025.0-wasm32", + prerelease: false, + ), + "3.14": PythonRelease( + standaloneVersion: "3.14.6", + standaloneReleaseDate: "20260610", + pyodideVersion: "314.0.0", + pyodidePlatformTag: "pyemscripten-2026.0-wasm32", + prerelease: false, + ), +}; diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle index 69de4cdc..90e2841f 100644 --- a/src/serious_python_android/android/build.gradle +++ b/src/serious_python_android/android/build.gradle @@ -1,10 +1,20 @@ group 'com.flet.serious_python_android' version '2.0.0' -def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: '3.14' -def python_full_version = System.getenv('SERIOUS_PYTHON_FULL_VERSION') ?: '3.14.6' -def python_build_date = System.getenv('SERIOUS_PYTHON_BUILD_DATE') ?: '20260611' -def dart_bridge_version = System.getenv('DART_BRIDGE_VERSION') ?: '1.2.1' +// Python runtime versions come from the generated python_versions.properties +// (a snapshot of python-build's manifest.json — see serious_python's +// `gen_version_tables`). SERIOUS_PYTHON_VERSION selects the version; everything +// else derives from the table. The per-field env vars are escape hatches. +def _pv = new Properties() +file('python_versions.properties').withInputStream { _pv.load(it) } +def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: _pv['default_python_version'] +def python_full_version = System.getenv('SERIOUS_PYTHON_FULL_VERSION') ?: _pv["${python_version}.full_version"] +def python_build_date = System.getenv('SERIOUS_PYTHON_BUILD_DATE') ?: _pv['python_build_release_date'] +def dart_bridge_version = System.getenv('DART_BRIDGE_VERSION') ?: _pv['dart_bridge_version'] +if (python_full_version == null) { + def known = _pv.keySet().findAll { it.endsWith('.full_version') }.collect { it - '.full_version' } + throw new GradleException("serious_python: unknown SERIOUS_PYTHON_VERSION '${python_version}'. Supported: ${known.join(', ')}") +} buildscript { repositories { diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties new file mode 100644 index 00000000..a5458009 --- /dev/null +++ b/src/serious_python_android/android/python_versions.properties @@ -0,0 +1,8 @@ +# GENERATED by `dart run serious_python:gen_version_tables` from +# python-build manifest.json (release 20260614). Do not edit by hand. +default_python_version=3.14 +dart_bridge_version=1.2.3 +python_build_release_date=20260614 +3.12.full_version=3.12.13 +3.13.full_version=3.13.14 +3.14.full_version=3.14.6 diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index bc9e2104..112501d6 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -1,14 +1,14 @@ python_version=${1:?} python_full_version=${2:?} python_build_date=${3:?} +# dart-bridge release (flet-dev/dart-bridge), passed in from the version table. +# The xcframework is abi3 and CPython-version-independent — one binary covers +# all 3.12+ Python versions. +dart_bridge_version=${4:?} script_dir=$(cd "$(dirname "$0")" && pwd -P) dist=$script_dir/dist_ios -# Pinned dart-bridge release (flet-dev/dart-bridge). The xcframework is abi3 and -# version-independent of CPython, so one binary covers all 3.12+ Python versions. -dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} - # Cross-plugin download cache; see prepare_macos.sh for the convention. cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" pb_cache="$cache_root/python-build/v$python_full_version" diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index 8ec84880..706067b0 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -1,14 +1,13 @@ python_version=${1:?} python_full_version=${2:?} python_build_date=${3:?} +# dart-bridge release (flet-dev/dart-bridge), passed in from the version table. +# Same xcframework is reused across iOS and macOS — it carries slices for both. +dart_bridge_version=${4:?} script_dir=$(cd "$(dirname "$0")" && pwd -P) dist=$script_dir/dist_macos -# Pinned dart-bridge release (flet-dev/dart-bridge). Same xcframework is reused -# across iOS and macOS — it carries slices for both. -dart_bridge_version=${DART_BRIDGE_VERSION:-1.2.1} - # Cross-plugin download cache. FLET_CACHE_DIR is the same env var the Android # gradle task + flet build's external tooling already use; ~/.flet/cache is # the shared default. Tarballs land here and survive `flutter clean`. diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties new file mode 100644 index 00000000..a5458009 --- /dev/null +++ b/src/serious_python_darwin/darwin/python_versions.properties @@ -0,0 +1,8 @@ +# GENERATED by `dart run serious_python:gen_version_tables` from +# python-build manifest.json (release 20260614). Do not edit by hand. +default_python_version=3.14 +dart_bridge_version=1.2.3 +python_build_release_date=20260614 +3.12.full_version=3.12.13 +3.13.full_version=3.13.14 +3.14.full_version=3.14.6 diff --git a/src/serious_python_darwin/darwin/serious_python_darwin.podspec b/src/serious_python_darwin/darwin/serious_python_darwin.podspec index 80a9d489..87b75939 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin.podspec +++ b/src/serious_python_darwin/darwin/serious_python_darwin.podspec @@ -32,17 +32,30 @@ Pod::Spec.new do |s| } s.swift_version = '5.0' - python_version = ENV['SERIOUS_PYTHON_VERSION'] || "3.14" - python_full_version = ENV['SERIOUS_PYTHON_FULL_VERSION'] || "3.14.6" - python_build_date = ENV['SERIOUS_PYTHON_BUILD_DATE'] || "20260611" + # Python runtime versions come from the generated python_versions.properties + # (a snapshot of python-build's manifest.json — see serious_python's + # `gen_version_tables`). SERIOUS_PYTHON_VERSION selects the version; the rest + # derive from the table. The per-field env vars are escape hatches. + pv = {} + File.foreach(File.join(__dir__, 'python_versions.properties')) do |line| + line = line.strip + next if line.empty? || line.start_with?('#') + k, v = line.split('=', 2) + pv[k] = v + end + python_version = ENV['SERIOUS_PYTHON_VERSION'] || pv['default_python_version'] + python_full_version = ENV['SERIOUS_PYTHON_FULL_VERSION'] || pv["#{python_version}.full_version"] + python_build_date = ENV['SERIOUS_PYTHON_BUILD_DATE'] || pv['python_build_release_date'] + dart_bridge_version = ENV['DART_BRIDGE_VERSION'] || pv['dart_bridge_version'] + raise "serious_python: unknown SERIOUS_PYTHON_VERSION '#{python_version}'" if python_full_version.nil? dist_ios = "dist_ios" dist_macos = "dist_macos" prepare_command = <<-CMD ./symlink_pod.sh - ./prepare_ios.sh #{python_version} #{python_full_version} #{python_build_date} - ./prepare_macos.sh #{python_version} #{python_full_version} #{python_build_date} + ./prepare_ios.sh #{python_version} #{python_full_version} #{python_build_date} #{dart_bridge_version} + ./prepare_macos.sh #{python_version} #{python_full_version} #{python_build_date} #{dart_bridge_version} ./sync_site_packages.sh CMD diff --git a/src/serious_python_linux/linux/CMakeLists.txt b/src/serious_python_linux/linux/CMakeLists.txt index 877da21b..a7e27c3d 100644 --- a/src/serious_python_linux/linux/CMakeLists.txt +++ b/src/serious_python_linux/linux/CMakeLists.txt @@ -8,26 +8,45 @@ cmake_minimum_required(VERSION 3.10) # Project-level configuration. set(PROJECT_NAME "serious_python_linux") +# Python runtime versions come from the generated python_versions.properties +# (a snapshot of python-build's manifest.json — see serious_python's +# gen_version_tables). SERIOUS_PYTHON_VERSION selects the version; the rest +# derive from the table. The per-field env vars are escape hatches. +set(_PV_FILE "${CMAKE_CURRENT_LIST_DIR}/python_versions.properties") +function(pv_get key out) + string(REPLACE "." "\\." _re "${key}") + file(STRINGS "${_PV_FILE}" _m REGEX "^${_re}=") + if(_m) + string(REGEX REPLACE "^[^=]*=" "" _v "${_m}") + set(${out} "${_v}" PARENT_SCOPE) + else() + set(${out} "" PARENT_SCOPE) + endif() +endfunction() + if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) set(PYTHON_VERSION "$ENV{SERIOUS_PYTHON_VERSION}") else() - set(PYTHON_VERSION "3.14") + pv_get("default_python_version" PYTHON_VERSION) endif() if(DEFINED ENV{SERIOUS_PYTHON_FULL_VERSION}) set(PYTHON_FULL_VERSION "$ENV{SERIOUS_PYTHON_FULL_VERSION}") else() - set(PYTHON_FULL_VERSION "3.14.6") + pv_get("${PYTHON_VERSION}.full_version" PYTHON_FULL_VERSION) endif() if(DEFINED ENV{SERIOUS_PYTHON_BUILD_DATE}) set(PYTHON_BUILD_DATE "$ENV{SERIOUS_PYTHON_BUILD_DATE}") else() - set(PYTHON_BUILD_DATE "20260611") + pv_get("python_build_release_date" PYTHON_BUILD_DATE) endif() set(PYTHON_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) if(DEFINED ENV{DART_BRIDGE_VERSION}) set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") else() - set(DART_BRIDGE_VERSION "1.2.3") + pv_get("dart_bridge_version" DART_BRIDGE_VERSION) +endif() +if(PYTHON_FULL_VERSION STREQUAL "") + message(FATAL_ERROR "serious_python: unknown SERIOUS_PYTHON_VERSION '${PYTHON_VERSION}'") endif() # Cross-plugin download cache. FLET_CACHE_DIR is the same env var used by the diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties new file mode 100644 index 00000000..a5458009 --- /dev/null +++ b/src/serious_python_linux/linux/python_versions.properties @@ -0,0 +1,8 @@ +# GENERATED by `dart run serious_python:gen_version_tables` from +# python-build manifest.json (release 20260614). Do not edit by hand. +default_python_version=3.14 +dart_bridge_version=1.2.3 +python_build_release_date=20260614 +3.12.full_version=3.12.13 +3.13.full_version=3.13.14 +3.14.full_version=3.14.6 diff --git a/src/serious_python_windows/windows/CMakeLists.txt b/src/serious_python_windows/windows/CMakeLists.txt index dd1efe6c..274b83d4 100644 --- a/src/serious_python_windows/windows/CMakeLists.txt +++ b/src/serious_python_windows/windows/CMakeLists.txt @@ -6,26 +6,45 @@ cmake_minimum_required(VERSION 3.14) # Project-level configuration. set(PROJECT_NAME "serious_python_windows") +# Python runtime versions come from the generated python_versions.properties +# (a snapshot of python-build's manifest.json — see serious_python's +# gen_version_tables). SERIOUS_PYTHON_VERSION selects the version; the rest +# derive from the table. The per-field env vars are escape hatches. +set(_PV_FILE "${CMAKE_CURRENT_LIST_DIR}/python_versions.properties") +function(pv_get key out) + string(REPLACE "." "\\." _re "${key}") + file(STRINGS "${_PV_FILE}" _m REGEX "^${_re}=") + if(_m) + string(REGEX REPLACE "^[^=]*=" "" _v "${_m}") + set(${out} "${_v}" PARENT_SCOPE) + else() + set(${out} "" PARENT_SCOPE) + endif() +endfunction() + if(DEFINED ENV{SERIOUS_PYTHON_VERSION}) set(PYTHON_VERSION "$ENV{SERIOUS_PYTHON_VERSION}") else() - set(PYTHON_VERSION "3.14") + pv_get("default_python_version" PYTHON_VERSION) endif() if(DEFINED ENV{SERIOUS_PYTHON_FULL_VERSION}) set(PYTHON_FULL_VERSION "$ENV{SERIOUS_PYTHON_FULL_VERSION}") else() - set(PYTHON_FULL_VERSION "3.14.6") + pv_get("${PYTHON_VERSION}.full_version" PYTHON_FULL_VERSION) endif() if(DEFINED ENV{SERIOUS_PYTHON_BUILD_DATE}) set(PYTHON_BUILD_DATE "$ENV{SERIOUS_PYTHON_BUILD_DATE}") else() - set(PYTHON_BUILD_DATE "20260611") + pv_get("python_build_release_date" PYTHON_BUILD_DATE) +endif() +if(PYTHON_FULL_VERSION STREQUAL "") + message(FATAL_ERROR "serious_python: unknown SERIOUS_PYTHON_VERSION '${PYTHON_VERSION}'") endif() string(REPLACE "." "" PYTHON_VERSION_NODOT "${PYTHON_VERSION}") if(DEFINED ENV{DART_BRIDGE_VERSION}) set(DART_BRIDGE_VERSION "$ENV{DART_BRIDGE_VERSION}") else() - set(DART_BRIDGE_VERSION "1.2.1") + pv_get("dart_bridge_version" DART_BRIDGE_VERSION) endif() # Cross-plugin download cache. FLET_CACHE_DIR is the same env var used by the diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties new file mode 100644 index 00000000..a5458009 --- /dev/null +++ b/src/serious_python_windows/windows/python_versions.properties @@ -0,0 +1,8 @@ +# GENERATED by `dart run serious_python:gen_version_tables` from +# python-build manifest.json (release 20260614). Do not edit by hand. +default_python_version=3.14 +dart_bridge_version=1.2.3 +python_build_release_date=20260614 +3.12.full_version=3.12.13 +3.13.full_version=3.13.14 +3.14.full_version=3.14.6 From 0e50c205840975dda02da540ca6051e3b98a97af Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sun, 14 Jun 2026 14:38:02 -0700 Subject: [PATCH 105/114] Upgrade to Flutter 3.44.2 across the repo Bump the pinned Flutter to 3.44.2 (.fvmrc) and address the breaking changes: - Regenerate all four example apps (bridge/flask/run/flet) to the genuine 3.44.2 template across android/ios/macos/linux/windows: Kotlin DSL Gradle (build.gradle.kts/settings.gradle.kts) with built-in kotlin-android, AGP 8.x, SceneDelegate, the new linux/runner layout, and regenerated Podfiles. - serious_python_android: AGP 7.3.0 -> 8.11.1, gradle-download-task 4.1.2 -> 5.6.0, compileSdk 31 -> 36, Java 8 -> 17. - Replace the removed android.bundle.enableUncompressedNativeLibs with useLegacyPackaging + keepDebugSymbols; drop the NDK pin (use flutter.ndkVersion). - Podfiles: restore use_modular_headers! (required for the static serious_python_darwin framework to link); app-sandbox disabled in profiles. - prepare_ios.sh/prepare_macos.sh: version-aware dist extraction guard (a stale dist_* from a previous Python version caused C-extension ABI "unknown slot ID" errors); re-extract when the version marker mismatches. - Update example READMEs (package commands, Kotlin-DSL packaging guidance); ignore .fvm/. --- .fvmrc | 4 +- .gitignore | 5 +- .../example/bridge_example/.metadata | 26 +-- .../example/bridge_example/README.md | 2 +- .../android/app/build.gradle.kts | 15 +- .../bridge_example/android/gradle.properties | 4 + .../android/settings.gradle.kts | 2 + .../example/bridge_example/ios/Podfile.lock | 23 +++ .../ios/Runner.xcodeproj/project.pbxproj | 154 +++++++++++++++ .../xcshareddata/xcschemes/Runner.xcscheme | 18 ++ .../contents.xcworkspacedata | 3 + .../macos/Runner/DebugProfile.entitlements | 2 +- .../macos/Runner/Release.entitlements | 2 +- .../example/flask_example/.gitignore | 2 + .../example/flask_example/.metadata | 22 ++- .../example/flask_example/README.md | 36 ++-- .../example/flask_example/android/.gitignore | 4 +- .../flask_example/android/app/build.gradle | 72 ------- .../android/app/build.gradle.kts | 63 ++++++ .../android/app/src/main/AndroidManifest.xml | 15 +- .../com/example/flask_example/MainActivity.kt | 3 +- .../flask_example/android/build.gradle | 31 --- .../flask_example/android/build.gradle.kts | 24 +++ .../flask_example/android/gradle.properties | 8 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../flask_example/android/settings.gradle | 11 -- .../flask_example/android/settings.gradle.kts | 28 +++ .../example/flask_example/app/app.zip.hash | 2 +- .../ios/Flutter/AppFrameworkInfo.plist | 2 - .../example/flask_example/ios/Podfile | 2 +- .../example/flask_example/ios/Podfile.lock | 23 +-- .../ios/Runner.xcodeproj/project.pbxproj | 179 +++++++++-------- .../xcshareddata/xcschemes/Runner.xcscheme | 5 +- .../ios/Runner/AppDelegate.swift | 11 +- .../flask_example/ios/Runner/Info.plist | 31 ++- .../ios/Runner/SceneDelegate.swift | 6 + .../flask_example/linux/CMakeLists.txt | 29 +-- .../linux/flutter/generated_plugins.cmake | 1 + .../flask_example/linux/runner/CMakeLists.txt | 26 +++ .../flask_example/linux/{ => runner}/main.cc | 0 .../linux/{ => runner}/my_application.cc | 64 +++++- .../linux/{ => runner}/my_application.h | 5 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 - .../example/flask_example/macos/Podfile.lock | 19 +- .../macos/Runner.xcodeproj/project.pbxproj | 128 +++++++----- .../xcshareddata/xcschemes/Runner.xcscheme | 3 +- .../macos/Runner/AppDelegate.swift | 6 +- .../macos/Runner/Configs/AppInfo.xcconfig | 2 +- .../macos/RunnerTests/RunnerTests.swift | 2 +- .../example/flask_example/pubspec.lock | 172 +++++++++++----- .../flask_example/windows/CMakeLists.txt | 6 + .../windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/generated_plugins.cmake | 1 + .../flask_example/windows/runner/Runner.rc | 2 +- .../windows/runner/runner.exe.manifest | 6 - .../flask_example/windows/runner/utils.cpp | 4 +- .../example/flet_example/.metadata | 25 ++- .../example/flet_example/android/.gitignore | 2 +- .../app/{build.gradle => build.gradle.kts} | 26 +-- .../com/example/flet_example/MainActivity.kt | 2 +- .../example/flet_example/android/build.gradle | 18 -- .../flet_example/android/build.gradle.kts | 24 +++ .../flet_example/android/gradle.properties | 3 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../flet_example/android/settings.gradle | 30 --- .../flet_example/android/settings.gradle.kts | 29 +++ .../ios/Flutter/AppFrameworkInfo.plist | 2 - .../example/flet_example/ios/Podfile | 2 +- .../example/flet_example/ios/Podfile.lock | 114 ----------- .../ios/Runner.xcodeproj/project.pbxproj | 132 ++----------- .../xcshareddata/xcschemes/Runner.xcscheme | 3 + .../contents.xcworkspacedata | 3 - .../flet_example/ios/Runner/AppDelegate.swift | 9 +- .../flet_example/ios/Runner/Info.plist | 31 ++- .../ios/Runner/SceneDelegate.swift | 6 + .../example/flet_example/linux/CMakeLists.txt | 42 +--- .../flet_example/linux/runner/CMakeLists.txt | 26 +++ .../flet_example/linux/{ => runner}/main.cc | 0 .../linux/{ => runner}/my_application.cc | 64 +++++- .../linux/runner}/my_application.h | 5 +- .../example/flet_example/macos/Podfile.lock | 108 ---------- .../macos/Runner.xcodeproj/project.pbxproj | 126 ++---------- .../contents.xcworkspacedata | 3 - .../macos/Runner/Configs/AppInfo.xcconfig | 2 +- .../macos/RunnerTests/RunnerTests.swift | 2 +- .../example/flet_example/pubspec.lock | 24 +-- .../example/flet_example/web/index.html | 33 +--- .../flet_example/windows/CMakeLists.txt | 6 + .../flet_example/windows/runner/Runner.rc | 2 +- .../windows/runner/runner.exe.manifest | 6 - .../flet_example/windows/runner/utils.cpp | 4 +- .../example/run_example/.metadata | 26 +-- .../example/run_example/README.md | 26 +-- .../example/run_example/android/.gitignore | 4 +- .../run_example/android/app/build.gradle | 76 -------- .../run_example/android/app/build.gradle.kts | 62 ++++++ .../android/app/src/main/AndroidManifest.xml | 12 ++ .../com/example/run_example/MainActivity.kt | 3 +- .../example/run_example/android/build.gradle | 30 --- .../run_example/android/build.gradle.kts | 24 +++ .../run_example/android/gradle.properties | 7 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../run_example/android/settings.gradle | 29 --- .../run_example/android/settings.gradle.kts | 28 +++ .../ios/Flutter/AppFrameworkInfo.plist | 2 - .../example/run_example/ios/Podfile | 2 +- .../example/run_example/ios/Podfile.lock | 21 +- .../ios/Runner.xcodeproj/project.pbxproj | 184 +++++++++++------- .../xcshareddata/xcschemes/Runner.xcscheme | 21 ++ .../run_example/ios/Runner/AppDelegate.swift | 9 +- .../example/run_example/ios/Runner/Info.plist | 29 ++- .../ios/Runner/SceneDelegate.swift | 6 + .../example/run_example/linux/CMakeLists.txt | 29 +-- .../linux/flutter/generated_plugins.cmake | 1 + .../run_example/linux/runner/CMakeLists.txt | 26 +++ .../run_example/linux/{ => runner}/main.cc | 0 .../linux/{ => runner}/my_application.cc | 64 +++++- .../linux/runner}/my_application.h | 5 +- .../Flutter/GeneratedPluginRegistrant.swift | 2 - .../example/run_example/macos/Podfile.lock | 13 +- .../macos/Runner.xcodeproj/project.pbxproj | 130 ++++++++----- .../macos/Runner/Configs/AppInfo.xcconfig | 2 +- .../macos/Runner/DebugProfile.entitlements | 18 +- .../macos/Runner/Release.entitlements | 10 +- .../macos/RunnerTests/RunnerTests.swift | 2 +- .../example/run_example/pubspec.lock | 176 ++++++++++++----- .../run_example/windows/CMakeLists.txt | 6 + .../windows/flutter/generated_plugins.cmake | 1 + .../run_example/windows/runner/Runner.rc | 2 +- .../windows/runner/runner.exe.manifest | 6 - .../run_example/windows/runner/utils.cpp | 4 +- .../android/build.gradle | 10 +- .../darwin/prepare_ios.sh | 10 +- .../darwin/prepare_macos.sh | 10 +- 134 files changed, 1870 insertions(+), 1503 deletions(-) create mode 100644 src/serious_python/example/bridge_example/ios/Podfile.lock delete mode 100644 src/serious_python/example/flask_example/android/app/build.gradle create mode 100644 src/serious_python/example/flask_example/android/app/build.gradle.kts delete mode 100644 src/serious_python/example/flask_example/android/build.gradle create mode 100644 src/serious_python/example/flask_example/android/build.gradle.kts delete mode 100644 src/serious_python/example/flask_example/android/settings.gradle create mode 100644 src/serious_python/example/flask_example/android/settings.gradle.kts create mode 100644 src/serious_python/example/flask_example/ios/Runner/SceneDelegate.swift create mode 100644 src/serious_python/example/flask_example/linux/runner/CMakeLists.txt rename src/serious_python/example/flask_example/linux/{ => runner}/main.cc (100%) rename src/serious_python/example/flask_example/linux/{ => runner}/my_application.cc (59%) rename src/serious_python/example/flask_example/linux/{ => runner}/my_application.h (70%) rename src/serious_python/example/flet_example/android/app/{build.gradle => build.gradle.kts} (64%) delete mode 100644 src/serious_python/example/flet_example/android/build.gradle create mode 100644 src/serious_python/example/flet_example/android/build.gradle.kts delete mode 100644 src/serious_python/example/flet_example/android/settings.gradle create mode 100644 src/serious_python/example/flet_example/android/settings.gradle.kts delete mode 100644 src/serious_python/example/flet_example/ios/Podfile.lock create mode 100644 src/serious_python/example/flet_example/ios/Runner/SceneDelegate.swift create mode 100644 src/serious_python/example/flet_example/linux/runner/CMakeLists.txt rename src/serious_python/example/flet_example/linux/{ => runner}/main.cc (100%) rename src/serious_python/example/flet_example/linux/{ => runner}/my_application.cc (59%) rename src/serious_python/example/{run_example/linux => flet_example/linux/runner}/my_application.h (70%) delete mode 100644 src/serious_python/example/flet_example/macos/Podfile.lock delete mode 100644 src/serious_python/example/run_example/android/app/build.gradle create mode 100644 src/serious_python/example/run_example/android/app/build.gradle.kts delete mode 100644 src/serious_python/example/run_example/android/build.gradle create mode 100644 src/serious_python/example/run_example/android/build.gradle.kts delete mode 100644 src/serious_python/example/run_example/android/settings.gradle create mode 100644 src/serious_python/example/run_example/android/settings.gradle.kts create mode 100644 src/serious_python/example/run_example/ios/Runner/SceneDelegate.swift create mode 100644 src/serious_python/example/run_example/linux/runner/CMakeLists.txt rename src/serious_python/example/run_example/linux/{ => runner}/main.cc (100%) rename src/serious_python/example/run_example/linux/{ => runner}/my_application.cc (59%) rename src/serious_python/example/{flet_example/linux => run_example/linux/runner}/my_application.h (70%) diff --git a/.fvmrc b/.fvmrc index 94d87f34..afd20432 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.41.7" -} + "flutter": "3.44.2" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index d74c253c..47c84825 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,7 @@ __pypackages__/ *.dylib *.dll *.egg-info/ -*.egg/ \ No newline at end of file +*.egg/ + +# FVM +.fvm/ diff --git a/src/serious_python/example/bridge_example/.metadata b/src/serious_python/example/bridge_example/.metadata index 814a9dca..d3f20b97 100644 --- a/src/serious_python/example/bridge_example/.metadata +++ b/src/serious_python/example/bridge_example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "cc0734ac716fbb8b90f3f9db8020958b1553afa7" + revision: "c9a6c484230f8b5e408ec57be1ef71dee1e77020" channel: "stable" project_type: app @@ -13,23 +13,23 @@ project_type: app migration: platforms: - platform: root - create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 - base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: android - create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 - base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: ios - create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 - base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: linux - create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 - base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: macos - create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 - base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: windows - create_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 - base_revision: cc0734ac716fbb8b90f3f9db8020958b1553afa7 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 # User provided section diff --git a/src/serious_python/example/bridge_example/README.md b/src/serious_python/example/bridge_example/README.md index 9acff260..3d045880 100644 --- a/src/serious_python/example/bridge_example/README.md +++ b/src/serious_python/example/bridge_example/README.md @@ -62,7 +62,7 @@ flutter test integration_test/interactivity_test.dart -d macos \ | Hardware | MacBook Pro M2 Pro, 32 GB | | OS | macOS 26.5 | | Python | CPython 3.14.6 (embedded via `libdart_bridge`) | -| Flutter | 3.41.7, Debug build | +| Flutter | 3.44.2, Debug build | | Test harness | `bridge_example/integration_test/` (`flutter test integration_test`) | ## Throughput diff --git a/src/serious_python/example/bridge_example/android/app/build.gradle.kts b/src/serious_python/example/bridge_example/android/app/build.gradle.kts index 509ae797..169d8b4b 100644 --- a/src/serious_python/example/bridge_example/android/app/build.gradle.kts +++ b/src/serious_python/example/bridge_example/android/app/build.gradle.kts @@ -1,7 +1,8 @@ plugins { id("com.android.application") - id("kotlin-android") - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + // Kotlin is provided by the Flutter Gradle Plugin (Built-in Kotlin), so the + // app no longer applies the Kotlin Gradle Plugin itself. + // The Flutter Gradle Plugin must be applied after the Android Gradle plugin. id("dev.flutter.flutter-gradle-plugin") } @@ -15,10 +16,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.flet.serious_python_bridge_example" @@ -39,6 +36,12 @@ android { } } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + flutter { source = "../.." } diff --git a/src/serious_python/example/bridge_example/android/gradle.properties b/src/serious_python/example/bridge_example/android/gradle.properties index fbee1d8c..d5da7278 100644 --- a/src/serious_python/example/bridge_example/android/gradle.properties +++ b/src/serious_python/example/bridge_example/android/gradle.properties @@ -1,2 +1,6 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/src/serious_python/example/bridge_example/android/settings.gradle.kts b/src/serious_python/example/bridge_example/android/settings.gradle.kts index ca7fe065..ca1f8f00 100644 --- a/src/serious_python/example/bridge_example/android/settings.gradle.kts +++ b/src/serious_python/example/bridge_example/android/settings.gradle.kts @@ -20,6 +20,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.11.1" apply false + // Declared (but not applied) so Built-in Kotlin — where the Flutter Gradle + // Plugin applies kotlin-android for us — uses this KGP version. id("org.jetbrains.kotlin.android") version "2.2.20" apply false } diff --git a/src/serious_python/example/bridge_example/ios/Podfile.lock b/src/serious_python/example/bridge_example/ios/Podfile.lock new file mode 100644 index 00000000..3542b7d0 --- /dev/null +++ b/src/serious_python/example/bridge_example/ios/Podfile.lock @@ -0,0 +1,23 @@ +PODS: + - Flutter (1.0.0) + - serious_python_darwin (2.0.0): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - serious_python_darwin (from `.symlinks/plugins/serious_python_darwin/darwin`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + serious_python_darwin: + :path: ".symlinks/plugins/serious_python_darwin/darwin" + +SPEC CHECKSUMS: + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 + +PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e + +COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.pbxproj index 13de7c7d..42b493f2 100644 --- a/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/project.pbxproj @@ -8,13 +8,16 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 322065C92ECD18A3C98F2E11 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AEAC0F331ED26F69BB615515 /* Pods_Runner.framework */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + BB71784870DB16DD1FC6B8E4 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D718E008AC07AD742D1D5F2A /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -41,6 +44,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0EA787A14BD0ED9CFE9C064B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; @@ -49,7 +53,9 @@ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 848FDA6EB4378C354BE9F993 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -57,6 +63,12 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AEAC0F331ED26F69BB615515 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B74C01FE66DFA70A7798AE72 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + BCF5E9006721CF8B1D8B3154 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + D718E008AC07AD742D1D5F2A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DA8C113A8CD3D0382C92CA01 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F334390AF67B5D9F075A9A9B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -64,6 +76,16 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + 322065C92ECD18A3C98F2E11 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BA6E6CB399860768894B99C0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BB71784870DB16DD1FC6B8E4 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -78,9 +100,24 @@ path = RunnerTests; sourceTree = ""; }; + 40476432BF971A28FA9657B8 /* Pods */ = { + isa = PBXGroup; + children = ( + 0EA787A14BD0ED9CFE9C064B /* Pods-Runner.debug.xcconfig */, + DA8C113A8CD3D0382C92CA01 /* Pods-Runner.release.xcconfig */, + F334390AF67B5D9F075A9A9B /* Pods-Runner.profile.xcconfig */, + 848FDA6EB4378C354BE9F993 /* Pods-RunnerTests.debug.xcconfig */, + BCF5E9006721CF8B1D8B3154 /* Pods-RunnerTests.release.xcconfig */, + B74C01FE66DFA70A7798AE72 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -96,6 +133,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 40476432BF971A28FA9657B8 /* Pods */, + D9D3ED68A64296A2A76B395E /* Frameworks */, ); sourceTree = ""; }; @@ -124,6 +163,15 @@ path = Runner; sourceTree = ""; }; + D9D3ED68A64296A2A76B395E /* Frameworks */ = { + isa = PBXGroup; + children = ( + AEAC0F331ED26F69BB615515 /* Pods_Runner.framework */, + D718E008AC07AD742D1D5F2A /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -131,8 +179,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + F3B1F0D1E68C4E672BCDCEAA /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + BA6E6CB399860768894B99C0 /* Frameworks */, ); buildRules = ( ); @@ -148,18 +198,24 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 72D7BF28028CDE740A51BCA6 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + B2C65F2690B6BBEF6E20F674 /* [CP] Embed Pods Frameworks */, + 1D3A8F88F6DC96CBAD5977F8 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -193,6 +249,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -225,6 +284,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 1D3A8F88F6DC96CBAD5977F8 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -241,6 +317,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 72D7BF28028CDE740A51BCA6 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -256,6 +354,45 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + B2C65F2690B6BBEF6E20F674 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + F3B1F0D1E68C4E672BCDCEAA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -382,6 +519,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 848FDA6EB4378C354BE9F993 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -399,6 +537,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BCF5E9006721CF8B1D8B3154 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -414,6 +553,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B74C01FE66DFA70A7798AE72 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -615,6 +755,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e3773d42..c3fedb29 100644 --- a/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/src/serious_python/example/bridge_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + + + diff --git a/src/serious_python/example/bridge_example/macos/Runner/DebugProfile.entitlements b/src/serious_python/example/bridge_example/macos/Runner/DebugProfile.entitlements index dddb8a30..9f56413f 100644 --- a/src/serious_python/example/bridge_example/macos/Runner/DebugProfile.entitlements +++ b/src/serious_python/example/bridge_example/macos/Runner/DebugProfile.entitlements @@ -3,7 +3,7 @@ com.apple.security.app-sandbox - + com.apple.security.cs.allow-jit com.apple.security.network.server diff --git a/src/serious_python/example/bridge_example/macos/Runner/Release.entitlements b/src/serious_python/example/bridge_example/macos/Runner/Release.entitlements index 852fa1a4..e89b7f32 100644 --- a/src/serious_python/example/bridge_example/macos/Runner/Release.entitlements +++ b/src/serious_python/example/bridge_example/macos/Runner/Release.entitlements @@ -3,6 +3,6 @@ com.apple.security.app-sandbox - + diff --git a/src/serious_python/example/flask_example/.gitignore b/src/serious_python/example/flask_example/.gitignore index 3efbe6a0..4be25775 100644 --- a/src/serious_python/example/flask_example/.gitignore +++ b/src/serious_python/example/flask_example/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/src/serious_python/example/flask_example/.metadata b/src/serious_python/example/flask_example/.metadata index 82c76b0e..d3f20b97 100644 --- a/src/serious_python/example/flask_example/.metadata +++ b/src/serious_python/example/flask_example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e" + revision: "c9a6c484230f8b5e408ec57be1ef71dee1e77020" channel: "stable" project_type: app @@ -13,11 +13,23 @@ project_type: app migration: platforms: - platform: root - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: android + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: ios + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: linux - create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e - base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: macos + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: windows + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 # User provided section diff --git a/src/serious_python/example/flask_example/README.md b/src/serious_python/example/flask_example/README.md index 831d854b..ac573f01 100644 --- a/src/serious_python/example/flask_example/README.md +++ b/src/serious_python/example/flask_example/README.md @@ -6,42 +6,52 @@ For Android: ``` export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages -dart run serious_python:main package app/src -p Android --requirements -r,app/src/requirements.txt +dart run serious_python:main package app/src -p Android -r -r -r app/src/requirements.txt ``` For iOS: ``` export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages -dart run serious_python:main package app/src -p iOS --requirements -r,app/src/requirements.txt +dart run serious_python:main package app/src -p iOS -r -r -r app/src/requirements.txt ``` For macOS: ``` -dart run serious_python:main package app/src -p Darwin --requirements -r,app/src/requirements.txt +export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages +dart run serious_python:main package app/src -p Darwin -r -r -r app/src/requirements.txt ``` For Windows: ``` -dart run serious_python:main package app/src -p Windows --requirements -r,app/src/requirements.txt +export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages +dart run serious_python:main package app/src -p Windows -r -r -r app/src/requirements.txt ``` For Linux: ``` -dart run serious_python:main package app/src -p Linux --requirements -r,app/src/requirements.txt +export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages +dart run serious_python:main package app/src -p Linux -r -r -r app/src/requirements.txt ``` -Important: to make `serious_python` work in your own Android app: +Important: to make `serious_python` work in your own Android app, the bundled +`libpython*.so` must be shipped uncompressed and extracted so the embedded +interpreter can `dlopen` them at runtime. In `android/app/build.gradle.kts`: -If you build an App Bundle Edit `android/gradle.properties` and add the flag: - -``` -android.bundle.enableUncompressedNativeLibs=false +```kotlin +android { + packaging { + jniLibs { + useLegacyPackaging = true + } + } +} ``` -If you build an APK Make sure `android/app/src/AndroidManifest.xml` has `android:extractNativeLibs="true"` in the `` tag. - -For more information, see the [public issue](https://issuetracker.google.com/issues/147096055). \ No newline at end of file +`useLegacyPackaging = true` is the modern replacement (AGP 8.1+) for both the +old `android.bundle.enableUncompressedNativeLibs=false` gradle property and the +`android:extractNativeLibs="true"` manifest attribute, and it covers both APK and +App Bundle builds. See the [public issue](https://issuetracker.google.com/issues/147096055). \ No newline at end of file diff --git a/src/serious_python/example/flask_example/android/.gitignore b/src/serious_python/example/flask_example/android/.gitignore index b776a2ff..be3943c9 100644 --- a/src/serious_python/example/flask_example/android/.gitignore +++ b/src/serious_python/example/flask_example/android/.gitignore @@ -5,10 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java -**/.cxx/ +.cxx/ # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/src/serious_python/example/flask_example/android/app/build.gradle b/src/serious_python/example/flask_example/android/app/build.gradle deleted file mode 100644 index 7dd8667f..00000000 --- a/src/serious_python/example/flask_example/android/app/build.gradle +++ /dev/null @@ -1,72 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - namespace "com.example.flask_example" - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.flask_example" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/src/serious_python/example/flask_example/android/app/build.gradle.kts b/src/serious_python/example/flask_example/android/app/build.gradle.kts new file mode 100644 index 00000000..465b665a --- /dev/null +++ b/src/serious_python/example/flask_example/android/app/build.gradle.kts @@ -0,0 +1,63 @@ +plugins { + id("com.android.application") + // Kotlin is provided by the Flutter Gradle Plugin (Built-in Kotlin), so the + // app no longer applies the Kotlin Gradle Plugin itself. + // The Flutter Gradle Plugin must be applied after the Android Gradle plugin. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.flask_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + // serious_python bundles libpython*.so. Use legacy (extracted, uncompressed) + // packaging so the embedded interpreter can dlopen them at runtime, and keep + // their symbols so they are not stripped. (Replaces the removed + // android.bundle.enableUncompressedNativeLibs flag.) + packaging { + jniLibs { + useLegacyPackaging = true + keepDebugSymbols += setOf( + "*/arm64-v8a/libpython*.so", + "*/armeabi-v7a/libpython*.so", + "*/x86/libpython*.so", + "*/x86_64/libpython*.so", + ) + } + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.flask_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + +flutter { + source = "../.." +} diff --git a/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml index ea56d134..9658760c 100644 --- a/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml +++ b/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml @@ -2,12 +2,12 @@ + android:icon="@mipmap/ic_launcher"> + + + + + + + diff --git a/src/serious_python/example/flask_example/android/app/src/main/kotlin/com/example/flask_example/MainActivity.kt b/src/serious_python/example/flask_example/android/app/src/main/kotlin/com/example/flask_example/MainActivity.kt index b2780adc..6ef2d40c 100644 --- a/src/serious_python/example/flask_example/android/app/src/main/kotlin/com/example/flask_example/MainActivity.kt +++ b/src/serious_python/example/flask_example/android/app/src/main/kotlin/com/example/flask_example/MainActivity.kt @@ -2,5 +2,4 @@ package com.example.flask_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { -} +class MainActivity : FlutterActivity() diff --git a/src/serious_python/example/flask_example/android/build.gradle b/src/serious_python/example/flask_example/android/build.gradle deleted file mode 100644 index f7eb7f63..00000000 --- a/src/serious_python/example/flask_example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/src/serious_python/example/flask_example/android/build.gradle.kts b/src/serious_python/example/flask_example/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/src/serious_python/example/flask_example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/src/serious_python/example/flask_example/android/gradle.properties b/src/serious_python/example/flask_example/android/gradle.properties index 4efbcd2b..d5da7278 100644 --- a/src/serious_python/example/flask_example/android/gradle.properties +++ b/src/serious_python/example/flask_example/android/gradle.properties @@ -1,4 +1,6 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true -android.enableJetifier=true -android.bundle.enableUncompressedNativeLibs=false \ No newline at end of file +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/src/serious_python/example/flask_example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/flask_example/android/gradle/wrapper/gradle-wrapper.properties index 3c472b99..e4ef43fb 100644 --- a/src/serious_python/example/flask_example/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/serious_python/example/flask_example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/src/serious_python/example/flask_example/android/settings.gradle b/src/serious_python/example/flask_example/android/settings.gradle deleted file mode 100644 index 44e62bcf..00000000 --- a/src/serious_python/example/flask_example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/src/serious_python/example/flask_example/android/settings.gradle.kts b/src/serious_python/example/flask_example/android/settings.gradle.kts new file mode 100644 index 00000000..ca1f8f00 --- /dev/null +++ b/src/serious_python/example/flask_example/android/settings.gradle.kts @@ -0,0 +1,28 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.11.1" apply false + // Declared (but not applied) so Built-in Kotlin — where the Flutter Gradle + // Plugin applies kotlin-android for us — uses this KGP version. + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/src/serious_python/example/flask_example/app/app.zip.hash b/src/serious_python/example/flask_example/app/app.zip.hash index 7099c3a9..d9d7e40e 100644 --- a/src/serious_python/example/flask_example/app/app.zip.hash +++ b/src/serious_python/example/flask_example/app/app.zip.hash @@ -1 +1 @@ -9abed4a7d914300e2cf342c04e7dfcf58a5dbda44fc93a99a86b0e8831207840 \ No newline at end of file +0a2b6372a4750525b5a93b7133028630a33e24134d59fae37d2950c8076a7a1f \ No newline at end of file diff --git a/src/serious_python/example/flask_example/ios/Flutter/AppFrameworkInfo.plist b/src/serious_python/example/flask_example/ios/Flutter/AppFrameworkInfo.plist index 9625e105..391a902b 100644 --- a/src/serious_python/example/flask_example/ios/Flutter/AppFrameworkInfo.plist +++ b/src/serious_python/example/flask_example/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 11.0 diff --git a/src/serious_python/example/flask_example/ios/Podfile b/src/serious_python/example/flask_example/ios/Podfile index 164df534..e51a31d9 100644 --- a/src/serious_python/example/flask_example/ios/Podfile +++ b/src/serious_python/example/flask_example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/src/serious_python/example/flask_example/ios/Podfile.lock b/src/serious_python/example/flask_example/ios/Podfile.lock index 60902061..9bae2c46 100644 --- a/src/serious_python/example/flask_example/ios/Podfile.lock +++ b/src/serious_python/example/flask_example/ios/Podfile.lock @@ -1,36 +1,23 @@ PODS: - Flutter (1.0.0) - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - serious_python_darwin (0.6.0): + - serious_python_darwin (2.0.0): - Flutter - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - serious_python_darwin (from `.symlinks/plugins/serious_python_darwin/darwin`) EXTERNAL SOURCES: Flutter: :path: Flutter - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" serious_python_darwin: :path: ".symlinks/plugins/serious_python_darwin/darwin" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 - serious_python_darwin: d5c85ae2cd4539b52c71ea8ba8af357aa6311647 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 -PODFILE CHECKSUM: 7be2f5f74864d463a8ad433546ed1de7e0f29aef +PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694 -COCOAPODS: 1.12.1 +COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flask_example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flask_example/ios/Runner.xcodeproj/project.pbxproj index c9cbbc0a..fdc569bd 100644 --- a/src/serious_python/example/flask_example/ios/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/flask_example/ios/Runner.xcodeproj/project.pbxproj @@ -10,12 +10,13 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 5B44F7E31402F865514A0858 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96528167AEF905EF935C1B41 /* Pods_Runner.framework */; }; - 6E599DE725A7D68A3238C543 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1AD4EBDB62E03C336C3EE77 /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 77A988A6D080EF4BC79BE58A /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE3BB40A3B4D14887033B8B8 /* Pods_RunnerTests.framework */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + C4B9804AA9F1E8A527A0A479 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C6DBFEFC8EEC088475FF3B8 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,20 +43,19 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0D382C05287807FE4CCE1EC4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 0C6DBFEFC8EEC088475FF3B8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 18C74EFCCAE277889ECB1AC4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 1D4ACE23F5F3798A85CB2B20 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 362FE1DD228E14D42ECA2A89 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 6045BC150A02902EDD944A0C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 72FB249CCFCF77C5BC56E58D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 8FDF69CA5955F9CAEB4BAD4C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 96528167AEF905EF935C1B41 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 970D04A203EFCE2DE0A80099 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -63,24 +63,26 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - AAF0F2A04A9A113E2FDEB3FE /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - E1AD4EBDB62E03C336C3EE77 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A325022E53B09E17C0E31FD6 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + AB437FB78677E7767CB7C835 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + AE3BB40A3B4D14887033B8B8 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D7FDA6251921B5D40B882887 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 865116BAEE02335192FC14A4 /* Frameworks */ = { + 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6E599DE725A7D68A3238C543 /* Pods_RunnerTests.framework in Frameworks */, + C4B9804AA9F1E8A527A0A479 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 97C146EB1CF9000F007C117D /* Frameworks */ = { + E49AB6DC08AE5F55BA07C643 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5B44F7E31402F865514A0858 /* Pods_Runner.framework in Frameworks */, + 77A988A6D080EF4BC79BE58A /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -95,16 +97,17 @@ path = RunnerTests; sourceTree = ""; }; - 579CE9A32D94B33B7F5FA9C5 /* Pods */ = { + 553BA73291320DECD34F1CAA /* Pods */ = { isa = PBXGroup; children = ( - AAF0F2A04A9A113E2FDEB3FE /* Pods-Runner.debug.xcconfig */, - 18C74EFCCAE277889ECB1AC4 /* Pods-Runner.release.xcconfig */, - 0D382C05287807FE4CCE1EC4 /* Pods-Runner.profile.xcconfig */, - 970D04A203EFCE2DE0A80099 /* Pods-RunnerTests.debug.xcconfig */, - 8FDF69CA5955F9CAEB4BAD4C /* Pods-RunnerTests.release.xcconfig */, - 362FE1DD228E14D42ECA2A89 /* Pods-RunnerTests.profile.xcconfig */, - ); + 72FB249CCFCF77C5BC56E58D /* Pods-Runner.debug.xcconfig */, + D7FDA6251921B5D40B882887 /* Pods-Runner.release.xcconfig */, + 1D4ACE23F5F3798A85CB2B20 /* Pods-Runner.profile.xcconfig */, + AB437FB78677E7767CB7C835 /* Pods-RunnerTests.debug.xcconfig */, + A325022E53B09E17C0E31FD6 /* Pods-RunnerTests.release.xcconfig */, + 6045BC150A02902EDD944A0C /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; path = Pods; sourceTree = ""; }; @@ -126,8 +129,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, - 579CE9A32D94B33B7F5FA9C5 /* Pods */, - C81B3572AEA9583327A6C83F /* Frameworks */, + 553BA73291320DECD34F1CAA /* Pods */, + D70B7ECD72C3A320543F16E4 /* Frameworks */, ); sourceTree = ""; }; @@ -150,16 +153,17 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; - C81B3572AEA9583327A6C83F /* Frameworks */ = { + D70B7ECD72C3A320543F16E4 /* Frameworks */ = { isa = PBXGroup; children = ( - 96528167AEF905EF935C1B41 /* Pods_Runner.framework */, - E1AD4EBDB62E03C336C3EE77 /* Pods_RunnerTests.framework */, + 0C6DBFEFC8EEC088475FF3B8 /* Pods_Runner.framework */, + AE3BB40A3B4D14887033B8B8 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -171,10 +175,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 22AE4D140A0649DD74A96896 /* [CP] Check Pods Manifest.lock */, + A09929865224B53C6EDC0DBA /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, - 865116BAEE02335192FC14A4 /* Frameworks */, + E49AB6DC08AE5F55BA07C643 /* Frameworks */, ); buildRules = ( ); @@ -190,14 +194,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 1EE0442A2A194508FAABE79B /* [CP] Check Pods Manifest.lock */, + C8F796EC5C0BBF75DD301401 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - D1EC2B1361F0757AC0569474 /* [CP] Embed Pods Frameworks */, + 76088B6348DC51E21B5F4330 /* [CP] Embed Pods Frameworks */, + CBA805DF563C72EDD8CF9420 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -215,7 +220,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { @@ -269,96 +274,113 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1EE0442A2A194508FAABE79B /* [CP] Check Pods Manifest.lock */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); + name = "Thin Binary"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 22AE4D140A0649DD74A96896 /* [CP] Check Pods Manifest.lock */ = { + 76088B6348DC51E21B5F4330 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); - name = "Thin Binary"; + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + A09929865224B53C6EDC0DBA /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "Run Script"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - D1EC2B1361F0757AC0569474 /* [CP] Embed Pods Frameworks */ = { + C8F796EC5C0BBF75DD301401 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + CBA805DF563C72EDD8CF9420 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -378,6 +400,7 @@ files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -415,6 +438,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -434,7 +458,6 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -445,6 +468,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -453,7 +477,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -469,7 +493,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -486,7 +509,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 970D04A203EFCE2DE0A80099 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = AB437FB78677E7767CB7C835 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -504,7 +527,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 8FDF69CA5955F9CAEB4BAD4C /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = A325022E53B09E17C0E31FD6 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -520,7 +543,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 362FE1DD228E14D42ECA2A89 /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = 6045BC150A02902EDD944A0C /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -538,6 +561,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -557,7 +581,6 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -568,6 +591,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -582,7 +606,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -594,6 +618,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -613,7 +638,6 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -624,6 +648,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -632,7 +657,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -650,7 +675,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -673,7 +697,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/src/serious_python/example/flask_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flask_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 87131a09..e3773d42 100644 --- a/src/serious_python/example/flask_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/src/serious_python/example/flask_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/src/serious_python/example/flask_example/ios/Runner/AppDelegate.swift b/src/serious_python/example/flask_example/ios/Runner/AppDelegate.swift index 70693e4a..c30b367e 100644 --- a/src/serious_python/example/flask_example/ios/Runner/AppDelegate.swift +++ b/src/serious_python/example/flask_example/ios/Runner/AppDelegate.swift @@ -1,13 +1,16 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/src/serious_python/example/flask_example/ios/Runner/Info.plist b/src/serious_python/example/flask_example/ios/Runner/Info.plist index def0a416..68366381 100644 --- a/src/serious_python/example/flask_example/ios/Runner/Info.plist +++ b/src/serious_python/example/flask_example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,29 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,11 +66,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/src/serious_python/example/flask_example/ios/Runner/SceneDelegate.swift b/src/serious_python/example/flask_example/ios/Runner/SceneDelegate.swift new file mode 100644 index 00000000..b9ce8ea2 --- /dev/null +++ b/src/serious_python/example/flask_example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/src/serious_python/example/flask_example/linux/CMakeLists.txt b/src/serious_python/example/flask_example/linux/CMakeLists.txt index 22a68fe4..86c06dc3 100644 --- a/src/serious_python/example/flask_example/linux/CMakeLists.txt +++ b/src/serious_python/example/flask_example/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # Project-level configuration. -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.13) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change @@ -54,25 +54,8 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) @@ -123,6 +106,12 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/src/serious_python/example/flask_example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/flask_example/linux/flutter/generated_plugins.cmake index 6d77107e..ab50859e 100644 --- a/src/serious_python/example/flask_example/linux/flutter/generated_plugins.cmake +++ b/src/serious_python/example/flask_example/linux/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python/example/flask_example/linux/runner/CMakeLists.txt b/src/serious_python/example/flask_example/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/src/serious_python/example/flask_example/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/src/serious_python/example/flask_example/linux/main.cc b/src/serious_python/example/flask_example/linux/runner/main.cc similarity index 100% rename from src/serious_python/example/flask_example/linux/main.cc rename to src/serious_python/example/flask_example/linux/runner/main.cc diff --git a/src/serious_python/example/flask_example/linux/my_application.cc b/src/serious_python/example/flask_example/linux/runner/my_application.cc similarity index 59% rename from src/serious_python/example/flask_example/linux/my_application.cc rename to src/serious_python/example/flask_example/linux/runner/my_application.cc index b4b17d9d..8ae8a7a8 100644 --- a/src/serious_python/example/flask_example/linux/my_application.cc +++ b/src/serious_python/example/flask_example/linux/runner/my_application.cc @@ -14,6 +14,11 @@ struct _MyApplication { G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView* view) { + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); @@ -48,31 +53,44 @@ static void my_application_activate(GApplication* application) { } gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 + // for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), + self); + gtk_widget_realize(GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; } g_application_activate(application); @@ -81,6 +99,24 @@ static gboolean my_application_local_command_line(GApplication* application, gch return TRUE; } +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); @@ -90,15 +126,23 @@ static void my_application_dispose(GObject* object) { static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); } diff --git a/src/serious_python/example/flask_example/linux/my_application.h b/src/serious_python/example/flask_example/linux/runner/my_application.h similarity index 70% rename from src/serious_python/example/flask_example/linux/my_application.h rename to src/serious_python/example/flask_example/linux/runner/my_application.h index 72271d5e..db16367a 100644 --- a/src/serious_python/example/flask_example/linux/my_application.h +++ b/src/serious_python/example/flask_example/linux/runner/my_application.h @@ -3,7 +3,10 @@ #include -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, +G_DECLARE_FINAL_TYPE(MyApplication, + my_application, + MY, + APPLICATION, GtkApplication) /** diff --git a/src/serious_python/example/flask_example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/flask_example/macos/Flutter/GeneratedPluginRegistrant.swift index 6bcae484..7ef3a6c2 100644 --- a/src/serious_python/example/flask_example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/src/serious_python/example/flask_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import path_provider_foundation import serious_python_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) } diff --git a/src/serious_python/example/flask_example/macos/Podfile.lock b/src/serious_python/example/flask_example/macos/Podfile.lock index 29066625..f59e9b47 100644 --- a/src/serious_python/example/flask_example/macos/Podfile.lock +++ b/src/serious_python/example/flask_example/macos/Podfile.lock @@ -1,35 +1,22 @@ PODS: - FlutterMacOS (1.0.0) - - package_info_plus (0.0.1): - - FlutterMacOS - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - serious_python_darwin (0.7.0): + - serious_python_darwin (2.0.0): - Flutter - FlutterMacOS DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) - - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral - package_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin serious_python_darwin: :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin SPEC CHECKSUMS: - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 - serious_python_darwin: 0a8c46a529057f91064a327d9c4037e773eef339 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 diff --git a/src/serious_python/example/flask_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flask_example/macos/Runner.xcodeproj/project.pbxproj index b29d7a56..17081519 100644 --- a/src/serious_python/example/flask_example/macos/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/flask_example/macos/Runner.xcodeproj/project.pbxproj @@ -21,14 +21,14 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 0C6C8140227664C7C6331564 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0B1620299264435604BE23 /* Pods_Runner.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 70DD4839623CB676776399F3 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 548A240DA134EA4087E0F195 /* Pods_RunnerTests.framework */; }; - DDFC9F9001D319D95A5CF60C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D812C755E14C4E5DB444838D /* Pods_Runner.framework */; }; + 627AC8E54BEE5230B268E008 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02D97E7CDB56C74FAC1AC299 /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -62,8 +62,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 2629974C32C79086ADA39ADC /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 27097D4FAA1E921277A516D2 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 02D97E7CDB56C74FAC1AC299 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 092BCFF76F3EA9D6C33B9BB2 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 15ACF585AD2FC8DF2FD2524D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; @@ -80,14 +81,13 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 3A957693B9A4702AF65EC727 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 548A240DA134EA4087E0F195 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6E578E07C23DB3D3504885B2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 5C0B1620299264435604BE23 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F8D84A5AD1A99A6D80D59CD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 8495C9548FCC5F61A98535B3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - D6193355C1ED786CF0CB5585 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - D812C755E14C4E5DB444838D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C47413595F7C13CAA683D0EE /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + CC1D86819F853AC4B987884B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + D37D6C2FF36414D977C848FA /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,7 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 70DD4839623CB676776399F3 /* Pods_RunnerTests.framework in Frameworks */, + 627AC8E54BEE5230B268E008 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -103,7 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DDFC9F9001D319D95A5CF60C /* Pods_Runner.framework in Frameworks */, + 0C6C8140227664C7C6331564 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -137,7 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, - CF3A62181C2613D4F67718E4 /* Pods */, + 6548A3E8A66FDC482E03923B /* Pods */, ); sourceTree = ""; }; @@ -185,15 +185,15 @@ path = Runner; sourceTree = ""; }; - CF3A62181C2613D4F67718E4 /* Pods */ = { + 6548A3E8A66FDC482E03923B /* Pods */ = { isa = PBXGroup; children = ( - 2629974C32C79086ADA39ADC /* Pods-Runner.debug.xcconfig */, - 8495C9548FCC5F61A98535B3 /* Pods-Runner.release.xcconfig */, - D6193355C1ED786CF0CB5585 /* Pods-Runner.profile.xcconfig */, - 3A957693B9A4702AF65EC727 /* Pods-RunnerTests.debug.xcconfig */, - 6E578E07C23DB3D3504885B2 /* Pods-RunnerTests.release.xcconfig */, - 27097D4FAA1E921277A516D2 /* Pods-RunnerTests.profile.xcconfig */, + 15ACF585AD2FC8DF2FD2524D /* Pods-Runner.debug.xcconfig */, + CC1D86819F853AC4B987884B /* Pods-Runner.release.xcconfig */, + 5F8D84A5AD1A99A6D80D59CD /* Pods-Runner.profile.xcconfig */, + 092BCFF76F3EA9D6C33B9BB2 /* Pods-RunnerTests.debug.xcconfig */, + C47413595F7C13CAA683D0EE /* Pods-RunnerTests.release.xcconfig */, + D37D6C2FF36414D977C848FA /* Pods-RunnerTests.profile.xcconfig */, ); name = Pods; path = Pods; @@ -202,8 +202,8 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - D812C755E14C4E5DB444838D /* Pods_Runner.framework */, - 548A240DA134EA4087E0F195 /* Pods_RunnerTests.framework */, + 5C0B1620299264435604BE23 /* Pods_Runner.framework */, + 02D97E7CDB56C74FAC1AC299 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -215,7 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 1814E9C1CD1BD4E59951D766 /* [CP] Check Pods Manifest.lock */, + A85DD80B1E9EE5F3FDA4D4B9 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -234,13 +234,14 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 88C1B0D60BC70E03B6C3518B /* [CP] Check Pods Manifest.lock */, + AF73544ED7B87AF7913AF777 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - 590DD7A4F3044A9A023D543F /* [CP] Embed Pods Frameworks */, + 8A958FB37A5E066386C02E70 /* [CP] Embed Pods Frameworks */, + 7F7330796DDC77B192CD6870 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -258,8 +259,9 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { @@ -322,67 +324,62 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1814E9C1CD1BD4E59951D766 /* [CP] Check Pods Manifest.lock */ = { + 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; - 3399D490228B24CF009A79C7 /* ShellScript */ = { + 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( + Flutter/ephemeral/tripwire, ); outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { + 7F7330796DDC77B192CD6870 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + name = "[CP] Copy Pods Resources"; outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; }; - 590DD7A4F3044A9A023D543F /* [CP] Embed Pods Frameworks */ = { + 8A958FB37A5E066386C02E70 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -399,7 +396,29 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 88C1B0D60BC70E03B6C3518B /* [CP] Check Pods Manifest.lock */ = { + A85DD80B1E9EE5F3FDA4D4B9 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + AF73544ED7B87AF7913AF777 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -472,7 +491,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3A957693B9A4702AF65EC727 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = 092BCFF76F3EA9D6C33B9BB2 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -487,7 +506,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6E578E07C23DB3D3504885B2 /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = C47413595F7C13CAA683D0EE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -502,7 +521,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 27097D4FAA1E921277A516D2 /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = D37D6C2FF36414D977C848FA /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -520,6 +539,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -543,9 +563,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -593,6 +615,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -616,9 +639,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -646,6 +671,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -669,9 +695,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/src/serious_python/example/flask_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flask_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3484ffe7..3d3f6b6c 100644 --- a/src/serious_python/example/flask_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/src/serious_python/example/flask_example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/src/serious_python/example/flask_example/macos/Runner/AppDelegate.swift b/src/serious_python/example/flask_example/macos/Runner/AppDelegate.swift index d53ef643..b3c17614 100644 --- a/src/serious_python/example/flask_example/macos/Runner/AppDelegate.swift +++ b/src/serious_python/example/flask_example/macos/Runner/AppDelegate.swift @@ -1,9 +1,13 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/src/serious_python/example/flask_example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python/example/flask_example/macos/Runner/Configs/AppInfo.xcconfig index 053430ce..3789df97 100644 --- a/src/serious_python/example/flask_example/macos/Runner/Configs/AppInfo.xcconfig +++ b/src/serious_python/example/flask_example/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = flask_example PRODUCT_BUNDLE_IDENTIFIER = com.example.flaskExample // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2026 com.example. All rights reserved. diff --git a/src/serious_python/example/flask_example/macos/RunnerTests/RunnerTests.swift b/src/serious_python/example/flask_example/macos/RunnerTests/RunnerTests.swift index 5418c9f5..61f3bd1f 100644 --- a/src/serious_python/example/flask_example/macos/RunnerTests/RunnerTests.swift +++ b/src/serious_python/example/flask_example/macos/RunnerTests/RunnerTests.swift @@ -1,5 +1,5 @@ -import FlutterMacOS import Cocoa +import FlutterMacOS import XCTest class RunnerTests: XCTestCase { diff --git a/src/serious_python/example/flask_example/pubspec.lock b/src/serious_python/example/flask_example/pubspec.lock index 4f7e8f44..4ecc87d8 100644 --- a/src/serious_python/example/flask_example/pubspec.lock +++ b/src/serious_python/example/flask_example/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.0.9" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" async: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.1" boolean_selector: dependency: transitive description: @@ -49,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.dev" + source: hosted + version: "1.2.1" collection: dependency: transitive description: @@ -61,18 +69,18 @@ packages: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.7" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" fake_async: dependency: transitive description: @@ -85,10 +93,10 @@ packages: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.0" file: dependency: transitive description: @@ -123,22 +131,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.dev" + source: hosted + version: "2.0.2" http: dependency: "direct main" description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.6.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" leak_tracker: dependency: transitive description: @@ -171,6 +203,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -191,10 +231,26 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" + url: "https://pub.dev" + source: hosted + version: "9.4.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" path: dependency: transitive description: @@ -207,26 +263,26 @@ packages: dependency: transitive description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.3.1" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.0" path_provider_linux: dependency: transitive description: @@ -255,18 +311,18 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.0" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -279,10 +335,26 @@ packages: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.dev" + source: hosted + version: "6.5.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "2.2.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" serious_python: dependency: "direct main" description: @@ -329,10 +401,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" sky_engine: dependency: transitive description: flutter @@ -342,10 +414,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.2" stack_trace: dependency: transitive description: @@ -382,10 +454,10 @@ packages: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.11" toml: dependency: transitive description: @@ -398,10 +470,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" vector_math: dependency: transitive description: @@ -414,26 +486,34 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.2.0" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "3.1.3" sdks: - dart: ">=3.9.0-0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" diff --git a/src/serious_python/example/flask_example/windows/CMakeLists.txt b/src/serious_python/example/flask_example/windows/CMakeLists.txt index aee3d683..dbc5f258 100644 --- a/src/serious_python/example/flask_example/windows/CMakeLists.txt +++ b/src/serious_python/example/flask_example/windows/CMakeLists.txt @@ -87,6 +87,12 @@ if(PLUGIN_BUNDLED_LIBRARIES) COMPONENT Runtime) endif() +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/src/serious_python/example/flask_example/windows/flutter/CMakeLists.txt b/src/serious_python/example/flask_example/windows/flutter/CMakeLists.txt index 930d2071..903f4899 100644 --- a/src/serious_python/example/flask_example/windows/flutter/CMakeLists.txt +++ b/src/serious_python/example/flask_example/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/src/serious_python/example/flask_example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/flask_example/windows/flutter/generated_plugins.cmake index 159536d6..f2f58d64 100644 --- a/src/serious_python/example/flask_example/windows/flutter/generated_plugins.cmake +++ b/src/serious_python/example/flask_example/windows/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python/example/flask_example/windows/runner/Runner.rc b/src/serious_python/example/flask_example/windows/runner/Runner.rc index f1bd5e34..e85dd602 100644 --- a/src/serious_python/example/flask_example/windows/runner/Runner.rc +++ b/src/serious_python/example/flask_example/windows/runner/Runner.rc @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "flask_example" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "flask_example" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2026 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "flask_example.exe" "\0" VALUE "ProductName", "flask_example" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/src/serious_python/example/flask_example/windows/runner/runner.exe.manifest b/src/serious_python/example/flask_example/windows/runner/runner.exe.manifest index a42ea768..153653e8 100644 --- a/src/serious_python/example/flask_example/windows/runner/runner.exe.manifest +++ b/src/serious_python/example/flask_example/windows/runner/runner.exe.manifest @@ -9,12 +9,6 @@ - - - - - - diff --git a/src/serious_python/example/flask_example/windows/runner/utils.cpp b/src/serious_python/example/flask_example/windows/runner/utils.cpp index b2b08734..3a0b4651 100644 --- a/src/serious_python/example/flask_example/windows/runner/utils.cpp +++ b/src/serious_python/example/flask_example/windows/runner/utils.cpp @@ -45,13 +45,13 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } - int target_length = ::WideCharToMultiByte( + unsigned int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr) -1; // remove the trailing null character int input_length = (int)wcslen(utf16_string); std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { + if (target_length == 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); diff --git a/src/serious_python/example/flet_example/.metadata b/src/serious_python/example/flet_example/.metadata index c7222470..cf4b47a9 100644 --- a/src/serious_python/example/flet_example/.metadata +++ b/src/serious_python/example/flet_example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3" + revision: "c9a6c484230f8b5e408ec57be1ef71dee1e77020" channel: "stable" project_type: app @@ -13,11 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 - base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: android - create_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 - base_revision: 68415ad1d920f6fe5ec284f5c2febf7c4dd5b0b3 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: ios + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: linux + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: macos + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: web + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + - platform: windows + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 # User provided section diff --git a/src/serious_python/example/flet_example/android/.gitignore b/src/serious_python/example/flet_example/android/.gitignore index 5fed52d9..be3943c9 100644 --- a/src/serious_python/example/flet_example/android/.gitignore +++ b/src/serious_python/example/flet_example/android/.gitignore @@ -5,7 +5,7 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java -**/.cxx/ +.cxx/ # Remember to never publicly share your keystore. # See https://flutter.dev/to/reference-keystore diff --git a/src/serious_python/example/flet_example/android/app/build.gradle b/src/serious_python/example/flet_example/android/app/build.gradle.kts similarity index 64% rename from src/serious_python/example/flet_example/android/app/build.gradle rename to src/serious_python/example/flet_example/android/app/build.gradle.kts index 852bab06..0a526eb6 100644 --- a/src/serious_python/example/flet_example/android/app/build.gradle +++ b/src/serious_python/example/flet_example/android/app/build.gradle.kts @@ -1,8 +1,10 @@ plugins { - id "com.android.application" - id "kotlin-android" - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" + id("com.android.application") + // Kotlin is provided by the Flutter Gradle Plugin (Built-in Kotlin) at the + // version declared in settings.gradle.kts, so the app no longer applies the + // Kotlin Gradle Plugin itself. + // The Flutter Gradle Plugin must be applied after the Android Gradle plugin. + id("dev.flutter.flutter-gradle-plugin") } android { @@ -11,12 +13,8 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } defaultConfig { @@ -34,11 +32,17 @@ android { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + flutter { source = "../.." } diff --git a/src/serious_python/example/flet_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt b/src/serious_python/example/flet_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt index cc08d6a6..99464aea 100644 --- a/src/serious_python/example/flet_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt +++ b/src/serious_python/example/flet_example/android/app/src/main/kotlin/com/example/flet_example/MainActivity.kt @@ -2,4 +2,4 @@ package com.example.flet_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() diff --git a/src/serious_python/example/flet_example/android/build.gradle b/src/serious_python/example/flet_example/android/build.gradle deleted file mode 100644 index d2ffbffa..00000000 --- a/src/serious_python/example/flet_example/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/src/serious_python/example/flet_example/android/build.gradle.kts b/src/serious_python/example/flet_example/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/src/serious_python/example/flet_example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/src/serious_python/example/flet_example/android/gradle.properties b/src/serious_python/example/flet_example/android/gradle.properties index 25971708..fbee1d8c 100644 --- a/src/serious_python/example/flet_example/android/gradle.properties +++ b/src/serious_python/example/flet_example/android/gradle.properties @@ -1,3 +1,2 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true -android.enableJetifier=true diff --git a/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties index efdcc4ac..e4ef43fb 100644 --- a/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/serious_python/example/flet_example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/src/serious_python/example/flet_example/android/settings.gradle b/src/serious_python/example/flet_example/android/settings.gradle deleted file mode 100644 index 01a36241..00000000 --- a/src/serious_python/example/flet_example/android/settings.gradle +++ /dev/null @@ -1,30 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - // AGP 8.9.1+ required by androidx.core 1.18.0 (transitive via Flet); - // AGP 8.9 requires Gradle 8.11+ (see gradle-wrapper.properties). - id "com.android.application" version "8.9.1" apply false - // KGP 2.3.x required: screen_brightness_android 2.1.5 ships with a - // Kotlin 2.3.21 stdlib whose metadata format (binary version 2.3.0) - // can't be read by KGP < 2.3. - id "org.jetbrains.kotlin.android" version "2.3.21" apply false -} - -include ":app" diff --git a/src/serious_python/example/flet_example/android/settings.gradle.kts b/src/serious_python/example/flet_example/android/settings.gradle.kts new file mode 100644 index 00000000..24f70299 --- /dev/null +++ b/src/serious_python/example/flet_example/android/settings.gradle.kts @@ -0,0 +1,29 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.11.1" apply false + // KGP 2.3.21 required: Flet's transitive screen_brightness_android ships a + // Kotlin 2.3.x stdlib whose metadata can't be read by KGP < 2.3 (the 3.44.2 + // template default is 2.2.20). + id("org.jetbrains.kotlin.android") version "2.3.21" apply false +} + +include(":app") diff --git a/src/serious_python/example/flet_example/ios/Flutter/AppFrameworkInfo.plist b/src/serious_python/example/flet_example/ios/Flutter/AppFrameworkInfo.plist index 7c569640..391a902b 100644 --- a/src/serious_python/example/flet_example/ios/Flutter/AppFrameworkInfo.plist +++ b/src/serious_python/example/flet_example/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 12.0 diff --git a/src/serious_python/example/flet_example/ios/Podfile b/src/serious_python/example/flet_example/ios/Podfile index 164df534..e51a31d9 100644 --- a/src/serious_python/example/flet_example/ios/Podfile +++ b/src/serious_python/example/flet_example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/src/serious_python/example/flet_example/ios/Podfile.lock b/src/serious_python/example/flet_example/ios/Podfile.lock deleted file mode 100644 index a6e90d98..00000000 --- a/src/serious_python/example/flet_example/ios/Podfile.lock +++ /dev/null @@ -1,114 +0,0 @@ -PODS: - - DKImagePickerController/Core (4.3.4): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.4) - - DKImagePickerController/PhotoGallery (4.3.4): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.4) - - DKPhotoGallery (0.0.17): - - DKPhotoGallery/Core (= 0.0.17) - - DKPhotoGallery/Model (= 0.0.17) - - DKPhotoGallery/Preview (= 0.0.17) - - DKPhotoGallery/Resource (= 0.0.17) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.17): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.17): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Flutter (1.0.0) - - integration_test (0.0.1): - - Flutter - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - SDWebImage (5.18.5): - - SDWebImage/Core (= 5.18.5) - - SDWebImage/Core (5.18.5) - - sensors_plus (0.0.1): - - Flutter - - serious_python_darwin (0.8.0): - - Flutter - - FlutterMacOS - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - SwiftyGif (5.4.4) - - url_launcher_ios (0.0.1): - - Flutter - -DEPENDENCIES: - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - Flutter (from `Flutter`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) - - serious_python_darwin (from `.symlinks/plugins/serious_python_darwin/darwin`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - -SPEC REPOS: - trunk: - - DKImagePickerController - - DKPhotoGallery - - SDWebImage - - SwiftyGif - -EXTERNAL SOURCES: - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - Flutter: - :path: Flutter - integration_test: - :path: ".symlinks/plugins/integration_test/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" - sensors_plus: - :path: ".symlinks/plugins/sensors_plus/ios" - serious_python_darwin: - :path: ".symlinks/plugins/serious_python_darwin/darwin" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - -SPEC CHECKSUMS: - DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 - package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - SDWebImage: 7ac2b7ddc5e8484c79aa90fc4e30b149d6a2c88f - sensors_plus: 42b9de1b8237675fa8d8121e4bb93be0f79fa61d - serious_python_darwin: 351e50099cb9e34f344f75af29b1d36d3c0922f2 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - -PODFILE CHECKSUM: 7be2f5f74864d463a8ad433546ed1de7e0f29aef - -COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flet_example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_example/ios/Runner.xcodeproj/project.pbxproj index 92eb9c48..c2fd4bea 100644 --- a/src/serious_python/example/flet_example/ios/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/flet_example/ios/Runner.xcodeproj/project.pbxproj @@ -8,11 +8,10 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2405649350EFCEC25599DE23 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */; }; - 2CA3C271D8189DF194697D7D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28A203680D8105B35D530F31 /* Pods_Runner.framework */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -42,20 +41,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1EE1648DA1E83A0AA44BC13A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 28A203680D8105B35D530F31 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 563D6173166309C998296F04 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 5FA1FBC3AE8269E16AA97AD1 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -63,8 +57,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,30 +64,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2CA3C271D8189DF194697D7D /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B920DD79982F64FC739571F8 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2405649350EFCEC25599DE23 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 103F5AA3589F7D2F915BFF32 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 28A203680D8105B35D530F31 /* Pods_Runner.framework */, - D0D7377221887A37973A9920 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -122,8 +96,6 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, - E36498D4F89A08F7B5C19AED /* Pods */, - 103F5AA3589F7D2F915BFF32 /* Frameworks */, ); sourceTree = ""; }; @@ -146,25 +118,12 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; - E36498D4F89A08F7B5C19AED /* Pods */ = { - isa = PBXGroup; - children = ( - 5FA1FBC3AE8269E16AA97AD1 /* Pods-Runner.debug.xcconfig */, - 563D6173166309C998296F04 /* Pods-Runner.release.xcconfig */, - 1EE1648DA1E83A0AA44BC13A /* Pods-Runner.profile.xcconfig */, - 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */, - 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */, - BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -172,10 +131,8 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 90579612B1A4EF4E391E0626 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, - B920DD79982F64FC739571F8 /* Frameworks */, ); buildRules = ( ); @@ -191,14 +148,12 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - C8A57305F206317D5468F600 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - AE52A9CBDBBC66A5CB483F7A /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -215,6 +170,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -285,28 +241,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 90579612B1A4EF4E391E0626 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -322,45 +256,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - AE52A9CBDBBC66A5CB483F7A /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - C8A57305F206317D5468F600 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -378,6 +273,7 @@ files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -415,6 +311,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -444,6 +341,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -452,7 +350,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -468,7 +366,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -485,7 +382,6 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 8273B2F287E69909A7E30065 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -503,7 +399,6 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 042C49DB469F256AAA571996 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -519,7 +414,6 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BC9388593FAE3C4B3E8FDE91 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -537,6 +431,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -566,6 +461,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -580,7 +476,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -592,6 +488,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -621,6 +518,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -629,7 +527,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -647,7 +545,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -670,7 +567,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = GXXRQJK434; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/src/serious_python/example/flet_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/flet_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5df..e3773d42 100644 --- a/src/serious_python/example/flet_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/src/serious_python/example/flet_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/src/serious_python/example/flet_example/ios/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_example/ios/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc14..1d526a16 100644 --- a/src/serious_python/example/flet_example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/src/serious_python/example/flet_example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,7 +4,4 @@ - - diff --git a/src/serious_python/example/flet_example/ios/Runner/AppDelegate.swift b/src/serious_python/example/flet_example/ios/Runner/AppDelegate.swift index b6363034..c30b367e 100644 --- a/src/serious_python/example/flet_example/ios/Runner/AppDelegate.swift +++ b/src/serious_python/example/flet_example/ios/Runner/AppDelegate.swift @@ -1,13 +1,16 @@ -import UIKit import Flutter +import UIKit @main -@objc class AppDelegate: FlutterAppDelegate { +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/src/serious_python/example/flet_example/ios/Runner/Info.plist b/src/serious_python/example/flet_example/ios/Runner/Info.plist index f536cf65..38b2b3d5 100644 --- a/src/serious_python/example/flet_example/ios/Runner/Info.plist +++ b/src/serious_python/example/flet_example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,29 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,11 +66,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/src/serious_python/example/flet_example/ios/Runner/SceneDelegate.swift b/src/serious_python/example/flet_example/ios/Runner/SceneDelegate.swift new file mode 100644 index 00000000..b9ce8ea2 --- /dev/null +++ b/src/serious_python/example/flet_example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/src/serious_python/example/flet_example/linux/CMakeLists.txt b/src/serious_python/example/flet_example/linux/CMakeLists.txt index 7ef35274..d17d15d3 100644 --- a/src/serious_python/example/flet_example/linux/CMakeLists.txt +++ b/src/serious_python/example/flet_example/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # Project-level configuration. -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.13) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change @@ -54,25 +54,8 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) @@ -123,20 +106,11 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) -# Link bundled libraries from plugins into main executable to enable dlopen -# with only library name. -# Will NOT be needed once: https://github.com/flutter/engine/pull/28525 lands in Flutter channel we are using -# Alternative approach is to update plugin's RUNPATH before packaging: -# chrpath -r \$ORIGIN ./build/linux/arm64/release/bundle/lib/libserious_python_linux_plugin.so -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - if(${plugin}_bundled_libraries) - target_link_libraries( - ${BINARY_NAME} - PRIVATE - ${${plugin}_bundled_libraries} - ) - endif() -endforeach(plugin) +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. diff --git a/src/serious_python/example/flet_example/linux/runner/CMakeLists.txt b/src/serious_python/example/flet_example/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/src/serious_python/example/flet_example/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/src/serious_python/example/flet_example/linux/main.cc b/src/serious_python/example/flet_example/linux/runner/main.cc similarity index 100% rename from src/serious_python/example/flet_example/linux/main.cc rename to src/serious_python/example/flet_example/linux/runner/main.cc diff --git a/src/serious_python/example/flet_example/linux/my_application.cc b/src/serious_python/example/flet_example/linux/runner/my_application.cc similarity index 59% rename from src/serious_python/example/flet_example/linux/my_application.cc rename to src/serious_python/example/flet_example/linux/runner/my_application.cc index 7f876fab..7c4258d0 100644 --- a/src/serious_python/example/flet_example/linux/my_application.cc +++ b/src/serious_python/example/flet_example/linux/runner/my_application.cc @@ -14,6 +14,11 @@ struct _MyApplication { G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView* view) { + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); @@ -48,31 +53,44 @@ static void my_application_activate(GApplication* application) { } gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 + // for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), + self); + gtk_widget_realize(GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; } g_application_activate(application); @@ -81,6 +99,24 @@ static gboolean my_application_local_command_line(GApplication* application, gch return TRUE; } +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); @@ -90,15 +126,23 @@ static void my_application_dispose(GObject* object) { static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); } diff --git a/src/serious_python/example/run_example/linux/my_application.h b/src/serious_python/example/flet_example/linux/runner/my_application.h similarity index 70% rename from src/serious_python/example/run_example/linux/my_application.h rename to src/serious_python/example/flet_example/linux/runner/my_application.h index 72271d5e..db16367a 100644 --- a/src/serious_python/example/run_example/linux/my_application.h +++ b/src/serious_python/example/flet_example/linux/runner/my_application.h @@ -3,7 +3,10 @@ #include -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, +G_DECLARE_FINAL_TYPE(MyApplication, + my_application, + MY, + APPLICATION, GtkApplication) /** diff --git a/src/serious_python/example/flet_example/macos/Podfile.lock b/src/serious_python/example/flet_example/macos/Podfile.lock deleted file mode 100644 index c631f6e1..00000000 --- a/src/serious_python/example/flet_example/macos/Podfile.lock +++ /dev/null @@ -1,108 +0,0 @@ -PODS: - - battery_plus (0.0.1): - - FlutterMacOS - - connectivity_plus (0.0.1): - - FlutterMacOS - - device_info_plus (0.0.1): - - FlutterMacOS - - file_picker (0.0.1): - - FlutterMacOS - - FlutterMacOS (1.0.0) - - package_info_plus (0.0.1): - - FlutterMacOS - - pasteboard (0.0.1): - - FlutterMacOS - - screen_brightness_macos (0.1.0): - - FlutterMacOS - - screen_retriever_macos (0.0.1): - - FlutterMacOS - - serious_python_darwin (2.0.0): - - Flutter - - FlutterMacOS - - share_plus (0.0.1): - - FlutterMacOS - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - url_launcher_macos (0.0.1): - - FlutterMacOS - - wakelock_plus (0.0.1): - - FlutterMacOS - - window_manager (0.5.0): - - FlutterMacOS - - window_to_front (0.0.4): - - FlutterMacOS - -DEPENDENCIES: - - battery_plus (from `Flutter/ephemeral/.symlinks/plugins/battery_plus/macos`) - - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) - - FlutterMacOS (from `Flutter/ephemeral`) - - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) - - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) - - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) - - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) - - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) - - window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`) - -EXTERNAL SOURCES: - battery_plus: - :path: Flutter/ephemeral/.symlinks/plugins/battery_plus/macos - connectivity_plus: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos - device_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos - file_picker: - :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos - FlutterMacOS: - :path: Flutter/ephemeral - package_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos - pasteboard: - :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos - screen_brightness_macos: - :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos - screen_retriever_macos: - :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos - serious_python_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin - share_plus: - :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos - shared_preferences_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin - url_launcher_macos: - :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos - wakelock_plus: - :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos - window_manager: - :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos - window_to_front: - :path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos - -SPEC CHECKSUMS: - battery_plus: f51ad29136e025b714b96f7d096f44f604615da7 - connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e - device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 - file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a - FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - package_info_plus: f0052d280d17aa382b932f399edf32507174e870 - pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 - screen_brightness_macos: 1058c18b5e0570f48f93016487a5ed66d6977fe0 - screen_retriever_macos: c5508cc3c66ff0d4db650480cf0ab691e220d933 - serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 - share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc - shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb - url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd - wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b - window_manager: b729e31d38fb04905235df9ea896128991cad99e - window_to_front: 2d7d31f268d0b13b7e63b26e31eb0a2e9612239e - -PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 - -COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj index 319e1e69..5f5d96ea 100644 --- a/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/flet_example/macos/Runner.xcodeproj/project.pbxproj @@ -21,14 +21,12 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 256EF705489316F00EF3962A /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 99AFA56BC7E7B7480D345FDA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -62,12 +60,11 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 11E10455E245EB5F22EB7A9A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flet_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flet_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* flet_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "flet_example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -79,15 +76,8 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - B126920E3C82A726215E0DE6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - F080949AB83300EBF0AAA1E4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,7 +85,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 256EF705489316F00EF3962A /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -103,27 +92,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 99AFA56BC7E7B7480D345FDA /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 2FD1AA06884986EE36A305B7 /* Pods */ = { - isa = PBXGroup; - children = ( - 11E10455E245EB5F22EB7A9A /* Pods-Runner.debug.xcconfig */, - F080949AB83300EBF0AAA1E4 /* Pods-Runner.release.xcconfig */, - B126920E3C82A726215E0DE6 /* Pods-Runner.profile.xcconfig */, - 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */, - 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */, - FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -151,7 +125,6 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, - 2FD1AA06884986EE36A305B7 /* Pods */, ); sourceTree = ""; }; @@ -202,8 +175,6 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - 41059CCFE2A63B7F56BFAF1E /* Pods_Runner.framework */, - 79EFD430F9D3561B7E79B636 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -215,7 +186,6 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -234,14 +204,11 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 8F5527630CCCD1FAF8A7F717 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */, - 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -259,6 +226,7 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; @@ -323,23 +291,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 2904FEB115C05FA6123619BA /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -378,67 +329,6 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 34E994862A40A68ACA87E29A /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3F5F528C0FAAB19B26F103EC /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 8F5527630CCCD1FAF8A7F717 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -490,7 +380,6 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3F15EFE98C2771E6DA7CBB05 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -505,7 +394,6 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5CC50136090D28DA48C52BD8 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -520,7 +408,6 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FE389693C8F3FA4062C95BD0 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -538,6 +425,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -561,9 +449,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -611,6 +501,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -634,9 +525,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -664,6 +557,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -687,9 +581,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/src/serious_python/example/flet_example/macos/Runner.xcworkspace/contents.xcworkspacedata b/src/serious_python/example/flet_example/macos/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc14..1d526a16 100644 --- a/src/serious_python/example/flet_example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/src/serious_python/example/flet_example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,7 +4,4 @@ - - diff --git a/src/serious_python/example/flet_example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python/example/flet_example/macos/Runner/Configs/AppInfo.xcconfig index 2cadea52..3f116d66 100644 --- a/src/serious_python/example/flet_example/macos/Runner/Configs/AppInfo.xcconfig +++ b/src/serious_python/example/flet_example/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = flet_example PRODUCT_BUNDLE_IDENTIFIER = com.example.fletExample // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2026 com.example. All rights reserved. diff --git a/src/serious_python/example/flet_example/macos/RunnerTests/RunnerTests.swift b/src/serious_python/example/flet_example/macos/RunnerTests/RunnerTests.swift index 5418c9f5..61f3bd1f 100644 --- a/src/serious_python/example/flet_example/macos/RunnerTests/RunnerTests.swift +++ b/src/serious_python/example/flet_example/macos/RunnerTests/RunnerTests.swift @@ -1,5 +1,5 @@ -import FlutterMacOS import Cocoa +import FlutterMacOS import XCTest class RunnerTests: XCTestCase { diff --git a/src/serious_python/example/flet_example/pubspec.lock b/src/serious_python/example/flet_example/pubspec.lock index 427dbdd5..ec64d540 100644 --- a/src/serious_python/example/flet_example/pubspec.lock +++ b/src/serious_python/example/flet_example/pubspec.lock @@ -198,10 +198,10 @@ packages: description: path: "packages/flet" ref: dart-bridge - resolved-ref: "33b3b972373fb3f268fe7acc84876b87dbb9a31c" + resolved-ref: f738809348606dc3b5071ebabf540d1f034d2d75 url: "https://github.com/flet-dev/flet.git" source: git - version: "0.85.3" + version: "0.86.0" flutter: dependency: "direct main" description: flutter @@ -433,10 +433,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" mime: dependency: transitive description: @@ -827,10 +827,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + sha256: "93ae5884a9df5d3bb696825bceb3a17590754548b5d740eba51500afc8d088f5" url: "https://pub.dev" source: hosted - version: "2.4.23" + version: "2.4.26" shared_preferences_foundation: dependency: transitive description: @@ -944,10 +944,10 @@ packages: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.11" toml: dependency: transitive description: @@ -992,10 +992,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" + sha256: b413d49b73867ac08dd2f9890efd3cc11f2a0e577618d50843440a1fb3776c32 url: "https://pub.dev" source: hosted - version: "6.3.30" + version: "6.3.32" url_launcher_ios: dependency: transitive description: @@ -1197,5 +1197,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/src/serious_python/example/flet_example/web/index.html b/src/serious_python/example/flet_example/web/index.html index 41f4ced7..d1962549 100644 --- a/src/serious_python/example/flet_example/web/index.html +++ b/src/serious_python/example/flet_example/web/index.html @@ -21,7 +21,7 @@ - + @@ -31,29 +31,16 @@ flet_example - - - - - + + diff --git a/src/serious_python/example/flet_example/windows/CMakeLists.txt b/src/serious_python/example/flet_example/windows/CMakeLists.txt index cee1b1bd..6bb428e1 100644 --- a/src/serious_python/example/flet_example/windows/CMakeLists.txt +++ b/src/serious_python/example/flet_example/windows/CMakeLists.txt @@ -87,6 +87,12 @@ if(PLUGIN_BUNDLED_LIBRARIES) COMPONENT Runtime) endif() +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/src/serious_python/example/flet_example/windows/runner/Runner.rc b/src/serious_python/example/flet_example/windows/runner/Runner.rc index 320618d6..45fe4e1b 100644 --- a/src/serious_python/example/flet_example/windows/runner/Runner.rc +++ b/src/serious_python/example/flet_example/windows/runner/Runner.rc @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "flet_example" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "flet_example" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2026 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "flet_example.exe" "\0" VALUE "ProductName", "flet_example" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/src/serious_python/example/flet_example/windows/runner/runner.exe.manifest b/src/serious_python/example/flet_example/windows/runner/runner.exe.manifest index a42ea768..153653e8 100644 --- a/src/serious_python/example/flet_example/windows/runner/runner.exe.manifest +++ b/src/serious_python/example/flet_example/windows/runner/runner.exe.manifest @@ -9,12 +9,6 @@ - - - - - - diff --git a/src/serious_python/example/flet_example/windows/runner/utils.cpp b/src/serious_python/example/flet_example/windows/runner/utils.cpp index b2b08734..3a0b4651 100644 --- a/src/serious_python/example/flet_example/windows/runner/utils.cpp +++ b/src/serious_python/example/flet_example/windows/runner/utils.cpp @@ -45,13 +45,13 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } - int target_length = ::WideCharToMultiByte( + unsigned int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr) -1; // remove the trailing null character int input_length = (int)wcslen(utf16_string); std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { + if (target_length == 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); diff --git a/src/serious_python/example/run_example/.metadata b/src/serious_python/example/run_example/.metadata index 44c50848..d3f20b97 100644 --- a/src/serious_python/example/run_example/.metadata +++ b/src/serious_python/example/run_example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "ead455963c12b453cdb2358cad34969c76daf180" + revision: "c9a6c484230f8b5e408ec57be1ef71dee1e77020" channel: "stable" project_type: app @@ -13,23 +13,23 @@ project_type: app migration: platforms: - platform: root - create_revision: ead455963c12b453cdb2358cad34969c76daf180 - base_revision: ead455963c12b453cdb2358cad34969c76daf180 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: android - create_revision: ead455963c12b453cdb2358cad34969c76daf180 - base_revision: ead455963c12b453cdb2358cad34969c76daf180 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: ios - create_revision: ead455963c12b453cdb2358cad34969c76daf180 - base_revision: ead455963c12b453cdb2358cad34969c76daf180 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: linux - create_revision: ead455963c12b453cdb2358cad34969c76daf180 - base_revision: ead455963c12b453cdb2358cad34969c76daf180 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: macos - create_revision: ead455963c12b453cdb2358cad34969c76daf180 - base_revision: ead455963c12b453cdb2358cad34969c76daf180 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 - platform: windows - create_revision: ead455963c12b453cdb2358cad34969c76daf180 - base_revision: ead455963c12b453cdb2358cad34969c76daf180 + create_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 + base_revision: c9a6c484230f8b5e408ec57be1ef71dee1e77020 # User provided section diff --git a/src/serious_python/example/run_example/README.md b/src/serious_python/example/run_example/README.md index 333e8df6..1ff3c267 100644 --- a/src/serious_python/example/run_example/README.md +++ b/src/serious_python/example/run_example/README.md @@ -45,23 +45,27 @@ dart run serious_python:main package app/src -p Emscripten -r -r -r app/src/requ For Android: -In `android/app/build.gradle`: +In `android/app/build.gradle.kts`: -``` +```kotlin android { - ndkVersion "25.1.8937393" - - packagingOptions { + // serious_python bundles libpython*.so. Use legacy (extracted, uncompressed) + // packaging so the embedded interpreter can dlopen them at runtime, and keep + // their symbols so they are not stripped. + packaging { jniLibs { - useLegacyPackaging true + useLegacyPackaging = true + keepDebugSymbols += setOf( + "*/arm64-v8a/libpython*.so", + "*/armeabi-v7a/libpython*.so", + "*/x86/libpython*.so", + "*/x86_64/libpython*.so", + ) } } - packagingOptions { - doNotStrip "*/arm64-v8a/libpython*.so" - doNotStrip "*/armeabi-v7a/libpython*.so" - doNotStrip "*/x86/libpython*.so" - doNotStrip "*/x86_64/libpython*.so" + defaultConfig { + minSdk = 23 } } ``` \ No newline at end of file diff --git a/src/serious_python/example/run_example/android/.gitignore b/src/serious_python/example/run_example/android/.gitignore index b776a2ff..be3943c9 100644 --- a/src/serious_python/example/run_example/android/.gitignore +++ b/src/serious_python/example/run_example/android/.gitignore @@ -5,10 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java -**/.cxx/ +.cxx/ # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/src/serious_python/example/run_example/android/app/build.gradle b/src/serious_python/example/run_example/android/app/build.gradle deleted file mode 100644 index 8a335a44..00000000 --- a/src/serious_python/example/run_example/android/app/build.gradle +++ /dev/null @@ -1,76 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -android { - namespace "com.example.run_example" - compileSdkVersion flutter.compileSdkVersion - ndkVersion "25.1.8937393" - - packagingOptions { - jniLibs { - useLegacyPackaging true - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - applicationId "com.example.run_example" - minSdkVersion 23 - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } - - packagingOptions { - doNotStrip "*/arm64-v8a/libpython*.so" - doNotStrip "*/armeabi-v7a/libpython*.so" - doNotStrip "*/x86/libpython*.so" - doNotStrip "*/x86_64/libpython*.so" - } -} - -flutter { - source '../..' -} - -dependencies {} diff --git a/src/serious_python/example/run_example/android/app/build.gradle.kts b/src/serious_python/example/run_example/android/app/build.gradle.kts new file mode 100644 index 00000000..5478ce2d --- /dev/null +++ b/src/serious_python/example/run_example/android/app/build.gradle.kts @@ -0,0 +1,62 @@ +plugins { + id("com.android.application") + // Kotlin is provided by the Flutter Gradle Plugin (Built-in Kotlin), so the + // app no longer applies the Kotlin Gradle Plugin itself. + // The Flutter Gradle Plugin must be applied after the Android Gradle plugin. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.run_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + // serious_python bundles libpython*.so. Use legacy (extracted, uncompressed) + // packaging so the embedded interpreter can dlopen them at runtime, and keep + // their symbols so they are not stripped. + packaging { + jniLibs { + useLegacyPackaging = true + keepDebugSymbols += setOf( + "*/arm64-v8a/libpython*.so", + "*/armeabi-v7a/libpython*.so", + "*/x86/libpython*.so", + "*/x86_64/libpython*.so", + ) + } + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.run_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + +flutter { + source = "../.." +} diff --git a/src/serious_python/example/run_example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/run_example/android/app/src/main/AndroidManifest.xml index bc6c6a0b..c4f8743d 100644 --- a/src/serious_python/example/run_example/android/app/src/main/AndroidManifest.xml +++ b/src/serious_python/example/run_example/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" + android:taskAffinity="" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" @@ -30,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/src/serious_python/example/run_example/android/app/src/main/kotlin/com/example/run_example/MainActivity.kt b/src/serious_python/example/run_example/android/app/src/main/kotlin/com/example/run_example/MainActivity.kt index 6f431aff..a5ed6181 100644 --- a/src/serious_python/example/run_example/android/app/src/main/kotlin/com/example/run_example/MainActivity.kt +++ b/src/serious_python/example/run_example/android/app/src/main/kotlin/com/example/run_example/MainActivity.kt @@ -2,5 +2,4 @@ package com.example.run_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { -} +class MainActivity : FlutterActivity() diff --git a/src/serious_python/example/run_example/android/build.gradle b/src/serious_python/example/run_example/android/build.gradle deleted file mode 100644 index 52d31f37..00000000 --- a/src/serious_python/example/run_example/android/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - ext.kotlin_version = '1.9.24' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/src/serious_python/example/run_example/android/build.gradle.kts b/src/serious_python/example/run_example/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/src/serious_python/example/run_example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/src/serious_python/example/run_example/android/gradle.properties b/src/serious_python/example/run_example/android/gradle.properties index 94adc3a3..d5da7278 100644 --- a/src/serious_python/example/run_example/android/gradle.properties +++ b/src/serious_python/example/run_example/android/gradle.properties @@ -1,3 +1,6 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true -android.enableJetifier=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/src/serious_python/example/run_example/android/gradle/wrapper/gradle-wrapper.properties b/src/serious_python/example/run_example/android/gradle/wrapper/gradle-wrapper.properties index a10c8212..e4ef43fb 100644 --- a/src/serious_python/example/run_example/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/serious_python/example/run_example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/src/serious_python/example/run_example/android/settings.gradle b/src/serious_python/example/run_example/android/settings.gradle deleted file mode 100644 index b64b2eb7..00000000 --- a/src/serious_python/example/run_example/android/settings.gradle +++ /dev/null @@ -1,29 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - } - settings.ext.flutterSdkPath = flutterSdkPath() - - includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } - - plugins { - id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.3.1" apply false -} - -include ":app" diff --git a/src/serious_python/example/run_example/android/settings.gradle.kts b/src/serious_python/example/run_example/android/settings.gradle.kts new file mode 100644 index 00000000..ca1f8f00 --- /dev/null +++ b/src/serious_python/example/run_example/android/settings.gradle.kts @@ -0,0 +1,28 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.11.1" apply false + // Declared (but not applied) so Built-in Kotlin — where the Flutter Gradle + // Plugin applies kotlin-android for us — uses this KGP version. + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/src/serious_python/example/run_example/ios/Flutter/AppFrameworkInfo.plist b/src/serious_python/example/run_example/ios/Flutter/AppFrameworkInfo.plist index 7c569640..391a902b 100644 --- a/src/serious_python/example/run_example/ios/Flutter/AppFrameworkInfo.plist +++ b/src/serious_python/example/run_example/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 12.0 diff --git a/src/serious_python/example/run_example/ios/Podfile b/src/serious_python/example/run_example/ios/Podfile index 3e44f9c6..e51a31d9 100644 --- a/src/serious_python/example/run_example/ios/Podfile +++ b/src/serious_python/example/run_example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '13.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/src/serious_python/example/run_example/ios/Podfile.lock b/src/serious_python/example/run_example/ios/Podfile.lock index a6e178aa..9bae2c46 100644 --- a/src/serious_python/example/run_example/ios/Podfile.lock +++ b/src/serious_python/example/run_example/ios/Podfile.lock @@ -1,36 +1,23 @@ PODS: - Flutter (1.0.0) - - integration_test (0.0.1): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - serious_python_darwin (0.9.0): + - serious_python_darwin (2.0.0): - Flutter - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - serious_python_darwin (from `.symlinks/plugins/serious_python_darwin/darwin`) EXTERNAL SOURCES: Flutter: :path: Flutter - integration_test: - :path: ".symlinks/plugins/integration_test/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" serious_python_darwin: :path: ".symlinks/plugins/serious_python_darwin/darwin" SPEC CHECKSUMS: - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - serious_python_darwin: f9c5bd0dc6fbe536075be8606baaf5eebae61ea8 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 -PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5 +PODFILE CHECKSUM: 4f1c12611da7338d21589c0b2ecd6bd20b109694 COCOAPODS: 1.14.3 diff --git a/src/serious_python/example/run_example/ios/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/run_example/ios/Runner.xcodeproj/project.pbxproj index 10450bff..0ac1996c 100644 --- a/src/serious_python/example/run_example/ios/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/run_example/ios/Runner.xcodeproj/project.pbxproj @@ -7,15 +7,17 @@ objects = { /* Begin PBXBuildFile section */ - 0ECD75C89334B57BDC8D90DC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC9102B96DB1483340228979 /* Pods_Runner.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - F3B4C2EDB0698819E36294C5 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C47F63012DFB4F35FF209FB9 /* Pods_RunnerTests.framework */; }; + CF84F7C589098D0D53F29EA5 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E49AE308051092F5430F53CA /* Pods_RunnerTests.framework */; }; + F30244A3211D5E427A78417D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62522B64782DFA6C89DF9AD7 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -44,14 +46,19 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1841A8366E682B7A1DD4DA5C /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 399AB64EF1EB6528E754BE1D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 554EB723AFF3B5087EF64DD5 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 62522B64782DFA6C89DF9AD7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6F2541DBDC3C124074F83922 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 8BF8669BA338C5B46090EC79 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 89AEA4B6F9B230A55D5C72EB /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -59,12 +66,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BCF9E5BC78A2EA746E6B84C4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - C47F63012DFB4F35FF209FB9 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D379499903D98867C36E25EA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - E4710682EF613043A76CB7D1 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - EC9102B96DB1483340228979 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F97D0BAFF74D61300512E0B1 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + DC483BFC8E634B1A5EC721CF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + E49AE308051092F5430F53CA /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E8D211C06EECAAA50D928D30 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,46 +76,57 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0ECD75C89334B57BDC8D90DC /* Pods_Runner.framework in Frameworks */, + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + F30244A3211D5E427A78417D /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - E39EF68C436C117B0971FD3C /* Frameworks */ = { + E7FF40BA447253FD9E843BD3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - F3B4C2EDB0698819E36294C5 /* Pods_RunnerTests.framework in Frameworks */, + CF84F7C589098D0D53F29EA5 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 331C8082294A63A400263BE5 /* RunnerTests */ = { + 221C24505F531D50849A1B61 /* Pods */ = { isa = PBXGroup; children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, + 6F2541DBDC3C124074F83922 /* Pods-Runner.debug.xcconfig */, + E8D211C06EECAAA50D928D30 /* Pods-Runner.release.xcconfig */, + 399AB64EF1EB6528E754BE1D /* Pods-Runner.profile.xcconfig */, + 554EB723AFF3B5087EF64DD5 /* Pods-RunnerTests.debug.xcconfig */, + 89AEA4B6F9B230A55D5C72EB /* Pods-RunnerTests.release.xcconfig */, + DC483BFC8E634B1A5EC721CF /* Pods-RunnerTests.profile.xcconfig */, ); - path = RunnerTests; + name = Pods; + path = Pods; sourceTree = ""; }; - 458CDDF0180A3495894DE30C /* Pods */ = { + 225F4D43375C96033CFFB13C /* Frameworks */ = { isa = PBXGroup; children = ( - D379499903D98867C36E25EA /* Pods-Runner.debug.xcconfig */, - 8BF8669BA338C5B46090EC79 /* Pods-Runner.release.xcconfig */, - BCF9E5BC78A2EA746E6B84C4 /* Pods-Runner.profile.xcconfig */, - 1841A8366E682B7A1DD4DA5C /* Pods-RunnerTests.debug.xcconfig */, - F97D0BAFF74D61300512E0B1 /* Pods-RunnerTests.release.xcconfig */, - E4710682EF613043A76CB7D1 /* Pods-RunnerTests.profile.xcconfig */, + 62522B64782DFA6C89DF9AD7 /* Pods_Runner.framework */, + E49AE308051092F5430F53CA /* Pods_RunnerTests.framework */, ); - name = Pods; - path = Pods; + name = Frameworks; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -127,8 +142,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, - 458CDDF0180A3495894DE30C /* Pods */, - E41C5AD26036F4028C7CEFA3 /* Frameworks */, + 221C24505F531D50849A1B61 /* Pods */, + 225F4D43375C96033CFFB13C /* Frameworks */, ); sourceTree = ""; }; @@ -151,20 +166,12 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; - E41C5AD26036F4028C7CEFA3 /* Frameworks */ = { - isa = PBXGroup; - children = ( - EC9102B96DB1483340228979 /* Pods_Runner.framework */, - C47F63012DFB4F35FF209FB9 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -172,10 +179,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 26D00038C892F3CE540EAA65 /* [CP] Check Pods Manifest.lock */, + C234C0FA752886C45FD765ED /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, - E39EF68C436C117B0971FD3C /* Frameworks */, + E7FF40BA447253FD9E843BD3 /* Frameworks */, ); buildRules = ( ); @@ -191,20 +198,24 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - C3AB7694CD38576DCB2BFAF8 /* [CP] Check Pods Manifest.lock */, + B35D7424D749C89CB3E981BE /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - B372FAA83F7FA6B86E511DBD /* [CP] Embed Pods Frameworks */, + 9C2BD3DE6890171FCDB2C70D /* [CP] Embed Pods Frameworks */, + 6071F178056A40A19D0FD492 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -238,6 +249,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -270,43 +284,38 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 26D00038C892F3CE540EAA65 /* [CP] Check Pods Manifest.lock */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); + name = "Thin Binary"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 6071F178056A40A19D0FD492 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Thin Binary"; - outputPaths = ( + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -323,7 +332,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - B372FAA83F7FA6B86E511DBD /* [CP] Embed Pods Frameworks */ = { + 9C2BD3DE6890171FCDB2C70D /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -340,7 +349,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - C3AB7694CD38576DCB2BFAF8 /* [CP] Check Pods Manifest.lock */ = { + B35D7424D749C89CB3E981BE /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -362,6 +371,28 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + C234C0FA752886C45FD765ED /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +410,7 @@ files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -416,6 +448,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -445,6 +478,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -453,7 +487,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -485,7 +519,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1841A8366E682B7A1DD4DA5C /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = 554EB723AFF3B5087EF64DD5 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -503,7 +537,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F97D0BAFF74D61300512E0B1 /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = 89AEA4B6F9B230A55D5C72EB /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -519,7 +553,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E4710682EF613043A76CB7D1 /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = DC483BFC8E634B1A5EC721CF /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -537,6 +571,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -566,6 +601,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -580,7 +616,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -592,6 +628,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -621,6 +658,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -629,7 +667,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -717,6 +755,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/src/serious_python/example/run_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/src/serious_python/example/run_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5df..c3fedb29 100644 --- a/src/serious_python/example/run_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/src/serious_python/example/run_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + diff --git a/src/serious_python/example/run_example/ios/Runner/AppDelegate.swift b/src/serious_python/example/run_example/ios/Runner/AppDelegate.swift index b6363034..c30b367e 100644 --- a/src/serious_python/example/run_example/ios/Runner/AppDelegate.swift +++ b/src/serious_python/example/run_example/ios/Runner/AppDelegate.swift @@ -1,13 +1,16 @@ -import UIKit import Flutter +import UIKit @main -@objc class AppDelegate: FlutterAppDelegate { +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/src/serious_python/example/run_example/ios/Runner/Info.plist b/src/serious_python/example/run_example/ios/Runner/Info.plist index 235b9830..ba514518 100644 --- a/src/serious_python/example/run_example/ios/Runner/Info.plist +++ b/src/serious_python/example/run_example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,29 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,9 +66,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/src/serious_python/example/run_example/ios/Runner/SceneDelegate.swift b/src/serious_python/example/run_example/ios/Runner/SceneDelegate.swift new file mode 100644 index 00000000..b9ce8ea2 --- /dev/null +++ b/src/serious_python/example/run_example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/src/serious_python/example/run_example/linux/CMakeLists.txt b/src/serious_python/example/run_example/linux/CMakeLists.txt index 45eb4503..d3f4ba4b 100644 --- a/src/serious_python/example/run_example/linux/CMakeLists.txt +++ b/src/serious_python/example/run_example/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # Project-level configuration. -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.13) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change @@ -54,25 +54,8 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) @@ -123,6 +106,12 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/src/serious_python/example/run_example/linux/flutter/generated_plugins.cmake b/src/serious_python/example/run_example/linux/flutter/generated_plugins.cmake index 6d77107e..ab50859e 100644 --- a/src/serious_python/example/run_example/linux/flutter/generated_plugins.cmake +++ b/src/serious_python/example/run_example/linux/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python/example/run_example/linux/runner/CMakeLists.txt b/src/serious_python/example/run_example/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/src/serious_python/example/run_example/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/src/serious_python/example/run_example/linux/main.cc b/src/serious_python/example/run_example/linux/runner/main.cc similarity index 100% rename from src/serious_python/example/run_example/linux/main.cc rename to src/serious_python/example/run_example/linux/runner/main.cc diff --git a/src/serious_python/example/run_example/linux/my_application.cc b/src/serious_python/example/run_example/linux/runner/my_application.cc similarity index 59% rename from src/serious_python/example/run_example/linux/my_application.cc rename to src/serious_python/example/run_example/linux/runner/my_application.cc index 07c0c106..1ed5d6e9 100644 --- a/src/serious_python/example/run_example/linux/my_application.cc +++ b/src/serious_python/example/run_example/linux/runner/my_application.cc @@ -14,6 +14,11 @@ struct _MyApplication { G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView* view) { + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); @@ -48,31 +53,44 @@ static void my_application_activate(GApplication* application) { } gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 + // for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), + self); + gtk_widget_realize(GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; } g_application_activate(application); @@ -81,6 +99,24 @@ static gboolean my_application_local_command_line(GApplication* application, gch return TRUE; } +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); @@ -90,15 +126,23 @@ static void my_application_dispose(GObject* object) { static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); } diff --git a/src/serious_python/example/flet_example/linux/my_application.h b/src/serious_python/example/run_example/linux/runner/my_application.h similarity index 70% rename from src/serious_python/example/flet_example/linux/my_application.h rename to src/serious_python/example/run_example/linux/runner/my_application.h index 72271d5e..db16367a 100644 --- a/src/serious_python/example/flet_example/linux/my_application.h +++ b/src/serious_python/example/run_example/linux/runner/my_application.h @@ -3,7 +3,10 @@ #include -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, +G_DECLARE_FINAL_TYPE(MyApplication, + my_application, + MY, + APPLICATION, GtkApplication) /** diff --git a/src/serious_python/example/run_example/macos/Flutter/GeneratedPluginRegistrant.swift b/src/serious_python/example/run_example/macos/Flutter/GeneratedPluginRegistrant.swift index 6bcae484..7ef3a6c2 100644 --- a/src/serious_python/example/run_example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/src/serious_python/example/run_example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import path_provider_foundation import serious_python_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) } diff --git a/src/serious_python/example/run_example/macos/Podfile.lock b/src/serious_python/example/run_example/macos/Podfile.lock index 6ee684c8..f59e9b47 100644 --- a/src/serious_python/example/run_example/macos/Podfile.lock +++ b/src/serious_python/example/run_example/macos/Podfile.lock @@ -1,29 +1,22 @@ PODS: - FlutterMacOS (1.0.0) - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - serious_python_darwin (0.9.2): + - serious_python_darwin (2.0.0): - Flutter - FlutterMacOS DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - serious_python_darwin (from `Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin`) EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin serious_python_darwin: :path: Flutter/ephemeral/.symlinks/plugins/serious_python_darwin/darwin SPEC CHECKSUMS: - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 - serious_python_darwin: 5e7e55250432119e32b7605144da0d592d39f3cc + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + serious_python_darwin: 6d58c9837595683a71e20114bdd4607568c98e84 PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 diff --git a/src/serious_python/example/run_example/macos/Runner.xcodeproj/project.pbxproj b/src/serious_python/example/run_example/macos/Runner.xcodeproj/project.pbxproj index 4eac939f..769f37a0 100644 --- a/src/serious_python/example/run_example/macos/Runner.xcodeproj/project.pbxproj +++ b/src/serious_python/example/run_example/macos/Runner.xcodeproj/project.pbxproj @@ -27,8 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 381D3A43A4DCB5E84EB5B553 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F59CC062D29D173B37B760E /* Pods_RunnerTests.framework */; }; - 386AE86EAE4E58B10CF59C89 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6C216A7A8AB7E5B2C660AF7 /* Pods_Runner.framework */; }; + 60F575BBFB05ECB5BC731F3A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBCD7A366CFB6AA3F26FB79B /* Pods_Runner.framework */; }; + 9A45524B786DA102A205EB20 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D27FB6937DE38CBCB05E2AB /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -62,9 +62,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1AA4B1F42A9761CAE6E497E8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 1AA56634FBFA9C118760D530 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 1F59CC062D29D173B37B760E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0BA9260A942C6E356B438163 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 23619C2850A7CB4DD832FA9E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; @@ -81,13 +80,14 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3AA9059D78CE7A3AC615A3B2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 8299D3315FCBC8C0435D08B4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 8D27FB6937DE38CBCB05E2AB /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - 9B5D5BE9E2D6FB3E0D60C9CC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - B6C216A7A8AB7E5B2C660AF7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BFF2A0270ACBFC22CF4B2E2A /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - F4B50254D7BFC1D34C17E1E6 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + AA5179947CAC375732FD65A1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + BA9E178CC85319DB5063AD2A /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + CBCD7A366CFB6AA3F26FB79B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F67D3A95F20A1A89B671545F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,7 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 381D3A43A4DCB5E84EB5B553 /* Pods_RunnerTests.framework in Frameworks */, + 9A45524B786DA102A205EB20 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -103,13 +103,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 386AE86EAE4E58B10CF59C89 /* Pods_Runner.framework in Frameworks */, + 60F575BBFB05ECB5BC731F3A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2838B11037D083B9C3FA026F /* Pods */ = { + isa = PBXGroup; + children = ( + 3AA9059D78CE7A3AC615A3B2 /* Pods-Runner.debug.xcconfig */, + AA5179947CAC375732FD65A1 /* Pods-Runner.release.xcconfig */, + F67D3A95F20A1A89B671545F /* Pods-Runner.profile.xcconfig */, + 0BA9260A942C6E356B438163 /* Pods-RunnerTests.debug.xcconfig */, + BA9E178CC85319DB5063AD2A /* Pods-RunnerTests.release.xcconfig */, + 23619C2850A7CB4DD832FA9E /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -137,7 +151,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, - 4F482484045CE84A88119B79 /* Pods */, + 2838B11037D083B9C3FA026F /* Pods */, ); sourceTree = ""; }; @@ -185,25 +199,11 @@ path = Runner; sourceTree = ""; }; - 4F482484045CE84A88119B79 /* Pods */ = { - isa = PBXGroup; - children = ( - 8299D3315FCBC8C0435D08B4 /* Pods-Runner.debug.xcconfig */, - 1AA56634FBFA9C118760D530 /* Pods-Runner.release.xcconfig */, - 9B5D5BE9E2D6FB3E0D60C9CC /* Pods-Runner.profile.xcconfig */, - F4B50254D7BFC1D34C17E1E6 /* Pods-RunnerTests.debug.xcconfig */, - 1AA4B1F42A9761CAE6E497E8 /* Pods-RunnerTests.release.xcconfig */, - BFF2A0270ACBFC22CF4B2E2A /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - B6C216A7A8AB7E5B2C660AF7 /* Pods_Runner.framework */, - 1F59CC062D29D173B37B760E /* Pods_RunnerTests.framework */, + CBCD7A366CFB6AA3F26FB79B /* Pods_Runner.framework */, + 8D27FB6937DE38CBCB05E2AB /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -215,7 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 214AA595C9EEB7AC3063D2BE /* [CP] Check Pods Manifest.lock */, + BAF9ECAC5469ED3242173EBB /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -234,13 +234,14 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 3FE72586F90C485D67A2EB9B /* [CP] Check Pods Manifest.lock */, + DC6E30DB7C03C90D6695EB76 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - C4A6FCD43E8738D6785662D3 /* [CP] Embed Pods Frameworks */, + 0D22FFDAE571FF7D9AE2FDA7 /* [CP] Embed Pods Frameworks */, + 319F254C714166AC17D0BA17 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -258,6 +259,7 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; @@ -322,26 +324,38 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 214AA595C9EEB7AC3063D2BE /* [CP] Check Pods Manifest.lock */ = { + 0D22FFDAE571FF7D9AE2FDA7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 319F254C714166AC17D0BA17 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; 3399D490228B24CF009A79C7 /* ShellScript */ = { @@ -382,7 +396,7 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 3FE72586F90C485D67A2EB9B /* [CP] Check Pods Manifest.lock */ = { + BAF9ECAC5469ED3242173EBB /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -397,28 +411,33 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - C4A6FCD43E8738D6785662D3 /* [CP] Embed Pods Frameworks */ = { + DC6E30DB7C03C90D6695EB76 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -472,7 +491,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F4B50254D7BFC1D34C17E1E6 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = 0BA9260A942C6E356B438163 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -487,7 +506,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1AA4B1F42A9761CAE6E497E8 /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = BA9E178CC85319DB5063AD2A /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -502,7 +521,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BFF2A0270ACBFC22CF4B2E2A /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = 23619C2850A7CB4DD832FA9E /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -520,6 +539,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -543,9 +563,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -593,6 +615,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -616,9 +639,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -646,6 +671,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -669,9 +695,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/src/serious_python/example/run_example/macos/Runner/Configs/AppInfo.xcconfig b/src/serious_python/example/run_example/macos/Runner/Configs/AppInfo.xcconfig index 532b6b72..f2d73e5a 100644 --- a/src/serious_python/example/run_example/macos/Runner/Configs/AppInfo.xcconfig +++ b/src/serious_python/example/run_example/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = run_example PRODUCT_BUNDLE_IDENTIFIER = com.example.runExample // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2026 com.example. All rights reserved. diff --git a/src/serious_python/example/run_example/macos/Runner/DebugProfile.entitlements b/src/serious_python/example/run_example/macos/Runner/DebugProfile.entitlements index cf2172f7..9f56413f 100644 --- a/src/serious_python/example/run_example/macos/Runner/DebugProfile.entitlements +++ b/src/serious_python/example/run_example/macos/Runner/DebugProfile.entitlements @@ -1,12 +1,12 @@ - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - \ No newline at end of file + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/src/serious_python/example/run_example/macos/Runner/Release.entitlements b/src/serious_python/example/run_example/macos/Runner/Release.entitlements index 781649c8..e89b7f32 100644 --- a/src/serious_python/example/run_example/macos/Runner/Release.entitlements +++ b/src/serious_python/example/run_example/macos/Runner/Release.entitlements @@ -1,8 +1,8 @@ - - com.apple.security.app-sandbox - - - \ No newline at end of file + + com.apple.security.app-sandbox + + + diff --git a/src/serious_python/example/run_example/macos/RunnerTests/RunnerTests.swift b/src/serious_python/example/run_example/macos/RunnerTests/RunnerTests.swift index 5418c9f5..61f3bd1f 100644 --- a/src/serious_python/example/run_example/macos/RunnerTests/RunnerTests.swift +++ b/src/serious_python/example/run_example/macos/RunnerTests/RunnerTests.swift @@ -1,5 +1,5 @@ -import FlutterMacOS import Cocoa +import FlutterMacOS import XCTest class RunnerTests: XCTestCase { diff --git a/src/serious_python/example/run_example/pubspec.lock b/src/serious_python/example/run_example/pubspec.lock index 7cd1c7e3..3b9666fe 100644 --- a/src/serious_python/example/run_example/pubspec.lock +++ b/src/serious_python/example/run_example/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.0.9" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" async: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.1" boolean_selector: dependency: transitive description: @@ -49,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.dev" + source: hosted + version: "1.2.1" collection: dependency: transitive description: @@ -61,18 +69,18 @@ packages: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.7" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" fake_async: dependency: transitive description: @@ -85,10 +93,10 @@ packages: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.0" file: dependency: transitive description: @@ -133,27 +141,51 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.dev" + source: hosted + version: "2.0.2" http: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.6.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" integration_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" leak_tracker: dependency: transitive description: @@ -186,6 +218,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -206,10 +246,26 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" + url: "https://pub.dev" + source: hosted + version: "9.4.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" path: dependency: "direct main" description: @@ -222,26 +278,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.3.1" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.0" path_provider_linux: dependency: transitive description: @@ -270,10 +326,10 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.0" platform: dependency: transitive description: @@ -294,18 +350,34 @@ packages: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.5.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + url: "https://pub.dev" + source: hosted + version: "5.0.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "2.2.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" serious_python: dependency: "direct main" description: @@ -352,10 +424,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" sky_engine: dependency: transitive description: flutter @@ -365,10 +437,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.2" stack_trace: dependency: transitive description: @@ -413,10 +485,10 @@ packages: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.11" toml: dependency: transitive description: @@ -429,10 +501,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" vector_math: dependency: transitive description: @@ -445,34 +517,42 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.2.0" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" webdriver: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.1.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "3.1.3" sdks: - dart: ">=3.9.0-0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" diff --git a/src/serious_python/example/run_example/windows/CMakeLists.txt b/src/serious_python/example/run_example/windows/CMakeLists.txt index 4dcd8dd3..619b57d2 100644 --- a/src/serious_python/example/run_example/windows/CMakeLists.txt +++ b/src/serious_python/example/run_example/windows/CMakeLists.txt @@ -87,6 +87,12 @@ if(PLUGIN_BUNDLED_LIBRARIES) COMPONENT Runtime) endif() +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/src/serious_python/example/run_example/windows/flutter/generated_plugins.cmake b/src/serious_python/example/run_example/windows/flutter/generated_plugins.cmake index 159536d6..f2f58d64 100644 --- a/src/serious_python/example/run_example/windows/flutter/generated_plugins.cmake +++ b/src/serious_python/example/run_example/windows/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/src/serious_python/example/run_example/windows/runner/Runner.rc b/src/serious_python/example/run_example/windows/runner/Runner.rc index 7814ed45..6065c87b 100644 --- a/src/serious_python/example/run_example/windows/runner/Runner.rc +++ b/src/serious_python/example/run_example/windows/runner/Runner.rc @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "run_example" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "run_example" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2026 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "run_example.exe" "\0" VALUE "ProductName", "run_example" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/src/serious_python/example/run_example/windows/runner/runner.exe.manifest b/src/serious_python/example/run_example/windows/runner/runner.exe.manifest index a42ea768..153653e8 100644 --- a/src/serious_python/example/run_example/windows/runner/runner.exe.manifest +++ b/src/serious_python/example/run_example/windows/runner/runner.exe.manifest @@ -9,12 +9,6 @@ - - - - - - diff --git a/src/serious_python/example/run_example/windows/runner/utils.cpp b/src/serious_python/example/run_example/windows/runner/utils.cpp index b2b08734..3a0b4651 100644 --- a/src/serious_python/example/run_example/windows/runner/utils.cpp +++ b/src/serious_python/example/run_example/windows/runner/utils.cpp @@ -45,13 +45,13 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } - int target_length = ::WideCharToMultiByte( + unsigned int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr) -1; // remove the trailing null character int input_length = (int)wcslen(utf16_string); std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { + if (target_length == 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle index 90e2841f..f59db36a 100644 --- a/src/serious_python_android/android/build.gradle +++ b/src/serious_python_android/android/build.gradle @@ -24,8 +24,8 @@ buildscript { dependencies { // The Android Gradle Plugin knows how to build native code with the NDK. - classpath 'com.android.tools.build:gradle:7.3.0' - classpath 'de.undercouch:gradle-download-task:4.1.2' + classpath 'com.android.tools.build:gradle:8.11.1' + classpath 'de.undercouch:gradle-download-task:5.6.0' } } @@ -44,15 +44,15 @@ android { // Bumping the plugin compileSdkVersion requires all clients of this plugin // to bump the version in their app. - compileSdkVersion 31 + compileSdkVersion 36 // No native code is compiled here — libdart_bridge.so is downloaded as a // pre-built artifact from flet-dev/dart-bridge releases (see the // downloadDartBridge_$abi tasks below) and dropped into jniLibs. compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } defaultConfig { diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index 112501d6..817ae1ae 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -24,10 +24,18 @@ if [ ! -f "$python_ios_dist_path" ]; then mv "$python_ios_dist_path.tmp" "$python_ios_dist_path" fi -if [ ! -d "$dist" ]; then +# Re-extract when $dist is missing OR was assembled for a different Python +# version. The guard used to be `[ ! -d "$dist" ]`, which left a stale dist_ios +# from a previous Python version in place — e.g. bundling 3.12 under 3.14 +# site-packages, which trips C-extension ABI errors ("unknown slot ID") at +# import. A version marker keys the extracted dist to $python_full_version. +marker="$dist/.python_full_version" +if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$python_full_version" ]; then + rm -rf "$dist" mkdir -p "$dist" tar -xzf "$python_ios_dist_path" -C "$dist" mv "$dist/python-stdlib" "$dist/stdlib" + echo "$python_full_version" > "$marker" fi # ---- flet-dev/dart-bridge (xcframework) ----------------------------------- diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index 706067b0..1e4479ce 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -26,7 +26,14 @@ if [ ! -f "$python_macos_dist_path" ]; then mv "$python_macos_dist_path.tmp" "$python_macos_dist_path" fi -if [ ! -d "$dist" ]; then +# Re-extract when $dist is missing OR was assembled for a different Python +# version. The guard used to be `[ ! -d "$dist" ]`, which left a stale dist_macos +# from a previous Python version in place — e.g. bundling 3.12 under 3.14 +# site-packages, which trips C-extension ABI errors ("unknown slot ID") at +# import. A version marker keys the extracted dist to $python_full_version. +marker="$dist/.python_full_version" +if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$python_full_version" ]; then + rm -rf "$dist" mkdir -p "$dist" tar -xzf "$python_macos_dist_path" -C "$dist" mv "$dist/python-stdlib" "$dist/stdlib" @@ -41,6 +48,7 @@ if [ ! -d "$dist" ]; then # unexpectedly" crash dialog. We don't need this launcher for embedded # use; libdart_bridge dlopens Python.framework's main binary directly. find "$dist/xcframeworks" -type d -name 'Python.app' -prune -exec rm -rf {} + + echo "$python_full_version" > "$marker" fi # ---- flet-dev/dart-bridge (xcframework, same archive for macOS + iOS) ----- From 1fbf829a0b19652beecd3f39ce9bb727b7582f09 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sun, 14 Jun 2026 17:22:18 -0700 Subject: [PATCH 106/114] Drop bare in-place version-switching machinery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switching the bundled Python version between builds is a rare scenario, and a clean rebuild is the natural, expected way to handle it (flet build now wipes its build dir on a version change). The dedicated machinery to make a bare in-place switch take effect without a clean was disproportionate and couldn't fully cover the downstream Xcode/CocoaPods incremental bundle copy anyway. Remove: - the `configure` command and `stageDarwinRuntime` (+ its call in `package`) - the run_example version_test + its main.py version probe - the gated python-version-switching workflow - the `configure` docs Kept (these are anti-drift / correctness, not switching): the manifest-driven single-source version resolution, and the version-aware `rm -rf dist` marker guard in prepare_ios.sh/prepare_macos.sh — that guard is what makes a clean build pick up a new version, since the embedded dist lives in the shared pub-cache and a build-dir clean doesn't touch it. --- .../workflows/python-version-switching.yml | 99 ------------------- src/serious_python/README.md | 17 +--- src/serious_python/bin/configure_command.dart | 62 ------------ src/serious_python/bin/main.dart | 2 - src/serious_python/bin/package_command.dart | 58 ----------- .../example/run_example/app/app.zip.hash | 2 +- .../example/run_example/app/src/main.py | 12 --- .../integration_test/version_test.dart | 46 --------- 8 files changed, 5 insertions(+), 293 deletions(-) delete mode 100644 .github/workflows/python-version-switching.yml delete mode 100644 src/serious_python/bin/configure_command.dart delete mode 100644 src/serious_python/example/run_example/integration_test/version_test.dart diff --git a/.github/workflows/python-version-switching.yml b/.github/workflows/python-version-switching.yml deleted file mode 100644 index f77f3bd2..00000000 --- a/.github/workflows/python-version-switching.yml +++ /dev/null @@ -1,99 +0,0 @@ -name: Python version switching - -# Regression guard for switching the embedded Python version on a single -# machine: the matrix CI (one VM per version) can't catch a stale runtime left -# over from a previous version, so this job builds run_example for several -# versions *sequentially on the same runner* (including a downgrade) and asserts -# the running interpreter — and its numpy wheel — match each requested version. -# -# Gated (heavy: per-version package + build) — runs on PRs that touch the -# version/darwin machinery, manually, and nightly. -on: - workflow_dispatch: - schedule: - - cron: "0 6 * * *" - pull_request: - paths: - - "src/serious_python_darwin/**" - - "src/serious_python/lib/src/python_versions.dart" - - "src/serious_python/bin/**" - - "src/serious_python/example/run_example/**" - - ".github/workflows/python-version-switching.yml" - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - switch_macos: - name: Switch Python versions on macOS - runs-on: macos-26 - timeout-minutes: 40 - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: ".fvmrc" - cache: true - - - name: Package + run version_test for each Python (same VM) - working-directory: src/serious_python/example/run_example - run: | - set -euo pipefail - export SERIOUS_PYTHON_SITE_PACKAGES="$(pwd)/build/site-packages" - flutter pub get - for v in 3.12 3.13 3.14 3.12; do - echo "::group::Python $v" - export SERIOUS_PYTHON_VERSION=$v - # NOTE: no `rm -rf Pods` — package stages the interpreter so a bare - # repackage + rebuild switches versions on its own. - dart run serious_python:main package app/src \ - --platform Darwin --python-version "$v" -r -r -r app/src/requirements.txt - flutter test integration_test/version_test.dart -d macos \ - --dart-define=EXPECTED_PYTHON_VERSION="$v" - echo "::endgroup::" - done - - switch_ios: - name: Switch Python versions on iOS - runs-on: macos-26 - timeout-minutes: 50 - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: ".fvmrc" - cache: true - - - name: Setup iOS Simulator - id: simulator - uses: futureware-tech/simulator-action@v5 - with: - model: "iPhone 17 Pro Max" - os: "iOS" - os_version: "26.5" - shutdown_after_job: true - wait_for_boot: true - - - name: Package + run version_test for each Python (same VM) - working-directory: src/serious_python/example/run_example - run: | - set -euo pipefail - export SERIOUS_PYTHON_SITE_PACKAGES="$(pwd)/build/site-packages" - flutter pub get - for v in 3.12 3.13 3.14 3.12; do - echo "::group::Python $v" - export SERIOUS_PYTHON_VERSION=$v - dart run serious_python:main package app/src \ - --platform iOS --python-version "$v" -r -r -r app/src/requirements.txt - flutter test integration_test/version_test.dart \ - -d ${{ steps.simulator.outputs.udid }} \ - --dart-define=EXPECTED_PYTHON_VERSION="$v" - echo "::endgroup::" - done diff --git a/src/serious_python/README.md b/src/serious_python/README.md index 10090f4d..ad965893 100644 --- a/src/serious_python/README.md +++ b/src/serious_python/README.md @@ -151,19 +151,10 @@ read by each platform plugin's build script (`build.gradle`, the phase and the Flutter build phase. See the [Python versions](#python-versions) table above for the matching CPython and Pyodide releases. -#### Running a script without packaging (`configure`) - -The `package` command stages the embedded Darwin (iOS/macOS) runtime for the -selected version automatically. For the bare "run a Python script" flow where -you skip `package`, stage it yourself with `configure`, then build: - -``` -export SERIOUS_PYTHON_VERSION=3.13 -dart run serious_python:main configure --platform Darwin # or iOS -``` - -Android, Linux and Windows download the runtime during their native build, so -`configure` is a no-op there. +> **Note:** changing the bundled Python version for an app you've already built +> requires a clean build (delete the app's `build/` directory, or run +> `flutter clean`) so stale compiled bytecode from the previous version isn't +> reused. #### Installing requirements diff --git a/src/serious_python/bin/configure_command.dart b/src/serious_python/bin/configure_command.dart deleted file mode 100644 index 6618b9b5..00000000 --- a/src/serious_python/bin/configure_command.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'package:serious_python/src/python_versions.dart'; - -import 'package_command.dart' show stageDarwinRuntime, sitePackagesEnvironmentVariable; - -/// `configure` subcommand: stages the embedded Python runtime for a platform and -/// version without packaging an app. Useful when running a bare Python script -/// (no `package` step) and to make a version switch take effect on a rebuild. -/// -/// Only Darwin (iOS/macOS) needs explicit staging — the Android/Linux/Windows -/// native builds download the runtime themselves from the version table. -class ConfigureCommand extends Command { - @override - final name = "configure"; - - @override - final description = - "Stage the embedded Python runtime for a platform/version (Darwin)."; - - ConfigureCommand() { - argParser.addOption('platform', - abbr: "p", - allowed: ["iOS", "Android", "Emscripten", "Windows", "Linux", "Darwin"], - mandatory: true, - help: "Platform to stage the runtime for, e.g. 'iOS' or 'Darwin'."); - argParser.addOption('python-version', - allowed: pythonReleases.keys.toList(), - help: "Short Python version to stage (e.g. 3.13). Defaults to " - "\$$pythonVersionEnvironmentVariable env var or " - "'$defaultPythonVersion'."); - } - - @override - Future run() async { - final platform = argResults!['platform'] as String; - final shortVersion = (argResults!['python-version'] as String?) ?? - Platform.environment[pythonVersionEnvironmentVariable] ?? - defaultPythonVersion; - - if (platform != "iOS" && platform != "Darwin") { - stdout.writeln("configure: nothing to stage for $platform — its native " - "build downloads the runtime from python_versions.properties."); - return; - } - - final sitePackagesRoot = - Platform.environment[sitePackagesEnvironmentVariable]; - if (sitePackagesRoot == null || sitePackagesRoot.trim().isEmpty) { - stderr.writeln("serious_python: set $sitePackagesEnvironmentVariable to " - "the app's site-packages directory before running configure."); - exit(2); - } - - await stageDarwinRuntime( - platform: platform, - shortVersion: shortVersion, - sitePackagesRoot: sitePackagesRoot, - ); - } -} diff --git a/src/serious_python/bin/main.dart b/src/serious_python/bin/main.dart index 372dab98..7e03cff1 100644 --- a/src/serious_python/bin/main.dart +++ b/src/serious_python/bin/main.dart @@ -1,6 +1,5 @@ import 'package:args/command_runner.dart'; -import 'configure_command.dart'; import 'package_command.dart'; import 'version_command.dart'; @@ -8,7 +7,6 @@ void main(List arguments) async { var runner = CommandRunner("dart run serious_python:main", "A tool for packaging Python apps to work with serious_python package.") ..addCommand(PackageCommand()) - ..addCommand(ConfigureCommand()) ..addCommand(VersionCommand()); await runner.run(arguments); diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index baf4607c..3d4a4c16 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -31,56 +31,6 @@ const allowSourceDistrosEnvironmentVariable = // snapshot of python-build's manifest.json; regenerate with // `dart run serious_python:gen_version_tables`. -/// Stages the embedded Darwin (iOS/macOS) Python runtime for [shortVersion] by -/// running the plugin's version-aware prepare script through the `.pod` symlink -/// in [sitePackagesRoot]. This is what makes a version switch take effect on a -/// bare rebuild (no `pod install` re-run needed). No-op for non-Darwin platforms, -/// whose native build stages the runtime itself. Returns false if skipped. Used -/// by both the `package` and `configure` commands. -Future stageDarwinRuntime({ - required String platform, - required String shortVersion, - required String sitePackagesRoot, -}) async { - final script = platform == "iOS" - ? "prepare_ios.sh" - : platform == "Darwin" - ? "prepare_macos.sh" - : null; - if (script == null) return false; - final release = pythonReleases[shortVersion]; - if (release == null) { - stderr.writeln("serious_python: unknown Python version '$shortVersion'. " - "Supported: ${pythonReleases.keys.join(", ")}"); - exit(2); - } - final fullVersion = - Platform.environment[pythonFullVersionEnvironmentVariable] ?? - release.standaloneVersion; - final buildDate = Platform.environment[pythonBuildDateEnvironmentVariable] ?? - pythonReleaseDate; - final bridge = Platform.environment[dartBridgeVersionEnvironmentVariable] ?? - dartBridgeVersion; - final sh = File(path.join(sitePackagesRoot, ".pod", script)); - if (!await sh.exists()) { - stdout.writeln("serious_python: $script not found under " - "$sitePackagesRoot/.pod — build the app once so CocoaPods creates the " - "plugin symlink, then re-run."); - return false; - } - stdout.writeln( - "Staging $platform Python $shortVersion (CPython $fullVersion) runtime..."); - final process = await Process.start( - "/bin/sh", [sh.path, shortVersion, fullVersion, buildDate, bridge], - mode: ProcessStartMode.inheritStdio); - final code = await process.exitCode; - if (code != 0) { - stderr.writeln("serious_python: $script failed (exit $code)."); - exit(code); - } - return true; -} - const platforms = { "iOS": { "iphoneos.arm64": {"tag": "ios-13.0-arm64-iphoneos", "mac_ver": ""}, @@ -551,14 +501,6 @@ class PackageCommand extends Command { _verbose); } - // Stage the embedded Darwin interpreter for the selected version so the - // build uses it without `pod install` having to re-run prepare. - await stageDarwinRuntime( - platform: platform, - shortVersion: _pythonShortVersion, - sitePackagesRoot: sitePackagesRoot, - ); - // synchronize pod var syncSh = File(path.join(sitePackagesRoot, ".pod", "sync_site_packages.sh")); diff --git a/src/serious_python/example/run_example/app/app.zip.hash b/src/serious_python/example/run_example/app/app.zip.hash index 9377386a..615dadf3 100644 --- a/src/serious_python/example/run_example/app/app.zip.hash +++ b/src/serious_python/example/run_example/app/app.zip.hash @@ -1 +1 @@ -9ad98bb4d417761b6ef015d8603109a1b20c4c20798c41e7fb05c356062c4743 \ No newline at end of file +2b009202b20832851c62f09fd3dc603131d9efa45da27efb94eb21b32da28ed0 \ No newline at end of file diff --git a/src/serious_python/example/run_example/app/src/main.py b/src/serious_python/example/run_example/app/src/main.py index ddaf0816..a08b287d 100644 --- a/src/serious_python/example/run_example/app/src/main.py +++ b/src/serious_python/example/run_example/app/src/main.py @@ -10,18 +10,6 @@ _imp.extension_suffixes() -# Version probe for the version-switching integration test: when -# PYTHON_VERSION_FILENAME is set, import numpy (a native-extension ABI canary — -# a wrong interpreter for the packaged cp wheels fails this import) and -# write the running interpreter's short version, then exit. -_version_file = os.getenv("PYTHON_VERSION_FILENAME") -if _version_file: - import numpy # noqa: F401 - - with open(_version_file, "w") as _vf: - _vf.write(f"{sys.version_info.major}.{sys.version_info.minor}") - sys.exit(0) - print("HELLO!") print("sys.path:", sys.path) diff --git a/src/serious_python/example/run_example/integration_test/version_test.dart b/src/serious_python/example/run_example/integration_test/version_test.dart deleted file mode 100644 index bfca3b25..00000000 --- a/src/serious_python/example/run_example/integration_test/version_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; -import 'package:path/path.dart' as p; -import 'package:serious_python/serious_python.dart'; - -/// Asserts the embedded Python runtime is the version we asked for. Pass the -/// expected short version via `--dart-define=EXPECTED_PYTHON_VERSION=3.x`. -/// -/// The packaged app (app/src/main.py) imports numpy when `PYTHON_VERSION_FILENAME` -/// is set — a native-extension ABI canary that fails if the bundled interpreter -/// doesn't match the packaged cp wheels — then writes its short version to -/// that file. This is the regression guard for switching Python versions on one -/// machine (see .github/workflows/python-version-switching.yml). -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - testWidgets('embedded Python matches EXPECTED_PYTHON_VERSION', (tester) async { - const expected = String.fromEnvironment('EXPECTED_PYTHON_VERSION'); - expect(expected, isNotEmpty, - reason: 'pass --dart-define=EXPECTED_PYTHON_VERSION=3.x'); - - final tempDir = await Directory.systemTemp.createTemp('version_test'); - final versionFile = p.join(tempDir.path, 'pyversion.txt'); - - unawaited(SeriousPython.run('app/app.zip', - environmentVariables: {'PYTHON_VERSION_FILENAME': versionFile}, - sync: false)); - - String? actual; - for (var i = 0; i < 60; i++) { - await tester.pump(const Duration(seconds: 1)); - final f = File(versionFile); - if (await f.exists()) { - actual = (await f.readAsString()).trim(); - if (actual.isNotEmpty) break; - } - } - - expect(actual, expected, - reason: 'the embedded interpreter (and its numpy wheel) should be the ' - 'requested Python version'); - }); -} From 91a14b2f6e99ce2a4b62779fb8850148f647e5cf Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 15 Jun 2026 15:33:00 -0700 Subject: [PATCH 107/114] Prepare 3.0.0 release Bump all six federated packages 2.0.0 -> 3.0.0 (pubspecs + darwin podspec + android build.gradle) and add 3.0.0 CHANGELOG sections. 3.0.0 highlights since 2.0.0: - In-process Python via the dart_bridge FFI transport (PythonBridge); the Python lifecycle is absorbed into the dart_bridge native library on every platform. - Requires Flutter 3.44.2 (Android: AGP 8.11.1 / compileSdk 36 / Java 17). - Python versions resolved from a committed snapshot of python-build's date-keyed manifest.json; SERIOUS_PYTHON_VERSION is the single knob. - Add `serious_python:main version [--json]`; remove the scaffold getPlatformVersion. Also restores each ## 2.0.0 section to exactly what the v2.0.0 tag published (the post-tag date-keyed-scheme bullets move into 3.0.0). --- src/serious_python/CHANGELOG.md | 16 +++++++++++++--- src/serious_python/pubspec.yaml | 2 +- src/serious_python_android/CHANGELOG.md | 8 +++++++- src/serious_python_android/android/build.gradle | 2 +- src/serious_python_android/pubspec.yaml | 2 +- src/serious_python_darwin/CHANGELOG.md | 8 +++++++- .../darwin/serious_python_darwin.podspec | 2 +- src/serious_python_darwin/pubspec.yaml | 2 +- src/serious_python_linux/CHANGELOG.md | 8 +++++++- src/serious_python_linux/pubspec.yaml | 2 +- .../CHANGELOG.md | 5 +++++ .../pubspec.yaml | 2 +- src/serious_python_windows/CHANGELOG.md | 8 +++++++- src/serious_python_windows/pubspec.yaml | 2 +- 14 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index edc318ab..fb7aba82 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,14 +1,24 @@ +## 3.0.0 + +* **New in-process transport (dart_bridge FFI).** `SeriousPython.run` can now run the embedded interpreter **in-process** through the `dart_bridge` FFI bridge instead of talking to it over a socket. The Python lifecycle (initialize / run / teardown) is absorbed into the `dart_bridge` native library on every platform — `dart_bridge.xcframework` (iOS/macOS), `libdart_bridge.so` (Android/Linux), and `dart_bridge.dll` / `dart_bridge.pyd` (Windows) — and a new `PythonBridge` API exposes a MsgPack control channel plus dedicated binary data channels between Dart and Python. See the `bridge_example` app. The bundled `dart_bridge` is **1.2.3**. +* **Breaking change:** requires Flutter **3.44.2** / Dart 3.12+. The Android plugin moves to AGP **8.11.1**, `compileSdk` **36**, Java **17**, and the Kotlin-DSL Gradle build; the removed `android.bundle.enableUncompressedNativeLibs` flag is replaced with `useLegacyPackaging` + `keepDebugSymbols` for the bundled `libpython*.so`. +* Python runtime versions are now a committed snapshot of `flet-dev/python-build`'s date-keyed `manifest.json`, generated by `dart run serious_python:gen_version_tables`. **`SERIOUS_PYTHON_VERSION`** (short, e.g. `3.14`) is the single input — the full CPython version, python-build release date, Pyodide version + platform tag, and `dart_bridge` version all derive from it. `SERIOUS_PYTHON_FULL_VERSION`, `SERIOUS_PYTHON_BUILD_DATE`, and `DART_BRIDGE_VERSION` remain as rarely-needed escape hatches. The native build configs (Android `build.gradle`, Darwin podspec, Linux/Windows `CMakeLists.txt`) read the generated `python_versions.properties`, and a CI job fails if the snapshots drift from the manifest. This replaces the per-config hardcoded defaults and the `flet build`-exported `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` introduced in 2.0.0. +* Bundle **3.12.13 / 3.13.14 / 3.14.6** (python-build `20260614`); Pyodide **0.27.7 / 0.29.4 / 314.0.0** (314.0.0 GA, up from the 314.0.0a2 in 2.0.0). +* Add **`dart run serious_python:main version [--json]`** — prints the serious_python version, the pinned python-build release, and the supported Python / Pyodide / dart_bridge matrix. +* The embedded Darwin runtime re-extracts when the selected Python version changes (a version marker guards `dist_ios` / `dist_macos`), so a clean build after switching `--python-version` can't mix C-extension ABIs (`bad magic number` / `unknown slot ID`). +* Cache downloaded Python distributions and `dart_bridge` artifacts under `$FLET_CACHE_DIR` (default `~/.flet/cache`) across all platforms. +* Remove the scaffold `getPlatformVersion` method from the platform plugins. +* **Bug fix:** the Pyodide 0.29 wheel platform tag for the 3.13 row was `pyodide-2025.0-wasm32`, but Pyodide publishes 0.29 wheels under `pyemscripten_2025_0_wasm32`; corrected to `pyemscripten-2025.0-wasm32` so `flet build web --python-version 3.13` matches native wheels. + ## 2.0.0 * **Breaking change:** the `package` command's default Python is now the latest supported stable (3.14), up from the previously implicit 3.12. Scripts that ran `dart run serious_python:main package …` without `--python-version` will now download CPython 3.14, install 3.14 wheels, and use the matching Pyodide / Android platform tags. Pin explicitly with `--python-version 3.12` (or `SERIOUS_PYTHON_VERSION=3.12`) to preserve the old behavior. * **Breaking change:** Android `sysconfig.get_platform()` tag format changed from `android-24-arm64-v8a` to `android-24-arm64_v8a` (and similarly for `armeabi-v7a`). The emitted wheel tag (`android_24_arm64_v8a`) is unchanged, but anything reading the raw `sysconfig.get_platform()` string from `sitecustomize.py` should switch separators. * **Breaking change:** Windows host arch identifier dropped the `-shared` suffix (`x86_64-pc-windows-msvc-shared` → `x86_64-pc-windows-msvc`); follows astral-sh/python-build-standalone, which only publishes the combined (already shared) `install_only_stripped` build. * Multi-version Python support. The `package` command accepts `--python-version` (or `SERIOUS_PYTHON_VERSION` env var) to select between Python 3.12 / 3.13 / 3.14. The matching CPython-standalone build, Pyodide release, and Emscripten wheel platform tag are looked up from a new `_pythonReleases` table. Adding a future pre-release line (e.g. 3.15 beta) is a one-row append with `prerelease: true`; the Flet CLI uses that flag to keep open-ended `requires-python` specifiers (`>=3.14`) on stable, while still letting `--python-version 3.15` or `==3.15.*` opt in. -* The Emscripten pip platform tag is now derived per Python release (e.g. `pyodide-2024.0-wasm32` for 0.27.7, `pyemscripten-2026.0-wasm32` for 314.0.0), via a `pyodide_platform_tag` field in the version registry. The previous static `pyodide-2024.0-wasm32` entry in `platforms["Emscripten"]` has been removed. +* The Emscripten pip platform tag is now derived per Python release (e.g. `pyodide-2024.0-wasm32` for 0.27.7, `pyemscripten-2026.0-wasm32` for 314.0.0a2), via a `pyodide_platform_tag` field in the version registry. The previous static `pyodide-2024.0-wasm32` entry in `platforms["Emscripten"]` has been removed. * `sitecustomize.py` now shims `platform.android_ver` so the new pip / packaging that ships with python-build-standalone 20260602+ can compute Android wheel tags on Python 3.12 hosts (where `android_ver` didn't exist) and on Python 3.13+ hosts (where it returns `api_level=0` off-device). * Skip 32-bit Android ABIs (`armeabi-v7a`, `x86`) when Python ≥ 3.13 — PEP 738 dropped 32-bit Android support, and `flet-dev/python-build` no longer publishes those runtimes for those versions. -* Migrate the platform-plugin download URLs to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-*--*.tar.gz`) — one release tag now ships every supported Python patch instead of per-minor `v3.X` releases. Plugins (Android `build.gradle`, Darwin `prepare_*.sh`, Linux/Windows `CMakeLists.txt`) read two new env vars set by `flet build`: `SERIOUS_PYTHON_FULL_VERSION` (e.g. `3.14.6`) and `SERIOUS_PYTHON_BUILD_DATE` (e.g. `20260611`); both fall back to baked-in defaults so standalone (non-`flet build`) usage continues to work. Bump bundled versions to **3.12.13 / 3.13.14 / 3.14.6** (Astral PBS `20260610`, python-build `20260611`) and Pyodide for 3.14 to **314.0.0** (GA). -* **Bug fix:** the Pyodide 0.29 wheel platform tag for the 3.13 row in the version registry was `pyodide-2025.0-wasm32`, but Pyodide actually publishes its wheels under `pyemscripten_2025_0_wasm32` (the `pyodide_` → `pyemscripten_` prefix transition happened at 0.28/0.29, not at 314.0). `flet build web --python-version 3.13` would have failed to match any Pyodide-built native wheel; corrected to `pyemscripten-2025.0-wasm32` in the registry. ## 1.0.1 diff --git a/src/serious_python/pubspec.yaml b/src/serious_python/pubspec.yaml index 89d28bd7..610c1ca7 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: 2.0.0 +version: 3.0.0 platforms: ios: diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 63532f25..774ca11e 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -1,10 +1,16 @@ +## 3.0.0 + +* **In-process Python (dart_bridge FFI).** The Python lifecycle now runs through `libdart_bridge.so` (from `flet-dev/dart-bridge` **1.2.3**) instead of a socket transport; `extractNativeLibs=true` keeps `libpython*.so` extractable for `dlopen`. +* **Breaking change:** requires Flutter **3.44.2**. Moves to AGP **8.11.1**, Gradle 8.11.1, `compileSdk` **36** and Java **17**; `useLegacyPackaging` + `keepDebugSymbols` for the bundled `libpython*.so` replace the removed `android.bundle.enableUncompressedNativeLibs`. +* `build.gradle` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version, build date and `dart_bridge` version derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` / `DART_BRIDGE_VERSION` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. +* Remove the scaffold `getPlatformVersion` method. + ## 2.0.0 * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). Apps built without an explicit `SERIOUS_PYTHON_VERSION` env var pull the 3.14 python-build distribution and ship `libpython3.14.so`. Set `SERIOUS_PYTHON_VERSION=3.12` (typically threaded through `flet build`) to preserve the previous default. * Multi-version Python support. `python_version` in `android/build.gradle` reads from `SERIOUS_PYTHON_VERSION` and drives the `flet-dev/python-build` download URL. * The Dart runtime no longer hardcodes `libpython3.12.so` — it scans `nativeLibraryDir` for `libpython3.*.so` so whichever libpython the plugin bundled is loaded automatically. * `abiFilters` now branches on `python_version`: keep `armeabi-v7a` for 3.12, restrict to `arm64-v8a` + `x86_64` for 3.13+ (python-build dropped 32-bit Android per PEP 738). -* Migrate `downloadDistArchive_*` to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-android-dart--.tar.gz` instead of `…/v/python-android-dart--.tar.gz`). Two new env vars — `SERIOUS_PYTHON_FULL_VERSION` (e.g. `3.14.6`) and `SERIOUS_PYTHON_BUILD_DATE` (e.g. `20260611`) — are read alongside `SERIOUS_PYTHON_VERSION`, both with baked-in defaults so standalone (non-`flet build`) usage continues to work. The cache directory key (`$FLET_CACHE_DIR/python-build/v<…>/`) switches from short to full version so patch bumps don't reuse a stale tarball. ## 1.0.1 diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle index f59db36a..b6dd6e28 100644 --- a/src/serious_python_android/android/build.gradle +++ b/src/serious_python_android/android/build.gradle @@ -1,5 +1,5 @@ group 'com.flet.serious_python_android' -version '2.0.0' +version '3.0.0' // Python runtime versions come from the generated python_versions.properties // (a snapshot of python-build's manifest.json — see serious_python's diff --git a/src/serious_python_android/pubspec.yaml b/src/serious_python_android/pubspec.yaml index e17a7902..a96d2251 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: 2.0.0 +version: 3.0.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 aa337eb7..e7402f59 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -1,8 +1,14 @@ +## 3.0.0 + +* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `dart_bridge.xcframework` (from `flet-dev/dart-bridge` **1.2.3**) instead of a socket transport; the Swift plugin registers the dart_bridge inittab, the pod is declared `static_framework` for xcframework vendoring, and the embedded `Python.app` is stripped from `Python.framework`. +* **Breaking change:** requires Flutter **3.44.2**. +* The podspec resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`) and passes the full version, build date and `dart_bridge` version to `prepare_ios.sh` / `prepare_macos.sh` (`dart_bridge_version` is `$4`); `SERIOUS_PYTHON_VERSION` is the knob, the per-field env vars are escape hatches. The prepare scripts re-extract `dist_ios` / `dist_macos` when the selected version changes (a version marker) so a clean build can't mix C-extension ABIs. +* Remove the scaffold `getPlatformVersion` method. + ## 2.0.0 * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). Apps built without an explicit `SERIOUS_PYTHON_VERSION` env var pull `python-ios-dart-3.14.tar.gz` / `python-macos-dart-3.14.tar.gz` from `flet-dev/python-build`. Set `SERIOUS_PYTHON_VERSION=3.12` to preserve the previous default. * Multi-version Python support. `python_version` in `serious_python_darwin.podspec` reads from `SERIOUS_PYTHON_VERSION`; `prepare_ios.sh` / `prepare_macos.sh` already took the version as `$1` and download the matching tarballs. -* Migrate `prepare_ios.sh` / `prepare_macos.sh` to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-{ios,macos}-dart-.tar.gz`). The podspec now reads `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` (defaults baked in) and passes them as positional args `$2` / `$3` to the prepare scripts. ## 1.0.1 diff --git a/src/serious_python_darwin/darwin/serious_python_darwin.podspec b/src/serious_python_darwin/darwin/serious_python_darwin.podspec index 87b75939..809d0bd8 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 = '2.0.0' + s.version = '3.0.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. diff --git a/src/serious_python_darwin/pubspec.yaml b/src/serious_python_darwin/pubspec.yaml index e2b781e2..0252505e 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: 2.0.0 +version: 3.0.0 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index babf5411..313af1e7 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -1,8 +1,14 @@ +## 3.0.0 + +* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `libdart_bridge.so` (from `flet-dev/dart-bridge` **1.2.3**, `DT_RPATH $ORIGIN`) instead of a socket transport. +* **Breaking change:** requires Flutter **3.44.2**. +* `CMakeLists.txt` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version and build date derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. +* Remove the scaffold `getPlatformVersion` method. + ## 2.0.0 * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). The plugin downloads `python-linux-dart-3.14-.tar.gz` from `flet-dev/python-build` and bundles `libpython3.14.so.1.0` unless `SERIOUS_PYTHON_VERSION=3.12` is set in the build environment. * Multi-version Python support. `PYTHON_VERSION` in `linux/CMakeLists.txt` reads from `SERIOUS_PYTHON_VERSION`, and all `python3.12` / `libpython3.12.so.1.0` / `lib/python3.12` paths are derived from it. The plugin source receives the version via a `SERIOUS_PYTHON_VERSION` compile-time macro so the runtime module path matches the bundled distro. -* Migrate the `python-linux-dart` download URL to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-linux-dart--.tar.gz`). `CMakeLists.txt` now reads `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` from the environment (with baked-in defaults) and the cache directory key uses the full version so patch bumps don't reuse a stale tarball. ## 1.0.1 diff --git a/src/serious_python_linux/pubspec.yaml b/src/serious_python_linux/pubspec.yaml index c1d5ae83..9650b97d 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: 2.0.0 +version: 3.0.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 c9131d19..c5982886 100644 --- a/src/serious_python_platform_interface/CHANGELOG.md +++ b/src/serious_python_platform_interface/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.0.0 + +* Remove the scaffold `getPlatformVersion` method from the platform interface and its method-channel implementation. +* Version bump aligning with the `serious_python_*` 3.0.0 release (in-process `dart_bridge` FFI transport, Flutter 3.44.2). + ## 2.0.0 * Version bump aligning with the major release of the `serious_python_*` platform plugins (multi-version Python support, default Python now 3.14). No interface changes. diff --git a/src/serious_python_platform_interface/pubspec.yaml b/src/serious_python_platform_interface/pubspec.yaml index 36688468..0496dbda 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: 2.0.0 +version: 3.0.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 2abda4a4..8b615ddc 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -1,8 +1,14 @@ +## 3.0.0 + +* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `dart_bridge.dll` / `dart_bridge.pyd` (from `flet-dev/dart-bridge` **1.2.3**) instead of a socket transport; both Release and Debug `dart_bridge.pyd` ship so 3.13/3.14 Debug builds resolve too. +* **Breaking change:** requires Flutter **3.44.2**. +* `CMakeLists.txt` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version and build date derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. +* Remove the scaffold `getPlatformVersion` method. + ## 2.0.0 * **Breaking change:** default bundled Python version is now 3.14 (was 3.12). The plugin downloads `python-windows-for-dart-3.14.zip` and bundles `python314.dll` / `python314.lib` unless `SERIOUS_PYTHON_VERSION=3.12` is set in the build environment. * Multi-version Python support. `PYTHON_VERSION` in `windows/CMakeLists.txt` reads from `SERIOUS_PYTHON_VERSION`; the `python-build` download URL and the `python312.lib` / `python312.dll` filenames are derived from it (e.g. `python313.lib`, `python314.dll`). -* Migrate the `python-windows-for-dart` download URL to `flet-dev/python-build`'s new date-keyed release scheme (`…//python-windows-for-dart-.zip`). `CMakeLists.txt` now reads `SERIOUS_PYTHON_FULL_VERSION` and `SERIOUS_PYTHON_BUILD_DATE` from the environment (with baked-in defaults) and the cache directory key uses the full version so patch bumps don't reuse a stale zip. ## 1.0.1 diff --git a/src/serious_python_windows/pubspec.yaml b/src/serious_python_windows/pubspec.yaml index c71248af..0d44c07b 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: 2.0.0 +version: 3.0.0 environment: sdk: '>=3.1.3 <4.0.0' From 473a8c01ebedc93a85d01796bfa0238292277e1d Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 16 Jun 2026 11:47:41 -0700 Subject: [PATCH 108/114] feat: FFI bindings for libdart_bridge 1.3.0 session-restart + native log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DartBridge gains `isPythonInitialized` (true on Android process reuse where the OS kept this OS process alive across a Dart VM restart) and `signalDartSession(Map)` (fires Python's registered session-restart handlers with the new native port numbers). * Both use a soft `lookupOrNull` against the underlying C symbols, so pre-1.3.0 libdart_bridge binaries still load cleanly — calls into the new wrappers become safe no-ops (`isPythonInitialized` returns false, `signalDartSession` is dropped on the floor). Decouples the Dart/Python rollout from the libdart_bridge release cadence. * Re-export `DartBridge` from `package:serious_python/bridge.dart` so embedders (notably the `flet build` template's `native_runtime.dart`) don't need a direct dependency on `serious_python_platform_interface`. Consumer wiring lands in flet's build template + flet.app runtime; this commit is just the lower-level FFI surface. --- src/serious_python/lib/bridge.dart | 7 +- .../lib/src/dart_bridge_ffi.dart | 79 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/serious_python/lib/bridge.dart b/src/serious_python/lib/bridge.dart index 53676175..b1e4b51c 100644 --- a/src/serious_python/lib/bridge.dart +++ b/src/serious_python/lib/bridge.dart @@ -1,6 +1,11 @@ /// In-process Dart ↔ Python byte channel. /// -/// See [PythonBridge] for usage. +/// See [PythonBridge] for the per-channel API. The lower-level [DartBridge] +/// singleton (from the platform-interface package) is re-exported here for +/// embedders that need the process-reuse / session-restart hooks added in +/// libdart_bridge 1.3.0 — `isPythonInitialized` and `signalDartSession`. library; +export 'package:serious_python_platform_interface/src/dart_bridge_ffi.dart' + show DartBridge; export 'src/python_bridge.dart' show PythonBridge; diff --git a/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart b/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart index 380119cf..acef515e 100644 --- a/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart +++ b/src/serious_python_platform_interface/lib/src/dart_bridge_ffi.dart @@ -62,6 +62,14 @@ typedef _DartBridgeEnqueueMessageNative = Int32 Function( typedef _DartBridgeEnqueueMessageDart = int Function( int, Pointer, int); +typedef _DartBridgeIsPythonInitializedNative = Int32 Function(); +typedef _DartBridgeIsPythonInitializedDart = int Function(); + +typedef _DartBridgeSignalDartSessionNative = Void Function( + Int32, Pointer>, Pointer); +typedef _DartBridgeSignalDartSessionDart = void Function( + int, Pointer>, Pointer); + // --------------------------------------------------------------------------- // Library binding // --------------------------------------------------------------------------- @@ -82,12 +90,41 @@ class DartBridge { .lookup>( 'DartBridge_EnqueueMessage') .asFunction<_DartBridgeEnqueueMessageDart>(); + // dart_bridge >= 1.3.0 exports. Use lookupOrNull so older binaries + // still load (calls into the wrappers below become safe no-ops); + // makes the Dart/Python rollout decoupled from the libdart_bridge + // release cadence. + _isPythonInitialized = _lookupOrNull<_DartBridgeIsPythonInitializedNative, + _DartBridgeIsPythonInitializedDart>( + 'dart_bridge_is_python_initialized', + (f) => f.asFunction<_DartBridgeIsPythonInitializedDart>(), + ); + _signalDartSession = _lookupOrNull<_DartBridgeSignalDartSessionNative, + _DartBridgeSignalDartSessionDart>( + 'dart_bridge_signal_dart_session', + (f) => f.asFunction<_DartBridgeSignalDartSessionDart>(), + ); + } + + // Generic helper for soft symbol lookup — returns null if the binary + // doesn't export the symbol (e.g. running against a pre-1.3.0 + // libdart_bridge). + T? _lookupOrNull( + String name, T Function(Pointer>) bind) { + try { + final ptr = _lib.lookup>(name); + return bind(ptr); + } on ArgumentError { + return null; + } } final DynamicLibrary _lib; late final _SeriousPythonRunDart _run; late final _DartBridgeInitDartApiDLDart _initApiDL; late final _DartBridgeEnqueueMessageDart _enqueueMessage; + late final _DartBridgeIsPythonInitializedDart? _isPythonInitialized; + late final _DartBridgeSignalDartSessionDart? _signalDartSession; static DartBridge? _instance; @@ -141,6 +178,48 @@ class DartBridge { /// or -2 if the interpreter is not initialized. int enqueueMessage(int port, Pointer data, int len) => _enqueueMessage(port, data, len); + + /// True if libdart_bridge has already brought up an embedded CPython. + /// On Android process reuse (OS keeps the process alive across a Dart + /// VM restart), this returns true on the second Dart VM's PythonBridge + /// construction. + /// + /// Returns false when running against a pre-1.3.0 libdart_bridge that + /// doesn't export the underlying C function — callers should treat that + /// as "fresh start path", which is the correct behaviour on every + /// platform that hasn't seen this binary update yet. + bool get isPythonInitialized { + final f = _isPythonInitialized; + if (f == null) return false; + return f() != 0; + } + + /// Signal the running Python program that a new Dart VM session is + /// active. On a fresh start where Python isn't loaded yet, this is a + /// cheap no-op inside libdart_bridge. On Android process reuse it fires + /// every Python callback registered via + /// `dart_bridge.add_session_restart_handler(...)`, carrying the new + /// native port numbers as a `{label: port}` map. + /// + /// [portMap] keys are arbitrary labels — current callers use + /// `"protocol"` and `"exit"` to match flet's build template wiring. + /// + /// No-op when running against a pre-1.3.0 libdart_bridge. + void signalDartSession(Map portMap) { + final f = _signalDartSession; + if (f == null || portMap.isEmpty) return; + using((Arena arena) { + final labels = arena>(portMap.length); + final ports = arena(portMap.length); + var i = 0; + for (final entry in portMap.entries) { + labels[i] = entry.key.toNativeUtf8(allocator: arena); + ports[i] = entry.value; + i++; + } + f(portMap.length, labels, ports); + }); + } } // --------------------------------------------------------------------------- From befc3645115bd1b9a4eee9b350245c851fb5fdb7 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 16 Jun 2026 12:06:12 -0700 Subject: [PATCH 109/114] Bump dart_bridge to 1.3.0 across all platform plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerated via `dart run serious_python:gen_version_tables` after the python-build manifest at release 20260614 was updated to point at libdart_bridge 1.3.0 (https://github.com/flet-dev/dart-bridge/releases/tag/v1.3.0). This activates the Dart/Python FFI bindings + flet build template changes already on this branch — Android process-reuse and native stdout/stderr → logcat redirection now wire up end-to-end on the next Android build. No code changes here; just the regenerated version tables. --- src/serious_python/lib/src/python_versions.dart | 2 +- src/serious_python_android/android/python_versions.properties | 2 +- src/serious_python_darwin/darwin/python_versions.properties | 2 +- src/serious_python_linux/linux/python_versions.properties | 2 +- src/serious_python_windows/windows/python_versions.properties | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart index d4848523..fc91c289 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 = "20260614"; -const dartBridgeVersion = "1.2.3"; +const dartBridgeVersion = "1.3.0"; const defaultPythonVersion = "3.14"; class PythonRelease { diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index a5458009..060cd10f 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.2.3 +dart_bridge_version=1.3.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index a5458009..060cd10f 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.2.3 +dart_bridge_version=1.3.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index a5458009..060cd10f 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.2.3 +dart_bridge_version=1.3.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index a5458009..060cd10f 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.2.3 +dart_bridge_version=1.3.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 From 4294a477d1fbb60e80e984bfaad0203faa3bf5a3 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 16 Jun 2026 12:52:19 -0700 Subject: [PATCH 110/114] Bump dart_bridge to 1.3.1 across all platform plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerated via `dart run serious_python:gen_version_tables` after the python-build manifest at release 20260614 was updated to point at libdart_bridge 1.3.1 (https://github.com/flet-dev/dart-bridge/releases/tag/v1.3.1). 1.3.1 fixes: * `__android_log_write` is now resolved via explicit `-llog` linkage, unblocking Android Python 3.12 (whose libpython doesn't transitively pull in liblog like 3.13/3.14 do). Should unstick the previously failing bridge_example test on the Android-Py3.12 CI matrix entry. * `print(x)` no longer produces blank logcat / os_log entries after every real line — pure-whitespace writes that come from CPython's trailing-newline sub-call are now skipped on the native log branches. Desktop passthrough is unchanged. No code changes here; just the regenerated version tables. --- src/serious_python/lib/src/python_versions.dart | 2 +- src/serious_python_android/android/python_versions.properties | 2 +- src/serious_python_darwin/darwin/python_versions.properties | 2 +- src/serious_python_linux/linux/python_versions.properties | 2 +- src/serious_python_windows/windows/python_versions.properties | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart index fc91c289..8c17534a 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 = "20260614"; -const dartBridgeVersion = "1.3.0"; +const dartBridgeVersion = "1.3.1"; const defaultPythonVersion = "3.14"; class PythonRelease { diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index 060cd10f..9562ca99 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.0 +dart_bridge_version=1.3.1 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index 060cd10f..9562ca99 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.0 +dart_bridge_version=1.3.1 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index 060cd10f..9562ca99 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.0 +dart_bridge_version=1.3.1 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index 060cd10f..9562ca99 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.0 +dart_bridge_version=1.3.1 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 From 6d962740e2e79713d831fa41bcd191ceb97e8989 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 16 Jun 2026 13:29:48 -0700 Subject: [PATCH 111/114] Bump dart_bridge to 1.3.2 Re-published Android binaries with explicit liblog linkage. 1.3.1's CMakeLists.txt fix was a no-op on Android (that platform builds via a hand-rolled clang line in the dart-bridge CI workflow, not CMake), so the shipped Android Py 3.12 binary still missed liblog and crashed at app start. 1.3.2's workflow adds -llog to the cross-compile and re-releases all platform binaries. Linux / Windows / Apple binaries are content-identical to 1.3.1. Regenerated via dart run serious_python:gen_version_tables. Release: https://github.com/flet-dev/dart-bridge/releases/tag/v1.3.2 --- src/serious_python/lib/src/python_versions.dart | 2 +- src/serious_python_android/android/python_versions.properties | 2 +- src/serious_python_darwin/darwin/python_versions.properties | 2 +- src/serious_python_linux/linux/python_versions.properties | 2 +- src/serious_python_windows/windows/python_versions.properties | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart index 8c17534a..dad2aa82 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 = "20260614"; -const dartBridgeVersion = "1.3.1"; +const dartBridgeVersion = "1.3.2"; const defaultPythonVersion = "3.14"; class PythonRelease { diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index 9562ca99..c72c7f8e 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.1 +dart_bridge_version=1.3.2 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index 9562ca99..c72c7f8e 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.1 +dart_bridge_version=1.3.2 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index 9562ca99..c72c7f8e 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.1 +dart_bridge_version=1.3.2 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index 9562ca99..c72c7f8e 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.1 +dart_bridge_version=1.3.2 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 From 6794126c03c79fe15c0c41591cac9beb582dd925 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 17 Jun 2026 11:58:07 -0700 Subject: [PATCH 112/114] Android: memory-map native modules from the APK (drop fake-.so / useLegacyPackaging) (#210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * android: migrate plugin build.gradle to Kotlin DSL Faithful, behavior-preserving port of the per-ABI task graph (gradle-download-task, tarTree/untar, copyOpt, zipSitePackages, dart-bridge download+rename, packaging, abiFilters) to build.gradle.kts. Verified green: run_example builds and runs on the arm64 emulator with identical jniLibs and Python output (numpy works). Prerequisite for the native-split tasks. * android: add _sp_bootstrap.py native-module finder (Phase E) sys.meta_path finder that resolves relocated CPython extension modules from their .soref markers (jniLibs lib loaded by basename). Reads markers via frozen zipimport.get_data (zip-resident) or open() (extracted), imports only builtin/frozen machinery so it runs before any native is resolvable. Host-tested: zip + extracted-dir probes, idempotent install, pure imports fall through. Not yet wired into the build. * android: split native modules to jniLibs, pure code to stored zips (Phase A/B) The Kotlin split tasks replace zipSitePackages: they relocate every tagged CPython extension .so (stdlib lib-dynload + site-packages) to jniLibs//lib.so (dotted name, '.'->'-', readable & injective), leaving a .soref marker (content = lib name) at the module's path in ABI-common stored zips. stdlib bundle is cracked post-untar; libpythonbundle.so/libpythonsitepackages.so no longer ship. Pure code -> stdlib.zip/sitepackages.zip (assets, noCompress); allowlisted packages (SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES) -> extract.zip, excluded from sitepackages.zip. _sp_bootstrap.py embedded at stdlib.zip root. Verified by artifact inspection: 53 stdlib + 19 numpy natives mangled in jniLibs, markers present with matching libs, zips stored, no fake-zip .so. Runtime wiring (D/F) pending, so not yet runnable end-to-end. * android: runtime for native-mmap flow — first end-to-end green (Phase D) - AndroidPlugin.java: getFilesDir/extractAsset/unzipAsset (AssetManager + java.util.zip) to copy the stored zips to disk and unpack extract.zip. - serious_python_android.dart run(): copy stdlib.zip/sitepackages.zip once (version-keyed), unpack extract.zip; sys.path = [modulePaths, programDir, extract, sitepackages.zip, stdlib.zip]; PYTHONHOME=base. No fake-zip extraction. - _sp_bootstrap.py: resolve soname to an absolute origin under nativeLibraryDir when present (legacy packaging; CPython prepends ./ to a no-slash origin which breaks bare-soname load). - build.gradle.kts: inject interim sitecustomize.py (installs finder during site); declare split jniLibs/assets outputs + always-run so AGP's native-libs merge re-packages incrementally (no flutter clean needed). Verified on arm64 emulator: run_example runs fully — bz2, sqlite, and numpy all work, with pure code from stored zips (zipimport) and ALL native modules loaded via the finder from jniLibs. Legacy packaging still on (natives extracted); dropping it for mmap is next. * android: drop useLegacyPackaging — mmap natives from the APK (goal achieved) The finder now loads extension modules via Bionic's APK zip-path (base.apk!/lib//) when libs aren't extracted (modern packaging). AndroidPlugin exports ANDROID_APK_NATIVE_PREFIX (sourceDir + abi); _sp_bootstrap prefers an extracted nativeLibraryDir copy (legacy) else the APK zip-path. The run_example app sets useLegacyPackaging=false. Proven on arm64 emulator: program runs fully (bz2, sqlite, numpy), ZERO native extraction (no .so in app storage or nativeLibraryDir), and /proc//maps shows 32 r-xp executable mappings backed by base.apk — i.e. native modules are mmap'd directly from the APK. Pure code loads from stored zips via zipimport. * android: wire SERIOUS_PYTHON_DART_BRIDGE_DIST override; finder install via dart-bridge shim (F) - copyDartBridge_$abi uses a local dir of cross-compiled libdart_bridge-android--py.so when SERIOUS_PYTHON_DART_BRIDGE_DIST is set (mirrors SERIOUS_PYTHON_BUILD_DIST), bypassing the GitHub download for dev iteration on the bridge. - Drop the interim sitecustomize injection: the dart-bridge Android shim now installs the finder before site (proven on emulator: green with finder installed solely by the shim). Re-enable the sitecustomize fallback for bridges without the shim (commented in the task). This branch now requires the dart-bridge android-native-mmap bridge (via the override until released). * android: bootstrap audit probe + clean stale ABI jniLibs dirs - _sp_bootstrap.install(): report any extension module already imported at install time (loaded during core-init before the finder) — verified empty on emulator, so PyConfig core-init pulls only builtin/frozen modules (F's pre-site install is safe). - cleanStaleAbis: remove jniLibs/ dirs for ABIs not in the current set (e.g. stale armeabi-v7a 3.12 leftovers when building 3.14) so old fake-zip .so aren't packaged. Audits on arm64 emulator + AAB: importtime (no pre-finder natives), ABI-split (per-ABI natives, ~33MB pure payload shared ONCE in assets vs per-ABI duplication before), multi-ABI markers resolve in x86_64, allowlist partition+extract+import, 16KB-aligned. * Regenerate version tables from python-build 20260614 (dart_bridge 1.4.0) dart run serious_python:gen_version_tables --release-date 20260614 — the 20260614 manifest now pins dart_bridge_version 1.4.0 (the full-API/PyConfig Android bridge that installs the native-module finder before site). Python versions unchanged. Default build now downloads the released v1.4.0 bridge; verified green on the arm64 emulator (sqlite, numpy) with no env overrides. SERIOUS_PYTHON_DART_BRIDGE_DIST remains as a dev escape hatch. * docs: drop useLegacyPackaging consumer instructions; document native-mmap (CHANGELOGs) - run_example/flask_example READMEs: remove the useLegacyPackaging/keepDebugSymbols packaging block — consumers need no special native packaging now, just minSdk 23+. Document SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES for path-hungry packages. - run_example app build.gradle.kts: drop the packaging block entirely (modern packaging is AGP's default at minSdk 23+). Verified green on emulator with natives still mmap'd from base.apk (32 r-xp maps), zero extraction. - serious_python + serious_python_android CHANGELOGs (3.0.0): replace the useLegacyPackaging language with the native-mmap design; bump bundled dart_bridge to 1.4.0. * flask_example: add INTERNET permission to main manifest (fix release builds) The Flask app binds a local socket server, so it needs android.permission.INTERNET in all build types. It was only in the debug/profile manifests, so release builds hit 'PermissionError: [Errno 1] Operation not permitted' on socket() (the app isn't in the inet group). Verified: release APK now grants INTERNET and the Flask server starts (Running on http://127.0.0.1:55001) — flask/werkzeug from the zip, _socket via the finder. * android: split-aware APK native prefix (Play Store AAB) + drop dead getNativeLibraryDir - ANDROID_APK_NATIVE_PREFIX now points at whichever installed APK actually contains lib// — base.apk for single-APK builds, the per-ABI config split for Play Store AAB installs (where base.apk has no native libs). Detected by probing each of sourceDir + splitSourceDirs for the always-present libdart_bridge.so. - Remove the unused getNativeLibraryDir method-channel handler (run() uses getFilesDir). Verified with bundletool: built the AAB, build-apks + install-apks the device splits (base.apk + split_config.arm64_v8a.apk), ran green (numpy). adb-root /proc//maps shows 33 r-xp mappings from split_config.arm64_v8a.apk, 0 from base.apk, 0 extracted — natives mmap'd directly from the config split. * docs(readme): add 'How packaging works' section (per-platform layout) Document, per platform, where the stdlib and site-packages live, how native extension modules are shipped (Android: jniLibs mmap'd from the APK via a custom importer; iOS: xcframeworks + AppleFrameworkLoader; macOS: universal .so; Linux/Windows: on-disk; Web: Pyodide wheels), architecture handling, and how the user's app.zip is produced and extracted at runtime. Replace the stale Android note (enableUncompressedNativeLibs / extractNativeLibs) with the new no-config guidance (minSdk 23+). --- src/serious_python/CHANGELOG.md | 5 +- src/serious_python/README.md | 57 ++- .../example/flask_example/README.md | 21 +- .../android/app/src/main/AndroidManifest.xml | 3 + .../example/run_example/README.md | 28 +- .../run_example/android/app/build.gradle.kts | 17 +- .../lib/src/python_versions.dart | 2 +- src/serious_python_android/CHANGELOG.md | 5 +- src/serious_python_android/android/.gitignore | 1 + .../android/build.gradle | 176 ---------- .../android/build.gradle.kts | 331 ++++++++++++++++++ .../android/python_versions.properties | 2 +- .../serious_python_android/AndroidPlugin.java | 88 ++++- .../lib/serious_python_android.dart | 58 +-- .../python/_sp_bootstrap.py | 139 ++++++++ .../darwin/python_versions.properties | 2 +- .../linux/python_versions.properties | 2 +- .../windows/python_versions.properties | 2 +- 18 files changed, 671 insertions(+), 268 deletions(-) delete mode 100644 src/serious_python_android/android/build.gradle create mode 100644 src/serious_python_android/android/build.gradle.kts create mode 100644 src/serious_python_android/python/_sp_bootstrap.py diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index fb7aba82..069c0a61 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,7 +1,8 @@ ## 3.0.0 -* **New in-process transport (dart_bridge FFI).** `SeriousPython.run` can now run the embedded interpreter **in-process** through the `dart_bridge` FFI bridge instead of talking to it over a socket. The Python lifecycle (initialize / run / teardown) is absorbed into the `dart_bridge` native library on every platform — `dart_bridge.xcframework` (iOS/macOS), `libdart_bridge.so` (Android/Linux), and `dart_bridge.dll` / `dart_bridge.pyd` (Windows) — and a new `PythonBridge` API exposes a MsgPack control channel plus dedicated binary data channels between Dart and Python. See the `bridge_example` app. The bundled `dart_bridge` is **1.2.3**. -* **Breaking change:** requires Flutter **3.44.2** / Dart 3.12+. The Android plugin moves to AGP **8.11.1**, `compileSdk` **36**, Java **17**, and the Kotlin-DSL Gradle build; the removed `android.bundle.enableUncompressedNativeLibs` flag is replaced with `useLegacyPackaging` + `keepDebugSymbols` for the bundled `libpython*.so`. +* **New in-process transport (dart_bridge FFI).** `SeriousPython.run` can now run the embedded interpreter **in-process** through the `dart_bridge` FFI bridge instead of talking to it over a socket. The Python lifecycle (initialize / run / teardown) is absorbed into the `dart_bridge` native library on every platform — `dart_bridge.xcframework` (iOS/macOS), `libdart_bridge.so` (Android/Linux), and `dart_bridge.dll` / `dart_bridge.pyd` (Windows) — and a new `PythonBridge` API exposes a MsgPack control channel plus dedicated binary data channels between Dart and Python. See the `bridge_example` app. The bundled `dart_bridge` is **1.4.0**. +* **Android native packaging — memory-mapped from the APK.** Python extension modules are relocated into `jniLibs` and loaded **directly from the APK** (mmap, no extraction) by a custom importer that resolves them from `.soref` markers; pure Python ships in stored, ABI-common asset zips read via `zipimport` (no per-ABI duplication). Apps no longer need `useLegacyPackaging` / `keepDebugSymbols` — the brittle per-app packaging config is gone. Set **`SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES`** (comma-separated relative paths) to ship path-hungry packages extracted to disk. The dart-bridge Android binary uses the full CPython API (`PyConfig`) to install the importer before `site` runs. +* **Breaking change:** requires Flutter **3.44.2** / Dart 3.12+. The Android plugin moves to AGP **8.11.1**, `compileSdk` **36**, Java **17**, and the Kotlin-DSL Gradle build (`build.gradle.kts`). * Python runtime versions are now a committed snapshot of `flet-dev/python-build`'s date-keyed `manifest.json`, generated by `dart run serious_python:gen_version_tables`. **`SERIOUS_PYTHON_VERSION`** (short, e.g. `3.14`) is the single input — the full CPython version, python-build release date, Pyodide version + platform tag, and `dart_bridge` version all derive from it. `SERIOUS_PYTHON_FULL_VERSION`, `SERIOUS_PYTHON_BUILD_DATE`, and `DART_BRIDGE_VERSION` remain as rarely-needed escape hatches. The native build configs (Android `build.gradle`, Darwin podspec, Linux/Windows `CMakeLists.txt`) read the generated `python_versions.properties`, and a CI job fails if the snapshots drift from the manifest. This replaces the per-config hardcoded defaults and the `flet build`-exported `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` introduced in 2.0.0. * Bundle **3.12.13 / 3.13.14 / 3.14.6** (python-build `20260614`); Pyodide **0.27.7 / 0.29.4 / 314.0.0** (314.0.0 GA, up from the 314.0.0a2 in 2.0.0). * Add **`dart run serious_python:main version [--json]`** — prints the serious_python version, the pinned python-build release, and the supported Python / Pyodide / dart_bridge matrix. diff --git a/src/serious_python/README.md b/src/serious_python/README.md index ad965893..c1834aab 100644 --- a/src/serious_python/README.md +++ b/src/serious_python/README.md @@ -207,6 +207,47 @@ Additional Python binary packages for iOS and Android can be built with adding a Request additional packages for iOS and Android on [Flet Discussions - Packages](https://github.com/flet-dev/flet/discussions/categories/packages). +## How packaging works + +`dart run serious_python:main package` assembles two things, which the platform plugin then bundles into your Flutter app: + +1. **The CPython runtime + standard library** — a per-target build downloaded from [flet-dev/python-build](https://github.com/flet-dev/python-build) (and, for native extensions, [mobile-forge](https://github.com/flet-dev/mobile-forge)) and bundled by the plugin at build time. +2. **Your app + its dependencies** — your Python sources are zipped into an **asset** (`app/app.zip` by default), and `pip`-installed packages are placed where each platform expects them. + +At runtime the plugin sets `PYTHONHOME` / `PYTHONPATH` (or, on Android, installs a custom importer) so the interpreter finds the stdlib, your dependencies, and your app. + +The on-disk layout differs per platform, mostly because each OS has different rules for shipping **native (compiled) extension modules** — the `.so`/`.pyd`/`.dylib` files inside packages like `numpy`: + +| Platform | Standard library | Site-packages (deps) | Native extension modules | Architectures | +| --- | --- | --- | --- | --- | +| **Android** | `stdlib.zip` asset, read via `zipimport` | `sitepackages.zip` asset, read via `zipimport` | relocated to `jniLibs//`, **memory-mapped from the APK** (no extraction), resolved by a custom importer | natives per-ABI in `jniLibs`; pure zips are ABI-common (shipped once) | +| **iOS** | dir inside the framework resource bundle | dir inside the framework resource bundle | each `.so` wrapped in a signed `.framework` inside an `.xcframework`, loaded via CPython's `AppleFrameworkLoader` (`.fwork` markers) | device `arm64` + simulator `arm64`/`x86_64` xcframework slices | +| **macOS** | dir inside the framework resource bundle | dir (universal) | universal (`lipo`'d `arm64`+`x86_64`) `.so`, loaded directly | `arm64`+`x86_64` merged into fat binaries | +| **Linux** | `/python/` | `/site-packages/` | on-disk `.so` (in `lib-dynload` / package dirs) | one of `x86_64` / `aarch64` per build | +| **Windows** | `/Lib/` | `/site-packages/` | on-disk `.pyd`/`.dll` in `/DLLs/` | `x86_64` | +| **Web** | bundled inside Pyodide | `__pypackages__/` inside `app.zip` | Pyodide WebAssembly wheels | `wasm32` | + +### Your app program (all platforms) + +`package` copies your Python sources into a temp dir (honoring `--exclude` globs, optionally compiling to `.pyc` with `--compile-app`), zips it to `app/app.zip` (override with `-a`/`--asset`), and writes an `app.zip.hash` next to it. At runtime the asset is extracted once to the app's support directory (`/flet/app`), guarded by a hash + an optional `invalidateKey` (typically your app version) so it only re-extracts when the bundle changes — debug builds always re-extract. Your app dir is placed first on `sys.path`; a sibling `__pypackages__/` is also added (so you can vendor pure-Python deps next to your code). + +`pip install` output goes to `build/site-packages` by default (override with the `SERIOUS_PYTHON_SITE_PACKAGES` env var). For mobile, packages are installed **per architecture** (a `sitecustomize.py` shim spoofs the wheel platform tag so the correct mobile wheels resolve), then merged or split per platform as shown above. + +### Android specifics + +- **Pure Python** (stdlib + dependencies) ships in two **stored** (uncompressed) ABI-common zips — `stdlib.zip` and `sitepackages.zip` — copied once to the app's files dir and imported in place via `zipimport`. Final `sys.path` (highest first): your app dir, the extract dir, `sitepackages.zip`, `stdlib.zip`. +- **Native modules** (stdlib `lib-dynload` and site-package extensions) are relocated to `jniLibs//lib.so` and loaded **directly from the APK** (memory-mapped, never extracted to disk); a `sys.meta_path` finder resolves them from `.soref` markers left in the zips. This is why Android needs **no** `useLegacyPackaging` / `keepDebugSymbols` config and the stdlib is **not** duplicated per ABI. +- **Path-hungry packages** (those that read bundled data via `__file__` / `pkg_resources` rather than `importlib.resources`) can be shipped extracted to disk instead of inside the zip — list them (comma-separated relative paths) in `SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES`; they go into `extract.zip` and are unpacked to disk at first launch. +- Works for both **single APK** (`flutter build apk`) and **Play Store App Bundles** (per-ABI config splits); under legacy packaging / `minSdk < 23` the same finder falls back to loading from the extracted `nativeLibraryDir`. + +### iOS / macOS specifics + +The CPython runtime, stdlib, and (on iOS) native extensions are bundled into `serious_python_darwin.framework` as resources. On **iOS**, the App Store forbids loose `.dylib`s, so every native extension `.so` is repackaged into a signed `.framework` inside an `.xcframework`, with a `.fwork` text marker left at the module's import path; CPython's `AppleFrameworkLoader` reads the marker and loads the framework binary. On **macOS**, native extensions stay as plain `.so`, merged into universal (`arm64`+`x86_64`) binaries at package time. `PYTHONHOME` is the framework's resource path; `sys.path` includes `/site-packages`, `/stdlib`, and `/stdlib/lib-dynload`. + +### Linux / Windows specifics + +The CPython runtime (`libpython3.so` + `libpython.so` on Linux; `python3.dll` + `python.dll` on Windows), `libdart_bridge`, the stdlib, and native modules are copied next to your app's executable at build time. `PYTHONHOME` is the executable's directory. On Windows, extension modules (`.pyd`) and their dependent DLLs live in `/DLLs/`, which is added to `sys.path`. + ## Platform notes ### Build matrix @@ -238,18 +279,16 @@ MACOSX_DEPLOYMENT_TARGET = 10.15; ### Android -To make `serious_python` work in your own Android app: +No special native-library packaging config is required (see [How packaging works](#how-packaging-works)). serious_python loads native modules directly from the APK and ships pure Python in stored asset zips, so you don't need `useLegacyPackaging`, `keepDebugSymbols`, `extractNativeLibs`, or `android.bundle.enableUncompressedNativeLibs`. Just use a `minSdk` of 23+ so native libs stay uncompressed/page-aligned in the APK: -If you build an App Bundle Edit `android/gradle.properties` and add the flag: - -``` -android.bundle.enableUncompressedNativeLibs=false +```kotlin +android { + defaultConfig { + minSdk = 23 + } +} ``` -If you build an APK Make sure `android/app/src/AndroidManifest.xml` has `android:extractNativeLibs="true"` in the `` tag. - -For more information, see the [public issue](https://issuetracker.google.com/issues/147096055). - ## Troubleshooting ### Detailed logging diff --git a/src/serious_python/example/flask_example/README.md b/src/serious_python/example/flask_example/README.md index ac573f01..24c72c17 100644 --- a/src/serious_python/example/flask_example/README.md +++ b/src/serious_python/example/flask_example/README.md @@ -37,21 +37,16 @@ export SERIOUS_PYTHON_SITE_PACKAGES=$(pwd)/build/site-packages dart run serious_python:main package app/src -p Linux -r -r -r app/src/requirements.txt ``` -Important: to make `serious_python` work in your own Android app, the bundled -`libpython*.so` must be shipped uncompressed and extracted so the embedded -interpreter can `dlopen` them at runtime. In `android/app/build.gradle.kts`: +For Android, no special native-library packaging config is required. +`serious_python` relocates Python extension modules into `jniLibs` and loads them +directly from the APK (memory-mapped, no extraction), and ships pure Python in +stored asset zips. Just use a `minSdk` of 23+ so native libs stay uncompressed and +page-aligned in the APK: ```kotlin android { - packaging { - jniLibs { - useLegacyPackaging = true - } + defaultConfig { + minSdk = 23 } } -``` - -`useLegacyPackaging = true` is the modern replacement (AGP 8.1+) for both the -old `android.bundle.enableUncompressedNativeLibs=false` gradle property and the -`android:extractNativeLibs="true"` manifest attribute, and it covers both APK and -App Bundle builds. See the [public issue](https://issuetracker.google.com/issues/147096055). \ No newline at end of file +``` \ No newline at end of file diff --git a/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml b/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml index 9658760c..97e1ff4d 100644 --- a/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml +++ b/src/serious_python/example/flask_example/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,7 @@ + + /lib.so` and loaded directly from the APK by a custom `sys.meta_path` finder that resolves them from `.soref` markers — no extraction to disk, still ABI-split by the Play Store. Pure Python ships in **stored, ABI-common asset zips** read via `zipimport`, so the stdlib is no longer duplicated per ABI. This replaces the previous scheme of zipping stdlib/site-packages into fake `lib*.so` files (which required `useLegacyPackaging`). The dart-bridge Android binary now uses the full CPython API (`PyConfig`) to install the finder before `site` runs. Set **`SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES`** (comma-separated relative paths) to ship path-hungry packages extracted to disk instead. +* **Breaking change:** requires Flutter **3.44.2**. Moves to AGP **8.11.1**, Gradle 8.11.1, `compileSdk` **36**, Java **17**, and the **Kotlin-DSL** Gradle build (`build.gradle.kts`). * `build.gradle` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version, build date and `dart_bridge` version derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` / `DART_BRIDGE_VERSION` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. * Remove the scaffold `getPlatformVersion` method. diff --git a/src/serious_python_android/android/.gitignore b/src/serious_python_android/android/.gitignore index a4f3c175..642cbe42 100644 --- a/src/serious_python_android/android/.gitignore +++ b/src/serious_python_android/android/.gitignore @@ -8,3 +8,4 @@ /captures .cxx /src/main/jniLibs +/src/main/assets diff --git a/src/serious_python_android/android/build.gradle b/src/serious_python_android/android/build.gradle deleted file mode 100644 index b6dd6e28..00000000 --- a/src/serious_python_android/android/build.gradle +++ /dev/null @@ -1,176 +0,0 @@ -group 'com.flet.serious_python_android' -version '3.0.0' - -// Python runtime versions come from the generated python_versions.properties -// (a snapshot of python-build's manifest.json — see serious_python's -// `gen_version_tables`). SERIOUS_PYTHON_VERSION selects the version; everything -// else derives from the table. The per-field env vars are escape hatches. -def _pv = new Properties() -file('python_versions.properties').withInputStream { _pv.load(it) } -def python_version = System.getenv('SERIOUS_PYTHON_VERSION') ?: _pv['default_python_version'] -def python_full_version = System.getenv('SERIOUS_PYTHON_FULL_VERSION') ?: _pv["${python_version}.full_version"] -def python_build_date = System.getenv('SERIOUS_PYTHON_BUILD_DATE') ?: _pv['python_build_release_date'] -def dart_bridge_version = System.getenv('DART_BRIDGE_VERSION') ?: _pv['dart_bridge_version'] -if (python_full_version == null) { - def known = _pv.keySet().findAll { it.endsWith('.full_version') }.collect { it - '.full_version' } - throw new GradleException("serious_python: unknown SERIOUS_PYTHON_VERSION '${python_version}'. Supported: ${known.join(', ')}") -} - -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - // The Android Gradle Plugin knows how to build native code with the NDK. - classpath 'com.android.tools.build:gradle:8.11.1' - classpath 'de.undercouch:gradle-download-task:5.6.0' - } -} - -rootProject.allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: 'com.android.library' -apply plugin: 'de.undercouch.download' - -android { - namespace "com.flet.serious_python_android" - - // Bumping the plugin compileSdkVersion requires all clients of this plugin - // to bump the version in their app. - compileSdkVersion 36 - - // No native code is compiled here — libdart_bridge.so is downloaded as a - // pre-built artifact from flet-dev/dart-bridge releases (see the - // downloadDartBridge_$abi tasks below) and dropped into jniLibs. - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - defaultConfig { - minSdkVersion 21 - - ndk { - // python-build dropped 32-bit Android in 3.13 (PEP 738), so the - // python-android-dart--armeabi-v7a tarball only exists for 3.12. - if (python_version == '3.12') { - abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64' - } else { - abiFilters 'arm64-v8a', 'x86_64' - } - } - } - - packagingOptions { - doNotStrip "*/arm64-v8a/libpython*.so" - doNotStrip "*/armeabi-v7a/libpython*.so" - doNotStrip "*/x86/libpython*.so" - doNotStrip "*/x86_64/libpython*.so" - } -} - -import de.undercouch.gradle.tasks.download.Download - -def fletCacheRoot = System.getenv('FLET_CACHE_DIR') -def pythonCacheDir = new File( - fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), - "python-build/v${python_full_version}" -) -def dartBridgeCacheDir = new File( - fletCacheRoot ? new File(fletCacheRoot) : new File(System.getProperty('user.home'), '.flet/cache'), - "dart-bridge/v${dart_bridge_version}" -) - -task copyBuildDist(type: Copy) { - def srcDir = System.getenv('SERIOUS_PYTHON_BUILD_DIST') - if (srcDir != null) { - from srcDir - into 'src/main/jniLibs' - } -} - -// Loop through abiFilters -def packageTasks = [] -android.defaultConfig.ndk.abiFilters.each { abi -> - - def srcDir = System.getenv('SERIOUS_PYTHON_SITE_PACKAGES') - if (srcDir == null || srcDir.allWhitespace) { - throw new InvalidUserDataException("SERIOUS_PYTHON_SITE_PACKAGES environment variable is not set.") - } - - packageTasks.add("zipSitePackages_$abi") - packageTasks.add("copyOpt_$abi") - - tasks.register("jniCleanUp_$abi", Delete) { - delete "src/main/jniLibs/$abi" - } - - tasks.register("downloadDistArchive_$abi", Download) { - src "https://github.com/flet-dev/python-build/releases/download/${python_build_date}/python-android-dart-${python_full_version}-${abi}.tar.gz" - dest new File(pythonCacheDir, "python-android-dart-${python_full_version}-${abi}.tar.gz") - onlyIfModified true - useETag "all" - tempAndMove true - doFirst { dest.parentFile.mkdirs() } - } - tasks.register("untarFile_$abi", Copy) { - from tarTree(tasks.named("downloadDistArchive_$abi").get().dest) - into "src/main/jniLibs/$abi" - dependsOn "jniCleanUp_$abi", "downloadDistArchive_$abi" - } - - tasks.register("copyOpt_$abi", Copy) { - from fileTree(dir: "$srcDir/$abi/opt", include: ["**/*.so"]) - into "src/main/jniLibs/$abi" - eachFile { - path = name - } - includeEmptyDirs = false - dependsOn "jniCleanUp_$abi" - } - - tasks.register("zipSitePackages_$abi", Zip) { - from fileTree(dir: "$srcDir/$abi") - archiveFileName = "libpythonsitepackages.so" - destinationDirectory = file("src/main/jniLibs/$abi") - dependsOn "jniCleanUp_$abi", "untarFile_$abi" - } - - // dart-bridge ships a per-(abi × Python-minor-version) prebuilt .so. The - // binary's DT_NEEDED is libpython3.X.so (version-specific), so the bridge - // .so MUST match the libpython bundled in the same APK. We download from - // the pinned dart_bridge_version release into a cache shared across - // builds, then drop it as `libdart_bridge.so` (no version suffix) so the - // Dart side can DynamicLibrary.open by a stable short name. - tasks.register("downloadDartBridge_$abi", Download) { - src "https://github.com/flet-dev/dart-bridge/releases/download/v${dart_bridge_version}/libdart_bridge-android-${abi}-py${python_version}.so" - dest new File(dartBridgeCacheDir, "libdart_bridge-android-${abi}-py${python_version}.so") - onlyIfModified true - useETag "all" - tempAndMove true - doFirst { dest.parentFile.mkdirs() } - } - tasks.register("copyDartBridge_$abi", Copy) { - from tasks.named("downloadDartBridge_$abi").get().dest - into "src/main/jniLibs/$abi" - rename '.*', 'libdart_bridge.so' - dependsOn "downloadDartBridge_$abi", "jniCleanUp_$abi" - } - packageTasks.add("copyDartBridge_$abi") -} - -if (System.getenv('SERIOUS_PYTHON_BUILD_DIST')) { - task copyOrUntar(dependsOn: 'copyBuildDist') -} else { - task copyOrUntar(dependsOn: packageTasks) -} - -preBuild.dependsOn copyOrUntar diff --git a/src/serious_python_android/android/build.gradle.kts b/src/serious_python_android/android/build.gradle.kts new file mode 100644 index 00000000..751be497 --- /dev/null +++ b/src/serious_python_android/android/build.gradle.kts @@ -0,0 +1,331 @@ +import com.android.build.gradle.LibraryExtension +import de.undercouch.gradle.tasks.download.Download +import org.gradle.api.InvalidUserDataException +import java.io.File +import java.util.Properties +import java.util.zip.CRC32 +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream + +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + // The Android Gradle Plugin knows how to build native code with the NDK. + classpath("com.android.tools.build:gradle:8.11.1") + classpath("de.undercouch:gradle-download-task:5.6.0") + } +} + +group = "com.flet.serious_python_android" +version = "3.0.0" + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply(plugin = "com.android.library") +apply(plugin = "de.undercouch.download") + +// Python runtime versions come from the generated python_versions.properties +// (a snapshot of python-build's manifest.json — see serious_python's +// `gen_version_tables`). SERIOUS_PYTHON_VERSION selects the version; everything +// else derives from the table. The per-field env vars are escape hatches. +val pv = Properties().apply { + file("python_versions.properties").inputStream().use { load(it) } +} +val pythonVersion: String = System.getenv("SERIOUS_PYTHON_VERSION") ?: pv.getProperty("default_python_version") +val pythonFullVersion: String? = System.getenv("SERIOUS_PYTHON_FULL_VERSION") ?: pv.getProperty("$pythonVersion.full_version") +val pythonBuildDate: String = System.getenv("SERIOUS_PYTHON_BUILD_DATE") ?: pv.getProperty("python_build_release_date") +val dartBridgeVersion: String = System.getenv("DART_BRIDGE_VERSION") ?: pv.getProperty("dart_bridge_version") +if (pythonFullVersion == null) { + val known = pv.keys.map { it.toString() }.filter { it.endsWith(".full_version") }.map { it.removeSuffix(".full_version") } + throw GradleException("serious_python: unknown SERIOUS_PYTHON_VERSION '$pythonVersion'. Supported: ${known.joinToString(", ")}") +} + +// python-build dropped 32-bit Android in 3.13 (PEP 738), so the +// python-android-dart--armeabi-v7a tarball only exists for 3.12. +val abis: List = if (pythonVersion == "3.12") + listOf("arm64-v8a", "armeabi-v7a", "x86_64") +else + listOf("arm64-v8a", "x86_64") + +configure { + namespace = "com.flet.serious_python_android" + + // Bumping the plugin compileSdk requires all clients of this plugin to bump too. + compileSdk = 36 + + // No native code is compiled here — libdart_bridge.so is downloaded as a + // pre-built artifact from flet-dev/dart-bridge releases (see the + // downloadDartBridge_$abi tasks below) and dropped into jniLibs. + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + defaultConfig { + minSdk = 21 + ndk { + abiFilters.addAll(abis) + } + } + + packaging { + jniLibs { + keepDebugSymbols += setOf( + "*/arm64-v8a/libpython*.so", + "*/armeabi-v7a/libpython*.so", + "*/x86/libpython*.so", + "*/x86_64/libpython*.so", + ) + } + } + + // Keep the stdlib/sitepackages/extract zips stored (uncompressed) in the APK so + // zipimport can read members without zlib. + androidResources { + noCompress.add("zip") + } +} + +val fletCacheRoot: String? = System.getenv("FLET_CACHE_DIR") +val cacheBase: File = if (fletCacheRoot != null) File(fletCacheRoot) else File(System.getProperty("user.home"), ".flet/cache") +val pythonCacheDir = File(cacheBase, "python-build/v$pythonFullVersion") +val dartBridgeCacheDir = File(cacheBase, "dart-bridge/v$dartBridgeVersion") + +tasks.register("copyBuildDist") { + val srcDir = System.getenv("SERIOUS_PYTHON_BUILD_DIST") + if (srcDir != null) { + from(srcDir) + into("src/main/jniLibs") + } +} + +val siteSrcDir: String? = System.getenv("SERIOUS_PYTHON_SITE_PACKAGES") + +// ---- native split ----------------------------------------------------------- +// Relocate CPython extension modules to jniLibs//lib.so (loaded by +// basename via the linker namespace), leaving a .soref marker (content = the lib +// name) at each module's path in the pure zip. Pure code ships in ABI-common +// stored zips; path-hungry packages from SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES +// are moved whole into extract.zip and excluded from sitepackages.zip. +val extractPackages: List = (System.getenv("SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES") ?: "") + .split(",").map { it.trim() }.filter { it.isNotEmpty() } +val primaryAbi = abis.first() // pure zips are ABI-common: build once +val assetsDir = file("src/main/assets") +val bootstrapPy = file("../python/_sp_bootstrap.py") + +val extTag = Regex("""\.(cpython-[^/]+|abi3)\.so$""") // tagged extension module +fun isExtModule(name: String) = extTag.containsMatchIn(name) +fun extDottedName(rel: String): String { // slash-rel path -> dotted import name + val dir = rel.substringBeforeLast('/', "") + val mod = rel.substringAfterLast('/').replace(extTag, "") + return (if (dir.isEmpty()) "" else dir.replace('/', '.') + ".") + mod +} +fun mangledLib(dotted: String) = "lib" + dotted.replace('.', '-') + ".so" +fun sorefPath(rel: String) = rel.replace(extTag, ".soref") +fun isAllowlisted(rel: String) = extractPackages.any { rel == it || rel.startsWith("$it/") } + +// Minimal STORED (uncompressed) zip so members stay readable via zipimport.get_data +// with no zlib at runtime. +class StoredZip(val out: ZipOutputStream) { + fun add(name: String, data: ByteArray) { + val e = ZipEntry(name).apply { + method = ZipEntry.STORED + size = data.size.toLong() + compressedSize = data.size.toLong() + crc = CRC32().apply { update(data) }.value + } + out.putNextEntry(e); out.write(data); out.closeEntry() + } + fun close() = out.close() +} +fun storedZip(f: File): StoredZip { + f.parentFile.mkdirs() + return StoredZip(ZipOutputStream(f.outputStream()).apply { setMethod(ZipOutputStream.STORED) }) +} + +// Loop through abiFilters +val packageTasks = mutableListOf() + +// Remove jniLibs/ dirs for ABIs not in the current set (e.g. stale armeabi-v7a +// 3.12 leftovers when building 3.14) so they aren't packaged into the APK/AAB. +val jniLibsRoot = file("src/main/jniLibs") +tasks.register("cleanStaleAbis") { + doLast { + jniLibsRoot.listFiles()?.forEach { d -> + if (d.isDirectory && d.name !in abis) d.deleteRecursively() + } + } +} +packageTasks.add("cleanStaleAbis") + +for (abi in abis) { + if (siteSrcDir == null || siteSrcDir.isBlank()) { + throw InvalidUserDataException("SERIOUS_PYTHON_SITE_PACKAGES environment variable is not set.") + } + + packageTasks.add("splitStdlib_$abi") + packageTasks.add("splitSitePackages_$abi") + packageTasks.add("copyOpt_$abi") + + tasks.register("jniCleanUp_$abi") { + delete("src/main/jniLibs/$abi") + } + + val distFile = File(pythonCacheDir, "python-android-dart-$pythonFullVersion-$abi.tar.gz") + tasks.register("downloadDistArchive_$abi") { + src("https://github.com/flet-dev/python-build/releases/download/$pythonBuildDate/python-android-dart-$pythonFullVersion-$abi.tar.gz") + dest(distFile) + onlyIfModified(true) + useETag("all") + tempAndMove(true) + doFirst { distFile.parentFile.mkdirs() } + } + tasks.register("untarFile_$abi") { + from(tarTree(distFile)) + into("src/main/jniLibs/$abi") + dependsOn("jniCleanUp_$abi", "downloadDistArchive_$abi") + } + + tasks.register("copyOpt_$abi") { + from(fileTree("$siteSrcDir/$abi/opt") { include("**/*.so") }) + into("src/main/jniLibs/$abi") + eachFile { path = name } + includeEmptyDirs = false + dependsOn("jniCleanUp_$abi") + } + + val jniDir = file("src/main/jniLibs/$abi") + val abiSiteDir = file("$siteSrcDir/$abi") + val bundleFile = File(jniDir, "libpythonbundle.so") + val isPrimary = abi == primaryAbi + + // Crack the stdlib bundle (libpythonbundle.so): modules/*.so -> mangled jniLibs + // (+ .soref markers in stdlib.zip), stdlib/* -> stdlib.zip root, then delete it. + tasks.register("splitStdlib_$abi") { + dependsOn("untarFile_$abi") + // The doLast rewrites jniLibs/ (mangled libs in, bundle out); declare it as a + // tracked output and always re-run so AGP's native-libs merge re-packages. + outputs.dir(jniDir) + outputs.dir(assetsDir) + outputs.upToDateWhen { false } + doLast { + if (!bundleFile.exists()) throw GradleException("libpythonbundle.so missing in jniLibs/$abi") + val zip = if (isPrimary) storedZip(File(assetsDir, "stdlib.zip")) else null + ZipFile(bundleFile).use { zf -> + val en = zf.entries() + while (en.hasMoreElements()) { + val e = en.nextElement() + if (e.isDirectory) continue + val data = zf.getInputStream(e).readBytes() + val name = e.name + when { + name.startsWith("modules/") -> { + val rel = name.removePrefix("modules/") // top-level module file + when { + isExtModule(rel) -> { + val lib = mangledLib(extDottedName(rel)) + File(jniDir, lib).writeBytes(data) + zip?.add(sorefPath(rel), lib.toByteArray()) + } + rel.endsWith(".so") -> File(jniDir, File(rel).name).writeBytes(data) + else -> zip?.add(rel, data) + } + } + name.startsWith("stdlib/") -> zip?.add(name.removePrefix("stdlib/"), data) + else -> zip?.add(name, data) + } + } + } + zip?.add("_sp_bootstrap.py", bootstrapPy.readBytes()) // finder at zip root + // The dart-bridge Android shim (F) installs the finder before `site`. A + // sitecustomize fallback can be re-enabled for bridges without that shim: + // zip?.add("sitecustomize.py", "import _sp_bootstrap\n_sp_bootstrap.install()\n".toByteArray()) + zip?.close() + bundleFile.delete() // fake-zip must not ship + } + } + + // Site-packages tree: tagged .so -> mangled jniLibs (+ .soref markers), pure -> + // sitepackages.zip (or extract.zip if allowlisted); opt/ is left to copyOpt. + tasks.register("splitSitePackages_$abi") { + dependsOn("untarFile_$abi") + mustRunAfter("copyOpt_$abi", "splitStdlib_$abi") + outputs.dir(jniDir) + outputs.dir(assetsDir) + outputs.upToDateWhen { false } + doLast { + jniDir.mkdirs() + val siteZip = if (isPrimary) storedZip(File(assetsDir, "sitepackages.zip")) else null + val extractZip = if (isPrimary) storedZip(File(assetsDir, "extract.zip")) else null + abiSiteDir.walkTopDown().filter { it.isFile }.forEach { f -> + val rel = f.relativeTo(abiSiteDir).path.replace(File.separatorChar, '/') + if (rel == "opt" || rel.startsWith("opt/")) return@forEach // dep libs -> copyOpt + val zip = if (isAllowlisted(rel)) extractZip else siteZip + when { + isExtModule(rel) -> { + val lib = mangledLib(extDottedName(rel)) + f.copyTo(File(jniDir, lib), overwrite = true) + zip?.add(sorefPath(rel), lib.toByteArray()) + } + rel.endsWith(".so") -> f.copyTo(File(jniDir, f.name), overwrite = true) // untagged -> dep + else -> zip?.add(rel, f.readBytes()) + } + } + siteZip?.close() + extractZip?.close() + } + } + + // dart-bridge ships a per-(abi × Python-minor-version) prebuilt .so. The + // binary's DT_NEEDED is libpython3.X.so (version-specific), so the bridge + // .so MUST match the libpython bundled in the same APK. We download from + // the pinned dart_bridge_version release into a cache shared across + // builds, then drop it as `libdart_bridge.so` (no version suffix) so the + // Dart side can DynamicLibrary.open by a stable short name. + // SERIOUS_PYTHON_DART_BRIDGE_DIST: local-dev override pointing at a dir of + // freshly cross-compiled libdart_bridge-android--py.so, bypassing the + // GitHub release download (mirrors the SERIOUS_PYTHON_BUILD_DIST escape hatch). + val dartBridgeDist = System.getenv("SERIOUS_PYTHON_DART_BRIDGE_DIST") + val bridgeFile = if (dartBridgeDist != null) + File(dartBridgeDist, "libdart_bridge-android-$abi-py$pythonVersion.so") + else + File(dartBridgeCacheDir, "libdart_bridge-android-$abi-py$pythonVersion.so") + tasks.register("downloadDartBridge_$abi") { + src("https://github.com/flet-dev/dart-bridge/releases/download/v$dartBridgeVersion/libdart_bridge-android-$abi-py$pythonVersion.so") + dest(bridgeFile) + onlyIfModified(true) + useETag("all") + tempAndMove(true) + doFirst { bridgeFile.parentFile.mkdirs() } + } + tasks.register("copyDartBridge_$abi") { + from(bridgeFile) + into("src/main/jniLibs/$abi") + rename(".*", "libdart_bridge.so") + if (dartBridgeDist == null) dependsOn("downloadDartBridge_$abi") + dependsOn("jniCleanUp_$abi") + } + packageTasks.add("copyDartBridge_$abi") +} + +val copyOrUntar = tasks.register("copyOrUntar") { + if (System.getenv("SERIOUS_PYTHON_BUILD_DIST") != null) { + dependsOn("copyBuildDist") + } else { + dependsOn(packageTasks) + } +} + +tasks.named("preBuild") { + dependsOn(copyOrUntar) +} diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index c72c7f8e..7cc4bbe2 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.2 +dart_bridge_version=1.4.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java index de434d49..54ba8f80 100644 --- a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java +++ b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java @@ -38,13 +38,47 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBindin channel.setMethodCallHandler(this); this.context = flutterPluginBinding.getApplicationContext(); try { - Os.setenv(ANDROID_NATIVE_LIBRARY_DIR, - new ContextWrapper(this.context).getApplicationInfo().nativeLibraryDir, true); + android.content.pm.ApplicationInfo ai = + new ContextWrapper(this.context).getApplicationInfo(); + Os.setenv(ANDROID_NATIVE_LIBRARY_DIR, ai.nativeLibraryDir, true); + // Under modern packaging (useLegacyPackaging=false) native libs are NOT extracted + // to nativeLibraryDir; they live uncompressed/page-aligned inside the APK and are + // loadable via Bionic's zip-path (apk!/lib//). Export that prefix so + // the finder can dlopen them directly from the APK (mmap, no extraction). For Play + // Store AAB installs the libs are in a per-ABI config split, not base.apk, so pick + // whichever installed APK actually contains lib//. + String abi = (android.os.Build.SUPPORTED_ABIS != null + && android.os.Build.SUPPORTED_ABIS.length > 0) + ? android.os.Build.SUPPORTED_ABIS[0] : ""; + Os.setenv("ANDROID_APK_NATIVE_PREFIX", apkNativePrefix(ai, abi), true); } catch (Exception e) { // nothing to do } } + // Bionic zip-path prefix (!/lib//) of the installed APK that holds the + // native libs. Single-APK builds -> base.apk; Play Store AAB installs -> the + // per-ABI config split (base.apk has no libs then). Detected by probing for the + // always-present libdart_bridge.so. + private static String apkNativePrefix(android.content.pm.ApplicationInfo ai, String abi) { + java.util.List apks = new java.util.ArrayList<>(); + if (ai.sourceDir != null) apks.add(ai.sourceDir); + if (ai.splitSourceDirs != null) { + java.util.Collections.addAll(apks, ai.splitSourceDirs); + } + String member = "lib/" + abi + "/libdart_bridge.so"; + for (String apk : apks) { + try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(apk)) { + if (zf.getEntry(member) != null) { + return apk + "!/lib/" + abi + "/"; + } + } catch (Exception e) { + // unreadable apk — skip + } + } + return (ai.sourceDir != null ? ai.sourceDir : "") + "!/lib/" + abi + "/"; + } + @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { PythonActivity.mActivity = activityPluginBinding.getActivity(); @@ -69,10 +103,52 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { } catch (Exception e) { result.error("Error", e.getMessage(), null); } - } else if (call.method.equals("getNativeLibraryDir")) { - ContextWrapper contextWrapper = new ContextWrapper(context); - String nativeLibraryDir = contextWrapper.getApplicationInfo().nativeLibraryDir; - result.success(nativeLibraryDir); + } else if (call.method.equals("getFilesDir")) { + result.success(context.getFilesDir().getAbsolutePath()); + } else if (call.method.equals("extractAsset")) { + // Stream an APK asset to disk as one whole file (e.g. stdlib.zip). + try { + String asset = call.argument("asset"); + String dest = call.argument("dest"); + java.io.File destFile = new java.io.File(dest); + if (destFile.getParentFile() != null) destFile.getParentFile().mkdirs(); + byte[] buf = new byte[1 << 16]; + try (java.io.InputStream in = context.getAssets().open(asset); + java.io.OutputStream out = new java.io.FileOutputStream(destFile)) { + int n; + while ((n = in.read(buf)) > 0) out.write(buf, 0, n); + } + result.success(dest); + } catch (Exception e) { + result.error("extractAsset", e.getMessage(), null); + } + } else if (call.method.equals("unzipAsset")) { + // Unpack an APK asset zip (e.g. extract.zip) into a directory tree. + try { + String asset = call.argument("asset"); + String destDir = call.argument("dest"); + java.io.File root = new java.io.File(destDir); + byte[] buf = new byte[1 << 16]; + try (java.io.InputStream in = context.getAssets().open(asset); + java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(in)) { + java.util.zip.ZipEntry e; + while ((e = zis.getNextEntry()) != null) { + java.io.File f = new java.io.File(root, e.getName()); + if (e.isDirectory()) { + f.mkdirs(); + } else { + if (f.getParentFile() != null) f.getParentFile().mkdirs(); + try (java.io.OutputStream out = new java.io.FileOutputStream(f)) { + int n; + while ((n = zis.read(buf)) > 0) out.write(buf, 0, n); + } + } + } + } + result.success(destDir); + } catch (Exception e) { + result.error("unzipAsset", e.getMessage(), null); + } } else { result.notImplemented(); } diff --git a/src/serious_python_android/lib/serious_python_android.dart b/src/serious_python_android/lib/serious_python_android.dart index a7947bc5..7c7d4997 100644 --- a/src/serious_python_android/lib/serious_python_android.dart +++ b/src/serious_python_android/lib/serious_python_android.dart @@ -32,38 +32,48 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { List? modulePaths, Map? environmentVariables, bool? sync}) async { - final nativeLibraryDir = - await methodChannel.invokeMethod('getNativeLibraryDir'); - if (nativeLibraryDir == null) { - throw StateError( - 'serious_python: failed to resolve native library dir'); - } - - final bundlePath = '$nativeLibraryDir/libpythonbundle.so'; - if (!await File(bundlePath).exists()) { - throw Exception('Python bundle not found: $bundlePath'); + // Native extension modules now live in jniLibs (loaded by basename via the + // finder); pure code ships in stored Android-asset zips. Copy the zips to disk + // once (version-keyed) and unpack the allowlist payload; PYTHONPATH points at + // the zips so zipimport serves pure modules in place. + final filesDir = await methodChannel.invokeMethod('getFilesDir'); + if (filesDir == null) { + throw StateError('serious_python: failed to resolve files dir'); } + final base = p.join(filesDir, 'flet', 'py'); + final stdlibZip = p.join(base, 'stdlib.zip'); + final siteZip = p.join(base, 'sitepackages.zip'); + final extractDir = p.join(base, 'extract'); final appVersion = await _appVersion(); - final invalidateKey = appVersion != null ? 'app:$appVersion' : null; - - final pythonLibPath = await extractFileZip(bundlePath, - targetPath: 'python_bundle', invalidateKey: invalidateKey); - - final sitePackagesZip = '$nativeLibraryDir/libpythonsitepackages.so'; - String? sitePackagesPath; - if (await File(sitePackagesZip).exists()) { - sitePackagesPath = await extractFileZip(sitePackagesZip, - targetPath: 'python_site_packages', invalidateKey: invalidateKey); + final key = appVersion != null ? 'app:$appVersion' : 'app:dev'; + final marker = File(p.join(base, '.key')); + final upToDate = + await marker.exists() && (await marker.readAsString()) == key; + if (!upToDate) { + await Directory(base).create(recursive: true); + if (await Directory(extractDir).exists()) { + await Directory(extractDir).delete(recursive: true); + } + await methodChannel.invokeMethod( + 'extractAsset', {'asset': 'stdlib.zip', 'dest': stdlibZip}); + await methodChannel.invokeMethod( + 'extractAsset', {'asset': 'sitepackages.zip', 'dest': siteZip}); + await methodChannel.invokeMethod( + 'unzipAsset', {'asset': 'extract.zip', 'dest': extractDir}); + await marker.writeAsString(key); } final programDir = p.dirname(appPath); + // Highest -> lowest precedence. site-packages before stdlib so pip backports + // can override; extract-dir before sitepackages.zip. Natives resolve via the + // finder, not a sys.path entry. final pythonPaths = [ ...?modulePaths, programDir, - '$pythonLibPath/modules', - '$pythonLibPath/stdlib', - if (sitePackagesPath != null) sitePackagesPath, + extractDir, + siteZip, + stdlibZip, ]; final env = { @@ -72,7 +82,7 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { 'PYTHONNOUSERSITE': '1', 'PYTHONUNBUFFERED': '1', 'LC_CTYPE': 'UTF-8', - 'PYTHONHOME': pythonLibPath, + 'PYTHONHOME': base, 'PYTHONPATH': pythonPaths.join(':'), ...?environmentVariables, }; diff --git a/src/serious_python_android/python/_sp_bootstrap.py b/src/serious_python_android/python/_sp_bootstrap.py new file mode 100644 index 00000000..be29d3c6 --- /dev/null +++ b/src/serious_python_android/python/_sp_bootstrap.py @@ -0,0 +1,139 @@ +"""serious_python Android import bootstrap. + +Installed by the dart-bridge embedder *before* ``site`` runs, via the fixed call:: + + import _sp_bootstrap; _sp_bootstrap.install() + +It registers a ``sys.meta_path`` finder that resolves native CPython extension +modules which the build relocated into ``jniLibs//`` as real ``lib.so`` +files (loaded by basename through the Android linker namespace, exactly like +``libdart_bridge.so``). Pure ``.py``/``.pyc`` modules are left to ``zipimport`` / +``FileFinder`` — this finder returns ``None`` for them. + +For every relocated extension the build leaves a ``.soref`` marker at the module's +original path; its content is the ``lib.so`` filename. The marker is read +**lazily** in ``find_spec`` via the frozen ``zipimport`` ``get_data`` API (for zip +entries) or a plain ``open`` (for entries extracted to disk, e.g. ``extract.zip``). + +CRITICAL: this module must load and run *before any native module is resolvable*, +so it imports **only builtin/frozen** machinery — ``sys``, ``zipimport``, +``importlib.machinery`` — and never ``zipfile``/``struct``/``zlib`` (which would be +a chicken-and-egg: those are themselves native). +""" + +import sys +import posix # builtin (native-free): read env without importing os +import zipimport +from importlib.machinery import ExtensionFileLoader, ModuleSpec + +_MARKER_SUFFIX = ".soref" +_installed = False + + +def _native_lib_dir(): + # nativeLibraryDir, exported by AndroidPlugin before Py_Initialize. Under legacy + # packaging the mangled libs are extracted there, so an absolute origin lets the + # interpreter dlopen them (some Android CPython builds prepend "./" to a no-slash + # origin, which breaks a bare-soname namespace lookup). Empty under modern + # packaging -> fall back to bare soname (linker-namespace resolution). + v = posix.environ.get(b"ANDROID_NATIVE_LIBRARY_DIR") + return v.decode("utf-8") if v else None + + +def _apk_native_prefix(): + # base.apk!/lib// — Bionic zip-path to libs mmap'd from the APK under modern + # packaging (useLegacyPackaging=false), where libs are NOT extracted to disk. + v = posix.environ.get(b"ANDROID_APK_NATIVE_PREFIX") + return v.decode("utf-8") if v else None + + +class _SorefFinder: + """meta_path finder: dotted name -> jniLibs lib via its ``.soref`` marker.""" + + def __init__(self): + # Cache one zipimporter per zip sys.path entry. Value is None for entries + # that are not zips (plain directories) so we don't retry zipimporter(). + self._zi_cache = {} + self._native_dir = _native_lib_dir() + self._apk_prefix = _apk_native_prefix() + + def _zipimporter(self, entry): + try: + return self._zi_cache[entry] + except KeyError: + try: + zi = zipimport.zipimporter(entry) + except Exception: + zi = None # not a zip (e.g. a directory) + self._zi_cache[entry] = zi + return zi + + def _read_marker(self, member): + """Return the soname recorded in ``member`` (.soref), or None if absent. + + Probes every current ``sys.path`` entry: zip entries via the frozen + ``zipimport.get_data`` (known member, no native deps), directory entries + via a plain ``open`` (covers packages unpacked from ``extract.zip``). + """ + for entry in sys.path: + if not entry: + continue + zi = self._zipimporter(entry) + if zi is not None: + try: + return zi.get_data(member) # archive-relative member path + except Exception: + continue + else: + # Directory entry: try the marker as a real file on disk. + path = entry + "/" + member + try: + with open(path, "rb") as f: + return f.read() + except OSError: + continue + return None + + def find_spec(self, fullname, path=None, target=None): + member = fullname.replace(".", "/") + _MARKER_SUFFIX + data = self._read_marker(member) + if data is None: + return None # not a relocated native module -> let others handle it + soname = data.decode("utf-8").strip() + # Resolve the lib to an absolute origin (CPython prepends "./" to a no-slash + # origin, which breaks bare-soname loading). Prefer the extracted copy under + # nativeLibraryDir (legacy packaging); else the Bionic APK zip-path (modern + # packaging, mmap'd from the APK, never extracted). + origin = soname + if self._native_dir: + cand = self._native_dir + "/" + soname + try: + open(cand, "rb").close() + origin = cand + except OSError: + pass + if origin == soname and self._apk_prefix: + origin = self._apk_prefix + soname + loader = ExtensionFileLoader(fullname, origin) + return ModuleSpec(fullname, loader, origin=origin) + + +def install(): + """Insert the finder at the front of ``sys.meta_path`` (idempotent).""" + global _installed + if _installed: + return + # Bootstrap audit: any extension module (.so) already imported at this point was + # loaded during interpreter core-init, BEFORE the finder existed — which only works + # if it was builtin/frozen. A non-empty list means that module must be made static + # (PyImport_AppendInittab) or it will fail under modern packaging. Expected: empty. + pre = [n for n, m in sys.modules.items() + if getattr(m, "__file__", None) and str(m.__file__).endswith(".so")] + if pre: + sys.stderr.write("SP_BOOTSTRAP pre-finder native modules: %r\n" % (pre,)) + for f in sys.meta_path: + if isinstance(f, _SorefFinder): + _installed = True + return + sys.meta_path.insert(0, _SorefFinder()) + _installed = True diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index c72c7f8e..7cc4bbe2 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.2 +dart_bridge_version=1.4.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index c72c7f8e..7cc4bbe2 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.2 +dart_bridge_version=1.4.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index c72c7f8e..7cc4bbe2 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 20260614). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.3.2 +dart_bridge_version=1.4.0 python_build_release_date=20260614 3.12.full_version=3.12.13 3.13.full_version=3.13.14 From ab92a098d6806f5a2ccd7aaafc029bee40dcacb6 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 17 Jun 2026 16:10:34 -0700 Subject: [PATCH 113/114] Remove the Android x86 (32-bit Intel) ABI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flutter no longer produces an x86 ABI on Android, so every x86 reference is dead. Builds target arm64-v8a + x86_64 (plus armeabi-v7a on Python 3.12); x86_64 (emulator / Intel macOS) and armeabi-v7a are untouched. - package_command.dart: drop the "x86" wheel platform-tag map entry and the `|| arch.key == "x86"` arm of the 32-bit skip condition. - serious_python_android/build.gradle.kts: remove the whole vestigial keepDebugSymbols block. It was a leftover from the old fake-.so-zip scheme: this com.android.library only packages the downloaded libdart_bridge.so (the libpython*.so patterns match nothing it owns), the real native modules land in the consuming app's jniLibs and are real ELF that mmap fine when stripped, and the README/CHANGELOG already state native-mmap needs no keepDebugSymbols. - flask_example: drop the stale useLegacyPackaging + keepDebugSymbols block (the only example still on the old scheme); minSdk 24 → modern packaging applies. Verified: built + ran on an arm64 device, Flask serves from Python with native deps memory-mapped from the APK, APK ships arm64-v8a + x86_64 only. Also syncs flask_example's pubspec.lock to the 3.0.0 path-dep versions. --- src/serious_python/bin/package_command.dart | 3 +-- .../android/app/build.gradle.kts | 19 ++++--------------- .../example/flask_example/pubspec.lock | 12 ++++++------ src/serious_python_android/CHANGELOG.md | 1 + .../android/build.gradle.kts | 15 +++++---------- 5 files changed, 17 insertions(+), 33 deletions(-) diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index 3d4a4c16..720a1f09 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -51,7 +51,6 @@ const platforms = { "arm64-v8a": {"tag": "android-24-arm64_v8a", "mac_ver": ""}, "armeabi-v7a": {"tag": "android-24-armeabi_v7a", "mac_ver": ""}, "x86_64": {"tag": "android-24-x86_64", "mac_ver": ""}, - "x86": {"tag": "android-24-x86", "mac_ver": ""} }, "Emscripten": { // The actual wheel platform tag is resolved per Python release from @@ -355,7 +354,7 @@ class PackageCommand extends Command { // versions, so installing 32-bit wheels would be wasted work. if (platform == "Android" && _pythonShortVersion != "3.12" && - (arch.key == "armeabi-v7a" || arch.key == "x86")) { + arch.key == "armeabi-v7a") { continue; } String? sitePackagesDir; diff --git a/src/serious_python/example/flask_example/android/app/build.gradle.kts b/src/serious_python/example/flask_example/android/app/build.gradle.kts index 465b665a..2039132c 100644 --- a/src/serious_python/example/flask_example/android/app/build.gradle.kts +++ b/src/serious_python/example/flask_example/android/app/build.gradle.kts @@ -16,21 +16,10 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - // serious_python bundles libpython*.so. Use legacy (extracted, uncompressed) - // packaging so the embedded interpreter can dlopen them at runtime, and keep - // their symbols so they are not stripped. (Replaces the removed - // android.bundle.enableUncompressedNativeLibs flag.) - packaging { - jniLibs { - useLegacyPackaging = true - keepDebugSymbols += setOf( - "*/arm64-v8a/libpython*.so", - "*/armeabi-v7a/libpython*.so", - "*/x86/libpython*.so", - "*/x86_64/libpython*.so", - ) - } - } + // No native-library packaging config is needed: serious_python loads Python + // extension modules directly from the APK (memory-mapped) and ships pure + // Python in stored asset zips. Modern packaging (the default at minSdk 23+) is + // all that's required. defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). diff --git a/src/serious_python/example/flask_example/pubspec.lock b/src/serious_python/example/flask_example/pubspec.lock index 4ecc87d8..4c0ed4d0 100644 --- a/src/serious_python/example/flask_example/pubspec.lock +++ b/src/serious_python/example/flask_example/pubspec.lock @@ -361,42 +361,42 @@ packages: path: "../.." relative: true source: path - version: "2.0.0" + version: "3.0.0" serious_python_android: dependency: transitive description: path: "../../../serious_python_android" relative: true source: path - version: "2.0.0" + version: "3.0.0" serious_python_darwin: dependency: transitive description: path: "../../../serious_python_darwin" relative: true source: path - version: "2.0.0" + version: "3.0.0" serious_python_linux: dependency: transitive description: path: "../../../serious_python_linux" relative: true source: path - version: "2.0.0" + version: "3.0.0" serious_python_platform_interface: dependency: transitive description: path: "../../../serious_python_platform_interface" relative: true source: path - version: "2.0.0" + version: "3.0.0" serious_python_windows: dependency: transitive description: path: "../../../serious_python_windows" relative: true source: path - version: "2.0.0" + version: "3.0.0" shelf: dependency: transitive description: diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 6a296470..2476b774 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -4,6 +4,7 @@ * **Native modules are memory-mapped from the APK — no more `useLegacyPackaging`.** Python extension modules (stdlib `lib-dynload` and site-packages) are relocated into `jniLibs//lib.so` and loaded directly from the APK by a custom `sys.meta_path` finder that resolves them from `.soref` markers — no extraction to disk, still ABI-split by the Play Store. Pure Python ships in **stored, ABI-common asset zips** read via `zipimport`, so the stdlib is no longer duplicated per ABI. This replaces the previous scheme of zipping stdlib/site-packages into fake `lib*.so` files (which required `useLegacyPackaging`). The dart-bridge Android binary now uses the full CPython API (`PyConfig`) to install the finder before `site` runs. Set **`SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES`** (comma-separated relative paths) to ship path-hungry packages extracted to disk instead. * **Breaking change:** requires Flutter **3.44.2**. Moves to AGP **8.11.1**, Gradle 8.11.1, `compileSdk` **36**, Java **17**, and the **Kotlin-DSL** Gradle build (`build.gradle.kts`). * `build.gradle` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version, build date and `dart_bridge` version derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` / `DART_BRIDGE_VERSION` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. +* Drop the `x86` (32-bit Intel) ABI — Flutter no longer produces it. ABIs are `arm64-v8a` + `x86_64` (plus `armeabi-v7a` on Python 3.12). * Remove the scaffold `getPlatformVersion` method. ## 2.0.0 diff --git a/src/serious_python_android/android/build.gradle.kts b/src/serious_python_android/android/build.gradle.kts index 751be497..f50a6f80 100644 --- a/src/serious_python_android/android/build.gradle.kts +++ b/src/serious_python_android/android/build.gradle.kts @@ -78,16 +78,11 @@ configure { } } - packaging { - jniLibs { - keepDebugSymbols += setOf( - "*/arm64-v8a/libpython*.so", - "*/armeabi-v7a/libpython*.so", - "*/x86/libpython*.so", - "*/x86_64/libpython*.so", - ) - } - } + // No jniLibs packaging config needed: the native modules are real ELF .so that + // land in the consuming app's jniLibs (relocated by the split tasks) and are + // loaded memory-mapped from the APK — modern packaging (minSdk 23+) is all that + // is required. (The old keepDebugSymbols rules were only needed for the previous + // fake-.so-zip scheme.) // Keep the stdlib/sitepackages/extract zips stored (uncompressed) in the APK so // zipimport can read members without zlib. From 3633b78e380039207f0dfd34f71794190de97ede Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Wed, 17 Jun 2026 16:10:43 -0700 Subject: [PATCH 114/114] Complete the 3.0.0 CHANGELOGs - Fix the bundled dart_bridge version in the darwin/linux/windows CHANGELOGs: they said 1.2.3, but all three python_versions.properties pin 1.4.0 (the android CHANGELOG was already correct). - Document the x86 (32-bit Intel) Android ABI removal in the core CHANGELOG. - Document the removal of the `configure` command / bare in-place version-switching machinery (a clean rebuild now handles version switches) as a breaking change in the core CHANGELOG. --- src/serious_python/CHANGELOG.md | 2 ++ src/serious_python_darwin/CHANGELOG.md | 2 +- src/serious_python_linux/CHANGELOG.md | 2 +- src/serious_python_windows/CHANGELOG.md | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 069c0a61..72ce22b0 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -9,6 +9,8 @@ * The embedded Darwin runtime re-extracts when the selected Python version changes (a version marker guards `dist_ios` / `dist_macos`), so a clean build after switching `--python-version` can't mix C-extension ABIs (`bad magic number` / `unknown slot ID`). * Cache downloaded Python distributions and `dart_bridge` artifacts under `$FLET_CACHE_DIR` (default `~/.flet/cache`) across all platforms. * Remove the scaffold `getPlatformVersion` method from the platform plugins. +* Drop the `x86` (32-bit Intel) Android ABI — Flutter no longer produces it. Android builds target `arm64-v8a` + `x86_64` (plus `armeabi-v7a` on Python 3.12); the `x86` wheel platform-tag entry and the Android packaging rules referencing it are removed. +* **Breaking change:** the `configure` command (and the bare in-place version-switching machinery, including `stageDarwinRuntime`) is removed. Switching the bundled Python version between builds is now handled by a clean rebuild — `flet build` wipes its build dir on a version change, and the Darwin `dist_ios` / `dist_macos` version marker re-extracts the runtime — so a separate `serious_python configure` step is no longer needed. * **Bug fix:** the Pyodide 0.29 wheel platform tag for the 3.13 row was `pyodide-2025.0-wasm32`, but Pyodide publishes 0.29 wheels under `pyemscripten_2025_0_wasm32`; corrected to `pyemscripten-2025.0-wasm32` so `flet build web --python-version 3.13` matches native wheels. ## 2.0.0 diff --git a/src/serious_python_darwin/CHANGELOG.md b/src/serious_python_darwin/CHANGELOG.md index e7402f59..0e217db7 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -1,6 +1,6 @@ ## 3.0.0 -* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `dart_bridge.xcframework` (from `flet-dev/dart-bridge` **1.2.3**) instead of a socket transport; the Swift plugin registers the dart_bridge inittab, the pod is declared `static_framework` for xcframework vendoring, and the embedded `Python.app` is stripped from `Python.framework`. +* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `dart_bridge.xcframework` (from `flet-dev/dart-bridge` **1.4.0**) instead of a socket transport; the Swift plugin registers the dart_bridge inittab, the pod is declared `static_framework` for xcframework vendoring, and the embedded `Python.app` is stripped from `Python.framework`. * **Breaking change:** requires Flutter **3.44.2**. * The podspec resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`) and passes the full version, build date and `dart_bridge` version to `prepare_ios.sh` / `prepare_macos.sh` (`dart_bridge_version` is `$4`); `SERIOUS_PYTHON_VERSION` is the knob, the per-field env vars are escape hatches. The prepare scripts re-extract `dist_ios` / `dist_macos` when the selected version changes (a version marker) so a clean build can't mix C-extension ABIs. * Remove the scaffold `getPlatformVersion` method. diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index 313af1e7..d1341a8e 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -1,6 +1,6 @@ ## 3.0.0 -* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `libdart_bridge.so` (from `flet-dev/dart-bridge` **1.2.3**, `DT_RPATH $ORIGIN`) instead of a socket transport. +* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `libdart_bridge.so` (from `flet-dev/dart-bridge` **1.4.0**, `DT_RPATH $ORIGIN`) instead of a socket transport. * **Breaking change:** requires Flutter **3.44.2**. * `CMakeLists.txt` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version and build date derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. * Remove the scaffold `getPlatformVersion` method. diff --git a/src/serious_python_windows/CHANGELOG.md b/src/serious_python_windows/CHANGELOG.md index 8b615ddc..69db9e85 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -1,6 +1,6 @@ ## 3.0.0 -* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `dart_bridge.dll` / `dart_bridge.pyd` (from `flet-dev/dart-bridge` **1.2.3**) instead of a socket transport; both Release and Debug `dart_bridge.pyd` ship so 3.13/3.14 Debug builds resolve too. +* **In-process Python (dart_bridge FFI).** The Python lifecycle is absorbed into `dart_bridge.dll` / `dart_bridge.pyd` (from `flet-dev/dart-bridge` **1.4.0**) instead of a socket transport; both Release and Debug `dart_bridge.pyd` ship so 3.13/3.14 Debug builds resolve too. * **Breaking change:** requires Flutter **3.44.2**. * `CMakeLists.txt` resolves the Python version from the generated `python_versions.properties` (a snapshot of python-build's `manifest.json`): `SERIOUS_PYTHON_VERSION` selects the version; the full version and build date derive from the table, with `SERIOUS_PYTHON_FULL_VERSION` / `SERIOUS_PYTHON_BUILD_DATE` left as escape hatches. Downloads continue to use python-build's date-keyed release scheme. * Remove the scaffold `getPlatformVersion` method.