diff --git a/.github/workflows/qemu-test.yml b/.github/workflows/qemu-test.yml index 3a04184..545ef16 100644 --- a/.github/workflows/qemu-test.yml +++ b/.github/workflows/qemu-test.yml @@ -25,6 +25,7 @@ jobs: sudo apt-get update sudo apt-get install -y \ build-essential \ + cmake \ nasm \ qemu-system-x86 \ ovmf \ @@ -32,19 +33,21 @@ jobs: xorriso \ imagemagick - - name: Build bootloader + - name: Configure CMake run: | - cd bootloader - make + mkdir -p build + cd build + cmake .. - - name: Build kernel + - name: Build bootloader and kernel run: | - cd kernel - make + cd build + cmake --build . - name: Create bootable image run: | - make image + cd build + cmake --build . --target image - name: Start QEMU and capture screenshot run: | @@ -56,19 +59,22 @@ jobs: XVFB_PID=$! sleep 2 - # Verify disk image exists (created by 'make image') - if [ ! -f build/metalos.img ]; then - echo "Error: build/metalos.img not found!" + # Verify disk image exists (created by cmake build) + if [ ! -f build/build/metalos.img ]; then + echo "Error: build/build/metalos.img not found!" exit 1 fi + # Create directory for logs + mkdir -p build/logs + # Start QEMU in the background with a timeout timeout 30s qemu-system-x86_64 \ -bios /usr/share/OVMF/OVMF_CODE.fd \ - -drive format=raw,file=build/metalos.img \ + -drive format=raw,file=build/build/metalos.img \ -m 512M \ -display gtk \ - -serial file:build/serial.log \ + -serial file:build/logs/serial.log \ -no-reboot & QEMU_PID=$! @@ -77,7 +83,7 @@ jobs: # Take screenshot using ImageMagick (optional - don't fail if this doesn't work) # Using subshell to prevent 'set -e' from affecting this optional step - { import -window root build/qemu-screenshot.png; } || echo "Screenshot capture failed (non-fatal)" + { import -window root build/logs/qemu-screenshot.png; } || echo "Screenshot capture failed (non-fatal)" # Gracefully stop QEMU (don't fail if already stopped) kill $QEMU_PID 2>/dev/null || true @@ -91,9 +97,9 @@ jobs: - name: Show serial output if: always() run: | - if [ -f build/serial.log ]; then + if [ -f build/logs/serial.log ]; then echo "=== QEMU Serial Output ===" - cat build/serial.log + cat build/logs/serial.log else echo "No serial output captured" fi @@ -103,7 +109,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: qemu-screenshot - path: build/qemu-screenshot.png + path: build/logs/qemu-screenshot.png if-no-files-found: warn - name: Upload serial log @@ -111,7 +117,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: serial-log - path: build/serial.log + path: build/logs/serial.log if-no-files-found: warn - name: Upload built disk image @@ -119,5 +125,5 @@ jobs: uses: actions/upload-artifact@v4 with: name: metalos-disk-image - path: build/metalos.img + path: build/build/metalos.img if-no-files-found: warn diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f18bf22..0b95a83 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,25 +24,28 @@ jobs: sudo apt-get update sudo apt-get install -y \ build-essential \ + cmake \ nasm \ qemu-system-x86 \ ovmf \ mtools \ xorriso - - name: Build bootloader + - name: Configure CMake run: | - cd bootloader - make + mkdir -p build + cd build + cmake .. - - name: Build kernel + - name: Build bootloader and kernel run: | - cd kernel - make + cd build + cmake --build . - name: Create bootable image run: | - make image + cd build + cmake --build . --target image - name: Prepare release directory run: | @@ -51,29 +54,29 @@ jobs: mkdir -p release # Copy the bootable disk image (required) - if [ -f build/metalos.img ]; then - cp build/metalos.img release/ + if [ -f build/build/metalos.img ]; then + cp build/build/metalos.img release/ echo "✓ Copied metalos.img" else - echo "Error: build/metalos.img not found!" + echo "Error: build/build/metalos.img not found!" exit 1 fi # Copy bootloader if it exists (required) - if [ -f bootloader/bootx64.efi ]; then - cp bootloader/bootx64.efi release/ + if [ -f build/bootloader/bootx64.efi ]; then + cp build/bootloader/bootx64.efi release/ echo "✓ Copied bootx64.efi" else - echo "Error: bootloader/bootx64.efi not found!" + echo "Error: build/bootloader/bootx64.efi not found!" exit 1 fi # Copy kernel if it exists (required) - if [ -f kernel/metalos.bin ]; then - cp kernel/metalos.bin release/ + if [ -f build/kernel/metalos.bin ]; then + cp build/kernel/metalos.bin release/ echo "✓ Copied metalos.bin" else - echo "Error: kernel/metalos.bin not found!" + echo "Error: build/kernel/metalos.bin not found!" exit 1 fi diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index ce59676..9c36d61 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -22,17 +22,23 @@ jobs: set -e # Exit on any error sudo apt-get update - sudo apt-get install -y build-essential + sudo apt-get install -y build-essential cmake + + - name: Configure CMake + run: | + mkdir -p build + cd build + cmake .. - name: Build unit tests run: | - cd tests - make all + cd build + cmake --build . - name: Run unit tests run: | - cd tests - make test + cd build + ctest --output-on-failure - name: Test summary if: always() diff --git a/.gitignore b/.gitignore index 3fb71e7..43bb39a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,8 @@ # Build directories build/ build-*/ +cmake-build/ +cmake-build-*/ bootloader/build/ kernel/build/ _codeql_build_dir/ diff --git a/CMakeLists.txt b/CMakeLists.txt index d152d2f..0888c4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,9 +53,9 @@ endif() # Custom target to create bootable image find_program(MFORMAT mformat) find_program(MCOPY mcopy) -find_program(MDD mdd) +find_program(MMD mmd) -if(MFORMAT AND MCOPY) +if(MFORMAT AND MCOPY AND MMD) add_custom_target(image COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/build/iso/EFI/BOOT COMMAND ${CMAKE_COMMAND} -E copy @@ -65,10 +65,10 @@ if(MFORMAT AND MCOPY) ${CMAKE_BINARY_DIR}/kernel/metalos.bin ${CMAKE_BINARY_DIR}/build/iso/ COMMAND ${CMAKE_COMMAND} -E echo "Creating disk image..." - COMMAND dd if=/dev/zero of=${CMAKE_BINARY_DIR}/build/metalos.img bs=1M count=64 2>/dev/null + COMMAND dd if=/dev/zero of=${CMAKE_BINARY_DIR}/build/metalos.img bs=1M count=64 COMMAND ${MFORMAT} -i ${CMAKE_BINARY_DIR}/build/metalos.img -F -v METALOS :: - COMMAND ${MDD} -i ${CMAKE_BINARY_DIR}/build/metalos.img ::/EFI - COMMAND ${MDD} -i ${CMAKE_BINARY_DIR}/build/metalos.img ::/EFI/BOOT + COMMAND ${MMD} -i ${CMAKE_BINARY_DIR}/build/metalos.img ::/EFI + COMMAND ${MMD} -i ${CMAKE_BINARY_DIR}/build/metalos.img ::/EFI/BOOT COMMAND ${MCOPY} -i ${CMAKE_BINARY_DIR}/build/metalos.img ${CMAKE_BINARY_DIR}/build/iso/EFI/BOOT/bootx64.efi ::/EFI/BOOT/ COMMAND ${MCOPY} -i ${CMAKE_BINARY_DIR}/build/metalos.img @@ -143,6 +143,20 @@ if(QEMU) COMMENT "Running MetalOS in QEMU with GDB server (port 1234)" VERBATIM ) + + add_custom_target(qemu-uefi-test + COMMAND ${CMAKE_COMMAND} -E echo "Testing QEMU UEFI boot (no OS image)..." + COMMAND ${CMAKE_COMMAND} -E echo "Using OVMF firmware: ${OVMF_FIRMWARE}" + COMMAND ${CMAKE_COMMAND} -E echo "This will boot to UEFI shell in nographic mode." + COMMAND ${CMAKE_COMMAND} -E echo "You should see UEFI boot messages. Press Ctrl-A then X to exit QEMU." + COMMAND ${QEMU} + -drive if=pflash,format=raw,readonly=on,file=${OVMF_FIRMWARE} + -m 512M + -nographic + -net none + COMMENT "Testing QEMU UEFI setup without OS image" + VERBATIM + ) else() message(WARNING "OVMF firmware not found - QEMU targets will not be available") endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29199d3..86eba15 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -152,9 +152,19 @@ Closes #42 Every PR should be tested in QEMU: ```bash -make clean -make all -make qemu +mkdir build && cd build +cmake .. +cmake --build . +cmake --build . --target qemu +``` + +Or if you already have a build directory: + +```bash +cd build +cmake --build . --target clean +cmake --build . +cmake --build . --target qemu ``` Verify: diff --git a/Makefile b/Makefile deleted file mode 100644 index 37c601c..0000000 --- a/Makefile +++ /dev/null @@ -1,144 +0,0 @@ -# MetalOS Main Makefile -# Builds bootloader, kernel, and creates bootable image - -.PHONY: all bootloader kernel image qemu qemu-debug qemu-gdb qemu-uefi-test test clean distclean - -all: bootloader kernel - -# Run unit tests -test: - @echo "Running unit tests..." - @cd tests && $(MAKE) test - -bootloader: - @echo "Building bootloader..." - @cd bootloader && $(MAKE) || echo "Warning: Bootloader build failed (expected during Phase 1 development)" - -kernel: - @echo "Building kernel..." - @cd kernel && $(MAKE) || echo "Warning: Kernel build failed (expected during Phase 1 development)" - -# Create bootable disk image for UEFI/QEMU -image: bootloader kernel - @chmod +x scripts/create_image.sh - @./scripts/create_image.sh - -# Run in QEMU with UEFI firmware (OVMF) -# Automatically detects OVMF path and display mode -# Set QEMU_DISPLAY=gtk or QEMU_DISPLAY=sdl to use graphical mode -QEMU_DISPLAY ?= none - -qemu: image - @echo "Starting QEMU with UEFI firmware..." - @bash -c ' \ - if [ -f /usr/share/OVMF/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/OVMF/OVMF_CODE.fd"; \ - elif [ -f /usr/share/ovmf/OVMF.fd ]; then \ - OVMF="/usr/share/ovmf/OVMF.fd"; \ - elif [ -f /usr/share/edk2-ovmf/x64/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/edk2-ovmf/x64/OVMF_CODE.fd"; \ - elif [ -f /usr/share/qemu/ovmf-x86_64.bin ]; then \ - OVMF="/usr/share/qemu/ovmf-x86_64.bin"; \ - else \ - echo "Error: OVMF UEFI firmware not found!"; \ - echo "Install with:"; \ - echo " Ubuntu/Debian: sudo apt-get install ovmf"; \ - echo " Arch Linux: sudo pacman -S edk2-ovmf"; \ - echo " Fedora: sudo dnf install edk2-ovmf"; \ - exit 1; \ - fi; \ - echo "Using OVMF firmware: $$OVMF"; \ - echo "Display mode: $(QEMU_DISPLAY) (set QEMU_DISPLAY=gtk for graphical)"; \ - qemu-system-x86_64 \ - -drive if=pflash,format=raw,readonly=on,file=$$OVMF \ - -drive format=raw,file=build/metalos.img \ - -m 512M \ - -serial stdio \ - -display $(QEMU_DISPLAY) \ - -net none \ - ' - -qemu-debug: image - @echo "Starting QEMU with debug output..." - @bash -c ' \ - if [ -f /usr/share/OVMF/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/OVMF/OVMF_CODE.fd"; \ - elif [ -f /usr/share/ovmf/OVMF.fd ]; then \ - OVMF="/usr/share/ovmf/OVMF.fd"; \ - elif [ -f /usr/share/edk2-ovmf/x64/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/edk2-ovmf/x64/OVMF_CODE.fd"; \ - else \ - echo "Error: OVMF UEFI firmware not found!"; \ - exit 1; \ - fi; \ - qemu-system-x86_64 \ - -drive if=pflash,format=raw,readonly=on,file=$$OVMF \ - -drive format=raw,file=build/metalos.img \ - -m 512M \ - -serial stdio \ - -display $(QEMU_DISPLAY) \ - -net none \ - -d int,cpu_reset \ - ' - -qemu-gdb: image - @echo "Starting QEMU with GDB server on port 1234..." - @bash -c ' \ - if [ -f /usr/share/OVMF/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/OVMF/OVMF_CODE.fd"; \ - elif [ -f /usr/share/ovmf/OVMF.fd ]; then \ - OVMF="/usr/share/ovmf/OVMF.fd"; \ - elif [ -f /usr/share/edk2-ovmf/x64/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/edk2-ovmf/x64/OVMF_CODE.fd"; \ - else \ - echo "Error: OVMF UEFI firmware not found!"; \ - exit 1; \ - fi; \ - echo "QEMU will wait for GDB connection on localhost:1234"; \ - echo "In another terminal, run: gdb kernel/metalos.bin"; \ - echo "Then in GDB: target remote localhost:1234"; \ - qemu-system-x86_64 \ - -drive if=pflash,format=raw,readonly=on,file=$$OVMF \ - -drive format=raw,file=build/metalos.img \ - -m 512M \ - -serial stdio \ - -display $(QEMU_DISPLAY) \ - -net none \ - -s -S \ - ' - -# Quick UEFI test - boots to UEFI shell without OS (for verifying QEMU+OVMF setup) -qemu-uefi-test: - @echo "Testing QEMU UEFI boot (no OS image)..." - @bash -c ' \ - if [ -f /usr/share/OVMF/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/OVMF/OVMF_CODE.fd"; \ - elif [ -f /usr/share/ovmf/OVMF.fd ]; then \ - OVMF="/usr/share/ovmf/OVMF.fd"; \ - elif [ -f /usr/share/edk2-ovmf/x64/OVMF_CODE.fd ]; then \ - OVMF="/usr/share/edk2-ovmf/x64/OVMF_CODE.fd"; \ - else \ - echo "Error: OVMF UEFI firmware not found!"; \ - exit 1; \ - fi; \ - echo "Using OVMF firmware: $$OVMF"; \ - echo "This will boot to UEFI shell in nographic mode."; \ - echo "You should see UEFI boot messages. Press Ctrl-A then X to exit QEMU."; \ - qemu-system-x86_64 \ - -drive if=pflash,format=raw,readonly=on,file=$$OVMF \ - -m 512M \ - -nographic \ - -net none \ - ' - -clean: - @echo "Cleaning build artifacts..." - @cd bootloader && $(MAKE) clean - @cd kernel && $(MAKE) clean - @cd tests && $(MAKE) clean - @rm -rf build - -distclean: clean - @echo "Deep clean..." - @find . -name "*.o" -delete - @find . -name "*.d" -delete diff --git a/README.md b/README.md index 06883b4..439a12d 100644 --- a/README.md +++ b/README.md @@ -67,18 +67,18 @@ See [docs/ROADMAP.md](docs/ROADMAP.md) for detailed phase breakdown. ## Building -MetalOS supports **multiple build systems** - choose what works best for you! +MetalOS uses **CMake** as its build system for a modern, cross-platform build experience. -### Quick Start (Make - Traditional) +### Quick Start (CMake) ```bash -make all # Build bootloader, kernel, and userspace -make test # Run unit tests -make qemu # Test in QEMU with UEFI firmware -make clean # Clean build artifacts +mkdir build && cd build +cmake .. +cmake --build . +cmake --build . --target qemu ``` -### CMake + Ninja (Fast Modern Build) +### Using Ninja (Faster Builds) ```bash mkdir build && cd build @@ -103,19 +103,15 @@ The easiest way to build MetalOS with all dependencies: ```bash ./scripts/docker-build.sh # Build Docker image ./scripts/docker-run.sh scripts/setup-deps.sh # Setup dependencies -./scripts/docker-run.sh make all # Build everything -./scripts/docker-run.sh make qemu # Test in QEMU +./scripts/docker-run.sh cmake --build build # Build everything ``` -**See [docs/BUILD_SYSTEMS.md](docs/BUILD_SYSTEMS.md) for detailed comparison and usage of all build systems.** - **QEMU UEFI Testing**: ```bash -make qemu # Boot in QEMU with UEFI (headless) -make qemu QEMU_DISPLAY=gtk # Boot with graphical display -make qemu-debug # Boot with debug output -make qemu-gdb # Boot with GDB debugging -make qemu-uefi-test # Test UEFI firmware setup +cmake --build . --target qemu # Boot in QEMU with UEFI (headless) +cmake --build . --target qemu-debug # Boot with debug output +cmake --build . --target qemu-gdb # Boot with GDB debugging +cmake --build . --target qemu-uefi-test # Test UEFI firmware setup ``` See [docs/BUILD.md](docs/BUILD.md) for detailed build instructions and [docs/TESTING.md](docs/TESTING.md) for testing guide. diff --git a/bootloader/Makefile b/bootloader/Makefile deleted file mode 100644 index e94363f..0000000 --- a/bootloader/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# MetalOS Bootloader Makefile -# Builds UEFI bootloader (bootx64.efi) - -# Cross-compiler setup -CC = gcc -LD = ld -OBJCOPY = objcopy - -# Directories -SRC_DIR = src -INC_DIR = include -BUILD_DIR = build - -# Compiler flags for UEFI -CFLAGS = -Wall -Wextra -Werror \ - -ffreestanding -fno-stack-protector -fno-stack-check \ - -fshort-wchar -mno-red-zone \ - -I$(INC_DIR) \ - -DEFI_FUNCTION_WRAPPER - -# Linker flags for UEFI -LDFLAGS = -shared -Bsymbolic -nostdlib \ - -znocombreloc -T uefi.lds - -# Source files -SOURCES = $(wildcard $(SRC_DIR)/*.c) -OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SOURCES)) - -# Output -TARGET = bootx64.efi - -.PHONY: all clean - -all: $(BUILD_DIR) $(TARGET) - -$(BUILD_DIR): - mkdir -p $(BUILD_DIR) - -# Compile C files -$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c - $(CC) $(CFLAGS) -c $< -o $@ - -# Link and create EFI binary -$(TARGET): $(OBJECTS) - $(LD) $(LDFLAGS) $(OBJECTS) -o $(BUILD_DIR)/bootx64.so - $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ - -j .dynsym -j .rel -j .rela -j .reloc \ - --target=efi-app-x86_64 \ - $(BUILD_DIR)/bootx64.so $@ - -clean: - rm -rf $(BUILD_DIR) $(TARGET) - -# Note: This is a simplified Makefile -# A real implementation would use gnu-efi or proper UEFI SDK diff --git a/docs/BUILD.md b/docs/BUILD.md index 518ea52..c3af994 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -21,10 +21,12 @@ The easiest way to build MetalOS is using Docker, which provides a pre-configure ./scripts/docker-run.sh scripts/setup-deps.sh # 3. Build MetalOS -./scripts/docker-run.sh make all +mkdir build && cd build +cmake .. +cmake --build . # 4. Test in QEMU (headless mode) -./scripts/docker-run.sh make qemu +cmake --build . --target qemu # 5. Optional: Interactive shell in container ./scripts/docker-run.sh /bin/bash @@ -33,7 +35,7 @@ The easiest way to build MetalOS is using Docker, which provides a pre-configure ### What's Included in Docker The Docker image includes: -- **Build tools**: GCC, NASM, Make, CMake, Meson +- **Build tools**: GCC, NASM, CMake, Meson - **QEMU**: For testing with UEFI firmware - **OVMF**: UEFI firmware for QEMU - **Dependency management**: Scripts to download AMD firmware, Mesa RADV, QT6 @@ -127,11 +129,15 @@ This produces `kernel/metalos.bin` - the kernel binary. ## Creating Bootable Image ```bash -# From repository root -make image +# From repository root, if you haven't already +mkdir build && cd build +cmake .. + +# Create the bootable image +cmake --build . --target image ``` -This creates `build/metalos.img` - a bootable disk image containing: +This creates the bootable disk image at `/build/metalos.img` (e.g., `build/build/metalos.img` if your build directory is named `build/`). The image contains: - EFI System Partition with bootloader - Kernel binary - Any required data files @@ -146,41 +152,33 @@ Ensure QEMU and OVMF are installed: ```bash # Ubuntu/Debian -sudo apt-get install qemu-system-x86 ovmf mtools +sudo apt-get install qemu-system-x86 ovmf mtools cmake # Arch Linux -sudo pacman -S qemu-full edk2-ovmf mtools +sudo pacman -S qemu-full edk2-ovmf mtools cmake # Fedora -sudo dnf install qemu-system-x86 edk2-ovmf mtools +sudo dnf install qemu-system-x86 edk2-ovmf mtools cmake ``` ### Boot MetalOS in QEMU ```bash -make qemu +cd build +cmake --build . --target qemu ``` This will: -1. Build bootloader and kernel (or use placeholders if build fails) +1. Build bootloader and kernel 2. Create a bootable FAT32 disk image with UEFI boot structure 3. Launch QEMU with OVMF UEFI firmware in headless mode -4. Boot the system (will drop to UEFI shell until bootloader is complete) - -**Display Options**: By default, QEMU runs in headless mode (no graphics). To use graphical display: - -```bash -# Use GTK display (if available) -make qemu QEMU_DISPLAY=gtk - -# Use SDL display (if available) -make qemu QEMU_DISPLAY=sdl -``` +4. Boot the system ### Boot with Debug Output ```bash -make qemu-debug +cd build +cmake --build . --target qemu-debug ``` This includes CPU interrupt and reset debugging output. @@ -191,7 +189,8 @@ For debugging with GDB: ```bash # Terminal 1 - Start QEMU with GDB server -make qemu-gdb +cd build +cmake --build . --target qemu-gdb # Terminal 2 - Connect GDB gdb kernel/metalos.bin @@ -206,7 +205,8 @@ QEMU will wait for GDB connection before starting execution. To verify QEMU and OVMF are properly installed without needing a bootable OS image: ```bash -make qemu-uefi-test +cd build +cmake --build . --target qemu-uefi-test ``` This boots directly to the UEFI shell, confirming your QEMU+OVMF setup works correctly. @@ -292,10 +292,14 @@ ENABLE_SERIAL ?= 1 ```bash # Clean all build artifacts -make clean +cd build +cmake --build . --target clean -# Clean everything including dependencies -make distclean +# Or remove the build directory entirely +cd .. +rm -rf build +mkdir build && cd build +cmake .. ``` ## Troubleshooting diff --git a/docs/BUILD_SYSTEMS.md b/docs/BUILD_SYSTEMS.md index 33b9a3a..961c213 100644 --- a/docs/BUILD_SYSTEMS.md +++ b/docs/BUILD_SYSTEMS.md @@ -1,21 +1,15 @@ # MetalOS Build Systems Guide -MetalOS supports multiple build systems to accommodate different developer preferences and workflows. +MetalOS uses **CMake** as its primary build system, which can be used with different build backends for different workflows. ## Quick Start -### Using Make (Traditional) -```bash -make all # Build everything -make qemu # Test in QEMU -make clean # Clean build artifacts -``` - -### Using CMake + Make +### Using CMake (Default) ```bash mkdir build && cd build cmake .. cmake --build . +cmake --build . --target qemu # Test in QEMU ``` ### Using CMake + Ninja (Fastest) @@ -23,6 +17,7 @@ cmake --build . mkdir build && cd build cmake -G Ninja .. ninja +ninja qemu # Test in QEMU ``` ### Using Conan + CMake @@ -35,89 +30,38 @@ cmake --build . ## Build System Comparison -| Build System | Speed | Features | Best For | -|--------------|-------|----------|----------| -| **Make** | Medium | Simple, traditional | Quick builds, CI/CD | -| **CMake** | Medium | Cross-platform, modern | Complex projects, IDEs | +| Build Backend | Speed | Features | Best For | +|---------------|-------|----------|----------| +| **Make** (default) | Medium | Cross-platform, standard | General use, CI/CD | | **Ninja** | Fast | Parallel builds | Development, large projects | | **Conan** | Medium | Dependency management | Projects with external deps | ## Detailed Usage -### 1. Make (Traditional Build System) +### 1. CMake (Primary Build System) -The original build system using GNU Make. +CMake is the primary build system for MetalOS, providing cross-platform support and modern features. #### Build Commands ```bash -# Build all components -make all - -# Build individually -make bootloader -make kernel -make test - -# Create bootable image -make image - -# Run in QEMU -make qemu # Headless mode -make qemu QEMU_DISPLAY=gtk # With GUI -make qemu-debug # With debug output -make qemu-gdb # With GDB server - -# Clean -make clean # Clean build artifacts -make distclean # Deep clean -``` - -#### Advantages -- ✅ Simple and straightforward -- ✅ No additional dependencies -- ✅ Works on all Unix-like systems -- ✅ Easy to understand and modify - -#### Disadvantages -- ❌ Not cross-platform (Windows requires special setup) -- ❌ Can be slower for large projects -- ❌ Limited dependency tracking - ---- - -### 2. CMake (Modern Build Generator) - -CMake generates build files for various build systems (Make, Ninja, Visual Studio, etc.). - -#### Build Commands -```bash -# Configure (generates build files) +# Configure and build mkdir build && cd build cmake .. - -# Configure with specific generator -cmake -G "Unix Makefiles" .. -cmake -G Ninja .. -cmake -G "Visual Studio 17 2022" .. # Windows - -# Configure with options -cmake -DBUILD_BOOTLOADER=ON -DBUILD_KERNEL=ON -DBUILD_TESTS=ON .. -cmake -DCMAKE_BUILD_TYPE=Debug .. -cmake -DCMAKE_BUILD_TYPE=Release .. - -# Build cmake --build . -cmake --build . --parallel 8 # Use 8 parallel jobs # Build specific targets cmake --build . --target bootloader_efi cmake --build . --target kernel_bin cmake --build . --target image -# Run custom targets -cmake --build . --target qemu -cmake --build . --target qemu-debug -cmake --build . --target qemu-gdb +# Create bootable image +cmake --build . --target image + +# Run in QEMU +cmake --build . --target qemu # Headless mode +cmake --build . --target qemu-debug # With debug output +cmake --build . --target qemu-gdb # With GDB server +cmake --build . --target qemu-uefi-test # Test UEFI setup # Test ctest @@ -133,6 +77,23 @@ cmake --build . --target clean rm -rf build # Complete clean ``` +#### Advantages +- ✅ Cross-platform (Windows, Linux, macOS) +- ✅ IDE integration (CLion, VSCode, Visual Studio) +- ✅ Modern dependency management +- ✅ Better parallel build support +- ✅ Generates compile_commands.json for IDEs + +#### Disadvantages +- ❌ Requires cmake installation +- ❌ Slightly more complex setup + +--- + +### 2. Ninja (Fast Build Backend) + +Ninja is a fast build backend that can be used with CMake for faster incremental builds. + #### Advantages - ✅ Cross-platform (Windows, Linux, macOS) - ✅ IDE integration (CLion, Visual Studio, VS Code) diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 9c4d380..72e139d 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -63,9 +63,11 @@ add_executable(kernel_elf $ ${KERNEL_ASM_OBJECTS}) set_target_properties(kernel_elf PROPERTIES OUTPUT_NAME metalos.elf LINKER_LANGUAGE C + POSITION_INDEPENDENT_CODE OFF ) target_link_options(kernel_elf PRIVATE -nostdlib + -no-pie -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld ) diff --git a/kernel/Makefile b/kernel/Makefile deleted file mode 100644 index b071c32..0000000 --- a/kernel/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -# MetalOS Kernel Makefile - -# Cross-compiler (x86_64 bare metal) -CC = x86_64-elf-gcc -AS = nasm -LD = x86_64-elf-ld -OBJCOPY = x86_64-elf-objcopy - -# Check if cross-compiler exists, fallback to regular gcc -ifeq ($(shell which $(CC) 2>/dev/null),) - CC = gcc - LD = ld - OBJCOPY = objcopy -endif - -# Directories -SRC_DIR = src -INC_DIR = include -BUILD_DIR = build - -# Compiler flags -CFLAGS = -Wall -Wextra -Werror \ - -ffreestanding -fno-stack-protector \ - -mno-red-zone -mcmodel=large \ - -I$(INC_DIR) \ - -O2 - -# Assembler flags -ASFLAGS = -f elf64 - -# Linker flags -LDFLAGS = -nostdlib -T linker.ld - -# Source files -C_SOURCES = $(shell find $(SRC_DIR) -name '*.c') -ASM_SOURCES = $(shell find $(SRC_DIR) -name '*.asm') - -# Object files -C_OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(C_SOURCES)) -ASM_OBJECTS = $(patsubst $(SRC_DIR)/%.asm,$(BUILD_DIR)/%.o,$(ASM_SOURCES)) -OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS) - -# Output -TARGET = metalos.bin - -.PHONY: all clean - -all: $(BUILD_DIR) $(TARGET) - -$(BUILD_DIR): - mkdir -p $(BUILD_DIR) - mkdir -p $(BUILD_DIR)/core - mkdir -p $(BUILD_DIR)/hal - mkdir -p $(BUILD_DIR)/drivers - mkdir -p $(BUILD_DIR)/syscall - -# Compile C files -$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) -c $< -o $@ - -# Assemble ASM files -$(BUILD_DIR)/%.o: $(SRC_DIR)/%.asm - @mkdir -p $(dir $@) - $(AS) $(ASFLAGS) $< -o $@ - -# Link kernel -$(TARGET): $(OBJECTS) - $(LD) $(LDFLAGS) $(OBJECTS) -o $@ - -clean: - rm -rf $(BUILD_DIR) $(TARGET) - -# Print variables for debugging -info: - @echo "C Sources: $(C_SOURCES)" - @echo "ASM Sources: $(ASM_SOURCES)" - @echo "Objects: $(OBJECTS)" - @echo "Compiler: $(CC)" diff --git a/tests/Makefile b/tests/Makefile deleted file mode 100644 index bb441e6..0000000 --- a/tests/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# MetalOS Test Suite Makefile - -CC = gcc -CFLAGS = -Wall -Wextra -std=c11 -I../tests/include -I../kernel/include -I../bootloader/include -LDFLAGS = - -# Test source files -TEST_SOURCES = $(wildcard unit/*.c) -TEST_BINARIES = $(TEST_SOURCES:.c=) - -# Default target -.PHONY: all -all: $(TEST_BINARIES) - -# Build each test binary -unit/%: unit/%.c include/test_framework.h - @echo "Building test: $@" - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) - -# Run all tests -.PHONY: test -test: all - @echo "" - @echo "╔════════════════════════════════════════════╗" - @echo "║ Running MetalOS Test Suite ║" - @echo "╚════════════════════════════════════════════╝" - @echo "" - @for test in $(TEST_BINARIES); do \ - ./$$test || exit 1; \ - done - @echo "" - @echo "╔════════════════════════════════════════════╗" - @echo "║ All Test Suites Passed ✓ ║" - @echo "╚════════════════════════════════════════════╝" - @echo "" - -# Run tests with verbose output -.PHONY: test-verbose -test-verbose: all - @for test in $(TEST_BINARIES); do \ - echo "Running $$test..."; \ - ./$$test -v; \ - echo ""; \ - done - -# Clean test binaries -.PHONY: clean -clean: - @echo "Cleaning test binaries..." - @rm -f $(TEST_BINARIES) - @rm -f unit/*.o - @echo "Clean complete" - -# Help target -.PHONY: help -help: - @echo "MetalOS Test Suite Makefile" - @echo "" - @echo "Targets:" - @echo " all - Build all test binaries" - @echo " test - Build and run all tests" - @echo " test-verbose - Run tests with verbose output" - @echo " clean - Remove test binaries" - @echo " help - Show this help message"