Skip to content

Commit

Permalink
Merge pull request #33 from beeware/framework-lib
Browse files Browse the repository at this point in the history
Switch to a dynamic framework.
  • Loading branch information
mhsmith authored Aug 11, 2024
2 parents a80c3d3 + 1abe320 commit e2b216c
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 44 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,14 @@ 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", "pyside6", "pygame", "console" ]

exclude:
# PySide6 hasn't published 3.13 wheels.
- python-version: "3.13-dev"
framework: "pyside6"

# Pygame hasn't published 3.13 wheels.
- python-version: "3.13-dev"
framework: "pygame"
5 changes: 4 additions & 1 deletion .github/workflows/update-binary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ jobs:
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
python -m pip install git+https://github.com/beeware/briefcase.git
# TODO - Revert to the development version of Briefcase
# Use the development version of Briefcase
# python -m pip install git+https://github.com/beeware/briefcase.git
python -m pip install git+https://github.com/freakboy3742/briefcase.git@version-bumps
- name: Generate Xcode App Template
run: |
Expand Down
17 changes: 11 additions & 6 deletions {{ cookiecutter.format }}/briefcase.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Generated using Python {{ cookiecutter.python_version }}
[briefcase]
# This is the start of the framework-based support package era.
target_version = "0.3.20"

[paths]
app_path = "{{ cookiecutter.class_name }}/app"
app_packages_path = "{{ cookiecutter.class_name }}/app_packages"
Expand All @@ -7,13 +11,14 @@ entitlements_path = "{{ cookiecutter.class_name }}/{{ cookiecutter.app_name }}.e

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, "") }}

