#!/usr/bin/env python import sys import subprocess import threading import os from datetime import datetime __FILENAME = "" MAX_JOBS = max(1, len(os.sched_getaffinity(0)) - 2) TS_VRB = 2 CWD = os.path.dirname(os.path.abspath(__file__)) BUILD_D = f"{CWD}/build" def shift(arr): if not arr: return None # or raise IndexError if you prefer return arr.pop(0) def timestamp(dt=datetime.now(), fmt="hours"): return f"{dt.hour:0>2}:{dt.minute:0>2}:{dt.second:0>2}" def run(*cmds, parallel=False, tag=None, interactive=False): threads = [] def run_single(cmd, tag): env = os.environ.copy() env["MAKE_TERMOUT"] = "true" env["MAKE_TERMERR"] = "true" start_time = datetime.now() print(f"{f"{timestamp(start_time)} | " if TS_VRB > 0 else ""}CMD: {cmd}") with subprocess.Popen( cmd, shell=True, stdout=None if interactive else subprocess.PIPE, stderr=None if interactive else subprocess.STDOUT, # text=None if interactive else True, ) as proc: if not interactive: for line in proc.stdout: dt = datetime.now() if tag: print(f"{f"{timestamp(dt)} | " if TS_VRB > 0 else ""}stdout ({tag}): ", flush=True, end='') else: print(f"{f"{timestamp(dt)} | " if TS_VRB > 0 else ""}stdout: ", flush=True, end='') sys.stdout.buffer.write(line) sys.stdout.buffer.flush() proc.wait() if proc.returncode != 0: print(f"ERROR: Command '{ cmd}' exited with code {proc.returncode}") exit(1) for i, command in enumerate(cmds): current_tag = tag if len(cmds) <= 1 else ( f"{tag}-{i}" if tag else None) if parallel: t = threading.Thread( target=run_single, args=(command, current_tag)) t.start() threads.append(t) else: run_single(command, current_tag) for t in threads: t.join() def todo(reason): print(f"ERROR: Unimplemented {reason}") exit(1) def cmd_configure(args): def cmd_help(): print(f"Usage: {__FILENAME} configure [component]") print("Components:") print(" help - Show this help") print(" kernel - The linux kernel") print(" busybox - Busybox") # $(MAKE) -C $(MAKEFILE_DIR)/kernel O=$(KERNEL_BUILD_DIR) KCONFIG_CONFIG="$(MAKEFILE_DIR)/.kernel-config" menuconfig subc = shift(args) if not subc or subc == "help": cmd_help() exit(1) elif subc == "kernel": run(f"make -C {CWD}/linux/kernel O={BUILD_D}/linux/kernel KCONFIG_CONFIG='{ CWD}/linux/.kernel-config' menuconfig", interactive=True) elif subc == "busybox": run(f"make -C {CWD}/linux/busybox O={BUILD_D}/linux/busybox KCONFIG_CONFIG='{ CWD}/linux/.busybox-config' menuconfig", interactive=True) else: print(f"ERROR: Unknown component {subc}") cmd_help() exit(1) def cmd_build(args): def cmd_help(): print(f"Usage: {__FILENAME} build [component]") print("Components:") print(" help - Show this help") print(" all - Builds everything") print(" linux - Everything bellow") print(" kernel - The linux kernel") print(" busybox - Busybox") print(" rust - Builds all of the rust components") print(" img - Rebuilds the image") def build_init(): run( f"mkdir -p {BUILD_D}/linux/kernel", f"mkdir -p {BUILD_D}/linux/busybox", parallel=True ) def build_kernel(args): run(f"make -C {CWD}/linux/kernel O={BUILD_D}/linux/kernel KCONFIG_CONFIG='{ CWD}/linux/.kernel-config' -j{MAX_JOBS}", tag="kernel") def build_busybox(args): run( f"cp {CWD}/linux/.busybox-config { BUILD_D}/linux/busybox/.config", f"make -C {CWD}/linux/busybox O={BUILD_D}/linux/busybox KCONFIG_CONFIG='{ CWD}/linux/.busybox-config' -j{MAX_JOBS}", tag="busybox" ) def build_rust(args): todo("build_rust") def build_image(args): # for the later bootable.img or whatever file todo("build_image") cmd = shift(args) if not cmd or cmd == "help": cmd_help() exit(1) elif cmd == "all": build_init() build_kernel(args) build_busybox(args) build_rust(args) build_image(args) elif cmd == "linux": build_init() build_kernel(args) build_busybox(args) elif cmd == "kernel": build_init() build_kernel(args) elif cmd == "busybox": build_init() build_busybox(args) elif cmd == "rust": build_init() build_rust(args) elif cmd == "img": build_init() build_image(args) else: print(f"ERROR: Unknown component '{cmd}'") cmd_help() exit(1) AVAILABLE_SUBCOMMANDS = { "help": help, "configure": cmd_configure, "build": cmd_build } def help(): print(f"Usage: {__FILENAME} [subcommand]") print("Subcommands:") print(" help - Show this help") print(" configure - Configure components") print(" build - Compile/build components") if __name__ == "__main__": args = sys.argv __FILENAME = shift(args) cmd = shift(args) if not cmd: help() exit(1) cmd_v = AVAILABLE_SUBCOMMANDS[cmd] if not cmd_v: print(f"ERROR: Unknown subcommand '{cmd}'") help() exit(1) (cmd_v)(args) exit(0)