universalisos/kernel/uos-check.sh

472 lines
13 KiB
Bash
Executable file

#!/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 "$@"