#!/usr/bin/env python3 """Dieselben TBL-Bytes auf jedem Releaseziel: Linken und echte Standalone-Ausführung.""" import argparse import hashlib import json import os from pathlib import Path import platform import shutil import subprocess import tempfile DIGEST = '5d25c2f8c95ae535e55a6c84c1ddd0d964358863f4f3c780c50ac4a2eb3594df' TARGETS = { ('Windows', 'AMD64'): 'x86_64-pc-windows-msvc', ('Darwin', 'arm64'): 'aarch64-apple-darwin', ('Linux', 'x86_64'): 'x86_64-unknown-linux-gnu', ('Linux', 'aarch64'): 'aarch64-unknown-linux-gnu', } SOURCE = '''COMMON SHARED shared& OPEN "round.txt" FOR APPEND AS #1 old&=LOF(1) PRINT #1, "x" CLOSE #1 DIM a&(WIDTH) DIM r AS Record n&=3 CALL Work(a&(),r,n&) PRINT a&(1);r.value;n&;shared& PRINT r.text IF old&=0 THEN RUN END ''' EXPECTED = b' 1 \n 7 3 9 1 \nTB \n' # RUN setzt auch den Textbildschirm zurück. def run(args, cwd, env): result = subprocess.run([str(a) for a in args], cwd=cwd, env=env, input=b'', capture_output=True, timeout=30) assert result.returncode == 0, (result.args, result.returncode, result.stdout, result.stderr) return result.stdout.replace(b'\r\n', b'\n') def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--bin-dir', type=Path, default=Path('target/release')) parser.add_argument('--library', type=Path, default=Path(__file__).resolve().parents[1] / 'libraries/portable.tbl') args = parser.parse_args() target = TARGETS.get((platform.system(), platform.machine())) assert target, f'Kein Releaseziel: {platform.system()} {platform.machine()}' digest = hashlib.sha256(args.library.read_bytes()).hexdigest() assert digest == DIGEST, f'Gemeinsames TBL-Artefakt verändert: {digest}' binaries = args.bin_dir.resolve() suffix = '.exe' if platform.system() == 'Windows' else '' compiler = binaries / ('tbc' + suffix) template_tool = binaries / ('tb-template' + suffix) env = dict(os.environ, PATH='') with tempfile.TemporaryDirectory(prefix='tb-library-') as work: root = Path(work) reference, clean = root / 'reference', root / 'clean' reference.mkdir() clean.mkdir() library = root / 'library.tbl' shutil.copyfile(args.library, library) template = root / ('runtime' + suffix) shutil.copy2(binaries / ('tbrt' + suffix), template) run([template_tool, template, target], root, env) source = root / 'consumer.bas' source.write_text(SOURCE, encoding='utf-8') linked = root / 'consumer.tbc' run([compiler, 'link', source, library, '-o', linked], root, env) expected = run([compiler, 'run', linked], reference, env) assert expected == EXPECTED, expected executable = clean / ('consumer' + suffix) run([compiler, 'link', source, library, '--exe', '--target', target, '--template', template, '-o', executable], root, env) source.unlink() library.unlink() linked.unlink() template.unlink() Path(str(template) + '.meta').unlink() actual = run([executable], clean, env) assert actual == EXPECTED, actual assert (reference / 'round.txt').read_bytes() == (clean / 'round.txt').read_bytes() assert (clean / 'round.txt').read_text().splitlines() == ['x', 'x'] assert sorted(p.name for p in clean.iterdir()) == ['consumer' + suffix, 'round.txt'] print(json.dumps({'target': target, 'tbl_sha256': digest, 'native_execution': True, 'source_free': True, 'run_reset': True, 'output': actual.decode()}, ensure_ascii=False)) if __name__ == '__main__': main()