def freeze(dist): """Freeze the given distribution data using py2exe.""" includes = dist.includes excludes = dist.excludes options = dist.freezer_options # Merge in any encludes/excludes given in freezer_options includes.append("esky") for inc in options.pop("includes",()): includes.append(inc) for exc in options.pop("excludes",()): excludes.append(exc) if "pypy" not in includes and "pypy" not in excludes: excludes.append("pypy") # py2exe expects some arguments on the main distribution object. # We handle data_files ourselves, so fake it out for py2exe. if getattr(dist.distribution,"console",None): msg = "don't call setup(console=[...]) with esky;" msg += " use setup(scripts=[...]) instead" raise RuntimeError(msg) if getattr(dist.distribution,"windows",None): msg = "don't call setup(windows=[...]) with esky;" msg += " use setup(scripts=[...]) instead" raise RuntimeError(msg) dist.distribution.console = [] dist.distribution.windows = [] my_data_files = dist.distribution.data_files dist.distribution.data_files = [] for exe in dist.get_executables(): # Pass any executable kwds through to py2exe. # We handle "icon" and "gui_only" ourselves. s = exe._kwds.copy() s["script"] = exe.script s["dest_base"] = exe.name[:-4] if exe.icon is not None and "icon_resources" not in s: s["icon_resources"] = [(1,exe.icon)] if exe.gui_only: dist.distribution.windows.append(s) else: dist.distribution.console.append(s) if "zipfile" in options: dist.distribution.zipfile = options.pop("zipfile") # Create the py2exe cmd and adjust its options cmd = custom_py2exe(dist.distribution) cmd.includes = includes cmd.excludes = excludes if "bundle_files" in options: if options["bundle_files"] < 3 and dist.compile_bootstrap_exes: err = "can't compile bootstrap exes when bundle_files < 3" raise RuntimeError(err) for (nm,val) in options.iteritems(): setattr(cmd,nm,val) cmd.dist_dir = dist.freeze_dir cmd.finalize_options() # Actually run the freeze process cmd.run() # Copy data files into the freeze dir dist.distribution.data_files = my_data_files for (src,dst) in dist.get_data_files(): dst = os.path.join(dist.freeze_dir,dst) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): dist.mkpath(dstdir) dist.copy_file(src,dst) # Place a marker file so we know how it was frozen os.mkdir(os.path.join(dist.freeze_dir,ESKY_CONTROL_DIR)) marker_file = os.path.join(ESKY_CONTROL_DIR,"f-py2exe-%d%d.txt")%sys.version_info[:2] open(os.path.join(dist.freeze_dir,marker_file),"w").close() # Copy package data into the library.zip # For now, we don't try to put package data into a bundled zipfile. dist_zipfile = dist.distribution.zipfile if dist_zipfile is None: for (src,arcnm) in dist.get_package_data(): err = "zipfile=None can't be used with package_data (yet...)" raise RuntimeError(err) elif not cmd.skip_archive: lib = zipfile.ZipFile(os.path.join(dist.freeze_dir,dist_zipfile),"a") for (src,arcnm) in dist.get_package_data(): lib.write(src,arcnm) lib.close() else: for (src,arcnm) in dist.get_package_data(): lib = os.path.join(dist.freeze_dir,os.path.dirname(dist_zipfile)) dest = os.path.join(lib, os.path.dirname(src)) f = os.path.basename(src) if not os.path.isdir(dest): dist.mkpath(dest) dist.copy_file(src,os.path.join(dest, f)) # There's no need to copy library.zip into the bootstrap env, as the # chainloader will run before py2exe goes looking for it. pass # Create the bootstraping code, using custom code if specified. # It gets stored as a marshalled list of code objects directly in the exe. esky_name = dist.distribution.get_name() code_source = ["__esky_name__ = %r" % (esky_name,)] code_source.append(inspect.getsource(esky.bootstrap)) if dist.compile_bootstrap_exes: from esky.bdist_esky import pypy_libpython from esky.bdist_esky import pypy_winres code_source.append(inspect.getsource(pypy_libpython)) code_source.append(inspect.getsource(pypy_winres)) code_source.append(_CUSTOM_PYPY_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source = "\n".join(code_source) for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue fexe = os.path.join(dist.freeze_dir,exe.name) bsexe = dist.compile_to_bootstrap_exe(exe,code_source) winres.copy_safe_resources(fexe,bsexe) # We may also need the bundled MSVCRT libs for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm) and nm.startswith("Microsoft"): dist.copy_to_bootstrap_env(nm) else: code_source.append(_FAKE_ESKY_BOOTSTRAP_MODULE) code_source.append(_CUSTOM_WIN32_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source.append("bootstrap()") code_source = "\n".join(code_source) code = marshal.dumps([compile(code_source,"__main__.py","exec")]) # Copy any core dependencies into the bootstrap env. for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm): dist.copy_to_bootstrap_env(nm) # Copy the loader program for each script into the bootstrap env. for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = dist.copy_to_bootstrap_env(exe.name) # Read the py2exe metadata from the frozen exe. We will # need to duplicate some of these fields when to rewrite it. coderes = winres.load_resource(exepath,u"PYTHONSCRIPT",1,0) headsz = struct.calcsize("iiii") (magic,optmz,unbfrd,codesz) = struct.unpack("iiii",coderes[:headsz]) assert magic == 0x78563412 # Insert the bootstrap code into the exe as a resource. # This appears to have the happy side-effect of stripping any # extra data from the end of the exe, which is exactly what we # want when zipfile=None is specified; otherwise each bootstrap # exe would also contain the whole bundled zipfile. coderes = struct.pack("iiii", magic, # magic value used for integrity checking, optmz, # optimization level to enable unbfrd, # whether to use unbuffered output len(code), ) + "\x00" + code + "\x00\x00" winres.add_resource(exepath,coderes,u"PYTHONSCRIPT",1,0) # If the python dll hasn't been copied into the bootstrap env, # make sure it's stored in each bootstrap dll as a resource. pydll = u"python%d%d.dll" % sys.version_info[:2] if not os.path.exists(os.path.join(dist.bootstrap_dir,pydll)): buf = ctypes.create_string_buffer(3000) GetModuleFileNameA = ctypes.windll.kernel32.GetModuleFileNameA if not GetModuleFileNameA(sys.dllhandle,ctypes.byref(buf),3000): raise ctypes.WinError() with open(buf.value,"rb") as f: pydll_bytes = f.read() for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = os.path.join(dist.bootstrap_dir,exe.name) try: winres.load_resource(exepath,pydll.upper(),1,0) except EnvironmentError: winres.add_resource(exepath,pydll_bytes,pydll.upper(),1,0)
def freeze(dist): """Freeze the given distribution data using py2exe.""" includes = dist.includes excludes = dist.excludes options = dist.freezer_options # Merge in any encludes/excludes given in freezer_options includes.append("esky") for inc in options.pop("includes", ()): includes.append(inc) for exc in options.pop("excludes", ()): excludes.append(exc) if "pypy" not in includes and "pypy" not in excludes: excludes.append("pypy") # py2exe expects some arguments on the main distribution object. # We handle data_files ourselves, so fake it out for py2exe. if getattr(dist.distribution, "console", None): msg = "don't call setup(console=[...]) with esky;" msg += " use setup(scripts=[...]) instead" raise RuntimeError(msg) if getattr(dist.distribution, "windows", None): msg = "don't call setup(windows=[...]) with esky;" msg += " use setup(scripts=[...]) instead" raise RuntimeError(msg) dist.distribution.console = [] dist.distribution.windows = [] my_data_files = dist.distribution.data_files dist.distribution.data_files = [] for exe in dist.get_executables(): # Pass any executable kwds through to py2exe. # We handle "icon" and "gui_only" ourselves. s = exe._kwds.copy() s["script"] = exe.script s["dest_base"] = exe.name[:-4] if exe.icon is not None and "icon_resources" not in s: s["icon_resources"] = [(1, exe.icon)] if exe.gui_only: dist.distribution.windows.append(s) else: dist.distribution.console.append(s) if "zipfile" in options: dist.distribution.zipfile = options.pop("zipfile") # Create the py2exe cmd and adjust its options cmd = custom_py2exe(dist.distribution) cmd.includes = includes cmd.excludes = excludes if "bundle_files" in options: if options["bundle_files"] < 3 and dist.compile_bootstrap_exes: err = "can't compile bootstrap exes when bundle_files < 3" raise RuntimeError(err) for (nm, val) in options.iteritems(): setattr(cmd, nm, val) cmd.dist_dir = dist.freeze_dir cmd.finalize_options() # Actually run the freeze process cmd.run() # Copy data files into the freeze dir dist.distribution.data_files = my_data_files for (src, dst) in dist.get_data_files(): dst = os.path.join(dist.freeze_dir, dst) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): dist.mkpath(dstdir) dist.copy_file(src, dst) # Place a marker file so we know how it was frozen os.mkdir(os.path.join(dist.freeze_dir, ESKY_CONTROL_DIR)) marker_file = os.path.join(ESKY_CONTROL_DIR, "f-py2exe-%d%d.txt") % sys.version_info[:2] open(os.path.join(dist.freeze_dir, marker_file), "w").close() # Copy package data into the library.zip # For now, we don't try to put package data into a bundled zipfile. dist_zipfile = dist.distribution.zipfile if dist_zipfile is None: for (src, arcnm) in dist.get_package_data(): err = "zipfile=None can't be used with package_data (yet...)" raise RuntimeError(err) elif not cmd.skip_archive: lib = zipfile.ZipFile(os.path.join(dist.freeze_dir, dist_zipfile), "a") for (src, arcnm) in dist.get_package_data(): lib.write(src, arcnm) lib.close() else: for (src, arcnm) in dist.get_package_data(): lib = os.path.join(dist.freeze_dir, os.path.dirname(dist_zipfile)) dest = os.path.join(lib, os.path.dirname(src)) f = os.path.basename(src) if not os.path.isdir(dest): dist.mkpath(dest) dist.copy_file(src, os.path.join(dest, f)) # There's no need to copy library.zip into the bootstrap env, as the # chainloader will run before py2exe goes looking for it. pass # Create the bootstraping code, using custom code if specified. # It gets stored as a marshalled list of code objects directly in the exe. esky_name = dist.distribution.get_name() code_source = ["__esky_name__ = %r" % (esky_name, )] code_source.append(inspect.getsource(esky.bootstrap)) if dist.compile_bootstrap_exes: from esky.bdist_esky import pypy_libpython from esky.bdist_esky import pypy_winres code_source.append(inspect.getsource(pypy_libpython)) code_source.append(inspect.getsource(pypy_winres)) code_source.append(_CUSTOM_PYPY_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source = "\n".join(code_source) for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue fexe = os.path.join(dist.freeze_dir, exe.name) bsexe = dist.compile_to_bootstrap_exe(exe, code_source) winres.copy_safe_resources(fexe, bsexe) # We may also need the bundled MSVCRT libs for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm) and nm.startswith("Microsoft"): dist.copy_to_bootstrap_env(nm) else: code_source.append(_FAKE_ESKY_BOOTSTRAP_MODULE) code_source.append(_CUSTOM_WIN32_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source.append("bootstrap()") code_source = "\n".join(code_source) code = marshal.dumps([compile(code_source, "__main__.py", "exec")]) # Copy any core dependencies into the bootstrap env. for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm): dist.copy_to_bootstrap_env(nm) # Copy the loader program for each script into the bootstrap env. for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = dist.copy_to_bootstrap_env(exe.name) # Read the py2exe metadata from the frozen exe. We will # need to duplicate some of these fields when to rewrite it. coderes = winres.load_resource(exepath, u"PYTHONSCRIPT", 1, 0) headsz = struct.calcsize("iiii") (magic, optmz, unbfrd, codesz) = struct.unpack("iiii", coderes[:headsz]) assert magic == 0x78563412 # Insert the bootstrap code into the exe as a resource. # This appears to have the happy side-effect of stripping any # extra data from the end of the exe, which is exactly what we # want when zipfile=None is specified; otherwise each bootstrap # exe would also contain the whole bundled zipfile. coderes = struct.pack( "iiii", magic, # magic value used for integrity checking, optmz, # optimization level to enable unbfrd, # whether to use unbuffered output len(code), ) + b"\x00" + code + b"\x00\x00" winres.add_resource(exepath, coderes, u"PYTHONSCRIPT", 1, 0) # If the python dll hasn't been copied into the bootstrap env, # make sure it's stored in each bootstrap dll as a resource. pydll = u"python%d%d.dll" % sys.version_info[:2] if not os.path.exists(os.path.join(dist.bootstrap_dir, pydll)): buf = ctypes.create_string_buffer(3000) GetModuleFileNameA = ctypes.windll.kernel32.GetModuleFileNameA if not GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf), 3000): raise ctypes.WinError() with open(buf.value, "rb") as f: pydll_bytes = f.read() for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = os.path.join(dist.bootstrap_dir, exe.name) try: winres.load_resource(exepath, pydll.upper(), 1, 0) except EnvironmentError: winres.add_resource(exepath, pydll_bytes, pydll.upper(), 1, 0)
def freeze(dist): """Freeze the given distribution data using cx_Freeze.""" includes = dist.includes excludes = dist.excludes options = dist.freezer_options # Merge in any encludes/excludes given in freezer_options for inc in options.pop("includes",()): includes.append(inc) for exc in options.pop("excludes",()): excludes.append(exc) if "esky" not in includes and "esky" not in excludes: includes.append("esky") if "pypy" not in includes and "pypy" not in excludes: excludes.append("pypy") # cx_Freeze doesn't seem to respect __path__ properly; hack it so # that the required distutils modules are always found correctly. def load_distutils(finder,module): module.path = distutils.__path__ + module.path finder.IncludeModule("distutils.dist") cx_Freeze.hooks.load_distutils = load_distutils # Build kwds arguments out of the given freezer opts. kwds = {} for (nm,val) in options.iteritems(): kwds[_normalise_opt_name(nm)] = val kwds["includes"] = includes kwds["excludes"] = excludes kwds["targetDir"] = dist.freeze_dir # Build an Executable object for each script. # To include the esky startup code, we write each to a tempdir. executables = [] for exe in dist.get_executables(): base = None if exe.gui_only and sys.platform == "win32": base = "Win32GUI" executables.append(cx_Freeze.Executable(exe.script,base=base,targetName=exe.name,icon=exe.icon,**exe._kwds)) # Freeze up the executables f = cx_Freeze.Freezer(executables,**kwds) f.Freeze() # Copy data files into the freeze dir for (src,dst) in dist.get_data_files(): dst = os.path.join(dist.freeze_dir,dst) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): dist.mkpath(dstdir) dist.copy_file(src,dst) # Copy package data into the library.zip # For now, this only works if there's a shared "library.zip" file. if f.createLibraryZip: lib = zipfile.ZipFile(os.path.join(dist.freeze_dir,"library.zip"),"a") for (src,arcnm) in dist.get_package_data(): lib.write(src,arcnm) lib.close() else: for (src,arcnm) in dist.get_package_data(): err = "use of package_data currently requires createLibraryZip=True" raise RuntimeError(err) # Create the bootstrap code, using custom code if specified. code_source = ["__name__ = '__main__'"] esky_name = dist.distribution.get_name() code_source.append("__esky_name__ = %r" % (esky_name,)) code_source.append(inspect.getsource(esky.bootstrap)) if dist.compile_bootstrap_exes: if sys.platform == "win32": # Unfortunately this doesn't work, because the cxfreeze exe # contains frozen modules that are inaccessible to a bootstrapped # interpreter. Disabled until I figure out a workaround. :-( pass # The pypy-compiled bootstrap exe will try to load a python env # into its own process and run this "take2" code to bootstrap. #take2_code = code_source[1:] #take2_code.append(_CUSTOM_WIN32_CHAINLOADER) #take2_code.append(dist.get_bootstrap_code()) #take2_code = compile("\n".join(take2_code),"<string>","exec") #take2_code = marshal.dumps(take2_code) #clscript = "import marshal; " #clscript += "exec marshal.loads(%r); " % (take2_code,) #clscript = clscript.replace("%","%%") #clscript += "chainload(\"%s\")" # Here's the actual source for the compiled bootstrap exe. #from esky.bdist_esky import pypy_libpython #code_source.append(inspect.getsource(pypy_libpython)) #code_source.append("_PYPY_CHAINLOADER_SCRIPT = %r" % (clscript,)) #code_source.append(_CUSTOM_PYPY_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source = "\n".join(code_source) for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue bsexe = dist.compile_to_bootstrap_exe(exe,code_source) if sys.platform == "win32": fexe = os.path.join(dist.freeze_dir,exe.name) winres.copy_safe_resources(fexe,bsexe) else: if sys.platform == "win32": code_source.append(_CUSTOM_WIN32_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source.append("bootstrap()") code_source = "\n".join(code_source) # Since Python 3.3 the .pyc file format contains the source size. # It's not used for anything at all except to check if the file is up to date. # We can set this value to zero to make Esky also work for Python 3.3 if sys.version_info[:2] < (3, 3): maincode = imp.get_magic() + struct.pack("<i",0) eskycode = imp.get_magic() + struct.pack("<i",0) eskybscode = imp.get_magic() + struct.pack("<i",0) else: maincode = imp.get_magic() + struct.pack("<ii",0,0) eskycode = imp.get_magic() + struct.pack("<ii",0,0) eskybscode = eskycode = imp.get_magic() + struct.pack("<ii",0,0) maincode += marshal.dumps(compile(code_source,INITNAME+".py","exec")) eskycode += marshal.dumps(compile("","esky/__init__.py","exec")) eskybscode += marshal.dumps(compile("","esky/bootstrap.py","exec")) # Copy any core dependencies if "fcntl" not in sys.builtin_module_names: for nm in os.listdir(dist.freeze_dir): if nm.startswith("fcntl"): dist.copy_to_bootstrap_env(nm) for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm): dist.copy_to_bootstrap_env(nm) # Copy the loader program for each script into the bootstrap env, and # append the bootstrapping code to it as a zipfile. for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = dist.copy_to_bootstrap_env(exe.name) if not dist.detached_bootstrap_library: #append library to the bootstrap exe. exepath = dist.copy_to_bootstrap_env(exe.name) bslib = zipfile.PyZipFile(exepath,"a",zipfile.ZIP_STORED) else: #Create a separate library.zip for the bootstrap exe. bslib_path = dist.copy_to_bootstrap_env("library.zip") bslib = zipfile.PyZipFile(bslib_path,"w",zipfile.ZIP_STORED) cdate = (2000,1,1,0,0,0) bslib.writestr(zipfile.ZipInfo(INITNAME+".pyc",cdate),maincode) bslib.writestr(zipfile.ZipInfo("esky/__init__.pyc",cdate),eskycode) bslib.writestr(zipfile.ZipInfo("esky/bootstrap.pyc",cdate),eskybscode) bslib.close()
def freeze(dist): """Freeze the given distribution data using bbfreeze.""" includes = dist.includes excludes = dist.excludes options = dist.freezer_options # Merge in any encludes/excludes given in freezer_options for inc in options.pop("includes",()): includes.append(inc) for exc in options.pop("excludes",()): excludes.append(exc) if "pypy" not in includes and "pypy" not in excludes: excludes.append("pypy") # Freeze up the given scripts f = bbfreeze.Freezer(dist.freeze_dir,includes=includes,excludes=excludes) for (nm,val) in options.iteritems(): setattr(f,nm,val) f.addModule("esky") tdir = tempfile.mkdtemp() try: for exe in dist.get_executables(): f.addScript(exe.script,gui_only=exe.gui_only) if "include_py" not in options: f.include_py = False if "linkmethod" not in options: # Since we're going to zip it up, the benefits of hard- # or sym-linking the loader exe will mostly be lost. f.linkmethod = "loader" f() finally: shutil.rmtree(tdir) # Copy data files into the freeze dir for (src,dst) in dist.get_data_files(): dst = os.path.join(dist.freeze_dir,dst) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): dist.mkpath(dstdir) dist.copy_file(src,dst) # Copy package data into the library.zip lib = zipfile.ZipFile(os.path.join(dist.freeze_dir,"library.zip"),"a") for (src,arcnm) in dist.get_package_data(): lib.write(src,arcnm) lib.close() # Create the bootstrap code, using custom code if specified. # For win32 we include a special chainloader that can suck the selected # version into the running process rather than spawn a new proc. code_source = ["__name__ = '__main__'"] esky_name = dist.distribution.get_name() code_source.append("__esky_name__ = %r" % (esky_name,)) code_source.append(inspect.getsource(esky.bootstrap)) if dist.compile_bootstrap_exes: if sys.platform == "win32": # The pypy-compiled bootstrap exe will try to load a python env # into its own process and run this "take2" code to bootstrap. take2_code = code_source[1:] take2_code.append(_CUSTOM_WIN32_CHAINLOADER) take2_code.append(dist.get_bootstrap_code()) take2_code = compile("\n".join(take2_code),"<string>","exec") take2_code = marshal.dumps(take2_code) clscript = "import marshal; " clscript += "exec marshal.loads(%r); " % (take2_code,) clscript = clscript.replace("%","%%") clscript += "chainload(\"%s\")" # Here's the actual source for the compiled bootstrap exe. from esky.bdist_esky import pypy_libpython code_source.append(inspect.getsource(pypy_libpython)) code_source.append("_PYPY_CHAINLOADER_SCRIPT = %r" % (clscript,)) code_source.append(_CUSTOM_PYPY_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source = "\n".join(code_source) for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue bsexe = dist.compile_to_bootstrap_exe(exe,code_source) if sys.platform == "win32": fexe = os.path.join(dist.freeze_dir,exe.name) winres.copy_safe_resources(fexe,bsexe) # We may also need the bundled MSVCRT libs if sys.platform == "win32": for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm) and nm.startswith("Microsoft"): dist.copy_to_bootstrap_env(nm) else: if sys.platform == "win32": code_source.append(_CUSTOM_WIN32_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source.append("bootstrap()") code_source = "\n".join(code_source) # For non-compiled bootstrap exe, store the bootstrapping code # into the library.zip as __main__. maincode = imp.get_magic() + struct.pack("<i",0) maincode += marshal.dumps(compile(code_source,"__main__.py","exec")) # Create code for a fake esky.bootstrap module eskycode = imp.get_magic() + struct.pack("<i",0) eskycode += marshal.dumps(compile("","esky/__init__.py","exec")) eskybscode = imp.get_magic() + struct.pack("<i",0) eskybscode += marshal.dumps(compile("","esky/bootstrap.py","exec")) # Store bootstrap code as __main__ in the bootstrap library.zip. # The frozen library.zip might have the loader prepended to it, but # that gets overwritten here. bslib_path = dist.copy_to_bootstrap_env("library.zip") bslib = zipfile.PyZipFile(bslib_path,"w",zipfile.ZIP_STORED) cdate = (2000,1,1,0,0,0) bslib.writestr(zipfile.ZipInfo("__main__.pyc",cdate),maincode) bslib.writestr(zipfile.ZipInfo("esky/__init__.pyc",cdate),eskycode) bslib.writestr(zipfile.ZipInfo("esky/bootstrap.pyc",cdate),eskybscode) bslib.close() # Copy any core dependencies if "fcntl" not in sys.builtin_module_names: for nm in os.listdir(dist.freeze_dir): if nm.startswith("fcntl"): dist.copy_to_bootstrap_env(nm) for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm): dist.copy_to_bootstrap_env(nm) # Copy the bbfreeze interpreter if necessary if f.include_py: if sys.platform == "win32": dist.copy_to_bootstrap_env("py.exe") else: dist.copy_to_bootstrap_env("py") # Copy the loader program for each script. # We explicitly strip the loader binaries, in case they were made # by linking to the library.zip. for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = dist.copy_to_bootstrap_env(exe.name) f.stripBinary(exepath)
def freeze(dist): """Freeze the given distribution data using cx_Freeze.""" includes = dist.includes excludes = dist.excludes options = dist.freezer_options # Merge in any encludes/excludes given in freezer_options for inc in options.pop("includes", ()): includes.append(inc) for exc in options.pop("excludes", ()): excludes.append(exc) if "esky" not in includes and "esky" not in excludes: includes.append("esky") if "pypy" not in includes and "pypy" not in excludes: excludes.append("pypy") # cx_Freeze doesn't seem to respect __path__ properly; hack it so # that the required distutils modules are always found correctly. def load_distutils(finder, module): module.path = distutils.__path__ + module.path finder.IncludeModule("distutils.dist") cx_Freeze.hooks.load_distutils = load_distutils # Build kwds arguments out of the given freezer opts. kwds = {} for (nm, val) in options.iteritems(): kwds[_normalise_opt_name(nm)] = val kwds["includes"] = includes kwds["excludes"] = excludes kwds["targetDir"] = dist.freeze_dir # Build an Executable object for each script. # To include the esky startup code, we write each to a tempdir. executables = [] for exe in dist.get_executables(): base = None if exe.gui_only and sys.platform == "win32": base = "Win32GUI" executables.append( cx_Freeze.Executable(exe.script, base=base, targetName=exe.name, icon=exe.icon, **exe._kwds)) # Freeze up the executables f = cx_Freeze.Freezer(executables, **kwds) f.Freeze() # Copy data files into the freeze dir for (src, dst) in dist.get_data_files(): dst = os.path.join(dist.freeze_dir, dst) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): dist.mkpath(dstdir) dist.copy_file(src, dst) # Copy package data into the library.zip # For now, this only works if there's a shared "library.zip" file. if f.createLibraryZip: lib = zipfile.ZipFile(os.path.join(dist.freeze_dir, "library.zip"), "a") for (src, arcnm) in dist.get_package_data(): lib.write(src, arcnm) lib.close() else: for (src, arcnm) in dist.get_package_data(): err = "use of package_data currently requires createLibraryZip=True" raise RuntimeError(err) # Create the bootstrap code, using custom code if specified. code_source = ["__name__ = '__main__'"] esky_name = dist.distribution.get_name() code_source.append("__esky_name__ = %r" % (esky_name, )) code_source.append(inspect.getsource(esky.bootstrap)) if dist.compile_bootstrap_exes: if sys.platform == "win32": # Unfortunately this doesn't work, because the cxfreeze exe # contains frozen modules that are inaccessible to a bootstrapped # interpreter. Disabled until I figure out a workaround. :-( pass # The pypy-compiled bootstrap exe will try to load a python env # into its own process and run this "take2" code to bootstrap. #take2_code = code_source[1:] #take2_code.append(_CUSTOM_WIN32_CHAINLOADER) #take2_code.append(dist.get_bootstrap_code()) #take2_code = compile("\n".join(take2_code),"<string>","exec") #take2_code = marshal.dumps(take2_code) #clscript = "import marshal; " #clscript += "exec marshal.loads(%r); " % (take2_code,) #clscript = clscript.replace("%","%%") #clscript += "chainload(\"%s\")" # Here's the actual source for the compiled bootstrap exe. #from esky.bdist_esky import pypy_libpython #code_source.append(inspect.getsource(pypy_libpython)) #code_source.append("_PYPY_CHAINLOADER_SCRIPT = %r" % (clscript,)) #code_source.append(_CUSTOM_PYPY_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source = "\n".join(code_source) for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue bsexe = dist.compile_to_bootstrap_exe(exe, code_source) if sys.platform == "win32": fexe = os.path.join(dist.freeze_dir, exe.name) winres.copy_safe_resources(fexe, bsexe) else: if sys.platform == "win32": code_source.append(_CUSTOM_WIN32_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source.append("bootstrap()") code_source = "\n".join(code_source) maincode = imp.get_magic() + struct.pack("<i", 0) maincode += marshal.dumps( compile(code_source, INITNAME + ".py", "exec")) # Create code for a fake esky.bootstrap module eskycode = imp.get_magic() + struct.pack("<i", 0) eskycode += marshal.dumps(compile("", "esky/__init__.py", "exec")) eskybscode = imp.get_magic() + struct.pack("<i", 0) eskybscode += marshal.dumps(compile("", "esky/bootstrap.py", "exec")) # Copy any core dependencies if "fcntl" not in sys.builtin_module_names: for nm in os.listdir(dist.freeze_dir): if nm.startswith("fcntl"): dist.copy_to_bootstrap_env(nm) for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm): dist.copy_to_bootstrap_env(nm) # Copy the loader program for each script into the bootstrap env, and # append the bootstrapping code to it as a zipfile. for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = dist.copy_to_bootstrap_env(exe.name) bslib = zipfile.PyZipFile(exepath, "a", zipfile.ZIP_STORED) cdate = (2000, 1, 1, 0, 0, 0) bslib.writestr(zipfile.ZipInfo(INITNAME + ".pyc", cdate), maincode) bslib.writestr(zipfile.ZipInfo("esky/__init__.pyc", cdate), eskycode) bslib.writestr(zipfile.ZipInfo("esky/bootstrap.pyc", cdate), eskybscode) bslib.close()
def freeze(dist): """Freeze the given distribution data using bbfreeze.""" includes = dist.includes excludes = dist.excludes options = dist.freezer_options # Merge in any encludes/excludes given in freezer_options for inc in options.pop("includes",()): includes.append(inc) for exc in options.pop("excludes",()): excludes.append(exc) if "pypy" not in includes and "pypy" not in excludes: excludes.append("pypy") # Freeze up the given scripts f = bbfreeze.Freezer(dist.freeze_dir,includes=includes,excludes=excludes) for (nm,val) in options.iteritems(): setattr(f,nm,val) f.addModule("esky") tdir = tempfile.mkdtemp() try: for exe in dist.get_executables(): f.addScript(exe.script,gui_only=exe.gui_only) if "include_py" not in options: f.include_py = False if "linkmethod" not in options: # Since we're going to zip it up, the benefits of hard- # or sym-linking the loader exe will mostly be lost. f.linkmethod = "loader" f() finally: shutil.rmtree(tdir) # Copy data files into the freeze dir for (src,dst) in dist.get_data_files(): dst = os.path.join(dist.freeze_dir,dst) dstdir = os.path.dirname(dst) if not os.path.isdir(dstdir): dist.mkpath(dstdir) dist.copy_file(src,dst) # Copy package data into the library.zip lib = zipfile.ZipFile(os.path.join(dist.freeze_dir,"library.zip"),"a") for (src,arcnm) in dist.get_package_data(): lib.write(src,arcnm) lib.close() # Create the bootstrap code, using custom code if specified. # For win32 we include a special chainloader that can suck the selected # version into the running process rather than spawn a new proc. code_source = ["__name__ = '__main__'"] code_source.append("__esky_name__ = '%s'" % (dist.distribution.get_name(),)) code_source.append(inspect.getsource(esky.bootstrap)) if dist.compile_bootstrap_exes: if sys.platform == "win32": # The pypy-compiled bootstrap exe will try to load a python env # into its own process and run this "take2" code to bootstrap. take2_code = code_source[1:] take2_code.append(_CUSTOM_WIN32_CHAINLOADER) take2_code.append(dist.get_bootstrap_code()) take2_code = compile("\n".join(take2_code),"<string>","exec") take2_code = marshal.dumps(take2_code) clscript = "import marshal; " clscript += "exec marshal.loads(%r); " % (take2_code,) clscript = clscript.replace("%","%%") clscript += "chainload(\"%s\")" # Here's the actual source for the compiled bootstrap exe. from esky.bdist_esky import pypy_libpython code_source.append(inspect.getsource(pypy_libpython)) code_source.append("_PYPY_CHAINLOADER_SCRIPT = %r" % (clscript,)) code_source.append(_CUSTOM_PYPY_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source = "\n".join(code_source) for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue bsexe = dist.compile_to_bootstrap_exe(exe,code_source) if sys.platform == "win32": fexe = os.path.join(dist.freeze_dir,exe.name) winres.copy_safe_resources(fexe,bsexe) # We may also need the bundled MSVCRT libs if sys.platform == "win32": for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm) and nm.startswith("Microsoft"): dist.copy_to_bootstrap_env(nm) else: if sys.platform == "win32": code_source.append(_CUSTOM_WIN32_CHAINLOADER) code_source.append(dist.get_bootstrap_code()) code_source.append("bootstrap()") code_source = "\n".join(code_source) # For non-compiled bootstrap exe, store the bootstrapping code # into the library.zip as __main__. maincode = imp.get_magic() + struct.pack("<i",0) maincode += marshal.dumps(compile(code_source,"__main__.py","exec")) # Create code for a fake esky.bootstrap module eskycode = imp.get_magic() + struct.pack("<i",0) eskycode += marshal.dumps(compile("","esky/__init__.py","exec")) eskybscode = imp.get_magic() + struct.pack("<i",0) eskybscode += marshal.dumps(compile("","esky/bootstrap.py","exec")) # Store bootstrap code as __main__ in the bootstrap library.zip. # The frozen library.zip might have the loader prepended to it, but # that gets overwritten here. bslib_path = dist.copy_to_bootstrap_env("library.zip") bslib = zipfile.PyZipFile(bslib_path,"w",zipfile.ZIP_STORED) cdate = (2000,1,1,0,0,0) bslib.writestr(zipfile.ZipInfo("__main__.pyc",cdate),maincode) bslib.writestr(zipfile.ZipInfo("esky/__init__.pyc",cdate),eskycode) bslib.writestr(zipfile.ZipInfo("esky/bootstrap.pyc",cdate),eskybscode) bslib.close() # Copy any core dependencies if "fcntl" not in sys.builtin_module_names: for nm in os.listdir(dist.freeze_dir): if nm.startswith("fcntl"): dist.copy_to_bootstrap_env(nm) for nm in os.listdir(dist.freeze_dir): if is_core_dependency(nm): dist.copy_to_bootstrap_env(nm) # Copy the bbfreeze interpreter if necessary if f.include_py: if sys.platform == "win32": dist.copy_to_bootstrap_env("py.exe") else: dist.copy_to_bootstrap_env("py") # Copy the loader program for each script. # We explicitly strip the loader binaries, in case they were made # by linking to the library.zip. for exe in dist.get_executables(normalise=False): if not exe.include_in_bootstrap_env: continue exepath = dist.copy_to_bootstrap_env(exe.name) f.stripBinary(exepath)