68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
"""Exercise the linker repair against a real native extension on Linux."""
|
|
from __future__ import annotations
|
|
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import sysconfig
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from scripts.termux import python_linkage
|
|
|
|
|
|
@pytest.mark.platforms("linux")
|
|
def test_python_symbols_gain_an_explicit_library_dependency(tmp_path):
|
|
import _cffi_backend
|
|
|
|
library = Path(sysconfig.get_config_var("LIBDIR")) / sysconfig.get_config_var("LDLIBRARY")
|
|
extension = tmp_path / Path(_cffi_backend.__file__).name
|
|
shutil.copy2(_cffi_backend.__file__, extension)
|
|
original = subprocess.check_output(["patchelf", "--print-needed", str(extension)], text=True).splitlines()
|
|
for name in original:
|
|
if name.startswith("libpython"):
|
|
subprocess.run(["patchelf", "--remove-needed", name, str(extension)], check=True)
|
|
assert python_linkage.link_extension(extension, library)
|
|
needed = subprocess.check_output(["patchelf", "--print-needed", str(extension)], text=True).splitlines()
|
|
soname = subprocess.check_output(["patchelf", "--print-soname", str(library)], text=True).strip()
|
|
assert soname in needed
|
|
assert not python_linkage.link_extension(extension, library), "a second pass must not edit a correct extension"
|
|
subprocess.run(
|
|
[sys.executable, "-c", "import _cffi_backend; print(_cffi_backend.__file__)"],
|
|
cwd=tmp_path, check=True,
|
|
)
|
|
|
|
|
|
def test_wheel_rewrite_regenerates_record_for_changed_member(tmp_path):
|
|
import base64
|
|
import csv
|
|
import hashlib
|
|
import io
|
|
import zipfile
|
|
|
|
wheel = tmp_path / "sample-1.0-cp311-cp311-linux_aarch64.whl"
|
|
record = "sample-1.0.dist-info/RECORD"
|
|
with zipfile.ZipFile(wheel, "w") as archive:
|
|
archive.writestr("sample/_native.so", b"unrepaired native bytes")
|
|
archive.writestr("sample/__init__.py", b"")
|
|
archive.writestr("sample-1.0.dist-info/WHEEL", "Wheel-Version: 1.0\nTag: cp311-cp311-linux_aarch64\n")
|
|
archive.writestr(record, "")
|
|
|
|
def repair(path, library):
|
|
assert library == tmp_path / "libpython.so"
|
|
path.write_bytes(b"repaired native bytes")
|
|
return True
|
|
|
|
python_linkage.repair_wheel(wheel, tmp_path / "libpython.so", repair=repair)
|
|
with zipfile.ZipFile(wheel) as archive:
|
|
assert archive.read("sample/_native.so") == b"repaired native bytes"
|
|
rows = {r[0]: r[1:] for r in csv.reader(io.StringIO(archive.read(record).decode()))}
|
|
for name in archive.namelist():
|
|
if name == record:
|
|
assert rows[name] == ["", ""]
|
|
continue
|
|
data = archive.read(name)
|
|
digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode()
|
|
assert rows[name] == ["sha256=" + digest, str(len(data))]
|