-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Issue 3037 scripts must not share globals #3038
base: develop
Are you sure you want to change the base?
Changes from all commits
8f5c214
e183b3e
d649976
6af0012
8f5fc8c
e982de9
a713136
e8f0773
daf60a6
97e200c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
#----------------------------------------------------------------------------- | ||
# Copyright (c) 2005-2017, PyInstaller Development Team. | ||
# | ||
# Distributed under the terms of the GNU General Public License with exception | ||
# for distributing bootloader. | ||
# | ||
# The full license is in the file COPYING.txt, distributed with this software. | ||
#----------------------------------------------------------------------------- | ||
|
||
""" | ||
Hooks to make ctypes.CDLL, .PyDLL, etc. look in sys._MEIPASS first. | ||
""" | ||
|
||
import sys | ||
|
||
def install(): | ||
"""Install the hooks. | ||
|
||
This can not be done at module-level, since the import machinery is not | ||
setup completely when this module is executed. | ||
""" | ||
|
||
import os | ||
try: | ||
import ctypes | ||
from ctypes import LibraryLoader, DEFAULT_MODE | ||
|
||
def _frozen_name(name): | ||
if name: | ||
frozen_name = os.path.join(sys._MEIPASS, os.path.basename(name)) | ||
if os.path.exists(frozen_name): | ||
name = frozen_name | ||
return name | ||
|
||
class PyInstallerImportError(OSError): | ||
def __init__(self, name): | ||
self.msg = ("Failed to load dynlib/dll %r. " | ||
"Most probably this dynlib/dll was not found " | ||
"when the application was frozen.") % name | ||
self.args = (self.msg,) | ||
|
||
class PyInstallerCDLL(ctypes.CDLL): | ||
def __init__(self, name, *args, **kwargs): | ||
name = _frozen_name(name) | ||
try: | ||
super(PyInstallerCDLL, self).__init__(name, *args, **kwargs) | ||
except Exception as base_error: | ||
raise PyInstallerImportError(name) | ||
|
||
ctypes.CDLL = PyInstallerCDLL | ||
ctypes.cdll = LibraryLoader(PyInstallerCDLL) | ||
|
||
class PyInstallerPyDLL(ctypes.PyDLL): | ||
def __init__(self, name, *args, **kwargs): | ||
name = _frozen_name(name) | ||
try: | ||
super(PyInstallerPyDLL, self).__init__(name, *args, **kwargs) | ||
except Exception as base_error: | ||
raise PyInstallerImportError(name) | ||
|
||
ctypes.PyDLL = PyInstallerPyDLL | ||
ctypes.pydll = LibraryLoader(PyInstallerPyDLL) | ||
|
||
if sys.platform.startswith('win'): | ||
class PyInstallerWinDLL(ctypes.WinDLL): | ||
def __init__(self, name,*args, **kwargs): | ||
name = _frozen_name(name) | ||
try: | ||
super(PyInstallerWinDLL, self).__init__(name, *args, **kwargs) | ||
except Exception as base_error: | ||
raise PyInstallerImportError(name) | ||
|
||
ctypes.WinDLL = PyInstallerWinDLL | ||
ctypes.windll = LibraryLoader(PyInstallerWinDLL) | ||
|
||
class PyInstallerOleDLL(ctypes.OleDLL): | ||
def __init__(self, name,*args, **kwargs): | ||
name = _frozen_name(name) | ||
try: | ||
super(PyInstallerOleDLL, self).__init__(name, *args, **kwargs) | ||
except Exception as base_error: | ||
raise PyInstallerImportError(name) | ||
|
||
ctypes.OleDLL = PyInstallerOleDLL | ||
ctypes.oledll = LibraryLoader(PyInstallerOleDLL) | ||
|
||
except ImportError: | ||
# ctypes is not frozen in this application | ||
pass | ||
|
||
# On Mac OS X insert sys._MEIPASS in the first position of the list of paths | ||
# that ctypes uses to search for libraries. | ||
# | ||
# Note: 'ctypes' module will NOT be bundled with every app because code in this | ||
# module is not scanned for module dependencies. It is safe to wrap | ||
# 'ctypes' module into 'try/except ImportError' block. | ||
if sys.platform.startswith('darwin'): | ||
try: | ||
from ctypes.macholib import dyld | ||
dyld.DEFAULT_LIBRARY_FALLBACK.insert(0, sys._MEIPASS) | ||
except ImportError: | ||
# Do nothing when module 'ctypes' is not available. | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -363,25 +363,20 @@ int | |
pyi_launch_run_scripts(ARCHIVE_STATUS *status) | ||
{ | ||
unsigned char *data; | ||
char buf[PATH_MAX]; | ||
size_t namelen; | ||
TOC * ptoc = status->tocbuff; | ||
PyObject *__main__; | ||
PyObject *__file__; | ||
PyObject *main_dict; | ||
PyObject *code, *retval; | ||
PyObject *__main__name; | ||
PyObject *sys_modules; | ||
PyObject *code, *module; | ||
|
||
__main__ = PI_PyImport_AddModule("__main__"); | ||
|
||
if (!__main__) { | ||
FATALERROR("Could not get __main__ module."); | ||
return -1; | ||
sys_modules = PI_PyImport_GetModuleDict(); /* borrowed reference */ | ||
if (is_py2) { | ||
__main__name = PI_PyString_FromString("__main__"); | ||
} | ||
|
||
main_dict = PI_PyModule_GetDict(__main__); | ||
|
||
if (!main_dict) { | ||
FATALERROR("Could not get __main__ module's dict."); | ||
else { | ||
__main__name = PI_PyUnicode_FromString("__main__"); | ||
} | ||
if (__main__name == NULL) { | ||
FATALERROR("Could not get object for string '__main__'."); | ||
return -1; | ||
} | ||
|
||
|
@@ -390,53 +385,48 @@ pyi_launch_run_scripts(ARCHIVE_STATUS *status) | |
if (ptoc->typcd == ARCHIVE_ITEM_PYSOURCE) { | ||
/* Get data out of the archive. */ | ||
data = pyi_arch_extract(status, ptoc); | ||
/* Set the __file__ attribute within the __main__ module, | ||
* for full compatibility with normal execution. */ | ||
namelen = strnlen(ptoc->name, PATH_MAX); | ||
if (namelen >= PATH_MAX-strlen(".py")-1) { | ||
FATALERROR("Name exceeds PATH_MAX\n"); | ||
return -1; | ||
} | ||
|
||
strcpy(buf, ptoc->name); | ||
strcat(buf, ".py"); | ||
VS("LOADER: Running %s\n", buf); | ||
|
||
if (is_py2) { | ||
__file__ = PI_PyString_FromString(buf); | ||
} | ||
else { | ||
__file__ = PI_PyUnicode_FromString(buf); | ||
}; | ||
PI_PyObject_SetAttrString(__main__, "__file__", __file__); | ||
Py_DECREF(__file__); | ||
VS("LOADER: Running %s.py\n", ptoc->name); | ||
|
||
/* Unmarshall code object */ | ||
code = PI_PyMarshal_ReadObjectFromString((const char *) data, ntohl(ptoc->ulen)); | ||
|
||
if (!code) { | ||
FATALERROR("Failed to unmarshal code object for %s\n", ptoc->name); | ||
PI_PyErr_Print(); | ||
return -1; | ||
} | ||
/* Run it */ | ||
retval = PI_PyEval_EvalCode(code, main_dict, main_dict); | ||
|
||
/* Run the code */ | ||
/* For full compatibility with normal execution, the __file__ | ||
* attribute within the __main__ module needs to be set. | ||
* PyImport_ExecCodeModule() will set it based on | ||
* code.co_filename. PyInstaller takes care that co_filename is | ||
* correct. */ | ||
module = PI_PyImport_ExecCodeModule("__main__", code); | ||
|
||
/* If retval is NULL, an error occured. Otherwise, it is a Python object. | ||
* (Since we evaluate module-level code, which is not allowed to return an | ||
* object, the Python object returned is always None.) */ | ||
if (!retval) { | ||
if (!module) { | ||
PI_PyErr_Print(); | ||
/* If the error was SystemExit, PyErr_Print calls exit() without | ||
* returning. So don't print "Failed to execute" on SystemExit. */ | ||
FATALERROR("Failed to execute script %s\n", ptoc->name); | ||
return -1; | ||
} | ||
Py_DECREF(module); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait, how can you decref the module and then complain when you can no longer access its attributes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would expect the code to reference the dict, too. But anyway, I also tried not decrementing the reference count here with no success. But I'll double-check. |
||
|
||
free(data); | ||
|
||
/* remove '__main__' from sys.modules */ | ||
if (PI_PyObject_DelItem(sys_modules, __main__name) != 0) { | ||
FATALERROR("Failed to remove '__main__' from sys.modules\n"); | ||
return -1; | ||
} | ||
} | ||
|
||
ptoc = pyi_arch_increment_toc_ptr(status, ptoc); | ||
} | ||
Py_DECREF(__main__name); | ||
return 0; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
assert __name__ == '__main__' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to remove this function? Seems like each iteration of the loop can be this:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be an idea to try. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not work either :-( Same effect as with my code.