Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for BRIEFCASE_DEBUG. #26

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"url": "https://example.com",
"description": "Short description of app",
"long_description": "Long description of app",
"console_app": false,
"briefcase_version": "0.3.X",
"python_version": "3.X.0",
"docker_base_image": "ubuntu:20.04",
Expand Down
52 changes: 34 additions & 18 deletions {{ cookiecutter.format }}/bootstrap/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

#include "pyversion.h"

// A global indicator of the debug level
char *debug_mode;

void debug_log(const char *format, ...);

int main(int argc, char *argv[]) {
int ret = 0;
PyStatus status;
Expand All @@ -31,12 +36,15 @@ int main(int argc, char *argv[]) {
PyObject *exc_traceback;
PyObject *systemExit_code;

// Set the global debug state based on the runtime environment
debug_mode = getenv("BRIEFCASE_DEBUG");

// Establish where the executable is located;
// other application paths will be computed relative to this location
exe_path = realpath("/proc/self/exe", NULL);
bin_path = dirname(strdup(exe_path));
install_path = dirname(bin_path);
printf("Install path: %s\n", install_path);
debug_log("Install path: %s\n", install_path);

// Generate an isolated Python configuration.
PyPreConfig_InitIsolatedConfig(&preconfig);
Expand All @@ -59,7 +67,7 @@ int main(int argc, char *argv[]) {
// into the running app's sys.path.
config.site_import = 0;

printf("Pre-initializing Python runtime...\n");
debug_log("Pre-initializing Python runtime...\n");
status = Py_PreInitialize(&preconfig);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to pre-initialize Python interpreter: %s", status.err_msg, nil]);
Expand All @@ -68,6 +76,7 @@ int main(int argc, char *argv[]) {
}

// Set the executable name to match the actual executable
debug_log("config.executable: %s\n", exe_path);
status = PyConfig_SetBytesString(&config, &config.executable, exe_path);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to set executable name: %s", status.err_msg);
Expand All @@ -83,6 +92,7 @@ int main(int argc, char *argv[]) {
if (app_module_name == NULL) {
app_module_name = "{{ cookiecutter.module_name }}";
}
debug_log("config.run_module: %s\n", app_module_name);
status = PyConfig_SetBytesString(&config, &config.run_module, app_module_name);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to set app module name: %s", status.err_msg);
Expand All @@ -99,12 +109,12 @@ int main(int argc, char *argv[]) {
}

// Set the full module path. This includes the stdlib, site-packages, and app code.
printf("PYTHONPATH:\n");
debug_log("PYTHONPATH:\n");
path = malloc(PATH_MAX);

// The unpacked form of the stdlib
strcpy(path, "/usr/{{ cookiecutter.lib_dir }}/python" PY_TAG);
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -116,7 +126,7 @@ int main(int argc, char *argv[]) {

// Add the stdlib binary modules path
strcpy(path, "/usr/{{ cookiecutter.lib_dir }}/python" PY_TAG "/lib-dynload");
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -129,7 +139,7 @@ int main(int argc, char *argv[]) {
// Add the app path
strcpy(path, install_path);
strcat(path, "/{{ cookiecutter.lib_dir }}/{{ cookiecutter.app_name }}/app");
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -142,7 +152,7 @@ int main(int argc, char *argv[]) {
// Add the app_packages path
strcpy(path, install_path);
strcat(path, "/{{ cookiecutter.lib_dir }}/{{ cookiecutter.app_name }}/app_packages");
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -154,15 +164,15 @@ int main(int argc, char *argv[]) {

free(path);

printf("Configure argc/argv...\n");
debug_log("Configure argc/argv...\n");
status = PyConfig_SetBytesArgv(&config, argc, argv);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to configured argc/argv: %s", status.err_msg);
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}

printf("Initializing Python runtime...\n");
debug_log("Initializing Python runtime...\n");
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to initialize Python interpreter: %s", status.err_msg);
Expand All @@ -177,7 +187,7 @@ int main(int argc, char *argv[]) {
// pymain_run_module() method); we need to re-implement it
// because we need to be able to inspect the error state of
// the interpreter, not just the return code of the module.
printf("Running app module: %s\n", app_module_name);
debug_log("Running app module: %s\n", app_module_name);
module = PyImport_ImportModule("runpy");
if (module == NULL) {
// crash_dialog(@"Could not import runpy module");
Expand All @@ -204,7 +214,7 @@ int main(int argc, char *argv[]) {

// Print a separator to differentiate Python startup logs from app logs,
// then flush stdout/stderr to ensure all startup logs have been output.
printf("---------------------------------------------------------------------------\n");
debug_log("---------------------------------------------------------------------------\n");
fflush(stdout);
fflush(stderr);

Expand All @@ -224,31 +234,37 @@ int main(int argc, char *argv[]) {
if (PyErr_GivenExceptionMatches(exc_value, PyExc_SystemExit)) {
systemExit_code = PyObject_GetAttrString(exc_value, "code");
if (systemExit_code == NULL) {
printf("Could not determine exit code\n");
debug_log("Could not determine exit code\n");
ret = -10;
}
else {
ret = (int) PyLong_AsLong(systemExit_code);
}
} else {
// Non-SystemExit; likely an uncaught exception
ret = -6;
}

if (ret != 0) {
printf("Application quit abnormally (Exit code %d)!\n", ret);
printf("---------------------------------------------------------------------------\n");
printf("Application quit abnormally!\n");

// Restore the error state of the interpreter.
PyErr_Restore(exc_type, exc_value, exc_traceback);

// Print exception to stderr.
// In case of SystemExit, this will call exit()
PyErr_Print();

exit(ret);
}
}

Py_Finalize();

return ret;
}

void debug_log(const char *format, ...) {
if (debug_mode) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
}