|
| 1 | +#import <Cocoa/Cocoa.h> |
| 2 | +#include <Python.h> |
| 3 | +#include <libgen.h> |
| 4 | +#include <limits.h> |
| 5 | +#include <unistd.h> |
| 6 | + |
| 7 | +int main(int argc, char *argv[]) { |
| 8 | + @autoreleasepool { |
| 9 | + char python_home[PATH_MAX]; |
| 10 | + char app_dir_c[PATH_MAX]; |
| 11 | + char *app_dir = realpath(argv[0], NULL); |
| 12 | + app_dir = dirname(dirname(app_dir)); |
| 13 | + strncpy(app_dir_c, app_dir, sizeof(app_dir_c) - 1); |
| 14 | + app_dir_c[sizeof(app_dir_c) - 1] = '\0'; |
| 15 | + |
| 16 | + snprintf(python_home, sizeof(python_home), "%s/Frameworks/Python.framework/Versions/Current", app_dir_c); |
| 17 | + |
| 18 | + // Set PYTHONUSERBASE to enable user plugins |
| 19 | + char *home = getenv("HOME"); |
| 20 | + if (home) { |
| 21 | + char python_user_base[PATH_MAX]; |
| 22 | + snprintf(python_user_base, sizeof(python_user_base), "%s/Library/Application Support/plover/plugins/mac", home); |
| 23 | + setenv("PYTHONUSERBASE", python_user_base, 1); |
| 24 | + } |
| 25 | + |
| 26 | + wchar_t *python_home_w = Py_DecodeLocale(python_home, NULL); |
| 27 | + if (python_home_w == NULL) { |
| 28 | + fprintf(stderr, "Fatal error: unable to decode python_home\n"); |
| 29 | + return 1; |
| 30 | + } |
| 31 | + |
| 32 | + // Set program name |
| 33 | + wchar_t* program = Py_DecodeLocale(argv[0], NULL); |
| 34 | + |
| 35 | + PyConfig config; |
| 36 | + PyConfig_InitPythonConfig(&config); |
| 37 | + PyConfig_SetString(&config, &config.home, python_home_w); |
| 38 | + PyConfig_SetString(&config, &config.program_name, program); |
| 39 | + PyConfig_SetBytesArgv(&config, argc, argv); // This automatically populates sys.argv |
| 40 | + |
| 41 | + Py_InitializeFromConfig(&config); |
| 42 | + PyConfig_Clear(&config); |
| 43 | + // ------------------------------ |
| 44 | + |
| 45 | + // After this point, we are in a Python interpreter. |
| 46 | + |
| 47 | + // Prepend the site-packages to sys.path |
| 48 | + char site_packages[PATH_MAX]; |
| 49 | + snprintf(site_packages, sizeof(site_packages), "%s/lib/python3.13/site-packages", python_home); |
| 50 | + wchar_t *site_packages_w = Py_DecodeLocale(site_packages, NULL); |
| 51 | + PyObject* sys_path = PySys_GetObject("path"); |
| 52 | + PyList_Insert(sys_path, 0, PyUnicode_FromWideChar(site_packages_w, -1)); |
| 53 | + PyMem_RawFree(site_packages_w); |
| 54 | + |
| 55 | + // Run the main script |
| 56 | + PyObject* pName = PyUnicode_FromString("plover.scripts.main"); |
| 57 | + PyObject* pModule = PyImport_Import(pName); |
| 58 | + Py_DECREF(pName); |
| 59 | + |
| 60 | + if (pModule != NULL) { |
| 61 | + PyObject* pFunc = PyObject_GetAttrString(pModule, "main"); |
| 62 | + if (pFunc && PyCallable_Check(pFunc)) { |
| 63 | + |
| 64 | + // Call main() - argv is already set in sys.argv! |
| 65 | + PyObject* pResult = PyObject_CallObject(pFunc, NULL); |
| 66 | + |
| 67 | + if (pResult == NULL) { |
| 68 | + PyErr_Print(); |
| 69 | + fprintf(stderr, "Call to main failed.\n"); |
| 70 | + return 1; |
| 71 | + } |
| 72 | + Py_DECREF(pResult); |
| 73 | + |
| 74 | + } else { |
| 75 | + if (PyErr_Occurred()) PyErr_Print(); |
| 76 | + fprintf(stderr, "Cannot find function \"main\"\n"); |
| 77 | + } |
| 78 | + Py_XDECREF(pFunc); |
| 79 | + Py_DECREF(pModule); |
| 80 | + } else { |
| 81 | + PyErr_Print(); |
| 82 | + fprintf(stderr, "Failed to load \"plover.scripts.main\"\n"); |
| 83 | + return 1; |
| 84 | + } |
| 85 | + |
| 86 | + Py_Finalize(); |
| 87 | + PyMem_RawFree(python_home_w); |
| 88 | + PyMem_RawFree(program); |
| 89 | + return 0; |
| 90 | + } |
| 91 | +} |
0 commit comments