def assemble(self): logger.info("Building PYZ (ZlibArchive) %s", self.name) # Do not bundle PyInstaller bootstrap modules into PYZ archive. toc = self.toc - self.dependencies for entry in toc[:]: if not entry[0] in self.code_dict and entry[2] == 'PYMODULE': # For some reason the code-object, modulegraph created # is not available. Recreate it try: self.code_dict[entry[0]] = get_code_object(entry[0], entry[1]) except SyntaxError: # Exclude the module in case this is code meant for a newer Python version. toc.remove(entry) # sort content alphabetically to support reproducible builds toc.sort() # Remove leading parts of paths in code objects self.code_dict = { key: strip_paths_in_code(code) for key, code in self.code_dict.items() } pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher) logger.info("Building PYZ (ZlibArchive) %s completed successfully.", self.name)
def assemble(self): if _check_path_overlap(self.name) and os.path.isdir(self.name): _rmtree(self.name) logger.info("Building COLLECT %s", self.tocbasename) os.makedirs(self.name) toc = add_suffix_to_extensions(self.toc) for inm, fnm, typ in toc: if not os.path.exists(fnm) or not os.path.isfile(fnm) and is_path_to_egg(fnm): # file is contained within python egg, it is added with the egg continue if os.pardir in os.path.normpath(inm) or os.path.isabs(inm): raise SystemExit('Security-Alert: try to store file outside ' 'of dist-directory. Aborting. %r' % inm) tofnm = os.path.join(self.name, inm) todir = os.path.dirname(tofnm) if not os.path.exists(todir): os.makedirs(todir) if typ in ('EXTENSION', 'BINARY'): fnm = checkCache(fnm, strip=self.strip_binaries, upx=(self.upx_binaries and (is_win or is_cygwin)), dist_nm=inm) if typ != 'DEPENDENCY': shutil.copy(fnm, tofnm) try: shutil.copystat(fnm, tofnm) except OSError: logger.warn("failed to copy flags of %s", fnm) if typ in ('EXTENSION', 'BINARY'): os.chmod(tofnm, 0o755)
def __init__(self, *args): """ Repeated dependencies are then present only once in the first executable in the 'args' list. Other executables depend on the first one. Other executables have to extract necessary files from the first executable. args dependencies in a list of (Analysis, id, filename) tuples. Replace id with the correct filename. """ # The first Analysis object with all dependencies. # Any item from the first executable cannot be removed. self._main = None self._dependencies = {} self._id_to_path = {} for _, i, p in args: self._id_to_path[os.path.normcase(i)] = p # Get the longest common path self._common_prefix = os.path.dirname(os.path.commonprefix([os.path.abspath(a.scripts[-1][1]) for a, _, _ in args])) if self._common_prefix[-1] != os.sep: self._common_prefix += os.sep logger.info("Common prefix: %s", self._common_prefix) self._merge_dependencies(args)
def assemble(self): logger.info("Building PYZ (ZlibArchive) %s", self.name) # Do not bundle PyInstaller bootstrap modules into PYZ archive. toc = self.toc - self.dependencies for entry in toc: if not entry[0] in self.code_dict and entry[2] == 'PYMODULE': # For some reason the code-object, modulegraph created # is not available. Recreate it self.code_dict[entry[0]] = self.__get_code(entry[0], entry[1]) pyz = ZlibArchiveWriter(code_dict=self.code_dict, cipher=self.cipher) pyz.build(self.name, toc)
def _check_guts(self, data, last_build): if not os.path.exists(self.name): logger.info("Rebuilding %s because %s missing", self.tocbasename, os.path.basename(self.name)) return 1 if not self.append_pkg and not os.path.exists(self.pkgname): logger.info("Rebuilding because %s missing", os.path.basename(self.pkgname)) return 1 if Target._check_guts(self, data, last_build): return True if (data['versrsrc'] or data['resources']) and not is_win: # todo: really ignore :-) logger.warn('ignoring version, manifest and resources, platform not capable') if data['icon'] and not (is_win or is_darwin): logger.warn('ignoring icon, platform not capable') mtm = data['mtm'] if mtm != misc.mtime(self.name): logger.info("Rebuilding %s because mtimes don't match", self.tocbasename) return True if mtm < misc.mtime(self.pkg.tocfilename): logger.info("Rebuilding %s because pkg is more recent", self.tocbasename) return True return False
def assemble(self): logger.info("Building PYZ (ZlibArchive) %s", self.name) # Do not bundle PyInstaller bootstrap modules into PYZ archive. toc = self.toc - self.dependencies for entry in toc: if not entry[0] in self.code_dict and entry[2] == 'PYMODULE': # For some reason the code-object, modulegraph created # is not available. Recreate it self.code_dict[entry[0]] = self.__get_code(entry[0], entry[1]) # sort content alphabetically to support reproducible builds toc.sort() # Remove leading parts of paths in code objects self.code_dict = { key: self._strip_paths_in_code(code) for key, code in self.code_dict.items() } pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher)
def assemble(self): logger.info("Building PYZ (ZlibArchive) %s", self.name) # Do not bundle PyInstaller bootstrap modules into PYZ archive. toc = self.toc - self.dependencies for entry in toc: if not entry[0] in self.code_dict and entry[2] == 'PYMODULE': # For some reason the code-object, modulegraph created # is not available. Recreate it self.code_dict[entry[0]] = get_code_object(entry[0], entry[1]) # sort content alphabetically to support reproducible builds toc.sort() # Remove leading parts of paths in code objects self.code_dict = { key: strip_paths_in_code(code) for key, code in self.code_dict.items() } pyz = ZlibArchiveWriter(self.name, toc, code_dict=self.code_dict, cipher=self.cipher)
def _bootloader_file(self, exe, extension=None): """ Pick up the right bootloader file - debug, console, windowed. """ # Having console/windowed bootolader makes sense only on Windows and # Mac OS X. if is_win or is_darwin: if not self.console: exe = exe + 'w' # There are two types of bootloaders: # run - release, no verbose messages in console. # run_d - contains verbose messages in console. if self.debug: exe = exe + '_d' if extension: exe = exe + extension bootloader_file = os.path.join(HOMEPATH, 'PyInstaller', 'bootloader', PLATFORM, exe) logger.info('Bootloader %s' % bootloader_file) return bootloader_file
def assemble(self): if _check_path_overlap(self.name) and os.path.isdir(self.name): _rmtree(self.name) logger.info("Building BUNDLE %s", self.tocbasename) # Create a minimal Mac bundle structure os.makedirs(os.path.join(self.name, "Contents", "MacOS")) os.makedirs(os.path.join(self.name, "Contents", "Resources")) os.makedirs(os.path.join(self.name, "Contents", "Frameworks")) # Copy icns icon to Resources directory. if os.path.exists(self.icon): shutil.copy(self.icon, os.path.join(self.name, 'Contents', 'Resources')) else: logger.warning("icon not found %s", self.icon) # Key/values for a minimal Info.plist file info_plist_dict = { "CFBundleDisplayName": self.appname, "CFBundleName": self.appname, # Required by 'codesign' utility. # The value for CFBundleIdentifier is used as the default unique # name of your program for Code Signing purposes. # It even identifies the APP for access to restricted OS X areas # like Keychain. # # The identifier used for signing must be globally unique. The usal # form for this identifier is a hierarchical name in reverse DNS # notation, starting with the toplevel domain, followed by the # company name, followed by the department within the company, and # ending with the product name. Usually in the form: # com.mycompany.department.appname # Cli option --osx-bundle-identifier sets this value. "CFBundleIdentifier": self.bundle_identifier, "CFBundleExecutable": os.path.basename(self.exename), "CFBundleIconFile": os.path.basename(self.icon), "CFBundleInfoDictionaryVersion": "6.0", "CFBundlePackageType": "APPL", "CFBundleShortVersionString": self.version, } # Set some default values. # But they still can be overwritten by the user. if self.console: # Setting EXE console=True implies LSBackgroundOnly=True. info_plist_dict['LSBackgroundOnly'] = True else: # Let's use high resolution by default. info_plist_dict['NSHighResolutionCapable'] = True # Merge info_plist settings from spec file if isinstance(self.info_plist, dict) and self.info_plist: info_plist_dict.update(self.info_plist) plist_filename = os.path.join(self.name, "Contents", "Info.plist") with open(plist_filename, "wb") as plist_fh: plistlib.dump(info_plist_dict, plist_fh) links = [] _QT_BASE_PATH = {'PySide2', 'PySide6', 'PyQt5', 'PySide6'} for inm, fnm, typ in self.toc: # Adjust name for extensions, if applicable inm, fnm, typ = add_suffix_to_extension(inm, fnm, typ) # Copy files from cache. This ensures that are used files with relative # paths to dynamic library dependencies (@executable_path) base_path = inm.split('/', 1)[0] if typ in ('EXTENSION', 'BINARY'): fnm = checkCache(fnm, strip=self.strip, upx=self.upx, upx_exclude=self.upx_exclude, dist_nm=inm, target_arch=self.target_arch, codesign_identity=self.codesign_identity, entitlements_file=self.entitlements_file) # Add most data files to a list for symlinking later. if typ == 'DATA' and base_path not in _QT_BASE_PATH: links.append((inm, fnm)) else: tofnm = os.path.join(self.name, "Contents", "MacOS", inm) todir = os.path.dirname(tofnm) if not os.path.exists(todir): os.makedirs(todir) if os.path.isdir(fnm): # beacuse shutil.copy2() is the default copy function # for shutil.copytree, this will also copy file metadata shutil.copytree(fnm, tofnm) else: shutil.copy(fnm, tofnm) logger.info('Moving BUNDLE data files to Resource directory') # Mac OS X Code Signing does not work when .app bundle contains # data files in dir ./Contents/MacOS. # # Put all data files in ./Resources and create symlinks in ./MacOS. bin_dir = os.path.join(self.name, 'Contents', 'MacOS') res_dir = os.path.join(self.name, 'Contents', 'Resources') for inm, fnm in links: tofnm = os.path.join(res_dir, inm) todir = os.path.dirname(tofnm) if not os.path.exists(todir): os.makedirs(todir) if os.path.isdir(fnm): # beacuse shutil.copy2() is the default copy function # for shutil.copytree, this will also copy file metadata shutil.copytree(fnm, tofnm) else: shutil.copy(fnm, tofnm) base_path = os.path.split(inm)[0] if base_path: if not os.path.exists(os.path.join(bin_dir, inm)): path = '' for part in iter(base_path.split(os.path.sep)): # Build path from previous path and the next part of the base path path = os.path.join(path, part) try: relative_source_path = os.path.relpath( os.path.join(res_dir, path), os.path.split(os.path.join(bin_dir, path))[0]) dest_path = os.path.join(bin_dir, path) os.symlink(relative_source_path, dest_path) break except FileExistsError: pass if not os.path.exists(os.path.join(bin_dir, inm)): relative_source_path = os.path.relpath( os.path.join(res_dir, inm), os.path.split(os.path.join(bin_dir, inm))[0]) dest_path = os.path.join(bin_dir, inm) os.symlink(relative_source_path, dest_path) else: # If path is empty, e.g., a top level file, try to just symlink the file os.symlink( os.path.relpath( os.path.join(res_dir, inm), os.path.split(os.path.join(bin_dir, inm))[0]), os.path.join(bin_dir, inm)) # Sign the bundle logger.info('Signing the BUNDLE...') try: osxutils.sign_binary(self.name, self.codesign_identity, self.entitlements_file, deep=True) except Exception as e: logger.warning("Error while signing the bundle: %s", e) logger.warning("You will need to sign the bundle manually!") logger.info("Building BUNDLE %s completed successfully.", self.tocbasename)
def assemble(self): logger.info("Building PKG (CArchive) %s", os.path.basename(self.name)) trash = [] mytoc = [] srctoc = [] seenInms = {} seenFnms = {} seenFnms_typ = {} toc = add_suffix_to_extensions(self.toc) # 'inm' - relative filename inside a CArchive # 'fnm' - absolute filename as it is on the file system. for inm, fnm, typ in toc: # Ensure filename 'fnm' is not None or empty string. Otherwise # it will fail in case of 'typ' being type OPTION. if fnm and not os.path.isfile(fnm) and is_path_to_egg(fnm): # file is contained within python egg, it is added with the egg continue if typ in ('BINARY', 'EXTENSION', 'DEPENDENCY'): if self.exclude_binaries and typ != 'DEPENDENCY': self.dependencies.append((inm, fnm, typ)) else: if typ == 'BINARY': # Avoid importing the same binary extension twice. This might # happen if they come from different sources (eg. once from # binary dependence, and once from direct import). if inm in seenInms: logger.warning('Two binaries added with the same internal name.') logger.warning(pprint.pformat((inm, fnm, typ))) logger.warning('was placed previously at') logger.warning(pprint.pformat((inm, seenInms[inm], seenFnms_typ[seenInms[inm]]))) logger.warning('Skipping %s.' % fnm) continue # Warn if the same binary extension was included # with multiple internal names if fnm in seenFnms: logger.warning('One binary added with two internal names.') logger.warning(pprint.pformat((inm, fnm, typ))) logger.warning('was placed previously at') logger.warning(pprint.pformat((seenFnms[fnm], fnm, seenFnms_typ[fnm]))) seenInms[inm] = fnm seenFnms[fnm] = inm seenFnms_typ[fnm] = typ fnm = checkCache(fnm, strip=self.strip_binaries, upx=(self.upx_binaries and (is_win or is_cygwin)), dist_nm=inm) mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b'))) elif typ == 'OPTION': mytoc.append((inm, '', 0, 'o')) elif typ in ('PYSOURCE', 'PYMODULE'): # collect sourcefiles and module in a toc of it's own # which will not be sorted. srctoc.append((inm, fnm, self.cdict[typ], self.xformdict[typ])) else: mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b'))) # Bootloader has to know the name of Python library. Pass python libname to CArchive. pylib_name = os.path.basename(bindepend.get_python_library_path()) # Sort content alphabetically by type and name to support # reproducible builds. mytoc.sort(key=itemgetter(3, 0)) # Do *not* sort modules and scripts, as their order is important. # TODO: Think about having all modules first and then all scripts. archive = CArchiveWriter(self.name, srctoc + mytoc, pylib_name=pylib_name) for item in trash: os.remove(item) logger.info("Building PKG (CArchive) %s completed successfully.", os.path.basename(self.name))
def assemble(self): logger.info("Building EXE from %s", self.tocbasename) trash = [] if not os.path.exists(os.path.dirname(self.name)): os.makedirs(os.path.dirname(self.name)) outf = open(self.name, 'wb') exe = self.exefiles[0][1] # pathname of bootloader if not os.path.exists(exe): raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG) if is_win and (self.icon or self.versrsrc or self.resources): tmpnm = tempfile.mktemp() shutil.copy2(exe, tmpnm) os.chmod(tmpnm, 0o755) if self.icon: icon.CopyIcons(tmpnm, self.icon) if self.versrsrc: versioninfo.SetVersion(tmpnm, self.versrsrc) for res in self.resources: res = res.split(",") for i in range(1, len(res)): try: res[i] = int(res[i]) except ValueError: pass resfile = res[0] restype = resname = reslang = None if len(res) > 1: restype = res[1] if len(res) > 2: resname = res[2] if len(res) > 3: reslang = res[3] try: winresource.UpdateResourcesFromResFile(tmpnm, resfile, [restype or "*"], [resname or "*"], [reslang or "*"]) except winresource.pywintypes.error as exc: if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT: logger.exception(exc) continue if not restype or not resname: logger.error("resource type and/or name not specified") continue if "*" in (restype, resname): logger.error("no wildcards allowed for resource type " "and name when source file does not " "contain resources") continue try: winresource.UpdateResourcesFromDataFile(tmpnm, resfile, restype, [resname], [reslang or 0]) except winresource.pywintypes.error as exc: logger.exception(exc) trash.append(tmpnm) exe = tmpnm exe = checkCache(exe, strip=self.strip, upx=self.upx) self.copy(exe, outf) if self.append_pkg: logger.info("Appending archive to EXE %s", self.name) self.copy(self.pkg.name, outf) else: logger.info("Copying archive to %s", self.pkgname) shutil.copy2(self.pkg.name, self.pkgname) outf.close() if is_darwin: # Fix Mach-O header for codesigning on OS X. logger.info("Fixing EXE for code signing %s", self.name) import PyInstaller.utils.osx as osxutils osxutils.fix_exe_for_code_signing(self.name) pass os.chmod(self.name, 0o755) # get mtime for storing into the guts self.mtm = misc.mtime(self.name) for item in trash: os.remove(item)
def assemble(self): logger.info("Building EXE from %s", self.tocbasename) trash = [] if os.path.exists(self.name): os.remove(self.name) if not os.path.exists(os.path.dirname(self.name)): os.makedirs(os.path.dirname(self.name)) exe = self.exefiles[0][1] # pathname of bootloader if not os.path.exists(exe): raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG) if is_win and (self.icon or self.versrsrc or self.resources): tmpnm = tempfile.mktemp() self._copyfile(exe, tmpnm) os.chmod(tmpnm, 0o755) if self.icon: icon.CopyIcons(tmpnm, self.icon) if self.versrsrc: versioninfo.SetVersion(tmpnm, self.versrsrc) for res in self.resources: res = res.split(",") for i in range(1, len(res)): try: res[i] = int(res[i]) except ValueError: pass resfile = res[0] restype = resname = reslang = None if len(res) > 1: restype = res[1] if len(res) > 2: resname = res[2] if len(res) > 3: reslang = res[3] try: winresource.UpdateResourcesFromResFile(tmpnm, resfile, [restype or "*"], [resname or "*"], [reslang or "*"]) except winresource.pywintypes.error as exc: if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT: logger.error("Error while updating resources in %s" " from resource file %s", tmpnm, resfile, exc_info=1) continue # Handle the case where the file contains no resources, and is # intended as a single resource to be added to the exe. if not restype or not resname: logger.error("resource type and/or name not specified") continue if "*" in (restype, resname): logger.error("no wildcards allowed for resource type " "and name when source file does not " "contain resources") continue try: winresource.UpdateResourcesFromDataFile(tmpnm, resfile, restype, [resname], [reslang or 0]) except winresource.pywintypes.error: logger.error("Error while updating resource %s %s in %s" " from data file %s", restype, resname, tmpnm, resfile, exc_info=1) trash.append(tmpnm) exe = tmpnm # NOTE: Do not look up for bootloader file in the cache because it might # get corrupted by UPX when UPX is available. See #1863 for details. if not self.append_pkg: logger.info("Copying bootloader exe to %s", self.name) self._copyfile(exe, self.name) logger.info("Copying archive to %s", self.pkgname) self._copyfile(self.pkg.name, self.pkgname) elif is_linux: self._copyfile(exe, self.name) logger.info("Appending archive to ELF section in EXE %s", self.name) retcode, stdout, stderr = exec_command_all( 'objcopy', '--add-section', 'pydata=%s' % self.pkg.name, self.name) logger.debug("objcopy returned %i", retcode) if stdout: logger.debug(stdout) if stderr: logger.debug(stderr) if retcode != 0: raise SystemError("objcopy Failure: %s" % stderr) else: # Fall back to just append on end of file logger.info("Appending archive to EXE %s", self.name) with open(self.name, 'wb') as outf: # write the bootloader data with open(exe, 'rb') as infh: shutil.copyfileobj(infh, outf, length=64*1024) # write the archive data with open(self.pkg.name, 'rb') as infh: shutil.copyfileobj(infh, outf, length=64*1024) if is_darwin: # Fix Mach-O header for codesigning on OS X. logger.info("Fixing EXE for code signing %s", self.name) import PyInstaller.utils.osx as osxutils osxutils.fix_exe_for_code_signing(self.name) os.chmod(self.name, 0o755) # get mtime for storing into the guts self.mtm = misc.mtime(self.name) for item in trash: os.remove(item) logger.info("Building EXE from %s completed successfully.", self.tocbasename)
def assemble(self): logger.info("Building PKG (CArchive) %s", os.path.basename(self.name)) trash = [] mytoc = [] seenInms = {} seenFnms = {} seenFnms_typ = {} toc = add_suffix_to_extensions(self.toc) # 'inm' - relative filename inside a CArchive # 'fnm' - absolute filename as it is on the file system. for inm, fnm, typ in toc: # Ensure filename 'fnm' is not None or empty string. Otherwise # it will fail in case of 'typ' being type OPTION. if fnm and not os.path.isfile(fnm) and is_path_to_egg(fnm): # file is contained within python egg, it is added with the egg continue if typ in ('BINARY', 'EXTENSION', 'DEPENDENCY'): if self.exclude_binaries and typ != 'DEPENDENCY': self.dependencies.append((inm, fnm, typ)) else: if typ == 'BINARY': # Avoid importing the same binary extension twice. This might # happen if they come from different sources (eg. once from # binary dependence, and once from direct import). if inm in seenInms: logger.warn('Two binaries added with the same internal name.') logger.warn(pprint.pformat((inm, fnm, typ))) logger.warn('was placed previously at') logger.warn(pprint.pformat((inm, seenInms[inm], seenFnms_typ[seenInms[inm]]))) logger.warn('Skipping %s.' % fnm) continue # Warn if the same binary extension was included # with multiple internal names if fnm in seenFnms: logger.warn('One binary added with two internal names.') logger.warn(pprint.pformat((inm, fnm, typ))) logger.warn('was placed previously at') logger.warn(pprint.pformat((seenFnms[fnm], fnm, seenFnms_typ[fnm]))) seenInms[inm] = fnm seenFnms[fnm] = inm seenFnms_typ[fnm] = typ fnm = checkCache(fnm, strip=self.strip_binaries, upx=(self.upx_binaries and (is_win or is_cygwin)), dist_nm=inm) mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b'))) elif typ == 'OPTION': mytoc.append((inm, '', 0, 'o')) else: mytoc.append((inm, fnm, self.cdict.get(typ, 0), self.xformdict.get(typ, 'b'))) # Bootloader has to know the name of Python library. Pass python libname to CArchive. pylib_name = os.path.basename(bindepend.get_python_library_path()) archive = CArchiveWriter(pylib_name=pylib_name) archive.build(self.name, mytoc) for item in trash: os.remove(item)
def __init__(self, *args, **kws): from PyInstaller.config import CONF # BUNDLE only has a sense under Mac OS X, it's a noop on other platforms if not is_darwin: return # get a path to a .icns icon for the app bundle. self.icon = kws.get('icon') if not self.icon: # --icon not specified; use the default in the pyinstaller folder self.icon = os.path.join( os.path.dirname(os.path.dirname(__file__)), 'bootloader', 'images', 'icon-windowed.icns') else: # user gave an --icon=path. If it is relative, make it # relative to the spec file location. if not os.path.isabs(self.icon): self.icon = os.path.join(CONF['specpath'], self.icon) # ensure icon path is absolute self.icon = os.path.abspath(self.icon) Target.__init__(self) # .app bundle is created in DISTPATH. self.name = kws.get('name', None) base_name = os.path.basename(self.name) self.name = os.path.join(CONF['distpath'], base_name) self.appname = os.path.splitext(base_name)[0] self.version = kws.get("version", "0.0.0") self.toc = TOC() self.strip = False self.upx = False self.console = True self.target_arch = None self.codesign_identity = None self.entitlements_file = None # .app bundle identifier for Code Signing self.bundle_identifier = kws.get('bundle_identifier') if not self.bundle_identifier: # Fallback to appname. self.bundle_identifier = self.appname self.info_plist = kws.get('info_plist', None) for arg in args: if isinstance(arg, EXE): self.toc.append( (os.path.basename(arg.name), arg.name, arg.typ)) self.toc.extend(arg.dependencies) self.strip = arg.strip self.upx = arg.upx self.upx_exclude = arg.upx_exclude self.console = arg.console self.target_arch = arg.target_arch self.codesign_identity = arg.codesign_identity self.entitlements_file = arg.entitlements_file elif isinstance(arg, TOC): self.toc.extend(arg) # TOC doesn't have a strip or upx attribute, so there is no way for us to # tell which cache we should draw from. elif isinstance(arg, COLLECT): self.toc.extend(arg.toc) self.strip = arg.strip_binaries self.upx = arg.upx_binaries self.upx_exclude = arg.upx_exclude self.console = arg.console self.target_arch = arg.target_arch self.codesign_identity = arg.codesign_identity self.entitlements_file = arg.entitlements_file else: logger.info("unsupported entry %s", arg.__class__.__name__) # Now, find values for app filepath (name), app name (appname), and name # of the actual executable (exename) from the first EXECUTABLE item in # toc, which might have come from a COLLECT too (not from an EXE). for inm, name, typ in self.toc: if typ == "EXECUTABLE": self.exename = name break self.__postinit__()
def assemble(self): logger.info("Building EXE from %s", self.tocbasename) trash = [] if not os.path.exists(os.path.dirname(self.name)): os.makedirs(os.path.dirname(self.name)) exe = self.exefiles[0][1] # pathname of bootloader if not os.path.exists(exe): raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG) if is_win and (self.icon or self.versrsrc or self.resources): tmpnm = tempfile.mktemp() self._copyfile(exe, tmpnm) os.chmod(tmpnm, 0o755) if self.icon: icon.CopyIcons(tmpnm, self.icon) if self.versrsrc: versioninfo.SetVersion(tmpnm, self.versrsrc) for res in self.resources: res = res.split(",") for i in range(1, len(res)): try: res[i] = int(res[i]) except ValueError: pass resfile = res[0] restype = resname = reslang = None if len(res) > 1: restype = res[1] if len(res) > 2: resname = res[2] if len(res) > 3: reslang = res[3] try: winresource.UpdateResourcesFromResFile(tmpnm, resfile, [restype or "*"], [resname or "*"], [reslang or "*"]) except winresource.pywintypes.error as exc: if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT: logger.error("Error while updating resources in %s" " from resource file %s", tmpnm, resfile, exc_info=1) continue # Handle the case where the file contains no resources, and is # intended as a single resource to be added to the exe. if not restype or not resname: logger.error("resource type and/or name not specified") continue if "*" in (restype, resname): logger.error("no wildcards allowed for resource type " "and name when source file does not " "contain resources") continue try: winresource.UpdateResourcesFromDataFile(tmpnm, resfile, restype, [resname], [reslang or 0]) except winresource.pywintypes.error: logger.error("Error while updating resource %s %s in %s" " from data file %s", restype, resname, tmpnm, resfile, exc_info=1) trash.append(tmpnm) exe = tmpnm # NOTE: Do not look up for bootloader file in the cache because it might # get corrupted by UPX when UPX is available. See #1863 for details. if not self.append_pkg: logger.info("Copying bootloader exe to %s", self.name) self._copyfile(exe, self.name) logger.info("Copying archive to %s", self.pkgname) self._copyfile(self.pkg.name, self.pkgname) elif is_linux: self._copyfile(exe, self.name) logger.info("Appending archive to ELF section in EXE %s", self.name) retcode, stdout, stderr = exec_command_all( 'objcopy', '--add-section', 'pydata=%s' % self.pkg.name, self.name) logger.debug("objcopy returned %i", retcode) if stdout: logger.debug(stdout) if stderr: logger.debug(stderr) if retcode != 0: raise SystemError("objcopy Failure: %s" % stderr) else: # Fall back to just append on end of file logger.info("Appending archive to EXE %s", self.name) with open(self.name, 'wb') as outf: # write the bootloader data with open(exe, 'rb') as infh: shutil.copyfileobj(infh, outf, length=64*1024) # write the archive data with open(self.pkg.name, 'rb') as infh: shutil.copyfileobj(infh, outf, length=64*1024) if is_darwin: # Fix Mach-O header for codesigning on OS X. logger.info("Fixing EXE for code signing %s", self.name) import PyInstaller.utils.osx as osxutils osxutils.fix_exe_for_code_signing(self.name) os.chmod(self.name, 0o755) # get mtime for storing into the guts self.mtm = misc.mtime(self.name) for item in trash: os.remove(item) logger.info("Building EXE from %s completed successfully.", self.tocbasename)