#!/usr/bin/env python3 """ Zephyr build helper for app_i_core_link. Usage: python zbuild.py dr2501a_g070rb python zbuild.py dr2501a_g070rb -p auto python zbuild.py -p always (auto-detect board from west.yml) python zbuild.py dr2501a_g070rb -T sample.helloworld Options: board Board name (optional, auto-detected from west.yml if omitted) -p PURSE Pristine option: auto / always / never -t TARGET CMake target to run after build, e.g. test / flash -T TEST Test name/sample identifier (e.g. sample.helloworld) Steps: 1. west topdir → find Zephyr workspace root 2. west config --local manifest.file /west.yml 3. west build [-p PURSE] -b BOARD [-t TARGET] [-T TEST] """ import argparse import os import re import subprocess import sys def get_script_dir() -> str: """Absolute path to the directory containing this script.""" return os.path.dirname(os.path.abspath(__file__)) def run(cmd: list[str], cwd: str | None = None) -> str: """Run a command and return stdout. Exit on failure.""" proc = subprocess.run(cmd, capture_output=True, text=True, cwd=cwd) if proc.returncode != 0: print(f" ✗ {' '.join(cmd)}", file=sys.stderr) print(f" {proc.stderr.strip()}", file=sys.stderr) sys.exit(proc.returncode) return proc.stdout.strip() def discover_boards(manifest_path: str) -> list[str]: """Parse west.yml and return board names whose path starts with 'boards/'.""" if not os.path.exists(manifest_path): return [] with open(manifest_path) as f: content = f.read() # Match entries like: # - name: # path: boards/ boards = re.findall(r"name:\s*(\S+)\s*\n\s+path:\s*boards/\S+", content) return boards def main(): parser = argparse.ArgumentParser( description="Zephyr build helper for app_i_core_link" ) parser.add_argument( "board", nargs="?", default=None, help="Board name (optional, auto-detected from west.yml if omitted)", ) parser.add_argument( "-p", "--pristine", default=None, choices=["auto", "always", "never"], help="Pristine build option", ) parser.add_argument( "-t", "--target", default=None, help="CMake target to run after build (e.g. test, flash)", ) parser.add_argument( "-T", "--test", default=None, dest="test_id", help="Test name / sample identifier (e.g. sample.helloworld)", ) parser.add_argument( "--update", action="store_true", help="Run west update after setting manifest", ) args = parser.parse_args() # ── 0. Auto-detect board from west.yml when not specified ─── if args.board is None: script_dir = get_script_dir() manifest = os.path.join(script_dir, "west.yml") boards = discover_boards(manifest) if len(boards) == 0: print( " ✗ No board specified and no board found in west.yml " "(no entry with path: boards/...)", file=sys.stderr, ) sys.exit(1) elif len(boards) == 1: args.board = boards[0] print(f" → Auto-detected board: {args.board}") else: print( " ✗ No board specified. Multiple boards found in west.yml:", ", ".join(boards), "\n Please specify one explicitly.", file=sys.stderr, ) sys.exit(1) script_dir = get_script_dir() manifest = os.path.join(script_dir, "west.yml") print(f" script dir : {script_dir}") print(f" board : {args.board}") print(f" pristine : {args.pristine or '(none)'}") print(f" target : {args.target or '(none)'}") print(f" test : {args.test_id or '(none)'}") print(f" update : {'yes' if args.update else 'no'}") # ── 1. Find workspace root ─────────────────────────────── print("\n [1/3] Finding west workspace root...") topdir = run(["west", "topdir"]) print(f" → {topdir}") # ── 2. Set local manifest ──────────────────────────────── print("\n [2/3] Setting local manifest...") if not os.path.exists(manifest): print(f" ✗ manifest not found: {manifest}", file=sys.stderr) sys.exit(1) run(["west", "config", "--local", "manifest.file", manifest], cwd=topdir) print(f" → manifest.file = {manifest}") # ── 2.5. Run west update (optional) ─────────────────────── if args.update: print("\n [2.5/3] Running west update...") run(["west", "update", "--fetch", "smart"], cwd=topdir) print(" → update done") # ── 3. Run west build ───────────────────────────────────── print("\n [3/3] Running west build...") build_cmd = ["west", "build"] if args.pristine: build_cmd += ["-p", args.pristine] build_cmd += ["-b", args.board] if args.target: build_cmd += ["-t", args.target] if args.test_id: build_cmd += ["-T", args.test_id] build_cmd += [script_dir] print(f" $ {' '.join(build_cmd)}") proc = subprocess.run(build_cmd, cwd=topdir) if proc.returncode != 0: print(f"\n ✗ Build failed (exit code {proc.returncode})") sys.exit(proc.returncode) print("\n ✓ Build succeeded") if __name__ == "__main__": main()