tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

portable_fixture.py (2052B)


      1 #!/usr/bin/env python3
      2 """Build a relocated Python/glibc test OS, separate from the distributed library."""
      3 import argparse
      4 import shutil
      5 import subprocess
      6 from pathlib import Path
      7 from portable import dependencies
      8 
      9 def is_elf(path):
     10     if not path.is_file():
     11         return False
     12     with path.open('rb') as stream:
     13         return stream.read(4) == b'\x7fELF'
     14 
     15 
     16 p = argparse.ArgumentParser(description=__doc__)
     17 p.add_argument('--python', type=Path, required=True)
     18 p.add_argument('--stdlib', type=Path, required=True)
     19 p.add_argument('--loader', type=Path, required=True)
     20 p.add_argument('--output', type=Path, required=True)
     21 a = p.parse_args()
     22 root = a.output
     23 (root/'python/bin').mkdir(parents=True)
     24 (root/'system/lib').mkdir(parents=True)
     25 shutil.copytree(a.stdlib, root/'python/lib'/a.stdlib.name,
     26                 ignore=shutil.ignore_patterns('__pycache__', 'site-packages', 'test', 'tests', 'config-*'))
     27 shutil.copyfile(a.python.resolve(), root/'python/bin/python3')
     28 elfs = [path for path in (root/'python').rglob('*')
     29         if is_elf(path)]
     30 native = {}
     31 for path in elfs:
     32     path.chmod(0o755)
     33     for name, original in dependencies(path).items():
     34         if name in native and native[name] != original:
     35             raise RuntimeError(f'ambiguous test-system dependency: {name}')
     36         native[name] = original
     37 # Supply the test OS's full glibc surface, including librt used by the RTS.
     38 for path in a.loader.parent.glob('*.so*'):
     39     if is_elf(path):
     40         native[path.name] = path.resolve()
     41 native[a.loader.name] = a.loader
     42 for name, original in native.items():
     43     target = root/'system/lib'/name
     44     shutil.copyfile(original, target)
     45     elfs.append(target)
     46 for path in elfs:
     47     path.chmod(0o755)
     48     # Preserve the loader's own ELF layout; only loaded objects need RUNPATH.
     49     if path.name != a.loader.name:
     50         subprocess.run(['patchelf', '--set-rpath', '/system/lib', str(path)], check=True)
     51 subprocess.run(['patchelf', '--set-interpreter', '/system/lib/'+a.loader.name,
     52                 str(root/'python/bin/python3')], check=True)