11"""
22This is PyInstaller hook file for CEF Python. This file
3- helps pyinstaller find CEF Python dependencies that are
3+ helps PyInstaller find CEF Python dependencies that are
44required to run final executable.
55
66See PyInstaller docs for hooks:
1313import re
1414import sys
1515import PyInstaller
16- from PyInstaller .utils .hooks import is_module_satisfies
16+ from PyInstaller .utils .hooks import is_module_satisfies , get_package_paths
17+ from PyInstaller .compat import is_win , is_darwin , is_linux , is_py2
1718from PyInstaller import log as logging
1819
1920# Constants
2425# TODO: use this code to work cross-platform:
2526# > from PyInstaller.utils.hooks import get_package_paths
2627# > get_package_paths("cefpython3")
27- CEFPYTHON3_DIR = os .path .join (
28- os .path .dirname (sys .executable ),
29- 'Lib' , 'site-packages' , 'cefpython3' )
3028
31- if platform .system () == "Windows" :
32- CYTHON_MODULE_EXT = ".pyd"
33- else :
34- CYTHON_MODULE_EXT = ".so"
29+ CEFPYTHON3_DIR = get_package_paths ("cefpython3" )[1 ]
30+
31+ CYTHON_MODULE_EXT = ".pyd" if is_win else ".so"
3532
3633# Globals
3734logger = logging .getLogger (__name__ )
3835
3936
4037# Functions
4138def check_platforms ():
42- if platform . system () != "Windows" :
43- raise SystemExit ("Error: Currently only Windows platform is "
44- " supported, see Issue #135." )
39+ if not is_win and not is_darwin and not is_linux :
40+ raise SystemExit ("Error: Currently only Windows, Linux and Darwin "
41+ "platforms are supported, see Issue #135." )
4542
4643
4744def check_pyinstaller_version ():
@@ -51,7 +48,7 @@ def check_pyinstaller_version():
5148 # Example version string for dev version of pyinstaller:
5249 # > 3.3.dev0+g5dc9557c
5350 version = PyInstaller .__version__
54- match = re .search (r"^\d+\.\d+" , version )
51+ match = re .search (r"^\d+\.\d+(\.\d+)? " , version )
5552 if not (match .group (0 ) >= PYINSTALLER_MIN_VERSION ):
5653 raise SystemExit ("Error: pyinstaller %s or higher is required"
5754 % PYINSTALLER_MIN_VERSION )
@@ -97,8 +94,8 @@ def get_excluded_cefpython_modules():
9794
9895
9996def get_cefpython3_datas ():
100- """Returning all cefpython binaries as DATAS, because
101- pyinstaller does strange things and fails if these are
97+ """Returning almost all of cefpython binaries as DATAS (see exception
98+ below), because pyinstaller does strange things and fails if these are
10299 returned as BINARIES. It first updates manifest in .dll files:
103100 >> Updating manifest in chrome_elf.dll
104101
@@ -114,32 +111,70 @@ def get_cefpython3_datas():
114111 as pyinstaller would fail to find binary depdendencies on
115112 these files.
116113
114+ One exception is subprocess (subprocess.exe on Windows) executable
115+ file, which is passed to pyinstaller as BINARIES in order to collect
116+ its dependecies.
117+
117118 DATAS are in format: tuple(full_path, dest_subdir).
118119 """
119120 ret = list ()
120121
122+ if is_win :
123+ cefdatadir = "."
124+ elif is_darwin or is_linux :
125+ cefdatadir = "."
126+ else :
127+ assert False , "Unsupported system {}" .format (platform .system ())
128+
121129 # Binaries, licenses and readmes in the cefpython3/ directory
122130 for filename in os .listdir (CEFPYTHON3_DIR ):
123131 # Ignore Cython modules which are already handled by
124132 # pyinstaller automatically.
125- if filename [:- 4 ] in get_cefpython_modules ():
133+ if filename [:- len ( CYTHON_MODULE_EXT ) ] in get_cefpython_modules ():
126134 continue
135+
127136 # CEF binaries and datas
128- if filename [- 4 :] in [".exe" , ".dll" , ".so" , ".pak" , ".dat" , ".bin" ,
129- ".txt" ]\
130- or filename in ["License" , "subprocess" ]:
131- logger .info ("Include cefpython3 data: %s" % filename )
132- ret .append ((os .path .join (CEFPYTHON3_DIR , filename ),
133- "" ))
134-
135- # The .pak files in cefpython3/locales/ directory
136- locales_dir = os .path .join (CEFPYTHON3_DIR , "locales" )
137- assert os .path .exists (locales_dir ), "locales/ dir not found in cefpython3"
138- for filename in os .listdir (locales_dir ):
139- logger .info ("Include cefpython3 data: %s/%s" % (
140- os .path .basename (locales_dir ), filename ))
141- ret .append ((os .path .join (locales_dir , filename ),
142- "locales" ))
137+ extension = os .path .splitext (filename )[1 ]
138+ if extension in \
139+ [".exe" , ".dll" , ".pak" , ".dat" , ".bin" , ".txt" , ".so" , ".plist" ] \
140+ or filename .lower ().startswith ("license" ):
141+ logger .info ("Include cefpython3 data: {}" .format (filename ))
142+ ret .append ((os .path .join (CEFPYTHON3_DIR , filename ), cefdatadir ))
143+
144+ if is_darwin :
145+ # "Chromium Embedded Framework.framework/Resources" with subdirectories
146+ # is required. Contain .pak files and locales (each locale in separate
147+ # subdirectory).
148+ resources_subdir = \
149+ os .path .join ("Chromium Embedded Framework.framework" , "Resources" )
150+ base_path = os .path .join (CEFPYTHON3_DIR , resources_subdir )
151+ assert os .path .exists (base_path ), \
152+ "{} dir not found in cefpython3" .format (resources_subdir )
153+ for path , dirs , files in os .walk (base_path ):
154+ for file in files :
155+ absolute_file_path = os .path .join (path , file )
156+ dest_path = os .path .relpath (path , CEFPYTHON3_DIR )
157+ ret .append ((absolute_file_path , dest_path ))
158+ logger .info ("Include cefpython3 data: {}" .format (dest_path ))
159+ elif is_win or is_linux :
160+ # The .pak files in cefpython3/locales/ directory
161+ locales_dir = os .path .join (CEFPYTHON3_DIR , "locales" )
162+ assert os .path .exists (locales_dir ), \
163+ "locales/ dir not found in cefpython3"
164+ for filename in os .listdir (locales_dir ):
165+ logger .info ("Include cefpython3 data: {}/{}" .format (
166+ os .path .basename (locales_dir ), filename ))
167+ ret .append ((os .path .join (locales_dir , filename ),
168+ os .path .join (cefdatadir , "locales" )))
169+
170+ # Optional .so/.dll files in cefpython3/swiftshader/ directory
171+ swiftshader_dir = os .path .join (CEFPYTHON3_DIR , "swiftshader" )
172+ if os .path .isdir (swiftshader_dir ):
173+ for filename in os .listdir (swiftshader_dir ):
174+ logger .info ("Include cefpython3 data: {}/{}" .format (
175+ os .path .basename (swiftshader_dir ), filename ))
176+ ret .append ((os .path .join (swiftshader_dir , filename ),
177+ os .path .join (cefdatadir , "swiftshader" )))
143178 return ret
144179
145180
@@ -162,7 +197,6 @@ def get_cefpython3_datas():
162197# TODO: Write a tool script that would find such imports in
163198# .pyx files automatically.
164199hiddenimports = [
165- "base64" ,
166200 "codecs" ,
167201 "copy" ,
168202 "datetime" ,
@@ -179,16 +213,21 @@ def get_cefpython3_datas():
179213 "urllib" ,
180214 "weakref" ,
181215]
182- if sys . version_info . major == 2 :
216+ if is_py2 :
183217 hiddenimports += [
184218 "urlparse" ,
185219 ]
186220
187221# Excluded modules
188222excludedimports = get_excluded_cefpython_modules ()
189223
190- # Include binaries
191- binaries = []
224+ # Include binaries requiring to collect its dependencies
225+ if is_darwin or is_linux :
226+ binaries = [(os .path .join (CEFPYTHON3_DIR , "subprocess" ), "." )]
227+ elif is_win :
228+ binaries = [(os .path .join (CEFPYTHON3_DIR , "subprocess.exe" ), "." )]
229+ else :
230+ binaries = []
192231
193232# Include datas
194233datas = get_cefpython3_datas ()
0 commit comments