""" The doit file. Because makefiles are old and hard to read. Can't promise this will be more readable, but at least it wont be old :) """ import os from enum import Enum from types import SimpleNamespace from typing import Iterator from pathlib import Path from doit.tools import Interactive class BoardTarget(Enum): RPI3B = 1 RPI4 = 2 ## Target BOARD_TARGET = BoardTarget.RPI3B ## Common constants consts = SimpleNamespace() consts.WORK_DIR = os.getcwd() # Rust equivalent to -Werror consts.RUSTC_FLAGS = "-D warnings " # Force documentation consts.RUSTC_FLAGS += "-D missing_docs" consts.CARGO_COMPILE_FLAGS = "--release" if BOARD_TARGET == BoardTarget.RPI3B: consts.TARGET = "aarch64-unknown-none-softfloat" consts.KERNEL_NAME = "kernel8.img" consts.QEMU_CMD = "qemu-system-aarch64" consts.QEMU_MACHINE = "raspi3b" consts.QEMU_ARGS = "-serial stdio -display none" consts.OBJDUMP_CMD = "aarch64-none-elf-objdump" consts.OBJDUMP_ARGS = "-D" consts.NM_CMD = "aarch64-none-elf-nm" consts.READELF_CMD = "aarch64-none-elf-readelf" consts.LD_SCRIPT_PATH = f"{consts.WORK_DIR}/linker.ld" consts.RUSTC_FLAGS = f"-C target-cpu=cortex-a53 -C link-arg=--script={consts.LD_SCRIPT_PATH} {consts.RUSTC_FLAGS}" consts.CARGO_COMPILE_FLAGS = f"--features target_rpi3 {consts.CARGO_COMPILE_FLAGS}" elif BOARD_TARGET == BoardTarget.RPI4: consts.TARGET = "aarch64-unknown-none-softfloat" consts.KERNEL_NAME = "kernel8.img" consts.QEMU_CMD = "qemu-system-aarch64" consts.QEMU_MACHINE = None consts.QEMU_ARGS = "-serial stdio -display none" consts.OBJDUMP_CMD = "aarch64-none-elf-objdump" consts.OBJDUMP_ARGS = "-D" consts.NM_CMD = "aarch64-none-elf-nm" consts.READELF_CMD = "aarch64-none-elf-readelf" consts.LD_SCRIPT_PATH = f"{consts.WORK_DIR}/linker.ld" consts.RUSTC_FLAGS = f"-C target-cpu=cortex-a72 -C link-arg=--script={consts.LD_SCRIPT_PATH} {consts.RUSTC_FLAGS}" consts.CARGO_COMPILE_FLAGS = f"--features target_rpi4 {consts.CARGO_COMPILE_FLAGS}" DOIT_CONFIG = { 'default_tasks': ['build'], } def get_rust_files() -> Iterator[str]: """ Get a list of the rust source files. """ return map(lambda p: str(p.resolve()), Path('./src').glob('**/*.rs')) def get_asm_files() -> Iterator[str]: """ Get a list of the assembly source files. """ return map(lambda p: str(p.resolve()), Path('./src').glob('**/*.s')) def get_build_dep() -> list[str]: """ Get a list of the files impacting the binary. """ # TODO: add dodo.py to the list? return [ consts.LD_SCRIPT_PATH, *get_rust_files(), *get_asm_files(), ] def task_install_dep(): """ Install some required tools. """ return { 'actions': [ 'cargo install cargo-binutils', f'rustup target add {consts.TARGET}', 'rustup component add llvm-tools-preview', ], } def task_check(): """ Run a compiler check on the code. """ task = { 'file_dep': get_build_dep(), 'actions': [f'RUSTFLAGS="{consts.RUSTC_FLAGS}" cargo check --target={consts.TARGET} {consts.CARGO_COMPILE_FLAGS}'], } print(task) return task def task_compile(): """ Compile the sources. """ task = { 'file_dep': get_build_dep(), 'targets': [f'{consts.WORK_DIR}/target/{consts.TARGET}/release/kernel'], 'actions': [f'RUSTFLAGS="{consts.RUSTC_FLAGS}" cargo rustc --target={consts.TARGET} {consts.CARGO_COMPILE_FLAGS}'], 'clean': [f'cargo clean'] } print(task) return task def task_build(): """ Strip the binary from ELF format to raw binary. """ return { 'file_dep': [f'{consts.WORK_DIR}/target/{consts.TARGET}/release/kernel'], 'targets': [f'{consts.WORK_DIR}/consts.KERNEL_NAME'], 'actions': [ f'rust-objcopy --strip-all -O binary {consts.WORK_DIR}/target/{consts.TARGET}/release/kernel {consts.WORK_DIR}/{consts.KERNEL_NAME}', ], 'clean': True, } def task_qemu(): """ Run the kernel in qemu. """ if consts.QEMU_MACHINE is None: raise Exception("qemu does not support emulation for this board yet") r = { 'file_dep': [f'{consts.WORK_DIR}/{consts.KERNEL_NAME}'], 'uptodate': [False], # Always run the cmd 'actions': [Interactive(f'{consts.QEMU_CMD} -M {consts.QEMU_MACHINE} {consts.QEMU_ARGS} -kernel {consts.KERNEL_NAME}')], } print(r) return r def task_objdump(): """ Inspect the ELF binary file. """ r = { 'file_dep': [f'{consts.WORK_DIR}/target/{consts.TARGET}/release/kernel'], 'uptodate': [False], # Always run the cmd 'actions': [Interactive(f'{consts.OBJDUMP_CMD} {consts.OBJDUMP_ARGS} {consts.WORK_DIR}/target/{consts.TARGET}/release/kernel')] } print(r) return r