#!/usr/bin/env python3 """Build the private X4 adapter through a versioned Linux build artifact. Input SDK bytes must already satisfy sdk-lock.json. No network, dependency installation, SDK execution, device access or mutation of system directories. """ import argparse import hashlib import json import os import platform import shutil import subprocess import tempfile from pathlib import Path from fetch_sdk import LOCK, ROOT, inspect_elf, verify def build(sdk, destination): if platform.system() != "Linux" or platform.machine() != "x86_64": raise RuntimeError("Native compilation requires Linux x86_64 and the declared compiler") lock = json.loads(LOCK.read_text()) verify(sdk, lock) if destination.exists(): raise ValueError("Do not replace a previously built adapter") destination.parent.mkdir(parents=True, exist_ok=True) stage = Path(tempfile.mkdtemp(prefix=".native-", dir=destination.parent)) env = {"PATH": "/usr/bin:/bin", "LANG": "C.UTF-8", "SOURCE_DATE_EPOCH": "1788825600"} try: target = stage / "libmissioncore_x4.so" subprocess.run( [ "/usr/bin/g++", "-std=c++17", "-O2", "-Wall", "-Wextra", "-Werror", "-fPIC", "-fvisibility=hidden", "-shared", "-pthread", "-ffile-prefix-map=" + str(ROOT) + "=/source/insta360-x4", "-I", str(sdk / "include"), str(ROOT / "native/bridge.cpp"), "-L", str(sdk / "lib"), "-Wl,-z,defs,-z,relro,-z,now", "-Wl,-rpath,$ORIGIN", "-lCameraSDK", "-o", str(target), ], env=env, check=True, timeout=120, ) elf = inspect_elf(target) if "libCameraSDK.so" not in elf["needed"]: raise ValueError("Built adapter does not depend on the admitted SDK") report = { "schema": "missioncore.insta360.native-build/v1", "abi": 1, "sdk_lock_sha256": hashlib.sha256(LOCK.read_bytes()).hexdigest(), "source": { p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted((ROOT / "native").glob("*")) if p.is_file() }, "compiler": subprocess.check_output( ["/usr/bin/g++", "--version"], env=env, text=True ).splitlines()[0], "binary": { "name": target.name, "bytes": target.stat().st_size, "sha256": hashlib.sha256(target.read_bytes()).hexdigest(), }, "elf": elf, "sdk_executed": False, "hardware_tested": False, } target.chmod(0o644) (stage / "provenance.json").write_text(json.dumps(report, indent=2) + "\n") os.rename(stage, destination) return report finally: if stage.exists(): shutil.rmtree(stage) if __name__ == "__main__": parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--sdk", type=Path, default=ROOT / "build/sdk") parser.add_argument("--output", type=Path, default=ROOT / "build/native") args = parser.parse_args() print(json.dumps(build(args.sdk.resolve(), args.output.resolve()), indent=2))