aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/scripts/depfixer.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/scripts/depfixer.py')
-rw-r--r--mesonbuild/scripts/depfixer.py78
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)