dylib.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2013-2023, 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. Manipulating with dynamic libraries.
  13. """
  14. import os
  15. import pathlib
  16. import re
  17. import sys
  18. from PyInstaller import compat
  19. import PyInstaller.log as logging
  20. logger = logging.getLogger(__name__)
  21. # Ignoring some system libraries speeds up packaging process
  22. _excludes = {
  23. # Ignore annoying warnings with Windows system DLLs.
  24. #
  25. # 'W: library kernel32.dll required via ctypes not found'
  26. # 'W: library coredll.dll required via ctypes not found'
  27. #
  28. # These these dlls has to be ignored for all operating systems because they might be resolved when scanning code for
  29. # ctypes dependencies.
  30. r'advapi32\.dll',
  31. r'ws2_32\.dll',
  32. r'gdi32\.dll',
  33. r'oleaut32\.dll',
  34. r'shell32\.dll',
  35. r'ole32\.dll',
  36. r'coredll\.dll',
  37. r'crypt32\.dll',
  38. r'kernel32',
  39. r'kernel32\.dll',
  40. r'msvcrt\.dll',
  41. r'rpcrt4\.dll',
  42. r'user32\.dll',
  43. # Some modules tries to import the Python library. e.g. pyreadline.console.console
  44. r'python\%s\%s',
  45. }
  46. # Regex includes - overrides excludes. Include list is used only to override specific libraries from exclude list.
  47. _includes = set()
  48. _win_includes = {
  49. # We need to allow collection of Visual Studio C++ (VC) runtime DLLs from system directories in order to avoid
  50. # missing DLL errors when the frozen application is run on a system that does not have the corresponding VC
  51. # runtime installed. The VC runtime DLLs may be dependencies of python shared library itself or of extension
  52. # modules provided by 3rd party packages.
  53. # Visual Studio 2010 (VC10) runtime
  54. # http://msdn.microsoft.com/en-us/library/8kche8ah(v=vs.100).aspx
  55. r'atl100\.dll',
  56. r'msvcr100\.dll',
  57. r'msvcp100\.dll',
  58. r'mfc100\.dll',
  59. r'mfc100u\.dll',
  60. r'mfcmifc80\.dll',
  61. r'mfcm100\.dll',
  62. r'mfcm100u\.dll',
  63. # Visual Studio 2012 (VC11) runtime
  64. # https://docs.microsoft.com/en-us/visualstudio/releases/2013/2012-redistribution-vs
  65. #
  66. # VC110.ATL
  67. r'atl110\.dll',
  68. # VC110.CRT
  69. r'msvcp110\.dll',
  70. r'msvcr110\.dll',
  71. r'vccorlib110\.dll',
  72. # VC110.CXXAMP
  73. r'vcamp110\.dll',
  74. # VC110.MFC
  75. r'mfc110\.dll',
  76. r'mfc110u\.dll',
  77. r'mfcm110\.dll',
  78. r'mfcm110u\.dll',
  79. # VC110.MFCLOC
  80. r'mfc110chs\.dll',
  81. r'mfc110cht\.dll',
  82. r'mfc110enu\.dll',
  83. r'mfc110esn\.dll',
  84. r'mfc110deu\.dll',
  85. r'mfc110fra\.dll',
  86. r'mfc110ita\.dll',
  87. r'mfc110jpn\.dll',
  88. r'mfc110kor\.dll',
  89. r'mfc110rus\.dll',
  90. # VC110.OpenMP
  91. r'vcomp110\.dll',
  92. # DIA SDK
  93. r'msdia110\.dll',
  94. # Visual Studio 2013 (VC12) runtime
  95. # https://docs.microsoft.com/en-us/visualstudio/releases/2013/2013-redistribution-vs
  96. #
  97. # VC120.CRT
  98. r'msvcp120\.dll',
  99. r'msvcr120\.dll',
  100. r'vccorlib120\.dll',
  101. # VC120.CXXAMP
  102. r'vcamp120\.dll',
  103. # VC120.MFC
  104. r'mfc120\.dll',
  105. r'mfc120u\.dll',
  106. r'mfcm120\.dll',
  107. r'mfcm120u\.dll',
  108. # VC120.MFCLOC
  109. r'mfc120chs\.dll',
  110. r'mfc120cht\.dll',
  111. r'mfc120deu\.dll',
  112. r'mfc120enu\.dll',
  113. r'mfc120esn\.dll',
  114. r'mfc120fra\.dll',
  115. r'mfc120ita\.dll',
  116. r'mfc120jpn\.dll',
  117. r'mfc120kor\.dll',
  118. r'mfc120rus\.dll',
  119. # VC120.OPENMP
  120. r'vcomp120\.dll',
  121. # DIA SDK
  122. r'msdia120\.dll',
  123. # Cpp REST Windows SDK
  124. r'casablanca120.winrt\.dll',
  125. # Mobile Services Cpp Client
  126. r'zumosdk120.winrt\.dll',
  127. # Cpp REST SDK
  128. r'casablanca120\.dll',
  129. # Universal C Runtime Library (since Visual Studio 2015)
  130. #
  131. # NOTE: these should be put under a switch, as they need not to be bundled if deployment target is Windows 10
  132. # and later, as "UCRT is now a system component in Windows 10 and later, managed by Windows Update".
  133. # (https://docs.microsoft.com/en-us/cpp/windows/determining-which-dlls-to-redistribute?view=msvc-170)
  134. # And as discovered in #6326, Windows prefers system-installed version over the bundled one, anyway
  135. # (see https://docs.microsoft.com/en-us/cpp/windows/universal-crt-deployment?view=msvc-170#local-deployment).
  136. r'api-ms-win-core.*',
  137. r'api-ms-win-crt.*',
  138. r'ucrtbase\.dll',
  139. # Visual Studio 2015/2017/2019/2022 (VC14) runtime
  140. # https://docs.microsoft.com/en-us/visualstudio/releases/2022/redistribution
  141. #
  142. # VC141.CRT/VC142.CRT/VC143.CRT
  143. r'concrt140\.dll',
  144. r'msvcp140\.dll',
  145. r'msvcp140_1\.dll',
  146. r'msvcp140_2\.dll',
  147. r'msvcp140_atomic_wait\.dll',
  148. r'msvcp140_codecvt_ids\.dll',
  149. r'vccorlib140\.dll',
  150. r'vcruntime140\.dll',
  151. r'vcruntime140_1\.dll',
  152. # VC141.CXXAMP/VC142.CXXAMP/VC143.CXXAMP
  153. r'vcamp140\.dll',
  154. # VC141.OpenMP/VC142.OpenMP/VC143.OpenMP
  155. r'vcomp140\.dll',
  156. # DIA SDK
  157. r'msdia140\.dll',
  158. # Allow pythonNN.dll, pythoncomNN.dll, pywintypesNN.dll
  159. r'py(?:thon(?:com(?:loader)?)?|wintypes)\d+\.dll',
  160. }
  161. _win_excludes = {
  162. # On Windows, only .dll files can be loaded.
  163. r'.*\.so',
  164. r'.*\.dylib',
  165. # MS assembly excludes
  166. r'Microsoft\.Windows\.Common-Controls',
  167. }
  168. _unix_excludes = {
  169. r'libc\.so(\..*)?',
  170. r'libdl\.so(\..*)?',
  171. r'libm\.so(\..*)?',
  172. r'libpthread\.so(\..*)?',
  173. r'librt\.so(\..*)?',
  174. r'libthread_db\.so(\..*)?',
  175. # glibc regex excludes.
  176. r'ld-linux\.so(\..*)?',
  177. r'libBrokenLocale\.so(\..*)?',
  178. r'libanl\.so(\..*)?',
  179. r'libcidn\.so(\..*)?',
  180. r'libcrypt\.so(\..*)?',
  181. r'libnsl\.so(\..*)?',
  182. r'libnss_compat.*\.so(\..*)?',
  183. r'libnss_dns.*\.so(\..*)?',
  184. r'libnss_files.*\.so(\..*)?',
  185. r'libnss_hesiod.*\.so(\..*)?',
  186. r'libnss_nis.*\.so(\..*)?',
  187. r'libnss_nisplus.*\.so(\..*)?',
  188. r'libresolv\.so(\..*)?',
  189. r'libutil\.so(\..*)?',
  190. # graphical interface libraries come with graphical stack (see libglvnd)
  191. r'libE?(Open)?GLX?(ESv1_CM|ESv2)?(dispatch)?\.so(\..*)?',
  192. r'libdrm\.so(\..*)?',
  193. # a subset of libraries included as part of the Nvidia Linux Graphics Driver as of 520.56.06:
  194. # https://download.nvidia.com/XFree86/Linux-x86_64/520.56.06/README/installedcomponents.html
  195. r'nvidia_drv\.so',
  196. r'libglxserver_nvidia\.so(\..*)?',
  197. r'libnvidia-egl-(gbm|wayland)\.so(\..*)?',
  198. r'libnvidia-(cfg|compiler|e?glcore|glsi|glvkspirv|rtcore|allocator|tls|ml)\.so(\..*)?',
  199. r'lib(EGL|GLX)_nvidia\.so(\..*)?',
  200. # libcuda.so, libcuda.so.1, and libcuda.so.{version} are run-time part of NVIDIA driver, and should not be
  201. # collected, as they need to match the rest of driver components on the target system.
  202. r'libcuda\.so(\..*)?',
  203. r'libcudadebugger\.so(\..*)?',
  204. # libxcb-dri changes ABI frequently (e.g.: between Ubuntu LTS releases) and is usually installed as dependency of
  205. # the graphics stack anyway. No need to bundle it.
  206. r'libxcb\.so(\..*)?',
  207. r'libxcb-dri.*\.so(\..*)?',
  208. # system running a Wayland compositor should already have these libraries
  209. # in versions that should not conflict with system drivers, unlike bundled
  210. r'libwayland.*\.so(\..*)?',
  211. }
  212. _aix_excludes = {
  213. r'libbz2\.a',
  214. r'libc\.a',
  215. r'libC\.a',
  216. r'libcrypt\.a',
  217. r'libdl\.a',
  218. r'libintl\.a',
  219. r'libpthreads\.a',
  220. r'librt\\.a',
  221. r'librtl\.a',
  222. r'libz\.a',
  223. }
  224. _solaris_excludes = {
  225. r'libsocket\.so(\..*)?',
  226. }
  227. _cygwin_excludes = {
  228. r'cygwin1\.dll',
  229. }
  230. _termux_excludes = {
  231. # These libandroid-*.so libraries seem to be part of the base system.
  232. r'libandroid-glob\.so',
  233. r'libandroid-posix-semaphore\.so',
  234. r'libandroid-selinux\.so',
  235. r'libandroid-support\.so',
  236. }
  237. if compat.is_win:
  238. _includes |= _win_includes
  239. _excludes |= _win_excludes
  240. elif compat.is_cygwin:
  241. _excludes |= _cygwin_excludes
  242. elif compat.is_aix:
  243. # The exclude list for AIX differs from other *nix platforms.
  244. _excludes |= _aix_excludes
  245. elif compat.is_solar:
  246. # The exclude list for Solaris differs from other *nix platforms.
  247. _excludes |= _solaris_excludes
  248. _excludes |= _unix_excludes
  249. elif compat.is_termux:
  250. # The exclude list for Termux has additional entries.
  251. _excludes |= _termux_excludes
  252. _excludes |= _unix_excludes
  253. elif compat.is_unix:
  254. # Common excludes for *nix platforms -- except AIX.
  255. _excludes |= _unix_excludes
  256. class MatchList:
  257. def __init__(self, entries):
  258. self._regex = re.compile('|'.join(entries), re.I) if entries else None
  259. def check_library(self, libname):
  260. if self._regex:
  261. return self._regex.match(os.path.basename(libname))
  262. return False
  263. if compat.is_darwin:
  264. import macholib.util
  265. class MacExcludeList(MatchList):
  266. def __init__(self, entries):
  267. super().__init__(entries)
  268. def check_library(self, libname):
  269. # Try the global exclude list.
  270. result = super().check_library(libname)
  271. if result:
  272. return result
  273. # Exclude libraries in standard system locations.
  274. return macholib.util.in_system_path(libname)
  275. exclude_list = MacExcludeList(_excludes)
  276. include_list = MatchList(_includes)
  277. elif compat.is_win:
  278. from PyInstaller.utils.win32 import winutils
  279. class WinExcludeList(MatchList):
  280. def __init__(self, entries):
  281. super().__init__(entries)
  282. self._windows_dir = pathlib.Path(winutils.get_windows_dir()).resolve()
  283. # When running as SYSTEM user, the home directory is `%WINDIR%\system32\config\systemprofile`.
  284. self._home_dir = pathlib.Path.home().resolve()
  285. self._system_home = self._windows_dir in self._home_dir.parents
  286. def check_library(self, libname):
  287. # Try the global exclude list. The global exclude list contains lower-cased names, so lower-case the input
  288. # for case-normalized comparison.
  289. result = super().check_library(libname.lower())
  290. if result:
  291. return result
  292. # Exclude everything from the Windows directory by default; but allow contents of user's gome directory if
  293. # that happens to be rooted under Windows directory (e.g., when running PyInstaller as SYSTEM user).
  294. lib_fullpath = pathlib.Path(libname).resolve()
  295. exclude = self._windows_dir in lib_fullpath.parents
  296. if exclude and self._system_home and self._home_dir in lib_fullpath.parents:
  297. exclude = False
  298. return exclude
  299. exclude_list = WinExcludeList(_excludes)
  300. include_list = MatchList(_includes)
  301. else:
  302. exclude_list = MatchList(_excludes)
  303. include_list = MatchList(_includes)
  304. _seen_wine_dlls = set() # Used for warning tracking in include_library()
  305. def include_library(libname):
  306. """
  307. Check if the dynamic library should be included with application or not.
  308. """
  309. if exclude_list.check_library(libname) and not include_list.check_library(libname):
  310. # Library is excluded and is not overridden by include list. It should be excluded.
  311. return False
  312. # If we are running under Wine and the library is a Wine built-in DLL, ensure that it is always excluded. Typically,
  313. # excluding a DLL leads to an incomplete bundle and run-time errors when the said DLL is not installed on the target
  314. # system. However, having Wine built-in DLLs collected is even more detrimental, as they usually provide Wine's
  315. # implementation of low-level functionality, and therefore cannot be used on actual Windows (i.e., system libraries
  316. # from the C:\Windows\system32 directory that might end up collected due to ``_win_includes`` list; a prominent
  317. # example are VC runtime DLLs, for which Wine provides their own implementation, unless user explicitly installs
  318. # Microsoft's VC redistributable package in their Wine environment). Therefore, excluding the Wine built-in DLLs
  319. # actually improves the chances of the bundle running on Windows, or at least makes the issue easier to debug by
  320. # turning it into the "standard" missing DLL problem. Exclusion should not affect the bundle's ability to run under
  321. # Wine itself, as the excluded DLLs are available there.
  322. if compat.is_win_wine and compat.is_wine_dll(libname):
  323. # Display warning message only once per DLL. Note that it is also displayed only if the DLL were to be included
  324. # in the first place.
  325. if libname not in _seen_wine_dlls:
  326. logger.warning("Excluding Wine built-in DLL: %s", libname)
  327. _seen_wine_dlls.add(libname)
  328. return False
  329. return True
  330. # Patterns for suppressing warnings about missing dynamically linked libraries
  331. _warning_suppressions = []
  332. # On some systems (e.g., openwrt), libc.so might point to ldd. Suppress warnings about it.
  333. if compat.is_linux:
  334. _warning_suppressions.append(r'ldd')
  335. # Suppress warnings about unresolvable UCRT DLLs (see issue #1566) on Windows 10+
  336. if compat.is_win and sys.getwindowsversion().major >= 10:
  337. _warning_suppressions.append(r'api-ms-win-.*\.dll')
  338. missing_lib_warning_suppression_list = MatchList(_warning_suppressions)
  339. def warn_missing_lib(libname):
  340. """
  341. Check if a missing-library warning should be displayed for the given library name (or full path).
  342. """
  343. return not missing_lib_warning_suppression_list.check_library(libname)