#!/bin/bash # UniversalisOS Hypervisor — Canonical Test/Lint/Build Suite # # This script provides the canonical commands for building, testing, and # linting the UniversalisOS hypervisor across all supported architectures. # # Usage: # ./uos-check.sh [command] # # Commands: # build-all Build all architectures (armv7, aarch64, riscv) # build-armv7 Build ARMv7 (qemu-arm-virt) # build-aarch64 Build AArch64 (qemu-aarch64-virt) # build-riscv Build RISC-V (polarfire) # test Run all tests (build + boot smoke tests) # lint Run lint checks (format, static analysis) # clean Clean all build trees # help Show this help # # Exit codes: # 0 = success # 1 = build failure # 2 = test failure # 3 = lint failure set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" KERNEL_DIR="$SCRIPT_DIR" BUILD_DIR="$KERNEL_DIR/build" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[PASS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[FAIL]${NC} $1" } # Check if a command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Check required tools check_tools() { local missing=() # ARMv7 toolchain if ! command_exists arm-none-eabi-gcc; then missing+=("arm-none-eabi-gcc") fi # AArch64 toolchain if ! command_exists aarch64-linux-gnu-gcc; then missing+=("aarch64-linux-gnu-gcc") fi # RISC-V toolchain if ! command_exists riscv64-unknown-elf-gcc; then missing+=("riscv64-unknown-elf-gcc") fi # QEMU if ! command_exists qemu-system-arm; then missing+=("qemu-system-arm") fi if ! command_exists qemu-system-aarch64; then missing+=("qemu-system-aarch64") fi if ! command_exists qemu-system-riscv64; then missing+=("qemu-system-riscv64") fi if [ ${#missing[@]} -gt 0 ]; then log_warning "Missing tools: ${missing[*]}" log_warning "Some builds may fail. Install with:" log_warning " sudo dnf install gcc-arm-none-eabi gcc-aarch64-linux-gnu gcc-riscv64-unknown-elf qemu-system-arm qemu-system-aarch64 qemu-system-riscv" fi return 0 } # Build a specific architecture build_arch() { local arch=$1 local platform=$2 local name=$3 log_info "Building $name ($arch/$platform)..." cd "$KERNEL_DIR" # Clean previous build make ARCH="$arch" PLATFORM="$platform" clean >/dev/null 2>&1 || true # Build if make ARCH="$arch" PLATFORM="$platform" 2>&1 | tee "/tmp/uos-build-$arch.log"; then # Check if ELF was produced local elf="$BUILD_DIR/$arch/$platform/universalisos.elf" if [ -f "$elf" ]; then local size=$(stat -c%s "$elf" 2>/dev/null || stat -f%z "$elf" 2>/dev/null) log_success "$name built successfully ($size bytes)" return 0 else log_error "$name build succeeded but ELF not found at $elf" return 1 fi else log_error "$name build failed (see /tmp/uos-build-$arch.log)" log_warning "Note: Some builds may fail due to pre-existing issues" return 1 fi } # Build core components only (for testing individual files) build_core() { log_info "Building core components..." cd "$KERNEL_DIR" # Test compile key files local files=( "src/core/abi/uos_posix_abi.cpp" "src/core/mm.cpp" "src/core/scheduler.cpp" ) local failed=0 for file in "${files[@]}"; do if [ -f "$file" ]; then log_info "Compiling $file..." if arm-none-eabi-g++ -Iinclude -Iinclude/universalisos -Iinclude/universalisos/j_space \ -Isrc/arch/armv7/inc -Isrc/platform/qemu-arm-virt/inc -Isrc/core -Isrc/platform \ -mcpu=cortex-a15 -DARCH_ARMV7 -DARCH_ARM -DPLATFORM_QEMU_ARM_VIRT \ -Wall -Wextra -ffreestanding -O2 -fno-tree-vectorize -g -fno-exceptions -fno-rtti \ -c "$file" -o "/tmp/$(basename "$file" .cpp).o" 2>/dev/null; then log_success "$file compiles" else log_error "$file failed to compile" failed=$((failed + 1)) fi fi done if [ $failed -eq 0 ]; then log_success "All core components compile" return 0 else log_error "$failed core component(s) failed to compile" return 1 fi } # Build all architectures build_all() { log_info "=== Building all architectures ===" local failed=0 # ARMv7 if ! build_arch "armv7" "qemu-arm-virt" "ARMv7"; then failed=$((failed + 1)) fi # AArch64 if ! build_arch "aarch64" "qemu-aarch64-virt" "AArch64"; then failed=$((failed + 1)) fi # RISC-V if ! build_arch "riscv" "polarfire" "RISC-V"; then failed=$((failed + 1)) fi if [ $failed -eq 0 ]; then log_success "All architectures built successfully" return 0 else log_error "$failed architecture(s) failed to build" return 1 fi } # Boot smoke test for ARMv7 test_boot_armv7() { log_info "Running ARMv7 boot smoke test..." local elf="$BUILD_DIR/armv7/qemu-arm-virt/universalisos.elf" if [ ! -f "$elf" ]; then log_error "ARMv7 ELF not found. Run 'build-armv7' first." return 1 fi # Run QEMU with timeout, capture output local output output=$(timeout 10 qemu-system-arm -M virt -cpu cortex-a15 -m 512M \ -nographic -kernel "$elf" 2>&1 || true) # Check for expected boot messages if echo "$output" | grep -q "UniversalisOS"; then log_success "ARMv7 boot smoke test passed" return 0 else log_error "ARMv7 boot smoke test failed (no boot banner)" echo "$output" | head -20 return 1 fi } # Boot smoke test for AArch64 test_boot_aarch64() { log_info "Running AArch64 boot smoke test..." local elf="$BUILD_DIR/aarch64/qemu-aarch64-virt/universalisos.elf" if [ ! -f "$elf" ]; then log_error "AArch64 ELF not found. Run 'build-aarch64' first." return 1 fi # Run QEMU with timeout, capture output local output output=$(timeout 10 qemu-system-aarch64 -M virt,gic-version=3,virtualization=on \ -cpu cortex-a53 -m 512M -smp 4 -nographic -kernel "$elf" 2>&1 || true) # Check for expected boot messages if echo "$output" | grep -q "UniversalisOS"; then log_success "AArch64 boot smoke test passed" return 0 else log_error "AArch64 boot smoke test failed (no boot banner)" echo "$output" | head -20 return 1 fi } # Boot smoke test for RISC-V test_boot_riscv() { log_info "Running RISC-V boot smoke test..." local elf="$BUILD_DIR/riscv/polarfire/universalisos.elf" if [ ! -f "$elf" ]; then log_error "RISC-V ELF not found. Run 'build-riscv' first." return 1 fi # Run QEMU with timeout, capture output local output output=$(timeout 10 qemu-system-riscv64 -machine microchip-icicle-kit \ -smp 5 -m 2G -nographic -bios none -kernel "$elf" 2>&1 || true) # Check for expected boot messages if echo "$output" | grep -q "UniversalisOS\|Partition"; then log_success "RISC-V boot smoke test passed" return 0 else log_error "RISC-V boot smoke test failed (no boot banner)" echo "$output" | head -20 return 1 fi } # Run all tests run_tests() { log_info "=== Running all tests ===" local failed=0 # Build first if ! build_all; then log_error "Build failed, skipping tests" return 1 fi # Boot smoke tests if ! test_boot_armv7; then failed=$((failed + 1)) fi if ! test_boot_aarch64; then failed=$((failed + 1)) fi if ! test_boot_riscv; then failed=$((failed + 1)) fi if [ $failed -eq 0 ]; then log_success "All tests passed" return 0 else log_error "$failed test(s) failed" return 2 fi } # Lint checks run_lint() { log_info "=== Running lint checks ===" local failed=0 # Check for TODO/FIXME/HACK comments log_info "Checking for TODO/FIXME/HACK comments..." local todo_count todo_count=$(grep -r "TODO\|FIXME\|HACK" "$KERNEL_DIR/src" --include="*.c" --include="*.cpp" --include="*.h" 2>/dev/null | wc -l) if [ "$todo_count" -gt 0 ]; then log_warning "Found $todo_count TODO/FIXME/HACK comments" else log_success "No TODO/FIXME/HACK comments found" fi # Check for trailing whitespace log_info "Checking for trailing whitespace..." local ws_count ws_count=$(grep -r " $" "$KERNEL_DIR/src" --include="*.c" --include="*.cpp" --include="*.h" 2>/dev/null | wc -l) if [ "$ws_count" -gt 0 ]; then log_warning "Found $ws_count lines with trailing whitespace" else log_success "No trailing whitespace found" fi # Check for tabs (should use spaces) log_info "Checking for tab characters..." local tab_count tab_count=$(grep -r $'\t' "$KERNEL_DIR/src" --include="*.c" --include="*.cpp" --include="*.h" 2>/dev/null | wc -l) if [ "$tab_count" -gt 0 ]; then log_warning "Found $tab_count lines with tab characters" else log_success "No tab characters found" fi # Check for long lines (>120 chars) log_info "Checking for long lines (>120 chars)..." local long_count long_count=$(find "$KERNEL_DIR/src" -name "*.c" -o -name "*.cpp" -o -name "*.h" 2>/dev/null | xargs awk 'length > 120 {count++} END {print count+0}' 2>/dev/null || echo "0") if [ "$long_count" -gt 0 ]; then log_warning "Found $long_count lines longer than 120 characters" else log_success "No long lines found" fi # Check for UOS-STUB markers log_info "Checking for UOS-STUB markers..." local stub_count stub_count=$(grep -r "UOS-STUB" "$KERNEL_DIR/src" --include="*.c" --include="*.cpp" --include="*.h" 2>/dev/null | wc -l) if [ "$stub_count" -gt 0 ]; then log_warning "Found $stub_count UOS-STUB markers (see docs/STUB_REGISTRY.md)" else log_success "No UOS-STUB markers found" fi # Check for unmarked stubs log_info "Checking for unmarked stubs..." local unmarked_count unmarked_count=$(grep -r "not implemented\|stub" "$KERNEL_DIR/src" --include="*.c" --include="*.cpp" --include="*.h" 2>/dev/null | grep -v "UOS-STUB" | wc -l) if [ "$unmarked_count" -gt 0 ]; then log_warning "Found $unmarked_count unmarked stubs (should use UOS-STUB marker)" else log_success "No unmarked stubs found" fi if [ $failed -eq 0 ]; then log_success "Lint checks completed" return 0 else log_error "$failed lint check(s) failed" return 3 fi } # Clean all build trees clean_all() { log_info "Cleaning all build trees..." cd "$KERNEL_DIR" make clean-all log_success "All build trees cleaned" } # Show help show_help() { cat << EOF UniversalisOS Hypervisor — Canonical Test/Lint/Build Suite Usage: $0 [command] Commands: build-core Build core components only (for testing individual files) build-all Build all architectures (armv7, aarch64, riscv) build-armv7 Build ARMv7 (qemu-arm-virt) build-aarch64 Build AArch64 (qemu-aarch64-virt) build-riscv Build RISC-V (polarfire) test Run all tests (build + boot smoke tests) lint Run lint checks (format, static analysis) clean Clean all build trees help Show this help Examples: $0 build-all # Build all architectures $0 test # Build and run boot smoke tests $0 lint # Run lint checks $0 clean # Clean all build trees Exit codes: 0 = success 1 = build failure 2 = test failure 3 = lint failure EOF } # Main main() { local command="${1:-help}" case "$command" in build-core) check_tools build_core ;; build-all) check_tools build_all ;; build-armv7) check_tools build_arch "armv7" "qemu-arm-virt" "ARMv7" ;; build-aarch64) check_tools build_arch "aarch64" "qemu-aarch64-virt" "AArch64" ;; build-riscv) check_tools build_arch "riscv" "polarfire" "RISC-V" ;; test) check_tools run_tests ;; lint) run_lint ;; clean) clean_all ;; help|--help|-h) show_help ;; *) log_error "Unknown command: $command" show_help exit 1 ;; esac } main "$@"