diff options
Diffstat (limited to 'mesonbuild/scripts/depfixer.py')
-rw-r--r-- | mesonbuild/scripts/depfixer.py | 78 |
1 files changed, 42 insertions, 36 deletions
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index f927693..a64caca 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -15,6 +15,7 @@ import sys, struct import shutil, subprocess +import typing as T from ..mesonlib import OrderedSet @@ -30,7 +31,7 @@ DT_MIPS_RLD_MAP_REL = 1879048245 INSTALL_NAME_TOOL = False class DataSizes: - def __init__(self, ptrsize, is_le): + def __init__(self, ptrsize: int, is_le: bool) -> None: if is_le: p = '<' else: @@ -57,7 +58,7 @@ class DataSizes: self.OffSize = 4 class DynamicEntry(DataSizes): - def __init__(self, ifile, ptrsize, is_le): + def __init__(self, ifile: T.BinaryIO, ptrsize: int, is_le: bool) -> None: super().__init__(ptrsize, is_le) self.ptrsize = ptrsize if ptrsize == 64: @@ -67,7 +68,7 @@ class DynamicEntry(DataSizes): self.d_tag = struct.unpack(self.Sword, ifile.read(self.SwordSize))[0] self.val = struct.unpack(self.Word, ifile.read(self.WordSize))[0] - def write(self, ofile): + def write(self, ofile: T.BinaryIO) -> None: if self.ptrsize == 64: ofile.write(struct.pack(self.Sxword, self.d_tag)) ofile.write(struct.pack(self.XWord, self.val)) @@ -76,7 +77,7 @@ class DynamicEntry(DataSizes): ofile.write(struct.pack(self.Word, self.val)) class SectionHeader(DataSizes): - def __init__(self, ifile, ptrsize, is_le): + def __init__(self, ifile: T.BinaryIO, ptrsize: int, is_le: bool) -> None: super().__init__(ptrsize, is_le) if ptrsize == 64: is_64 = True @@ -116,10 +117,12 @@ class SectionHeader(DataSizes): self.sh_entsize = struct.unpack(self.Word, ifile.read(self.WordSize))[0] class Elf(DataSizes): - def __init__(self, bfile, verbose=True): + def __init__(self, bfile: str, verbose: bool = True) -> None: self.bfile = bfile self.verbose = verbose self.bf = open(bfile, 'r+b') + self.sections = [] # type: T.List[SectionHeader] + self.dynamic = [] # type: T.List[DynamicEntry] try: (self.ptrsize, self.is_le) = self.detect_elf_type() super().__init__(self.ptrsize, self.is_le) @@ -130,18 +133,18 @@ class Elf(DataSizes): self.bf.close() raise - def __enter__(self): + def __enter__(self) -> 'Elf': return self - def __del__(self): + def __del__(self) -> None: if self.bf: self.bf.close() - def __exit__(self, exc_type, exc_value, traceback): + def __exit__(self, exc_type: T.Any, exc_value: T.Any, traceback: T.Any) -> None: self.bf.close() self.bf = None - def detect_elf_type(self): + def detect_elf_type(self) -> T.Tuple[int, bool]: data = self.bf.read(6) if data[1:4] != b'ELF': # This script gets called to non-elf targets too @@ -163,7 +166,7 @@ class Elf(DataSizes): sys.exit('File "%s" has unknown ELF endianness.' % self.bfile) return ptrsize, is_le - def parse_header(self): + def parse_header(self) -> None: self.bf.seek(0) self.e_ident = struct.unpack('16s', self.bf.read(16))[0] self.e_type = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] @@ -180,13 +183,12 @@ class Elf(DataSizes): self.e_shnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_shstrndx = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] - def parse_sections(self): + def parse_sections(self) -> None: self.bf.seek(self.e_shoff) - self.sections = [] for _ in range(self.e_shnum): self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le)) - def read_str(self): + def read_str(self) -> bytes: arr = [] x = self.bf.read(1) while x != b'\0': @@ -196,17 +198,17 @@ class Elf(DataSizes): raise RuntimeError('Tried to read past the end of the file') return b''.join(arr) - def find_section(self, target_name): + def find_section(self, target_name: bytes) -> T.Optional[SectionHeader]: section_names = self.sections[self.e_shstrndx] for i in self.sections: self.bf.seek(section_names.sh_offset + i.sh_name) name = self.read_str() if name == target_name: return i + return None - def parse_dynamic(self): + def parse_dynamic(self) -> None: sec = self.find_section(b'.dynamic') - self.dynamic = [] if sec is None: return self.bf.seek(sec.sh_offset) @@ -216,14 +218,14 @@ class Elf(DataSizes): if e.d_tag == 0: break - def print_section_names(self): + def print_section_names(self) -> None: section_names = self.sections[self.e_shstrndx] for i in self.sections: self.bf.seek(section_names.sh_offset + i.sh_name) name = self.read_str() print(name.decode()) - def print_soname(self): + def print_soname(self) -> None: soname = None strtab = None for i in self.dynamic: @@ -237,14 +239,16 @@ class Elf(DataSizes): self.bf.seek(strtab.val + soname.val) print(self.read_str()) - def get_entry_offset(self, entrynum): + def get_entry_offset(self, entrynum: int) -> T.Optional[int]: sec = self.find_section(b'.dynstr') for i in self.dynamic: if i.d_tag == entrynum: - return sec.sh_offset + i.val + res = sec.sh_offset + i.val + assert isinstance(res, int) + return res return None - def print_rpath(self): + def print_rpath(self) -> None: offset = self.get_entry_offset(DT_RPATH) if offset is None: print("This file does not have an rpath.") @@ -252,7 +256,7 @@ class Elf(DataSizes): self.bf.seek(offset) print(self.read_str()) - def print_runpath(self): + def print_runpath(self) -> None: offset = self.get_entry_offset(DT_RUNPATH) if offset is None: print("This file does not have a runpath.") @@ -260,7 +264,7 @@ class Elf(DataSizes): self.bf.seek(offset) print(self.read_str()) - def print_deps(self): + def print_deps(self) -> None: sec = self.find_section(b'.dynstr') deps = [] for i in self.dynamic: @@ -272,7 +276,7 @@ class Elf(DataSizes): name = self.read_str() print(name) - def fix_deps(self, prefix): + def fix_deps(self, prefix: bytes) -> None: sec = self.find_section(b'.dynstr') deps = [] for i in self.dynamic: @@ -290,15 +294,13 @@ class Elf(DataSizes): self.bf.seek(offset) self.bf.write(newname) - def fix_rpath(self, rpath_dirs_to_remove, new_rpath): + def fix_rpath(self, rpath_dirs_to_remove: T.List[bytes], new_rpath: bytes) -> None: # The path to search for can be either rpath or runpath. # Fix both of them to be sure. self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RPATH) self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RUNPATH) - def fix_rpathtype_entry(self, rpath_dirs_to_remove, new_rpath, entrynum): - if isinstance(new_rpath, str): - new_rpath = new_rpath.encode('utf8') + def fix_rpathtype_entry(self, rpath_dirs_to_remove: T.List[bytes], new_rpath: bytes, entrynum: int) -> None: rp_off = self.get_entry_offset(entrynum) if rp_off is None: if self.verbose: @@ -326,7 +328,7 @@ class Elf(DataSizes): new_rpath = b':'.join(new_rpaths) if len(old_rpath) < len(new_rpath): - msg = "New rpath must not be longer than the old one.\n Old: {}\n New: {}".format(old_rpath, new_rpath) + msg = "New rpath must not be longer than the old one.\n Old: {!r}\n New: {!r}".format(old_rpath, new_rpath) sys.exit(msg) # The linker does read-only string deduplication. If there is a # string that shares a suffix with the rpath, they might get @@ -343,7 +345,7 @@ class Elf(DataSizes): self.bf.write(new_rpath) self.bf.write(b'\0') - def remove_rpath_entry(self, entrynum): + def remove_rpath_entry(self, entrynum: int) -> None: sec = self.find_section(b'.dynamic') if sec is None: return None @@ -363,7 +365,7 @@ class Elf(DataSizes): entry.write(self.bf) return None -def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True): +def fix_elf(fname: str, rpath_dirs_to_remove: T.List[bytes], new_rpath: T.Optional[bytes], verbose: bool = True) -> None: with Elf(fname, verbose) as e: if new_rpath is None: e.print_rpath() @@ -371,7 +373,7 @@ def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True): else: e.fix_rpath(rpath_dirs_to_remove, new_rpath) -def get_darwin_rpaths_to_remove(fname): +def get_darwin_rpaths_to_remove(fname: str) -> T.List[str]: out = subprocess.check_output(['otool', '-l', fname], universal_newlines=True, stderr=subprocess.DEVNULL) @@ -389,7 +391,7 @@ def get_darwin_rpaths_to_remove(fname): result.append(rp) return result -def fix_darwin(fname, new_rpath, final_path, install_name_mappings): +def fix_darwin(fname: str, new_rpath: str, final_path: str, install_name_mappings: T.Dict[str, str]) -> None: try: rpaths = get_darwin_rpaths_to_remove(fname) except subprocess.CalledProcessError: @@ -439,7 +441,7 @@ def fix_darwin(fname, new_rpath, final_path, install_name_mappings): except Exception as err: raise SystemExit(err) -def fix_jar(fname): +def fix_jar(fname: str) -> None: subprocess.check_call(['jar', 'xfv', fname, 'META-INF/MANIFEST.MF']) with open('META-INF/MANIFEST.MF', 'r+') as f: lines = f.readlines() @@ -450,7 +452,7 @@ def fix_jar(fname): f.truncate() subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF']) -def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_mappings, verbose=True): +def fix_rpath(fname: str, rpath_dirs_to_remove: T.List[bytes], new_rpath: T.Union[str, bytes], final_path: str, install_name_mappings: T.Dict[str, str], verbose: bool = True) -> None: global INSTALL_NAME_TOOL # Static libraries, import libraries, debug information, headers, etc # never have rpaths @@ -461,6 +463,8 @@ def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_m if fname.endswith('.jar'): fix_jar(fname) return + if isinstance(new_rpath, str): + new_rpath = new_rpath.encode('utf8') fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose) return except SystemExit as e: @@ -473,6 +477,8 @@ def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_m # (upto 30ms), which is significant with --only-changed. For details, see: # https://github.com/mesonbuild/meson/pull/6612#discussion_r378581401 if INSTALL_NAME_TOOL is False: - INSTALL_NAME_TOOL = shutil.which('install_name_tool') + INSTALL_NAME_TOOL = bool(shutil.which('install_name_tool')) if INSTALL_NAME_TOOL: + if isinstance(new_rpath, bytes): + new_rpath = new_rpath.decode('utf8') fix_darwin(fname, new_rpath, final_path, install_name_mappings) |