diff --git a/cookiecutter.json b/cookiecutter.json index b978087..226cabe 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -17,6 +17,7 @@ "host_arch": "arm64", "min_os_version": "11.0", "use_framework": true, + "allow_subprocesses": false, "_extensions": [ "briefcase.integrations.cookiecutter.PythonVersionExtension", "briefcase.integrations.cookiecutter.PListExtension" diff --git a/{{ cookiecutter.format }}/briefcase.toml b/{{ cookiecutter.format }}/briefcase.toml index d329c55..f8a17e4 100644 --- a/{{ cookiecutter.format }}/briefcase.toml +++ b/{{ cookiecutter.format }}/briefcase.toml @@ -28,7 +28,12 @@ support_path = "Support" cleanup_paths = [ "Support/Python.xcframework/**/python*/config-*-darwin", "Support/Python.xcframework/**/pkgconfig", + {% if not cookiecutter.allow_subprocesses -%} + "Support/Python.xcframework/**/Python.framework/Versions/3.*/bin", + "Support/Python.xcframework/**/Python.framework/Versions/3.*/Resources/Python.app", + {% endif -%} ] + 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" diff --git a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m index 41ac8c7..cc2c7fb 100644 --- a/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m +++ b/{{ cookiecutter.format }}/{{ cookiecutter.class_name }}/main.m @@ -247,6 +247,26 @@ int main(int argc, char *argv[]) { setup_stdout(mainBundle); {% endif -%} + // Point sys.executable at bin/python3 so that the app can start Python subprocesses. + // If the executable doesn't exist, clear sys.executable so that subprocesses + // trying to use sys.executable can't fork-bomb the app. + path = [python_home stringByAppendingPathComponent:@"bin/python3"]; + if ([[NSFileManager defaultManager] isExecutableFileAtPath:path]) { + debug_log(@"Setting sys.executable: %@", path); + module_attr = PyUnicode_FromString([path UTF8String]); + } else { + debug_log(@"Clearing sys.executable"); + module_attr = PyUnicode_FromString(""); + } + + if (module_attr == NULL + || PySys_SetObject("executable", module_attr) < 0 + || PySys_SetObject("_base_executable", module_attr) < 0) { + crash_dialog(@"Could not set sys.executable"); + exit(-16); + } + Py_DECREF(module_attr); + // Start the app module. // // From here to Py_ObjectCall(runmodule...) is effectively