13# include <sys/sysctl.h>
17# include <mach-o/dyld.h>
25#if PY_MAJOR_VERSION >= 3
28# if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 5
29# define Py_DecodeLocale _Py_char2wchar
32# include "structmember.h"
37#define MAX_NUM_POINTERS 24
42 F_log_filename_strftime = 2,
43 F_keep_docstrings = 4,
50__attribute__((__visibility__(
"default"), used))
56 uint16_t num_pointers;
60 void *pointers[MAX_NUM_POINTERS];
64} blobinfo = {(uint64_t)-1};
69__declspec(dllexport) DWORD SymbolPlaceholder___________________ = 0x00000001;
70__declspec(dllexport) DWORD SymbolPlaceholder__ = 0x00000001;
74# define WIN32_LEAN_AND_MEAN
77extern void PyWinFreeze_ExeInit(
void);
78extern void PyWinFreeze_ExeTerm(
void);
80static struct _inittab extensions[] = {
84#if PY_MAJOR_VERSION >= 3
90static wchar_t *log_pathw = NULL;
93#if PY_VERSION_HEX >= 0x030b0000
96 const unsigned char *code;
100typedef struct _frozen ModuleDef;
103#if defined(_WIN32) && PY_VERSION_HEX < 0x03060000
104static int supports_code_page(UINT cp) {
111 if (cp != 0 && cp != 1252 && cp != 367 && cp != 437 && cp != 850 && cp != 819) {
112 const struct _frozen *moddef;
117 PyOS_snprintf(codec,
sizeof(codec),
"encodings.cp%u", (
unsigned int)cp);
119 moddef = PyImport_FrozenModules;
120 while (moddef->name) {
121 if (strcmp(moddef->name, codec) == 0) {
137static void set_main_dir(
char *main_dir) {
138 if (blobinfo.num_pointers >= 10) {
139 if (blobinfo.num_pointers == 10) {
140 ++blobinfo.num_pointers;
141 blobinfo.pointers[10] = NULL;
143 if (blobinfo.pointers[10] == NULL) {
144 blobinfo.pointers[10] = main_dir;
153static int mkdir_parent(
const wchar_t *path) {
155 wchar_t buffer[4096];
156 size_t buflen = wcslen(path);
157 if (buflen + 1 >= _countof(buffer)) {
160 wcscpy_s(buffer, _countof(buffer), path);
163 while (buflen-- > 0) {
164 if (buffer[buflen] ==
'/' || buffer[buflen] ==
'\\') {
169 if (buflen == (
size_t)-1 || buflen == 0) {
174 if (CreateDirectoryW(buffer, NULL) != 0) {
180 DWORD last_error = GetLastError();
181 if (last_error == ERROR_ALREADY_EXISTS) {
186 if (last_error == ERROR_PATH_NOT_FOUND) {
188 if (mkdir_parent(buffer)) {
190 if (CreateDirectoryW(buffer, NULL) != 0) {
199static int mkdir_parent(
const char *path) {
202 size_t buflen = strlen(path);
203 if (buflen + 1 >=
sizeof(buffer)) {
206 strcpy(buffer, path);
209 while (buflen-- > 0) {
210 if (buffer[buflen] ==
'/') {
215 if (buflen == (
size_t)-1 || buflen == 0) {
219 if (mkdir(buffer, 0755) == 0) {
225 if (errno == EEXIST) {
230 if (errno == ENOENT || errno == EACCES) {
232 if (mkdir_parent(buffer)) {
234 if (mkdir(buffer, 0755) == 0) {
250static int setup_logging(
const char *path,
int append) {
253 wchar_t *pathw = (
wchar_t *)malloc(
sizeof(
wchar_t) * MAX_PATH);
256 if (path[0] ==
'~' && (path[1] == 0 || path[1] ==
'/' || path[1] ==
'\\')) {
261 if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, pathw))) {
265 offset = wcslen(pathw);
269 if (MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw + offset,
270 (
int)(MAX_PATH - offset)) == 0) {
275 DWORD access = append ? FILE_APPEND_DATA : (GENERIC_READ | GENERIC_WRITE);
276 int creation = append ? OPEN_ALWAYS : CREATE_ALWAYS;
277 HANDLE handle = CreateFileW(pathw, access, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
278 NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
280 if (handle == INVALID_HANDLE_VALUE) {
283 handle = CreateFileW(pathw, access, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
284 NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
287 if (handle == INVALID_HANDLE_VALUE) {
295 SetFilePointer(handle, 0, NULL, FILE_END);
298 SetStdHandle(STD_OUTPUT_HANDLE, handle);
299 SetStdHandle(STD_ERROR_HANDLE, handle);
304 if (_fileno(stdout) < 0) {
306 _wfreopen(L
"\\\\.\\NUL", L
"w", stdout);
309 if (_fileno(stderr) < 0) {
311 _wfreopen(L
"\\\\.\\NUL", L
"w", stderr);
316 int fd = _open_osfhandle((intptr_t)handle, _O_WRONLY | _O_TEXT | _O_APPEND);
317 _dup2(fd, _fileno(stdout));
318 _dup2(fd, _fileno(stderr));
324 char buffer[PATH_MAX * 2];
326 if (path[0] ==
'~' && (path[1] == 0 || path[1] ==
'/')) {
331 const char *home_dir = getenv(
"HOME");
332 if (home_dir == NULL) {
333 home_dir = getpwuid(getuid())->pw_dir;
335 offset = strlen(home_dir);
336 assert(offset <
sizeof(buffer));
337 strncpy(buffer, home_dir,
sizeof(buffer));
341 strcpy(buffer + offset, path);
343 mode_t mode = O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC);
344 int fd = open(buffer, mode, 0644);
347 mkdir_parent(buffer);
348 fd = open(buffer, mode, 0644);
363 perror(
"setup_logging: close");
372#if PY_MAJOR_VERSION >= 3
373static int enable_line_buffering(PyObject *file) {
374#if PY_VERSION_HEX >= 0x03070000
376 PyObject *kwargs = _PyDict_NewPresized(1);
377 PyDict_SetItemString(kwargs,
"line_buffering", Py_True);
378 PyObject *args = PyTuple_New(0);
380 PyObject *method = PyObject_GetAttrString(file,
"reconfigure");
381 if (method != NULL) {
382 PyObject *result = PyObject_Call(method, args, kwargs);
386 if (result != NULL) {
403 PyTypeObject *type = Py_TYPE(file);
404 PyMemberDef *member = type->tp_members;
406 while (member != NULL && member->name != NULL) {
407 if (strcmp(member->name,
"line_buffering") == 0) {
408 *((
char *)file + member->offset) = 1;
422int Py_FrozenMain(
int argc,
wchar_t **argv)
424int Py_FrozenMain(
int argc,
char **argv)
434#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
437 wchar_t **argv_copy = NULL;
439 wchar_t **argv_copy2 = NULL;
442 argv_copy = (
wchar_t **)alloca(
sizeof(
wchar_t *) * argc);
443 argv_copy2 = (
wchar_t **)alloca(
sizeof(
wchar_t *) * argc);
447#if defined(MS_WINDOWS) && PY_VERSION_HEX >= 0x03040000 && PY_VERSION_HEX < 0x03060000
448 if (!supports_code_page(GetConsoleOutputCP()) ||
449 !supports_code_page(GetConsoleCP())) {
455 SetConsoleOutputCP(acp);
456 Py_SetStandardStreamEncoding(
"mbcs", NULL);
462 Py_NoUserSiteDirectory = 1;
464#if PY_VERSION_HEX >= 0x03020000
465 if (blobinfo.flags & F_keep_docstrings) {
473 if ((p = Py_GETENV(
"PYTHONINSPECT")) && *p !=
'\0')
476 if ((p = Py_GETENV(
"PYTHONUNBUFFERED")) && *p !=
'\0')
480 setbuf(stdin, (
char *)NULL);
481 setbuf(stdout, (
char *)NULL);
482 setbuf(stderr, (
char *)NULL);
485#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
486 oldloc = setlocale(LC_ALL, NULL);
487 setlocale(LC_ALL,
"");
488 for (i = 0; i < argc; i++) {
489 argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
490 argv_copy2[i] = argv_copy[i];
492 fprintf(stderr,
"Unable to decode the command line argument #%i\n",
498 setlocale(LC_ALL, oldloc);
502 PyImport_ExtendInittab(extensions);
506#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
507 Py_SetProgramName(argv_copy[0]);
509 Py_SetProgramName(argv[0]);
515 PyWinFreeze_ExeInit();
518#if defined(MS_WINDOWS) && PY_VERSION_HEX < 0x03040000
525#if PY_MAJOR_VERSION < 3
526 if (log_pathw != NULL) {
527 PyObject *uniobj = PyUnicode_FromWideChar(log_pathw, (Py_ssize_t)wcslen(log_pathw));
528 PyObject *file = PyObject_CallFunction((PyObject*)&PyFile_Type,
"Nsi", uniobj,
"a", 0);
531 PyFile_SetEncodingAndErrors(file,
"utf-8", NULL);
533 PySys_SetObject(
"stdout", file);
534 PySys_SetObject(
"stderr", file);
535 PySys_SetObject(
"__stdout__", file);
536 PySys_SetObject(
"__stderr__", file);
539 setbuf(stdout, (
char *)NULL);
540 setbuf(stderr, (
char *)NULL);
545 if (!supports_code_page(GetConsoleOutputCP()) ||
546 !supports_code_page(GetConsoleCP())) {
551 PyObject *sys_stream;
554 SetConsoleOutputCP(acp);
556 sys_stream = PySys_GetObject(
"stdin");
557 if (sys_stream && PyFile_Check(sys_stream)) {
558 PyFile_SetEncodingAndErrors(sys_stream,
"mbcs", NULL);
560 sys_stream = PySys_GetObject(
"stdout");
561 if (sys_stream && PyFile_Check(sys_stream)) {
562 PyFile_SetEncodingAndErrors(sys_stream,
"mbcs", NULL);
564 sys_stream = PySys_GetObject(
"stderr");
565 if (sys_stream && PyFile_Check(sys_stream)) {
566 PyFile_SetEncodingAndErrors(sys_stream,
"mbcs", NULL);
571#if defined(MS_WINDOWS) && PY_VERSION_HEX >= 0x03040000
575 PyObject *sys_stream;
576 sys_stream = PySys_GetObject(
"__stdout__");
577 if (sys_stream && !enable_line_buffering(sys_stream)) {
578 fprintf(stderr,
"Failed to enable line buffering on sys.stdout\n");
581 sys_stream = PySys_GetObject(
"__stderr__");
582 if (sys_stream && !enable_line_buffering(sys_stream)) {
583 fprintf(stderr,
"Failed to enable line buffering on sys.stderr\n");
590 fprintf(stderr,
"Python %s\n%s\n",
591 Py_GetVersion(), Py_GetCopyright());
593#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
594 PySys_SetArgv(argc, argv_copy);
596 PySys_SetArgv(argc, argv);
599#ifdef MACOS_APP_BUNDLE
601 char buffer[PATH_MAX];
602 uint32_t bufsize =
sizeof(buffer);
603 if (_NSGetExecutablePath(buffer, &bufsize) != 0) {
607 char resolved[PATH_MAX];
608 if (!realpath(buffer, resolved)) {
612 const char *dir = dirname(resolved);
613 sprintf(buffer,
"%s/../Frameworks", dir);
615 PyObject *sys_path = PyList_New(1);
616 #if PY_MAJOR_VERSION >= 3
617 PyList_SET_ITEM(sys_path, 0, PyUnicode_FromString(buffer));
619 PyList_SET_ITEM(sys_path, 0, PyString_FromString(buffer));
621 PySys_SetObject(
"path", sys_path);
626 sprintf(buffer,
"%s/../Resources", dir);
627 set_main_dir(buffer);
634 n = PyImport_ImportFrozenModule(
"__main__");
636 Py_FatalError(
"__main__ not frozen");
645 if (inspect && isatty((
int)fileno(stdin)))
646 sts = PyRun_AnyFile(stdin,
"<stdin>") != 0;
650 PyWinFreeze_ExeTerm();
654#if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
657 for (i = 0; i < argc; i++) {
658#if PY_MAJOR_VERSION > 3 || PY_MINOR_VERSION >= 4
659 PyMem_RawFree(argv_copy2[i]);
661 PyMem_Free(argv_copy2[i]);
673static void *map_blob(off_t offset,
size_t size) {
678 wchar_t buffer[2048];
679 GetModuleFileNameW(NULL, buffer, 2048);
680 runtime = _wfopen(buffer, L
"rb");
681#elif defined(__FreeBSD__)
682 size_t bufsize = 4096;
684 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
686 if (sysctl(mib, 4, (
void *)buffer, &bufsize, NULL, 0) == -1) {
690 runtime = fopen(buffer,
"rb");
691#elif defined(__APPLE__)
693 uint32_t bufsize =
sizeof(buffer);
694 if (_NSGetExecutablePath(buffer, &bufsize) != 0) {
697 runtime = fopen(buffer,
"rb");
700 ssize_t pathlen = readlink(
"/proc/self/exe", buffer,
sizeof(buffer) - 1);
702 perror(
"readlink(/proc/self/exe)");
705 buffer[pathlen] =
'\0';
706 runtime = fopen(buffer,
"rb");
710 if (blobinfo.version == 0) {
712 fseek(runtime, -8, SEEK_END);
713 end = ftell(runtime);
714 fread(&begin, 8, 1, runtime);
716 offset = (off_t)begin;
717 size = (size_t)(end - begin);
722 blob = (
void *)malloc(size);
723 assert(blob != NULL);
724 fseek(runtime, (
long)offset, SEEK_SET);
725 fread(blob, size, 1, runtime);
727 blob = (
void *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileno(runtime), offset);
728 assert(blob != MAP_FAILED);
738static void unmap_blob(
void *blob) {
743 munmap(blob, blobinfo.blob_size);
751#if defined(_WIN32) && PY_MAJOR_VERSION >= 3
752int wmain(
int argc,
wchar_t *argv[]) {
754int main(
int argc,
char *argv[]) {
758 const char *log_filename;
764 if (argc > 1 && strncmp(argv[1],
"-psn_", 5) == 0) {
782 if (blobinfo.version == 0 || blobinfo.blob_offset != 0) {
783 void *blob = map_blob((off_t)blobinfo.blob_offset, (
size_t)blobinfo.blob_size);
784 assert(blob != NULL);
787 if (blobinfo.version > 0 && blobinfo.num_pointers > 0) {
789 assert(blobinfo.num_pointers <= MAX_NUM_POINTERS);
790 for (i = 0; i < blobinfo.num_pointers; ++i) {
794 if (i == 0 || blobinfo.pointers[i] != 0) {
795 blobinfo.pointers[i] = (
void *)((uintptr_t)blobinfo.pointers[i] + (uintptr_t)blob);
798 if (blobinfo.num_pointers >= 12) {
799 log_filename = blobinfo.pointers[11];
802 blobinfo.pointers[0] = blob;
806 moddef = blobinfo.pointers[0];
807#if PY_VERSION_HEX < 0x030b0000
808 PyImport_FrozenModules = moddef;
810 while (moddef->name) {
811 moddef->name = (
char *)((uintptr_t)moddef->name + (uintptr_t)blob);
812 if (moddef->code != 0) {
813 moddef->code = (
unsigned char *)((uintptr_t)moddef->code + (uintptr_t)blob);
820#if PY_VERSION_HEX >= 0x030b0000
821 ModuleDef *moddef_end = moddef;
822 ptrdiff_t num_modules = moddef - (ModuleDef *)blobinfo.pointers[0];
823 struct _frozen *new_moddef = (
struct _frozen *)calloc(num_modules + 1,
sizeof(
struct _frozen));
824 PyImport_FrozenModules = new_moddef;
825 for (moddef = blobinfo.pointers[0]; moddef < moddef_end; ++moddef) {
826 new_moddef->name = moddef->name;
827 new_moddef->code = moddef->code;
828 new_moddef->size = moddef->size < 0 ? -(moddef->size) : moddef->size;
829 new_moddef->is_package = moddef->size < 0;
830#if PY_VERSION_HEX < 0x030d0000
831 new_moddef->get_code = NULL;
837 PyImport_FrozenModules = blobinfo.pointers[0];
840 if (log_filename != NULL) {
841 char log_filename_buf[4096];
842 if (blobinfo.flags & F_log_filename_strftime) {
843 log_filename_buf[0] = 0;
844 time_t now = time(NULL);
845 if (strftime(log_filename_buf,
sizeof(log_filename_buf), log_filename, localtime(&now)) > 0) {
846 log_filename = log_filename_buf;
849 setup_logging(log_filename, (blobinfo.flags & F_log_append) != 0);
853 if (blobinfo.codepage != 0) {
854 SetConsoleCP(blobinfo.codepage);
855 SetConsoleOutputCP(blobinfo.codepage);
860 retval = Py_FrozenMain(argc, argv);
865#if PY_VERSION_HEX >= 0x030b0000
866 free((
void *)PyImport_FrozenModules);
867 PyImport_FrozenModules = NULL;
875int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
wchar_t *lpCmdLine,
int nCmdShow) {
876 return wmain(__argc, __wargv);
879int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
char *lpCmdLine,
int nCmdShow) {
880 return main(__argc, __argv);