compat.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. # ----------------------------------------------------------------------------
  2. # Copyright (c) 2005-2022, PyInstaller Development Team.
  3. #
  4. # Distributed under the terms of the GNU General Public License (version 2
  5. # or later) with exception for distributing the bootloader.
  6. #
  7. # The full license is in the file COPYING.txt, distributed with this software.
  8. #
  9. # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
  10. # ----------------------------------------------------------------------------
  11. """
  12. Various classes and functions to provide some backwards-compatibility with previous versions of Python onward.
  13. """
  14. import errno
  15. import importlib.machinery
  16. import importlib.util
  17. import os
  18. import platform
  19. import site
  20. import subprocess
  21. import sys
  22. import shutil
  23. from PyInstaller._shared_with_waf import _pyi_machine
  24. from PyInstaller.exceptions import ExecCommandFailed
  25. # Copied from https://docs.python.org/3/library/platform.html#cross-platform.
  26. is_64bits = sys.maxsize > 2**32
  27. # Distinguish specific code for various Python versions. Variables 'is_pyXY' mean that Python X.Y and up is supported.
  28. # Keep even unsupported versions here to keep 3rd-party hooks working.
  29. is_py35 = sys.version_info >= (3, 5)
  30. is_py36 = sys.version_info >= (3, 6)
  31. is_py37 = sys.version_info >= (3, 7)
  32. is_py38 = sys.version_info >= (3, 8)
  33. is_py39 = sys.version_info >= (3, 9)
  34. is_py310 = sys.version_info >= (3, 10)
  35. is_win = sys.platform.startswith('win')
  36. is_win_10 = is_win and (platform.win32_ver()[0] == '10')
  37. is_win_wine = False # Running under Wine; determined later on.
  38. is_cygwin = sys.platform == 'cygwin'
  39. is_darwin = sys.platform == 'darwin' # Mac OS X
  40. # Unix platforms
  41. is_linux = sys.platform.startswith('linux')
  42. is_solar = sys.platform.startswith('sun') # Solaris
  43. is_aix = sys.platform.startswith('aix')
  44. is_freebsd = sys.platform.startswith('freebsd')
  45. is_openbsd = sys.platform.startswith('openbsd')
  46. is_hpux = sys.platform.startswith('hp-ux')
  47. # Some code parts are similar to several unix platforms (e.g. Linux, Solaris, AIX).
  48. # Mac OS is not considered as unix since there are many platform-specific details for Mac in PyInstaller.
  49. is_unix = is_linux or is_solar or is_aix or is_freebsd or is_hpux or is_openbsd
  50. # Linux distributions such as Alpine or OpenWRT use musl as their libc implementation and resultantly need specially
  51. # compiled bootloaders. On musl systems, ldd with no arguments prints 'musl' and its version.
  52. is_musl = is_linux and "musl" in subprocess.getoutput(["ldd"])
  53. # macOS version
  54. _macos_ver = tuple(int(x) for x in platform.mac_ver()[0].split('.')) if is_darwin else None
  55. # macOS 11 (Big Sur): if python is not compiled with Big Sur support, it ends up in compatibility mode by default, which
  56. # is indicated by platform.mac_ver() returning '10.16'. The lack of proper Big Sur support breaks find_library()
  57. # function from ctypes.util module, as starting with Big Sur, shared libraries are not visible on disk anymore. Support
  58. # for the new library search mechanism was added in python 3.9 when compiled with Big Sur support. In such cases,
  59. # platform.mac_ver() reports version as '11.x'. The behavior can be further modified via SYSTEM_VERSION_COMPAT
  60. # environment variable; which allows explicitly enabling or disabling the compatibility mode. However, note that
  61. # disabling the compatibility mode and using python that does not properly support Big Sur still leaves find_library()
  62. # broken (which is a scenario that we ignore at the moment).
  63. # The same logic applies to macOS 12 (Monterey).
  64. is_macos_11_compat = _macos_ver and _macos_ver[0:2] == (10, 16) # Big Sur or newer in compat mode
  65. is_macos_11_native = _macos_ver and _macos_ver[0:2] >= (11, 0) # Big Sur or newer in native mode
  66. is_macos_11 = is_macos_11_compat or is_macos_11_native # Big Sur or newer
  67. # On different platforms is different file for dynamic python library.
  68. # TODO: When removing support for is_py37, the "m" variants can be
  69. # removed, see <https://docs.python.org/3/whatsnew/3.8.html#build-and-c-api-changes>
  70. _pyver = sys.version_info[:2]
  71. if is_win or is_cygwin:
  72. PYDYLIB_NAMES = {
  73. 'python%d%d.dll' % _pyver,
  74. 'libpython%d%d.dll' % _pyver,
  75. 'libpython%d%dm.dll' % _pyver,
  76. 'libpython%d.%d.dll' % _pyver,
  77. 'libpython%d.%dm.dll' % _pyver
  78. } # For MSYS2 environment
  79. elif is_darwin:
  80. # libpython%d.%dm.dylib for Conda virtual environment installations
  81. PYDYLIB_NAMES = {
  82. 'Python', '.Python',
  83. 'Python%d' % _pyver[0],
  84. 'libpython%d.%d.dylib' % _pyver,
  85. 'libpython%d.%dm.dylib' % _pyver
  86. }
  87. elif is_aix:
  88. # Shared libs on AIX may be archives with shared object members, hence the ".a" suffix. However, starting with
  89. # python 2.7.11 libpython?.?.so and Python3 libpython?.?m.so files are produced.
  90. PYDYLIB_NAMES = {
  91. 'libpython%d.%d.a' % _pyver,
  92. 'libpython%d.%dm.a' % _pyver,
  93. 'libpython%d.%d.so' % _pyver,
  94. 'libpython%d.%dm.so' % _pyver
  95. }
  96. elif is_freebsd:
  97. PYDYLIB_NAMES = {
  98. 'libpython%d.%d.so.1' % _pyver,
  99. 'libpython%d.%dm.so.1' % _pyver,
  100. 'libpython%d.%d.so.1.0' % _pyver,
  101. 'libpython%d.%dm.so.1.0' % _pyver
  102. }
  103. elif is_openbsd:
  104. PYDYLIB_NAMES = {'libpython%d.%d.so.0.0' % _pyver, 'libpython%d.%dm.so.0.0' % _pyver}
  105. elif is_hpux:
  106. PYDYLIB_NAMES = {'libpython%d.%d.so' % _pyver}
  107. elif is_unix:
  108. # Other *nix platforms.
  109. # Python 2 .so library on Linux is: libpython2.7.so.1.0
  110. # Python 3 .so library on Linux is: libpython3.2mu.so.1.0, libpython3.3m.so.1.0
  111. PYDYLIB_NAMES = {
  112. 'libpython%d.%d.so.1.0' % _pyver,
  113. 'libpython%d.%dm.so.1.0' % _pyver,
  114. 'libpython%d.%dmu.so.1.0' % _pyver,
  115. 'libpython%d.%dm.so' % _pyver,
  116. 'libpython%d.%d.so' % _pyver
  117. }
  118. else:
  119. raise SystemExit('Your platform is not yet supported. Please define constant PYDYLIB_NAMES for your platform.')
  120. # Function with which to open files.
  121. open_file = open
  122. text_read_mode = 'r'
  123. # In Python 3 built-in function raw_input() was renamed to just 'input()'.
  124. stdin_input = input
  125. # Safe repr that always outputs ascii
  126. safe_repr = ascii
  127. # String types to replace `isinstance(foo, str)`. Obsolete since dropping support for Python 2.x.
  128. string_types = str
  129. # Correct extension ending: 'c' or 'o'
  130. PYCO = 'c'
  131. # In a virtual environment created by virtualenv (github.com/pypa/virtualenv) there exists sys.real_prefix with the path
  132. # to the base Python installation from which the virtual environment was created. This is true regardless of the version
  133. # of Python used to execute the virtualenv command.
  134. #
  135. # In a virtual environment created by the venv module available in the Python standard lib, there exists sys.base_prefix
  136. # with the path to the base implementation. This does not exist in a virtual environment created by virtualenv.
  137. #
  138. # The following code creates compat.is_venv and is.virtualenv that are True when running a virtual environment, and also
  139. # compat.base_prefix with the path to the base Python installation.
  140. base_prefix = os.path.abspath(getattr(sys, 'real_prefix', getattr(sys, 'base_prefix', sys.prefix)))
  141. # Ensure `base_prefix` is not containing any relative parts.
  142. is_venv = is_virtualenv = base_prefix != os.path.abspath(sys.prefix)
  143. # Conda environments sometimes have different paths or apply patches to packages that can affect how a hook or package
  144. # should access resources. Method for determining conda taken from https://stackoverflow.com/questions/47610844#47610844
  145. is_conda = os.path.isdir(os.path.join(base_prefix, 'conda-meta'))
  146. # Similar to ``is_conda`` but is ``False`` using another ``venv``-like manager on top. In this case, no packages
  147. # encountered will be conda packages meaning that the default non-conda behaviour is generally desired from PyInstaller.
  148. is_pure_conda = os.path.isdir(os.path.join(sys.prefix, 'conda-meta'))
  149. # Full path to python interpreter.
  150. python_executable = getattr(sys, '_base_executable', sys.executable)
  151. # Is this Python from Microsoft App Store (Windows only)? Python from Microsoft App Store has executable pointing at
  152. # empty shims.
  153. is_ms_app_store = is_win and os.path.getsize(python_executable) == 0
  154. if is_ms_app_store:
  155. # Locate the actual executable inside base_prefix.
  156. python_executable = os.path.join(base_prefix, os.path.basename(python_executable))
  157. if not os.path.exists(python_executable):
  158. raise SystemExit(
  159. 'PyInstaller cannot locate real python executable belonging to Python from Microsoft App Store!'
  160. )
  161. # Bytecode magic value
  162. BYTECODE_MAGIC = importlib.util.MAGIC_NUMBER
  163. # List of suffixes for Python C extension modules.
  164. EXTENSION_SUFFIXES = importlib.machinery.EXTENSION_SUFFIXES
  165. ALL_SUFFIXES = importlib.machinery.all_suffixes()
  166. # On Windows we require pywin32-ctypes.
  167. # -> all pyinstaller modules should use win32api from PyInstaller.compat to
  168. # ensure that it can work on MSYS2 (which requires pywin32-ctypes)
  169. if is_win:
  170. try:
  171. from win32ctypes.pywin32 import pywintypes # noqa: F401, E402
  172. from win32ctypes.pywin32 import win32api # noqa: F401, E402
  173. except ImportError:
  174. # This environment variable is set by setup.py
  175. # - It's not an error for pywin32 to not be installed at that point
  176. if not os.environ.get('PYINSTALLER_NO_PYWIN32_FAILURE'):
  177. raise SystemExit(
  178. 'PyInstaller cannot check for assembly dependencies.\n'
  179. 'Please install pywin32-ctypes.\n\n'
  180. 'pip install pywin32-ctypes\n'
  181. )
  182. except Exception:
  183. if sys.flags.optimize == 2:
  184. raise SystemExit(
  185. "pycparser, a Windows only indirect dependency of PyInstaller, is incompatible with "
  186. "Python's \"discard docstrings\" (-OO) flag mode. For more information see:\n"
  187. " https://github.com/pyinstaller/pyinstaller/issues/6345"
  188. )
  189. raise
  190. # macOS's platform.architecture() can be buggy, so we do this manually here. Based off the python documentation:
  191. # https://docs.python.org/3/library/platform.html#platform.architecture
  192. if is_darwin:
  193. architecture = '64bit' if sys.maxsize > 2**32 else '32bit'
  194. else:
  195. architecture = platform.architecture()[0]
  196. # Cygwin needs special handling, because platform.system() contains identifiers such as MSYS_NT-10.0-19042 and
  197. # CYGWIN_NT-10.0-19042 that do not fit PyInstaller's OS naming scheme. Explicitly set `system` to 'Cygwin'.
  198. system = 'Cygwin' if is_cygwin else platform.system()
  199. # Machine suffix for bootloader.
  200. machine = _pyi_machine(platform.machine(), platform.system())
  201. # Wine detection and support
  202. def is_wine_dll(filename):
  203. """
  204. Check if the given PE file is a Wine DLL (PE-converted built-in, or fake/placeholder one).
  205. Returns True if the given file is a Wine DLL, False if not (or if file cannot be analyzed or does not exist).
  206. """
  207. _WINE_SIGNATURES = (
  208. b'Wine builtin DLL', # PE-converted Wine DLL
  209. b'Wine placeholder DLL', # Fake/placeholder Wine DLL
  210. )
  211. _MAX_LEN = max([len(sig) for sig in _WINE_SIGNATURES])
  212. # Wine places their DLL signature in the padding area between the IMAGE_DOS_HEADER and IMAGE_NT_HEADERS. So we need
  213. # to compare the bytes that come right after IMAGE_DOS_HEADER, i.e., after initial 64 bytes. We can read the file
  214. # directly and avoid using the pefile library to avoid performance penalty associated with full header parsing.
  215. try:
  216. with open(filename, 'rb') as fp:
  217. fp.seek(64)
  218. signature = fp.read(_MAX_LEN)
  219. return signature.startswith(_WINE_SIGNATURES)
  220. except Exception:
  221. pass
  222. return False
  223. if is_win:
  224. try:
  225. import ctypes.util # noqa: E402
  226. is_win_wine = is_wine_dll(ctypes.util.find_library('kernel32'))
  227. except Exception:
  228. pass
  229. # Set and get environment variables does not handle unicode strings correctly on Windows.
  230. # Acting on os.environ instead of using getenv()/setenv()/unsetenv(), as suggested in
  231. # <http://docs.python.org/library/os.html#os.environ>: "Calling putenv() directly does not change os.environ, so it is
  232. # better to modify os.environ." (Same for unsetenv.)
  233. def getenv(name, default=None) -> str:
  234. """
  235. Returns unicode string containing value of environment variable 'name'.
  236. """
  237. return os.environ.get(name, default)
  238. def setenv(name, value):
  239. """
  240. Accepts unicode string and set it as environment variable 'name' containing value 'value'.
  241. """
  242. os.environ[name] = value
  243. def unsetenv(name):
  244. """
  245. Delete the environment variable 'name'.
  246. """
  247. # Some platforms (e.g., AIX) do not support `os.unsetenv()` and thus `del os.environ[name]` has no effect on the
  248. # real environment. For this case, we set the value to the empty string.
  249. os.environ[name] = ""
  250. del os.environ[name]
  251. # Exec commands in subprocesses.
  252. def exec_command(*cmdargs: str, encoding: str = None, raise_enoent: bool = None, **kwargs):
  253. """
  254. Run the command specified by the passed positional arguments, optionally configured by the passed keyword arguments.
  255. .. DANGER::
  256. **Ignore this function's return value** -- unless this command's standard output contains _only_ pathnames, in
  257. which case this function returns the correct filesystem-encoded string expected by PyInstaller. In all other
  258. cases, this function's return value is _not_ safely usable. Consider calling the general-purpose
  259. `exec_command_stdout()` function instead.
  260. For backward compatibility, this function's return value non-portably depends on the current Python version and
  261. passed keyword arguments:
  262. * Under Python 2.7, this value is an **encoded `str` string** rather than a decoded `unicode` string. This value
  263. _cannot_ be safely used for any purpose (e.g., string manipulation or parsing), except to be passed directly to
  264. another non-Python command.
  265. * Under Python 3.x, this value is a **decoded `str` string**. However, even this value is _not_ necessarily
  266. safely usable:
  267. * If the `encoding` parameter is passed, this value is guaranteed to be safely usable.
  268. * Else, this value _cannot_ be safely used for any purpose (e.g., string manipulation or parsing), except to be
  269. passed directly to another non-Python command. Why? Because this value has been decoded with the encoding
  270. specified by `sys.getfilesystemencoding()`, the encoding used by `os.fsencode()` and `os.fsdecode()` to
  271. convert from platform-agnostic to platform-specific pathnames. This is _not_ necessarily the encoding with
  272. which this command's standard output was encoded. Cue edge-case decoding exceptions.
  273. Parameters
  274. ----------
  275. cmdargs :
  276. Variadic list whose:
  277. 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the
  278. command to run.
  279. 2. Optional remaining elements are arguments to pass to this command.
  280. encoding : str, optional
  281. Optional keyword argument specifying the encoding with which to decode this command's standard output under
  282. Python 3. As this function's return value should be ignored, this argument should _never_ be passed.
  283. raise_enoent : boolean, optional
  284. Optional keyword argument to simply raise the exception if the executing the command fails since to the command
  285. is not found. This is useful to checking id a command exists.
  286. All remaining keyword arguments are passed as is to the `subprocess.Popen()` constructor.
  287. Returns
  288. ----------
  289. str
  290. Ignore this value. See discussion above.
  291. """
  292. proc = subprocess.Popen(cmdargs, stdout=subprocess.PIPE, **kwargs)
  293. try:
  294. out = proc.communicate(timeout=60)[0]
  295. except OSError as e:
  296. if raise_enoent and e.errno == errno.ENOENT:
  297. raise
  298. print('--' * 20, file=sys.stderr)
  299. print("Error running '%s':" % " ".join(cmdargs), file=sys.stderr)
  300. print(e, file=sys.stderr)
  301. print('--' * 20, file=sys.stderr)
  302. raise ExecCommandFailed("Error: Executing command failed!") from e
  303. except subprocess.TimeoutExpired:
  304. proc.kill()
  305. raise
  306. # stdout/stderr are returned as a byte array NOT as string, so we need to convert that to proper encoding.
  307. try:
  308. if encoding:
  309. out = out.decode(encoding)
  310. else:
  311. # If no encoding is given, assume we are reading filenames from stdout only because it is the common case.
  312. out = os.fsdecode(out)
  313. except UnicodeDecodeError as e:
  314. # The sub-process used a different encoding; provide more information to ease debugging.
  315. print('--' * 20, file=sys.stderr)
  316. print(str(e), file=sys.stderr)
  317. print('These are the bytes around the offending byte:', file=sys.stderr)
  318. print('--' * 20, file=sys.stderr)
  319. raise
  320. return out
  321. def exec_command_rc(*cmdargs: str, **kwargs) -> int:
  322. """
  323. Return the exit code of the command specified by the passed positional arguments, optionally configured by the
  324. passed keyword arguments.
  325. Parameters
  326. ----------
  327. cmdargs : list
  328. Variadic list whose:
  329. 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the
  330. command to run.
  331. 2. Optional remaining elements are arguments to pass to this command.
  332. All keyword arguments are passed as is to the `subprocess.call()` function.
  333. Returns
  334. ----------
  335. int
  336. This command's exit code as an unsigned byte in the range `[0, 255]`, where 0 signifies success and all other
  337. values signal a failure.
  338. """
  339. # 'encoding' keyword is not supported for 'subprocess.call'; remove it from kwargs.
  340. if 'encoding' in kwargs:
  341. kwargs.pop('encoding')
  342. return subprocess.call(cmdargs, **kwargs)
  343. def exec_command_stdout(*command_args: str, encoding: str = None, **kwargs) -> str:
  344. """
  345. Capture and return the standard output of the command specified by the passed positional arguments, optionally
  346. configured by the passed keyword arguments.
  347. Unlike the legacy `exec_command()` and `exec_command_all()` functions, this modern function is explicitly designed
  348. for cross-platform portability. The return value may be safely used for any purpose, including string manipulation
  349. and parsing.
  350. .. NOTE::
  351. If this command's standard output contains _only_ pathnames, this function does _not_ return the correct
  352. filesystem-encoded string expected by PyInstaller. If this is the case, consider calling the filesystem-specific
  353. `exec_command()` function instead.
  354. Parameters
  355. ----------
  356. command_args : list[str]
  357. Variadic list whose:
  358. 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the
  359. command to run.
  360. 2. Optional remaining elements are arguments to pass to this command.
  361. encoding : str, optional
  362. Optional name of the encoding with which to decode this command's standard output (e.g., `utf8`), passed as a
  363. keyword argument. If unpassed , this output will be decoded in a portable manner specific to to the current
  364. platform, shell environment, and system settings with Python's built-in `universal_newlines` functionality.
  365. All remaining keyword arguments are passed as is to the `subprocess.check_output()` function.
  366. Returns
  367. ----------
  368. str
  369. Unicode string of this command's standard output decoded according to the "encoding" keyword argument.
  370. """
  371. # If no encoding was specified, the current locale is defaulted to. Else, an encoding was specified. To ensure this
  372. # encoding is respected, the "universal_newlines" option is disabled if also passed. Nice, eh?
  373. kwargs['universal_newlines'] = encoding is None
  374. # Standard output captured from this command as a decoded Unicode string if "universal_newlines" is enabled or an
  375. # encoded byte array otherwise.
  376. stdout = subprocess.check_output(command_args, **kwargs)
  377. # Return a Unicode string, decoded from this encoded byte array if needed.
  378. return stdout if encoding is None else stdout.decode(encoding)
  379. def exec_command_all(*cmdargs: str, encoding: str = None, **kwargs):
  380. """
  381. Run the command specified by the passed positional arguments, optionally configured by the passed keyword arguments.
  382. .. DANGER::
  383. **Ignore this function's return value.** If this command's standard output consists solely of pathnames, consider
  384. calling `exec_command()`; otherwise, consider calling `exec_command_stdout()`.
  385. Parameters
  386. ----------
  387. cmdargs : str
  388. Variadic list whose:
  389. 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the
  390. command to run.
  391. 2. Optional remaining elements are arguments to pass to this command.
  392. encoding : str, optional
  393. Optional keyword argument specifying the encoding with which to decode this command's standard output. As this
  394. function's return value should be ignored, this argument should _never_ be passed.
  395. All remaining keyword arguments are passed as is to the `subprocess.Popen()` constructor.
  396. Returns
  397. ----------
  398. (int, str, str)
  399. Ignore this 3-element tuple `(exit_code, stdout, stderr)`. See the `exec_command()` function for discussion.
  400. """
  401. proc = subprocess.Popen(
  402. cmdargs,
  403. bufsize=-1, # Default OS buffer size.
  404. stdout=subprocess.PIPE,
  405. stderr=subprocess.PIPE,
  406. **kwargs
  407. )
  408. # Waits for subprocess to complete.
  409. try:
  410. out, err = proc.communicate(timeout=60)
  411. except subprocess.TimeoutExpired:
  412. proc.kill()
  413. raise
  414. # stdout/stderr are returned as a byte array NOT as string. Thus we need to convert that to proper encoding.
  415. try:
  416. if encoding:
  417. out = out.decode(encoding)
  418. err = err.decode(encoding)
  419. else:
  420. # If no encoding is given, assume we're reading filenames from stdout only because it's the common case.
  421. out = os.fsdecode(out)
  422. err = os.fsdecode(err)
  423. except UnicodeDecodeError as e:
  424. # The sub-process used a different encoding, provide more information to ease debugging.
  425. print('--' * 20, file=sys.stderr)
  426. print(str(e), file=sys.stderr)
  427. print('These are the bytes around the offending byte:', file=sys.stderr)
  428. print('--' * 20, file=sys.stderr)
  429. raise
  430. return proc.returncode, out, err
  431. def __wrap_python(args, kwargs):
  432. cmdargs = [sys.executable]
  433. # Mac OS X supports universal binaries (binary for multiple architectures. We need to ensure that subprocess
  434. # binaries are running for the same architecture as python executable. It is necessary to run binaries with 'arch'
  435. # command.
  436. if is_darwin:
  437. if architecture == '64bit':
  438. if platform.machine() == 'arm64':
  439. py_prefix = ['arch', '-arm64'] # Apple M1
  440. else:
  441. py_prefix = ['arch', '-x86_64'] # Intel
  442. elif architecture == '32bit':
  443. py_prefix = ['arch', '-i386']
  444. else:
  445. py_prefix = []
  446. # Since Mac OS 10.11, the environment variable DYLD_LIBRARY_PATH is no more inherited by child processes, so we
  447. # proactively propagate the current value using the `-e` option of the `arch` command.
  448. if 'DYLD_LIBRARY_PATH' in os.environ:
  449. path = os.environ['DYLD_LIBRARY_PATH']
  450. py_prefix += ['-e', 'DYLD_LIBRARY_PATH=%s' % path]
  451. cmdargs = py_prefix + cmdargs
  452. if not __debug__:
  453. cmdargs.append('-O')
  454. cmdargs.extend(args)
  455. env = kwargs.get('env')
  456. if env is None:
  457. env = dict(**os.environ)
  458. # Ensure python 3 subprocess writes 'str' as utf-8
  459. env['PYTHONIOENCODING'] = 'UTF-8'
  460. # ... and ensure we read output as utf-8
  461. kwargs['encoding'] = 'UTF-8'
  462. return cmdargs, kwargs
  463. def exec_python(*args, **kwargs):
  464. """
  465. Wrap running python script in a subprocess.
  466. Return stdout of the invoked command.
  467. """
  468. cmdargs, kwargs = __wrap_python(args, kwargs)
  469. return exec_command(*cmdargs, **kwargs)
  470. def exec_python_rc(*args, **kwargs):
  471. """
  472. Wrap running python script in a subprocess.
  473. Return exit code of the invoked command.
  474. """
  475. cmdargs, kwargs = __wrap_python(args, kwargs)
  476. return exec_command_rc(*cmdargs, **kwargs)
  477. # Path handling.
  478. def expand_path(path):
  479. """
  480. Replace initial tilde '~' in path with user's home directory, and also expand environment variables
  481. (i.e., ${VARNAME} on Unix, %VARNAME% on Windows).
  482. """
  483. return os.path.expandvars(os.path.expanduser(path))
  484. # Site-packages functions - use native function if available.
  485. def getsitepackages(prefixes=None):
  486. """
  487. Returns a list containing all global site-packages directories.
  488. For each directory present in ``prefixes`` (or the global ``PREFIXES``), this function finds its `site-packages`
  489. subdirectory depending on the system environment, and returns a list of full paths.
  490. """
  491. # This implementation was copied from the ``site`` module, python 3.7.3.
  492. sitepackages = []
  493. seen = set()
  494. if prefixes is None:
  495. prefixes = [sys.prefix, sys.exec_prefix]
  496. for prefix in prefixes:
  497. if not prefix or prefix in seen:
  498. continue
  499. seen.add(prefix)
  500. if os.sep == '/':
  501. sitepackages.append(os.path.join(prefix, "lib", "python%d.%d" % sys.version_info[:2], "site-packages"))
  502. else:
  503. sitepackages.append(prefix)
  504. sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
  505. return sitepackages
  506. # Backported for virtualenv. Module 'site' in virtualenv might not have this attribute.
  507. getsitepackages = getattr(site, 'getsitepackages', getsitepackages)
  508. # Wrapper to load a module from a Python source file. This function loads import hooks when processing them.
  509. def importlib_load_source(name, pathname):
  510. # Import module from a file.
  511. mod_loader = importlib.machinery.SourceFileLoader(name, pathname)
  512. return mod_loader.load_module()
  513. # Patterns of module names that should be bundled into the base_library.zip.
  514. PY3_BASE_MODULES = {
  515. # These modules are direct or indirect dependencies of encodings.* modules. encodings modules must be recursively
  516. # included to set the I/O encoding during python startup.
  517. '_collections_abc',
  518. '_weakrefset',
  519. 'abc',
  520. 'codecs',
  521. 'collections',
  522. 'copyreg',
  523. 'encodings',
  524. 'enum',
  525. 'functools',
  526. 'io',
  527. 'heapq',
  528. 'keyword',
  529. 'linecache',
  530. 'locale',
  531. 'operator',
  532. 're',
  533. 'reprlib',
  534. 'sre_compile',
  535. 'sre_constants',
  536. 'sre_parse',
  537. 'tokenize', # used by loader/pymod03_importers.py
  538. 'traceback', # for startup errors
  539. 'types',
  540. 'weakref',
  541. 'warnings',
  542. }
  543. if not is_py310:
  544. PY3_BASE_MODULES.add('_bootlocale')
  545. # Object types of Pure Python modules in modulegraph dependency graph.
  546. # Pure Python modules have code object (attribute co_code).
  547. PURE_PYTHON_MODULE_TYPES = {
  548. 'SourceModule',
  549. 'CompiledModule',
  550. 'Package',
  551. 'NamespacePackage',
  552. # Deprecated.
  553. # TODO Could these module types be removed?
  554. 'FlatPackage',
  555. 'ArchiveModule',
  556. }
  557. # Object types of special Python modules (built-in, run-time, namespace package) in modulegraph dependency graph that do
  558. # not have code object.
  559. SPECIAL_MODULE_TYPES = {
  560. 'AliasNode',
  561. 'BuiltinModule',
  562. 'RuntimeModule',
  563. 'RuntimePackage',
  564. # PyInstaller handles scripts differently and not as standard Python modules.
  565. 'Script',
  566. }
  567. # Object types of Binary Python modules (extensions, etc) in modulegraph dependency graph.
  568. BINARY_MODULE_TYPES = {
  569. 'Extension',
  570. 'ExtensionPackage',
  571. }
  572. # Object types of valid Python modules in modulegraph dependency graph.
  573. VALID_MODULE_TYPES = PURE_PYTHON_MODULE_TYPES | SPECIAL_MODULE_TYPES | BINARY_MODULE_TYPES
  574. # Object types of bad/missing/invalid Python modules in modulegraph dependency graph.
  575. # TODO: should be 'Invalid' module types also in the 'MISSING' set?
  576. BAD_MODULE_TYPES = {
  577. 'BadModule',
  578. 'ExcludedModule',
  579. 'InvalidSourceModule',
  580. 'InvalidCompiledModule',
  581. 'MissingModule',
  582. # Runtime modules and packages are technically valid rather than bad, but exist only in-memory rather than on-disk
  583. # (typically due to pre_safe_import_module() hooks), and hence cannot be physically frozen. For simplicity, these
  584. # nodes are categorized as bad rather than valid.
  585. 'RuntimeModule',
  586. 'RuntimePackage',
  587. }
  588. ALL_MODULE_TYPES = VALID_MODULE_TYPES | BAD_MODULE_TYPES
  589. # TODO: review this mapping to TOC, remove useless entries.
  590. # Dictionary to map ModuleGraph node types to TOC typecodes.
  591. MODULE_TYPES_TO_TOC_DICT = {
  592. # Pure modules.
  593. 'AliasNode': 'PYMODULE',
  594. 'Script': 'PYSOURCE',
  595. 'SourceModule': 'PYMODULE',
  596. 'CompiledModule': 'PYMODULE',
  597. 'Package': 'PYMODULE',
  598. 'FlatPackage': 'PYMODULE',
  599. 'ArchiveModule': 'PYMODULE',
  600. # Binary modules.
  601. 'Extension': 'EXTENSION',
  602. 'ExtensionPackage': 'EXTENSION',
  603. # Special valid modules.
  604. 'BuiltinModule': 'BUILTIN',
  605. 'NamespacePackage': 'PYMODULE',
  606. # Bad modules.
  607. 'BadModule': 'bad',
  608. 'ExcludedModule': 'excluded',
  609. 'InvalidSourceModule': 'invalid',
  610. 'InvalidCompiledModule': 'invalid',
  611. 'MissingModule': 'missing',
  612. 'RuntimeModule': 'runtime',
  613. 'RuntimePackage': 'runtime',
  614. # Other.
  615. 'does not occur': 'BINARY',
  616. }
  617. def check_requirements():
  618. """
  619. Verify that all requirements to run PyInstaller are met.
  620. Fail hard if any requirement is not met.
  621. """
  622. # Fail hard if Python does not have minimum required version
  623. if sys.version_info < (3, 7):
  624. raise EnvironmentError('PyInstaller requires at Python 3.7 or newer.')
  625. # There are some old packages which used to be backports of libraries which are now part of the standard library.
  626. # These backports are now unmaintained and contain only an older subset of features leading to obscure errors like
  627. # "enum has not attribute IntFlag" if installed.
  628. if is_py38:
  629. from importlib.metadata import distribution, PackageNotFoundError
  630. else:
  631. from importlib_metadata import distribution, PackageNotFoundError
  632. for name in ["enum34", "typing"]:
  633. try:
  634. distribution(name)
  635. except PackageNotFoundError:
  636. pass
  637. else:
  638. raise SystemExit(
  639. f"The '{name}' package is an obsolete backport of a standard library package and is "
  640. f"incompatible with PyInstaller. Please "
  641. f"`{'conda remove' if is_conda else 'pip uninstall'} {name}` then try again."
  642. )
  643. # Bail out if binutils is not installed.
  644. if is_linux and shutil.which("objdump") is None:
  645. raise SystemExit(
  646. "On Linux, objdump is required. It is typically provided by the 'binutils' package "
  647. "installable via your Linux distribution's package manager."
  648. )