cleanup_paths = [
]
icon.16 = "{{ cookiecutter.class_name }}/Assets.xcassets/{{ cookiecutter.formal_name }}.appiconset/icon-16.png"
icon.32 = "{{ cookiecutter.class_name }}/Assets.xcassets/{{ cookiecutter.formal_name }}.appiconset/icon-32.png"
icon.64 = "{{ cookiecutter.class_name }}/Assets.xcassets/{{ cookiecutter.formal_name }}.appiconset/icon-64.png"
Expand Down
33 changes: 17 additions & 16 deletions {{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
#include <Python.h>
#import <Python/Python.h>
#include <dlfcn.h>
#include <libgen.h>
#include <mach-o/dyld.h>
Expand All @@ -32,6 +32,8 @@ int main(int argc, char *argv[]) {
PyConfig config;
NSBundle *mainBundle;
NSString *resourcePath;
NSString *frameworksPath;
NSString *python_tag;
NSString *python_home;
NSString *app_module_name;
NSString *path;
Expand All @@ -55,6 +57,7 @@ int main(int argc, char *argv[]) {
// Set the resource path for the app
mainBundle = get_main_bundle();
resourcePath = [mainBundle resourcePath];
frameworksPath = [mainBundle privateFrameworksPath];

// Generate an isolated Python configuration.
debug_log(@"Configuring isolated Python...");
Expand All @@ -72,6 +75,8 @@ int main(int argc, char *argv[]) {
config.write_bytecode = 0;
// Isolated apps need to set the full PYTHONPATH manually.
config.module_search_paths_set = 1;
// Enable verbose logging for debug purposes
// config.verbose = 1;

debug_log(@"Pre-initializing Python runtime...");
status = Py_PreInitialize(&preconfig);
Expand All @@ -82,7 +87,8 @@ int main(int argc, char *argv[]) {
}

// Set the home for the Python interpreter
python_home = [NSString stringWithFormat:@"%@/support/python-stdlib", resourcePath, nil];
python_tag = @"{{ cookiecutter.python_version|py_tag }}";
python_home = [NSString stringWithFormat:@"%@/Python.framework/Versions/%@", frameworksPath, python_tag, nil];
debug_log(@"PythonHome: %@", python_home);
wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL);
status = PyConfig_SetString(&config, &config.home, wtmp_str);
Expand Down Expand Up @@ -125,20 +131,8 @@ int main(int argc, char *argv[]) {
// Set the full module path. This includes the stdlib, site-packages, and app code.
debug_log(@"PYTHONPATH:");

// The .zip form of the stdlib
path = [NSString stringWithFormat:@"%@/support/python{{ cookiecutter.python_version|py_libtag }}.zip", resourcePath, nil];
debug_log(@"- %@", 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:@"%@/support/python-stdlib", resourcePath, nil];
path = [NSString stringWithFormat:@"%@/lib/python%@", python_home, python_tag, nil];
debug_log(@"- %@", path);
wtmp_str = Py_DecodeLocale([path UTF8String], NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
Expand All @@ -150,7 +144,7 @@ int main(int argc, char *argv[]) {
PyMem_RawFree(wtmp_str);

// Add the stdlib binary modules path
path = [NSString stringWithFormat:@"%@/support/python-stdlib/lib-dynload", resourcePath, nil];
path = [NSString stringWithFormat:@"%@/lib/python%@/lib-dynload", python_home, python_tag, nil];
debug_log(@"- %@", path);
wtmp_str = Py_DecodeLocale([path UTF8String], NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
Expand Down Expand Up @@ -401,6 +395,13 @@ void setup_stdout(NSBundle *mainBundle) {
int ret = 0;
const char *nslog_script;

// If the app is running under Xcode 15 or later, we don't need to do anything,
// as stdout and stderr are automatically captured by the in-IDE console.
// See https://developer.apple.com/forums/thread/705868 for details.
if (getenv("IDE_DISABLED_OS_ACTIVITY_DT_MODE")) {
return;
}

// Install the nslog script to redirect stdout/stderr if available.
// Set the name of the python NSLog bootstrap script
nslog_script = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,30 @@
0D354FEF2551C249009178D1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D354FEE2551C249009178D1 /* Cocoa.framework */; };
0D7B44A82555E01500CBC44B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D7B44A72555E01500CBC44B /* Foundation.framework */; };
0D7B44DA2556C84100CBC44B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D354FD72551BFBD009178D1 /* main.m */; };
60A04BBF28AF5E7400DAA9E5 /* python-stdlib in Copy Python standard library */ = {isa = PBXBuildFile; fileRef = 60A04BBE28AF5E7400DAA9E5 /* python-stdlib */; };
60A04BC028AF5EC000DAA9E5 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60A04BBC28AF5E6900DAA9E5 /* Python.xcframework */; };
6060E7722AF0B40500C04AE0 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6060E76F2AF0B14D00C04AE0 /* Python.xcframework */; };
6060E7732AF0B40500C04AE0 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6060E76F2AF0B14D00C04AE0 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
0D7B44EB2556C8B800CBC44B /* Embed App Extensions */ = {
0D7B44EB2556C8B800CBC44B /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
);
name = "Embed App Extensions";
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
609384A728C873E2005B2A5D /* Copy Python standard library */ = {
6060E7742AF0B40500C04AE0 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = support;
dstSubfolderSpec = 7;
dstPath = "";
dstSubfolderSpec = 10;
files = (
60A04BBF28AF5E7400DAA9E5 /* python-stdlib in Copy Python standard library */,
6060E7732AF0B40500C04AE0 /* Python.xcframework in Embed Frameworks */,
);
name = "Copy Python standard library";
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
Expand All @@ -53,8 +53,7 @@
0D354FE52551C1E1009178D1 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
0D354FEE2551C249009178D1 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
0D7B44A72555E01500CBC44B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
60A04BBC28AF5E6900DAA9E5 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = "<group>"; };
60A04BBE28AF5E7400DAA9E5 /* python-stdlib */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "python-stdlib"; sourceTree = "<group>"; };
6060E76F2AF0B14D00C04AE0 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -64,8 +63,8 @@
files = (
0D354FE62551C1E1009178D1 /* AppKit.framework in Frameworks */,
0D354FEF2551C249009178D1 /* Cocoa.framework in Frameworks */,
60A04BC028AF5EC000DAA9E5 /* Python.xcframework in Frameworks */,
0D7B44A82555E01500CBC44B /* Foundation.framework in Frameworks */,
6060E7722AF0B40500C04AE0 /* Python.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -116,8 +115,7 @@
60A04BBB28AF5E1000DAA9E5 /* Support */ = {
isa = PBXGroup;
children = (
60A04BBE28AF5E7400DAA9E5 /* python-stdlib */,
60A04BBC28AF5E6900DAA9E5 /* Python.xcframework */,
6060E76F2AF0B14D00C04AE0 /* Python.xcframework */,
);
path = Support;
sourceTree = "<group>";
Expand All @@ -132,8 +130,8 @@
0D354FC42551BFBA009178D1 /* Sources */,
0D354FC52551BFBA009178D1 /* Frameworks */,
0D354FC62551BFBA009178D1 /* Resources */,
609384A728C873E2005B2A5D /* Copy Python standard library */,
0D7B44EB2556C8B800CBC44B /* Embed App Extensions */,
0D7B44EB2556C8B800CBC44B /* Embed Foundation Extensions */,
6060E7742AF0B40500C04AE0 /* Embed Frameworks */,
60A04BC128AF640400DAA9E5 /* Sign Python Binary Modules */,
);
buildRules = (
Expand All @@ -152,7 +150,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1330;
LastUpgradeCheck = 1540;
ORGANIZATIONNAME = "{{ cookiecutter.author }}";
TargetAttributes = {
0D354FC72551BFBA009178D1 = {
Expand Down Expand Up @@ -209,7 +207,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\necho \"Signed as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)\"\nfind \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/support/python-stdlib/lib-dynload\" -name \"*.so\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \\; \nfind \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/app_packages\" -name \"*.so\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \\; \nfind \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/app\" -name \"*.so\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \\; \n";
shellScript = "set -e\necho \"Signed as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)\"\nfind \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/app_packages\" -name \"*.so\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \\; \nfind \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/app\" -name \"*.so\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \\; \n";
};
/* End PBXShellScriptBuildPhase section */

Expand Down Expand Up @@ -259,9 +257,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
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;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(PROJECT_DIR)\"",
Expand Down Expand Up @@ -323,9 +323,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
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;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(PROJECT_DIR)\"",
Expand Down Expand Up @@ -354,12 +356,19 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
CODE_SIGN_ENTITLEMENTS = "{{ cookiecutter.class_name }}/{{ cookiecutter.app_name }}.entitlements";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(PROJECT_DIR)/Support\"",
);
GCC_C_LANGUAGE_STANDARD = gnu99;
HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
INFOPLIST_FILE = "{{ cookiecutter.class_name }}/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -368,7 +377,6 @@
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = "{{ cookiecutter.bundle }}.{{ cookiecutter.app_name }}";
PROVISIONING_PROFILE_SPECIFIER = "";
STRIP_INSTALLED_PRODUCT = NO;
};
name = Debug;
};
Expand All @@ -380,21 +388,27 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
CODE_SIGN_ENTITLEMENTS = "{{ cookiecutter.class_name }}/{{ cookiecutter.app_name }}.entitlements";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(PROJECT_DIR)/Support\"",
);
GCC_C_LANGUAGE_STANDARD = gnu99;
HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
INFOPLIST_FILE = "{{ cookiecutter.class_name }}/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_BUNDLE_IDENTIFIER = "{{ cookiecutter.bundle }}.{{ cookiecutter.app_name }}";
STRIP_INSTALLED_PRODUCT = NO;
};
name = Release;
};
Expand Down

0 comments on commit e2b216c

Please sign in to comment.