From 2c7dc4ad7e846b6bd000f1b35a3735b8daae19f5 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 14 Nov 2023 14:17:45 +0800 Subject: [PATCH 1/7] Switch to dynamic framework builds. --- .../{{ cookiecutter.class_name }}/main.m | 20 ++------ .../project.pbxproj | 50 ++++++++++++------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m index 06c28a7..8e4f11e 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m +++ b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m @@ -5,7 +5,7 @@ #import #import -#include +#include #include @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) { PyObject *systemExit_code; @autoreleasepool { - NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; + NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; // Generate an isolated Python configuration. NSLog(@"Configuring isolated Python..."); @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) { } // Set the home for the Python interpreter - python_home = [NSString stringWithFormat:@"%@/python-stdlib", resourcePath, nil]; + python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; NSLog(@"PythonHome: %@", python_home); wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); status = PyConfig_SetString(&config, &config.home, wtmp_str); @@ -99,20 +99,8 @@ int main(int argc, char *argv[]) { // Set the full module path. This includes the stdlib, site-packages, and app code. NSLog(@"PYTHONPATH:"); - // // The .zip form of the stdlib - // path = [NSString stringWithFormat:@"%@/python{{ cookiecutter.python_version|py_libtag }}.zip", resourcePath, nil]; - // NSLog(@"- %@", path); - // wtmp_str = Py_DecodeLocale([path UTF8String], NULL); - // status = PyWideStringList_Append(&config.module_search_paths, wtmp_str); - // if (PyStatus_Exception(status)) { - // crash_dialog([NSString stringWithFormat:@"Unable to set .zip form of stdlib path: %s", status.err_msg, nil]); - // PyConfig_Clear(&config); - // Py_ExitStatusException(status); - // } - // PyMem_RawFree(wtmp_str); - // The unpacked form of the stdlib - path = [NSString stringWithFormat:@"%@/python-stdlib", resourcePath, nil]; + path = [NSString stringWithFormat:@"%@/python/lib/python{{ cookiecutter.python_version|py_tag }}", resourcePath, nil]; NSLog(@"- %@", path); wtmp_str = Py_DecodeLocale([path UTF8String], NULL); status = PyWideStringList_Append(&config.module_search_paths, wtmp_str); diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj b/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj index f6a890b..55e019e 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj +++ b/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj @@ -15,18 +15,29 @@ 600000000000000000100200 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 610000000000000000100800 /* Images.xcassets */; }; 600000000000000000100300 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 610000000000000000100900 /* Launch Screen.storyboard */; }; 60754F822AA5926A0013A4FB /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 60754F802AA57C440013A4FB /* dylib-Info-template.plist */; }; - 60A04BC428B35ECB00DAA9E5 /* python-stdlib in Resources */ = {isa = PBXBuildFile; fileRef = 60A04BC328B35ECB00DAA9E5 /* python-stdlib */; }; - 60A04BC628B35ED400DAA9E5 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60A04BC528B35ED400DAA9E5 /* Python.xcframework */; }; + 60813D372B02EED200EFB492 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60813D352B02EBFC00EFB492 /* Python.xcframework */; }; + 60813D382B02EED200EFB492 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 60813D352B02EBFC00EFB492 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 60A04BC728B35FD000DAA9E5 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 610000000000000000100100 /* app */; }; - 60A421FE2AB4256300E46BC3 /* app_packages.iphonesimulator in Resources */ = {isa = PBXBuildFile; fileRef = 60A421FC2AB4256300E46BC3 /* app_packages.iphonesimulator */; }; - 60A421FF2AB4256300E46BC3 /* app_packages.iphoneos in Resources */ = {isa = PBXBuildFile; fileRef = 60A421FD2AB4256300E46BC3 /* app_packages.iphoneos */; }; 60C0057928F7DB9A008B9E84 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60C0057828F7DB9A008B9E84 /* WebKit.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + 6060E7A12AF8BF4400C04AE0 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 60813D382B02EED200EFB492 /* Python.xcframework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 60754F802AA57C440013A4FB /* dylib-Info-template.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "dylib-Info-template.plist"; sourceTree = ""; }; - 60A04BC328B35ECB00DAA9E5 /* python-stdlib */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "python-stdlib"; sourceTree = ""; }; - 60A04BC528B35ED400DAA9E5 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Python.xcframework; path = Support/Python.xcframework; sourceTree = ""; }; + 60813D352B02EBFC00EFB492 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; }; 60A421FC2AB4256300E46BC3 /* app_packages.iphonesimulator */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages.iphonesimulator; sourceTree = ""; }; 60A421FD2AB4256300E46BC3 /* app_packages.iphoneos */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages.iphoneos; sourceTree = ""; }; 60C0057828F7DB9A008B9E84 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; @@ -35,7 +46,7 @@ 610000000000000000000A00 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 610000000000000000100100 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = ""; }; 610000000000000000100300 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 610000000000000000100400 /* {{ cookiecutter.formal_name }}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{ cookiecutter.formal_name }}.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 610000000000000000100400 /* {{ cookiecutter.formal_name }}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = {{ cookiecutter.formal_name }}.app; sourceTree = BUILT_PRODUCTS_DIR; }; 610000000000000000100500 /* {{ cookiecutter.class_name }}-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "{{ cookiecutter.class_name }}-Info.plist"; sourceTree = ""; }; 610000000000000000100600 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 610000000000000000100700 /* {{ cookiecutter.class_name }}-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "{{ cookiecutter.class_name }}-Prefix.pch"; sourceTree = ""; }; @@ -50,9 +61,9 @@ files = ( 600000000000000000000800 /* CoreGraphics.framework in Frameworks */, 600000000000000000000900 /* Foundation.framework in Frameworks */, + 60813D372B02EED200EFB492 /* Python.xcframework in Frameworks */, 600000000000000000000A00 /* UIKit.framework in Frameworks */, 60C0057928F7DB9A008B9E84 /* WebKit.framework in Frameworks */, - 60A04BC628B35ED400DAA9E5 /* Python.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -63,7 +74,6 @@ isa = PBXGroup; children = ( 60A04BC228B35E9F00DAA9E5 /* Support */, - 60A04BC528B35ED400DAA9E5 /* Python.xcframework */, 60796EEB19190F4100A9926B /* {{ cookiecutter.class_name }} */, 60796EE419190F4100A9926B /* Frameworks */, 60796EE319190F4100A9926B /* Products */, @@ -117,7 +127,7 @@ 60A04BC228B35E9F00DAA9E5 /* Support */ = { isa = PBXGroup; children = ( - 60A04BC328B35ECB00DAA9E5 /* python-stdlib */, + 60813D352B02EBFC00EFB492 /* Python.xcframework */, ); path = Support; sourceTree = ""; @@ -132,8 +142,9 @@ 60796EDE19190F4100A9926B /* Sources */, 60796EDF19190F4100A9926B /* Frameworks */, 60796EE019190F4100A9926B /* Resources */, - 609384A628B5B958005B2A5D /* Purge Python Binary Modules for Non-Target Platforms */, + 609384A628B5B958005B2A5D /* Install target specific Python modules */, 609384A528B45C86005B2A5D /* Sign Python Binary Modules */, + 6060E7A12AF8BF4400C04AE0 /* Embed Frameworks */, ); buildRules = ( ); @@ -181,9 +192,6 @@ 600000000000000000100200 /* Images.xcassets in Resources */, 600000000000000000100300 /* Launch Screen.storyboard in Resources */, 60A04BC728B35FD000DAA9E5 /* app in Resources */, - 60A04BC428B35ECB00DAA9E5 /* python-stdlib in Resources */, - 60A421FF2AB4256300E46BC3 /* app_packages.iphoneos in Resources */, - 60A421FE2AB4256300E46BC3 /* app_packages.iphonesimulator in Resources */, 60754F822AA5926A0013A4FB /* dylib-Info-template.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -208,9 +216,9 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_DYLIB=$2\n\n # The name of the .dylib file\n DYLIB=$(basename \"$FULL_DYLIB\")\n # The name of the .dylib file, relative to the install base\n RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/}\n # The full dotted name of the binary module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_DYLIB\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleExecutable -string \"$DYLIB\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \n fi\n \n echo \"Installing binary for $RELATIVE_DYLIB\" \n mv \"$FULL_DYLIB\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n}\n\necho \"Install standard library dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/python-stdlib/lib-dynload\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib python-stdlib/lib-dynload \"$FULL_DYLIB\"\ndone\necho \"Install app package dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib app_packages \"$FULL_DYLIB\"\ndone\necho \"Install app dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib app \"$FULL_DYLIB\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\n\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; + shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_DYLIB=$2\n\n # The name of the .dylib file\n DYLIB=$(basename \"$FULL_DYLIB\")\n # The name of the .dylib file, relative to the install base\n RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/}\n # The full dotted name of the binary module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_DYLIB\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleExecutable -string \"$DYLIB\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \n fi\n \n echo \"Installing binary for $RELATIVE_DYLIB\" \n mv \"$FULL_DYLIB\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n}\n\necho \"Install standard library dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/python{{ cookiecutter.python_version|py_tag }}/lib-dynload\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib python/lib/python{{ cookiecutter.python_version|py_tag }}/lib-dynload \"$FULL_DYLIB\"\ndone\necho \"Install app package dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib app_packages \"$FULL_DYLIB\"\ndone\necho \"Install app dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib app \"$FULL_DYLIB\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\n\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; }; - 609384A628B5B958005B2A5D /* Purge Python Binary Modules for Non-Target Platforms */ = { + 609384A628B5B958005B2A5D /* Install target specific Python modules */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -220,14 +228,14 @@ ); inputPaths = ( ); - name = "Purge Python Binary Modules for Non-Target Platforms"; + name = "Install target specific Python modules"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "rm -rf \"$CODESIGNING_FOLDER_PATH/app_packages\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Purging Python modules for iOS Device\"\n rm -rf \"$CODESIGNING_FOLDER_PATH/app_packages.iphoneos\" \n mv \"$CODESIGNING_FOLDER_PATH/app_packages.iphonesimulator\" \"$CODESIGNING_FOLDER_PATH/app_packages\"\n find \"$CODESIGNING_FOLDER_PATH/python-stdlib\" -name \"*.*-iphoneos.dylib\" -exec rm -f \"{}\" \\;\nelse\n echo \"Purging Python modules for iOS Simulator\"\n rm -rf \"$CODESIGNING_FOLDER_PATH/app_packages.iphonesimulator\" \n mv \"$CODESIGNING_FOLDER_PATH/app_packages.iphoneos\" \"$CODESIGNING_FOLDER_PATH/app_packages\"\n find \"$CODESIGNING_FOLDER_PATH\" -name \"*.*-iphonesimulator.dylib\" -exec rm -f \"{}\" \\; \nfi\n"; + shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Support/Python.xcframework/iphonesimulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \n rsync -au --delete \"$PROJECT_DIR/{{ cookiecutter.class_name }}/app_packages.iphonesimulator/\" \"$CODESIGNING_FOLDER_PATH/app_packages\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Support/Python.xcframework/iphoneos/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib\" \n rsync -au --delete \"$PROJECT_DIR/{{ cookiecutter.class_name }}/app_packages.iphoneos/\" \"$CODESIGNING_FOLDER_PATH/app_packages\" \nfi\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -364,9 +372,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = "\"$(PROJECT_DIR)/Support\""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "{{ cookiecutter.class_name }}/{{ cookiecutter.class_name }}-Prefix.pch"; + HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; INFOPLIST_FILE = "{{ cookiecutter.class_name }}/{{ cookiecutter.class_name }}-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -383,10 +394,13 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ENABLE_BITCODE = NO; ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = "\"$(PROJECT_DIR)/Support\""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "{{ cookiecutter.class_name }}/{{ cookiecutter.class_name }}-Prefix.pch"; + HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; INFOPLIST_FILE = "{{ cookiecutter.class_name }}/{{ cookiecutter.class_name }}-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( From b30a3a19dda7b3034ea294389c8e33be7cdaef0a Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 4 Dec 2023 14:16:23 +0800 Subject: [PATCH 2/7] Disable user-site, and add explicit stdlib configuration. --- .../{{ cookiecutter.class_name }}/main.m | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m index 8e4f11e..fbb3ddb 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m +++ b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m @@ -51,6 +51,8 @@ int main(int argc, char *argv[]) { // Don't write bytecode; we can't modify the app bundle // after it has been signed. config.write_bytecode = 0; + // Disable the user site module + config.site_import = 0; // Isolated apps need to set the full PYTHONPATH manually. config.module_search_paths_set = 1; // For debugging - enable verbose mode. @@ -76,6 +78,18 @@ int main(int argc, char *argv[]) { } PyMem_RawFree(wtmp_str); + // Set the stdlib location + path = [NSString stringWithFormat:@"%@/python/lib/python{{ cookiecutter.python_version|py_tag }}", resourcePath, nil]; + NSLog(@"Stdlib dir: %@", path); + wtmp_str = Py_DecodeLocale([path UTF8String], NULL); + status = PyConfig_SetString(&config, &config.stdlib_dir, wtmp_str); + if (PyStatus_Exception(status)) { + crash_dialog([NSString stringWithFormat:@"Unable to set stdlib dir: %s", status.err_msg, nil]); + PyConfig_Clear(&config); + Py_ExitStatusException(status); + } + PyMem_RawFree(wtmp_str); + // Determine the app module name app_module_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MainModule"]; if (app_module_name == NULL) { From 4a2c0094137dbe116c14fccfa6b2fdcf4876b4c3 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 21 Mar 2024 12:02:12 +0800 Subject: [PATCH 3/7] Updates to support .fwork loader. --- .../{{ cookiecutter.class_name }}/main.m | 14 ++++++++++++-- .../project.pbxproj | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m index fbb3ddb..533a130 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m +++ b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m @@ -51,8 +51,6 @@ int main(int argc, char *argv[]) { // Don't write bytecode; we can't modify the app bundle // after it has been signed. config.write_bytecode = 0; - // Disable the user site module - config.site_import = 0; // Isolated apps need to set the full PYTHONPATH manually. config.module_search_paths_set = 1; // For debugging - enable verbose mode. @@ -125,6 +123,18 @@ int main(int argc, char *argv[]) { } PyMem_RawFree(wtmp_str); + // The binary modules in the stdlib + path = [NSString stringWithFormat:@"%@/python/lib/python{{ cookiecutter.python_version|py_tag }}/lib-dynload", resourcePath, nil]; + NSLog(@"- %@", path); + wtmp_str = Py_DecodeLocale([path UTF8String], NULL); + status = PyWideStringList_Append(&config.module_search_paths, wtmp_str); + if (PyStatus_Exception(status)) { + crash_dialog([NSString stringWithFormat:@"Unable to set unpacked form of stdlib path: %s", status.err_msg, nil]); + PyConfig_Clear(&config); + Py_ExitStatusException(status); + } + PyMem_RawFree(wtmp_str); + // Add the app_packages path path = [NSString stringWithFormat:@"%@/app_packages", resourcePath, nil]; NSLog(@"- %@", path); diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj b/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj index 5f1d8d2..6adda64 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj +++ b/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj @@ -216,7 +216,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_DYLIB=$2\n\n # The name of the .dylib file\n DYLIB=$(basename \"$FULL_DYLIB\")\n # The name of the .dylib file, relative to the install base\n RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/}\n # The full dotted name of the binary module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_DYLIB\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleExecutable -string \"$DYLIB\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n fi\n \n echo \"Installing binary for $RELATIVE_DYLIB\" \n mv \"$FULL_DYLIB\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n}\n\necho \"Install standard library dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/python{{ cookiecutter.python_version|py_tag }}/lib-dynload\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib python/lib/python{{ cookiecutter.python_version|py_tag }}/lib-dynload \"$FULL_DYLIB\"\ndone\necho \"Install app package dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib app_packages \"$FULL_DYLIB\"\ndone\necho \"Install app dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib app \"$FULL_DYLIB\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\n\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; + shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_EXT=$2\n\n # The name of the extension file\n EXT=$(basename \"$FULL_EXT\")\n # The location of the extension file, relative to the bundle\n RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} \n # The path to the extension file, relative to the install base\n PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}\n # The full dotted name of the extension module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_EXT\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleExecutable -string \"$FULL_MODULE_NAME\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n fi\n \n echo \"Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" \n mv \"$FULL_EXT\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\"\n # Create a placeholder .fwork file where the .so was\n echo \"$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" > ${FULL_EXT%.so}.fwork\n # Create a back reference to the .so file location in the framework\n echo \"${RELATIVE_EXT%.so}.fwork\" > \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin\" \n}\n\necho \"Install standard library extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/python3.13/lib-dynload\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib python/lib/python3.13/lib-dynload/ \"$FULL_EXT\"\ndone\necho \"Install app package extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app_packages/ \"$FULL_EXT\"\ndone\necho \"Install app extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app/ \"$FULL_EXT\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\n\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; }; 609384A628B5B958005B2A5D /* Install target specific Python modules */ = { isa = PBXShellScriptBuildPhase; From 2147c6982c3b86939961194151689e08d2bc72dd Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 30 Jul 2024 08:02:35 +0800 Subject: [PATCH 4/7] More project format tweaks; disable Python 3.8 testing. --- .github/workflows/ci.yml | 2 +- .../project.pbxproj | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d1c4d8..568f7e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,5 +38,5 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13-dev" ] framework: [ "toga" ] diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj b/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj index 6adda64..e58ce87 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj +++ b/{{ cookiecutter.format }}/{{ cookiecutter.formal_name }}.xcodeproj/project.pbxproj @@ -162,7 +162,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1500; + LastUpgradeCheck = 1540; ORGANIZATIONNAME = "Russell Keith-Magee"; }; buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "{{ cookiecutter.formal_name }}" */; @@ -297,6 +297,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = "\"$(PROJECT_DIR)\""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -312,6 +313,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; IPHONEOS_DEPLOYMENT_TARGET = 12.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -352,7 +354,9 @@ COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = "\"$(PROJECT_DIR)\""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -361,6 +365,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; IPHONEOS_DEPLOYMENT_TARGET = 12.0; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; From 26468b9ff4c8dd2898518a48b451814174d9df4f Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 30 Jul 2024 08:05:20 +0800 Subject: [PATCH 5/7] Bump expected support revisions and Briefcase target version. --- {{ cookiecutter.format }}/briefcase.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/{{ cookiecutter.format }}/briefcase.toml b/{{ cookiecutter.format }}/briefcase.toml index 688854e..d90f427 100644 --- a/{{ cookiecutter.format }}/briefcase.toml +++ b/{{ cookiecutter.format }}/briefcase.toml @@ -1,7 +1,7 @@ # Generated using Python {{ cookiecutter.python_version }} [briefcase] -# This is the start of the new-style dylib era. -target_version = "0.3.16" +# This is the start of the PEP 730 framework era. +target_version = "0.3.20" [paths] app_path = "{{ cookiecutter.class_name }}/app" @@ -9,11 +9,11 @@ app_packages_path = "{{ cookiecutter.class_name }}/app_packages" info_plist_path = "{{ cookiecutter.class_name }}/{{ cookiecutter.class_name }}-Info.plist" support_path = "Support" {{ { - "3.8": "support_revision = 14", - "3.9": "support_revision = 12", - "3.10": "support_revision = 8", - "3.11": "support_revision = 3", - "3.12": "support_revision = 2", + "3.9": "support_revision = 13", + "3.10": "support_revision = 9", + "3.11": "support_revision = 4", + "3.12": "support_revision = 3", + "3.13": "support_revision = 0", }.get(cookiecutter.python_version|py_tag, "") }} icon.20 = "{{ cookiecutter.class_name }}/Images.xcassets/AppIcon.appiconset/icon-20.png" From 1558c3ad0d1deed689fae874f59361e8bd0a51e8 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 6 Aug 2024 12:49:26 +0800 Subject: [PATCH 6/7] Remove explicit set of stdlib_dir. --- .../{{ cookiecutter.class_name }}/main.m | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m index 533a130..f6a9eec 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m +++ b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m @@ -76,18 +76,6 @@ int main(int argc, char *argv[]) { } PyMem_RawFree(wtmp_str); - // Set the stdlib location - path = [NSString stringWithFormat:@"%@/python/lib/python{{ cookiecutter.python_version|py_tag }}", resourcePath, nil]; - NSLog(@"Stdlib dir: %@", path); - wtmp_str = Py_DecodeLocale([path UTF8String], NULL); - status = PyConfig_SetString(&config, &config.stdlib_dir, wtmp_str); - if (PyStatus_Exception(status)) { - crash_dialog([NSString stringWithFormat:@"Unable to set stdlib dir: %s", status.err_msg, nil]); - PyConfig_Clear(&config); - Py_ExitStatusException(status); - } - PyMem_RawFree(wtmp_str); - // Determine the app module name app_module_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MainModule"]; if (app_module_name == NULL) { From 9de09f24972d6f173e3cdba35081999103c2eda5 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 9 Aug 2024 11:22:11 +0800 Subject: [PATCH 7/7] Factor out some common strings. --- .../{{ cookiecutter.class_name }}/main.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m index f6a9eec..9b8443d 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m +++ b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m @@ -17,6 +17,7 @@ int main(int argc, char *argv[]) { PyStatus status; PyPreConfig preconfig; PyConfig config; + NSString *python_tag; NSString *python_home; NSString *app_module_name; NSString *path; @@ -65,6 +66,7 @@ int main(int argc, char *argv[]) { } // Set the home for the Python interpreter + python_tag = @"{{ cookiecutter.python_version|py_tag }}"; python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; NSLog(@"PythonHome: %@", python_home); wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); @@ -100,7 +102,7 @@ int main(int argc, char *argv[]) { // Set the full module path. This includes the stdlib, site-packages, and app code. NSLog(@"PYTHONPATH:"); // The unpacked form of the stdlib - path = [NSString stringWithFormat:@"%@/python/lib/python{{ cookiecutter.python_version|py_tag }}", resourcePath, nil]; + path = [NSString stringWithFormat:@"%@/lib/python%@", python_home, python_tag, nil]; NSLog(@"- %@", path); wtmp_str = Py_DecodeLocale([path UTF8String], NULL); status = PyWideStringList_Append(&config.module_search_paths, wtmp_str); @@ -112,7 +114,7 @@ int main(int argc, char *argv[]) { PyMem_RawFree(wtmp_str); // The binary modules in the stdlib - path = [NSString stringWithFormat:@"%@/python/lib/python{{ cookiecutter.python_version|py_tag }}/lib-dynload", resourcePath, nil]; + path = [NSString stringWithFormat:@"%@/lib/python%@/lib-dynload", python_home, python_tag, nil]; NSLog(@"- %@", path); wtmp_str = Py_DecodeLocale([path UTF8String], NULL); status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);