int pyi_utils_set_environment(const ARCHIVE_STATUS *status) { int rc = 0; #ifdef __APPLE__ /* On Mac OS X we do not use environment variables DYLD_LIBRARY_PATH * or others to tell OS where to look for dynamic libraries. * There were some issues with this approach. In some cases some * system libraries were trying to load incompatible libraries from * the dist directory. For instance this was experienced with macprots * and PyQt4 applications. * * To tell the OS where to look for dynamic libraries we modify * .so/.dylib files to use relative paths to other dependend * libraries starting with @executable_path. * * For more information see: * http://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac * http://developer.apple.com/library/mac/#documentation/DeveloperTools/ \ * Conceptual/DynamicLibraries/100-Articles/DynamicLibraryUsageGuidelines.html */ /* For environment variable details see 'man dyld'. */ pyi_unsetenv("DYLD_FRAMEWORK_PATH"); pyi_unsetenv("DYLD_FALLBACK_FRAMEWORK_PATH"); pyi_unsetenv("DYLD_VERSIONED_FRAMEWORK_PATH"); pyi_unsetenv("DYLD_LIBRARY_PATH"); pyi_unsetenv("DYLD_FALLBACK_LIBRARY_PATH"); pyi_unsetenv("DYLD_VERSIONED_LIBRARY_PATH"); pyi_unsetenv("DYLD_ROOT_PATH"); #else /* Set library path to temppath. This is only for onefile mode.*/ if (status->temppath[0] != PYI_NULLCHAR) { rc = set_dynamic_library_path(status->temppath); } /* Set library path to homepath. This is for default onedir mode.*/ else { rc = set_dynamic_library_path(status->homepath); } #endif return rc; }
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; }
/* * Start python - return 0 on success */ int startPython(ARCHIVE_STATUS *status, int argc, char *argv[]) { /* Set PYTHONPATH so dynamic libs will load. * PYTHONHOME for function Py_SetPythonHome() should point * to a zero-terminated character string in static storage. */ static char pypath[2*PATH_MAX + 14]; int pathlen = 1; int i; char cmd[PATH_MAX+1+80]; char tmp[PATH_MAX+1]; PyObject *py_argv; PyObject *val; PyObject *sys; /* Set the PYTHONPATH */ VS("Manipulating evironment\n"); if (status->temppath[0] != '\0') { /* Temppath is setted */ #ifdef WIN32 /* On Windows pass path containing back slashes. */ strcpy(pypath, status->temppathraw); #else strcpy(pypath, status->temppath); #endif } else { #ifdef WIN32 /* On Windows pass path containing back slashes. */ strcpy(pypath, status->homepathraw); #else strcpy(pypath, status->homepath); #endif } /* don't chop off SEP if root directory */ #ifdef WIN32 if (strlen(pypath) > 14) #else if (strlen(pypath) > 12) #endif pypath[strlen(pypath)-1] = '\0'; pyi_setenv("PYTHONPATH", pypath); VS("PYTHONPATH=%s\n", pypath); /* Clear out PYTHONHOME to avoid clashing with any Python installation. */ pyi_unsetenv("PYTHONHOME"); /* Set PYTHONHOME by using function from Python C API. */ if (status->temppath[0] != '\0') { /* Use temppath as home. This is only for onefile mode. */ #ifdef WIN32 /* On Windows pass path containing back slashes. */ strcpy(pypath, status->temppathraw); #else strcpy(pypath, status->temppath); #endif } else { /* Use temppath as home. This is for default onedir mode.*/ #ifdef WIN32 /* On Windows pass path containing back slashes. */ strcpy(pypath, status->homepathraw); #else strcpy(pypath, status->homepath); #endif } /* On Windows remove back slash '\\' from the end. */ // TODO remove this hook when path handling is fixed in bootloader. #ifdef WIN32 /* Remove trailing slash in directory path. */ pypath[strlen(pypath)-1] = '\0'; #endif PI_Py_SetPythonHome(pypath); VS("PYTHONHOME=%s\n", pypath); /* Start python. */ /* VS("Loading python\n"); */ *PI_Py_NoSiteFlag = 1; /* maybe changed to 0 by setRuntimeOptions() */ *PI_Py_FrozenFlag = 1; setRuntimeOptions(status); PI_Py_SetProgramName(status->archivename); /*XXX*/ PI_Py_Initialize(); /* Set sys.path */ /* VS("Manipulating Python's sys.path\n"); */ PI_PyRun_SimpleString("import sys\n"); PI_PyRun_SimpleString("del sys.path[:]\n"); if (status->temppath[0] != '\0') { strcpy(tmp, status->temppath); tmp[strlen(tmp)-1] = '\0'; sprintf(cmd, "sys.path.append(r\"%s\")", tmp); PI_PyRun_SimpleString(cmd); } strcpy(tmp, status->homepath); tmp[strlen(tmp)-1] = '\0'; sprintf(cmd, "sys.path.append(r\"%s\")", tmp); PI_PyRun_SimpleString (cmd); /* Set argv[0] to be the archiveName */ py_argv = PI_PyList_New(0); val = PI_Py_BuildValue("s", status->archivename); PI_PyList_Append(py_argv, val); for (i = 1; i < argc; ++i) { val = PI_Py_BuildValue ("s", argv[i]); PI_PyList_Append (py_argv, val); } sys = PI_PyImport_ImportModule("sys"); /* VS("Setting sys.argv\n"); */ PI_PyObject_SetAttrString(sys, "argv", py_argv); /* Check for a python error */ if (PI_PyErr_Occurred()) { FATALERROR("Error detected starting Python VM."); return -1; } return 0; }