// TODO merge this function with windows version. static int pyi_get_temp_path(char *buff) { /* On OSX the variable TMPDIR is usually defined. */ static const char *envname[] = { "TMPDIR", "TEMP", "TMP", 0 }; static const char *dirname[] = { "/tmp", "/var/tmp", "/usr/tmp", 0 }; int i; char *p; for ( i=0; envname[i]; i++ ) { p = pyi_getenv(envname[i]); if (p) { strcpy(buff, p); if (pyi_test_temp_path(buff)) return 1; } } for ( i=0; dirname[i]; i++ ) { strcpy(buff, dirname[i]); if (pyi_test_temp_path(buff)) return 1; } return 0; }
int pyi_main(int argc, char * argv[]) { /* archive_status contain status information of the main process. */ ARCHIVE_STATUS *archive_status = NULL; char executable[PATH_MAX]; char homepath[PATH_MAX]; char archivefile[PATH_MAX]; int rc = 0; char *extractionpath = NULL; wchar_t * dllpath_w; int i = 0; #ifdef _MSC_VER /* Visual C runtime incorrectly buffers stderr */ setbuf(stderr, (char *)NULL); #endif /* _MSC_VER */ VS("PyInstaller Bootloader 3.x\n"); // TODO create special function to allocate memory for archive status pyi_arch_status_alloc_memory(archive_status); archive_status = (ARCHIVE_STATUS *) calloc(1,sizeof(ARCHIVE_STATUS)); if (archive_status == NULL) { FATALERROR("Cannot allocate memory for ARCHIVE_STATUS\n"); return -1; } pyi_path_executable(executable, argv[0]); pyi_path_archivefile(archivefile, executable); pyi_path_homepath(homepath, executable); /* For the curious: * On Windows, the UTF-8 form of MEIPASS2 is passed to pyi_setenv, which * decodes to UTF-16 before passing it to the Windows API. So the var's value * is full unicode. * * On OS X/Linux, the MEIPASS2 value is passed as the bytes received from the OS. * Only Python will care about its encoding, and it is passed to Python using * PyUnicode_DecodeFSDefault. */ extractionpath = pyi_getenv("_MEIPASS2"); /* If the Python program we are about to run invokes another PyInstaller * one-file program as subprocess, this subprocess must not be fooled into * thinking that it is already unpacked. Therefore, PyInstaller deletes * the _MEIPASS2 variable from the environment. */ pyi_unsetenv("_MEIPASS2"); VS("LOADER: _MEIPASS2 is %s\n", (extractionpath ? extractionpath : "NULL")); if (pyi_arch_setup(archive_status, homepath, &executable[strlen(homepath)])) { if (pyi_arch_setup(archive_status, homepath, &archivefile[strlen(homepath)])) { FATALERROR("Cannot open self %s or archive %s\n", executable, archivefile); return -1; } } /* These are used only in pyi_pylib_set_sys_argv, which converts to wchar_t */ archive_status->argc = argc; archive_status->argv = argv; #ifdef _WIN32 /* On Windows use single-process for --onedir mode. */ if (!extractionpath && !pyi_launch_need_to_extract_binaries(archive_status)) { VS("LOADER: No need to extract files to run; setting extractionpath to homepath\n"); extractionpath = homepath; } if(extractionpath) { /* Add extraction folder to DLL search path */ dllpath_w = pyi_win32_utils_from_utf8(NULL, extractionpath, 0); SetDllDirectory(dllpath_w); VS("LOADER: SetDllDirectory(%s)\n", extractionpath); free(dllpath_w); } #endif if (extractionpath) { VS("LOADER: Already in the child - running user's code.\n"); /* If binaries were extracted to temppath, * we pass it through status variable */ if (strcmp(homepath, extractionpath) != 0) { strcpy(archive_status->temppath, extractionpath); /* * Temp path exits - set appropriate flag and change * status->mainpath to point to temppath. */ archive_status->has_temp_directory = true; strcpy(archive_status->mainpath, archive_status->temppath); } /* Main code to initialize Python and run user's code. */ pyi_launch_initialize(archive_status); rc = pyi_launch_execute(archive_status); pyi_launch_finalize(archive_status); } else { /* status->temppath is created if necessary. */ if (pyi_launch_extract_binaries(archive_status)) { VS("LOADER: temppath is %s\n", archive_status->temppath); VS("LOADER: Error extracting binaries\n"); return -1; } /* Run the 'child' process, then clean up. */ VS("LOADER: Executing self as child\n"); pyi_setenv("_MEIPASS2", archive_status->temppath[0] != 0 ? archive_status->temppath : homepath); VS("LOADER: set _MEIPASS2 to %s\n", pyi_getenv("_MEIPASS2")); if (pyi_utils_set_environment(archive_status) == -1) return -1; /* Transform parent to background process on OSX only. */ pyi_parent_to_background(); /* Run user's code in a subprocess and pass command line arguments to it. */ rc = pyi_utils_create_child(executable, argc, argv); VS("LOADER: Back to parent (RC: %d)\n", rc); VS("LOADER: Doing cleanup\n"); if (archive_status->has_temp_directory == true) pyi_remove_temp_path(archive_status->temppath); pyi_arch_status_free_memory(archive_status); if (extractionpath != NULL) free(extractionpath); } return rc; }
int main(int argc, char* argv[]) #endif { /* archive_status contain status information of the main process. */ ARCHIVE_STATUS *archive_status = NULL; char executable[PATH_MAX]; char homepath[PATH_MAX]; char archivefile[PATH_MAX]; char MEIPASS2[PATH_MAX]; int rc = 0; char *extractionpath = NULL; #if defined(WIN32) && defined(WINDOWED) int argc = __argc; char **argv = __argv; #endif int i = 0; archive_status = (ARCHIVE_STATUS *) calloc(1,sizeof(ARCHIVE_STATUS)); if (archive_status == NULL) { FATALERROR("Cannot allocate memory for ARCHIVE_STATUS\n"); return -1; } pyi_path_executable(executable, argv[0]); pyi_path_archivefile(archivefile, executable); pyi_path_homepath(homepath, executable); extractionpath = pyi_getenv("_MEIPASS2"); VS("LOADER: _MEIPASS2 is %s\n", (extractionpath ? extractionpath : "NULL")); if (pyi_arch_setup(archive_status, homepath, &executable[strlen(homepath)])) { if (pyi_arch_setup(archive_status, homepath, &archivefile[strlen(homepath)])) { FATALERROR("Cannot open self %s or archive %s\n", executable, archivefile); return -1; } } #ifdef WIN32 /* On Windows use single-process for --onedir mode. */ if (!extractionpath && !pyi_launch_need_to_extract_binaries(archive_status)) { VS("LOADER: No need to extract files to run; setting extractionpath to homepath\n"); extractionpath = homepath; strcpy(MEIPASS2, homepath); pyi_setenv("_MEIPASS2", MEIPASS2); //Bootstrap sets sys._MEIPASS, plugins rely on it } #endif if (extractionpath) { VS("LOADER: Already in the child - running user's code.\n"); /* If binaries were extracted to temppath, * we pass it through status variable */ if (strcmp(homepath, extractionpath) != 0) { strcpy(archive_status->temppath, extractionpath); /* * Temp path exits - set appropriate flag and change * status->mainpath to point to temppath. */ archive_status->has_temp_directory = true; strcpy(archive_status->mainpath, archive_status->temppath); } /* Main code to initialize Python and run user's code. */ pyi_launch_initialize(executable, extractionpath); rc = pyi_launch_execute(archive_status, argc, argv); pyi_launch_finalize(archive_status); } else { /* status->temppath is created if necessary. */ if (pyi_launch_extract_binaries(archive_status)) { VS("LOADER: temppath is %s\n", archive_status->temppath); VS("LOADER: Error extracting binaries\n"); return -1; } VS("LOADER: Executing self as child\n"); /* Run the 'child' process, then clean up. */ pyi_setenv("_MEIPASS2", archive_status->temppath[0] != 0 ? archive_status->temppath : homepath); VS("LOADER: set _MEIPASS2 to %s\n", pyi_getenv("_MEIPASS2")); if (pyi_utils_set_environment(archive_status) == -1) return -1; /* Run user's code in a subprocess and pass command line arguments to it. */ rc = pyi_utils_create_child(executable, argc, argv); VS("LOADER: Back to parent\n"); VS("LOADER: Doing cleanup\n"); if (archive_status->has_temp_directory == true) pyi_remove_temp_path(archive_status->temppath); pyi_arch_status_free_memory(archive_status); if (extractionpath != NULL) free(extractionpath); } return rc; }