IMG_FILE := bootable.img IMG_SIZE_MB := 100 EFI_FILE := bootx64.efi MNT_DIR := esp_mnt USB_DEV ?= /dev/sdX .PHONY: all clean flash # The default target, which is to build the image file. all: $(EFI_FILE) @echo "--- Creating blank disk image: $(IMG_FILE) ($(IMG_SIZE_MB)MB)..." dd if=/dev/zero of=$(IMG_FILE) bs=1M count=$(IMG_SIZE_MB) status=none sudo -v @echo "--- Creating GPT and EFI System Partition..." # Use sgdisk for non-interactive partitioning. # --new=1:0:0 creates partition 1, starting at the first available sector and filling the disk. # --typecode=1:ef00 sets the partition type to 'EFI System'. sudo sgdisk --new=1:0:0 --typecode=1:ef00 $(IMG_FILE) @# This block handles setting up, using, and cleaning up a loop device and mount point. @# 'set -e' ensures the script will exit immediately if a command fails. @# The trap command guarantees that we unmount the partition and detach the loop device on exit, @# even if an error occurs. set -e; \ LOOP_DEV=$$(sudo losetup --partscan --show --find $(IMG_FILE)); \ trap 'echo "--- Cleaning up mount point and loop device..."; sudo umount $(MNT_DIR) 2>/dev/null || true; sudo losetup -d $$LOOP_DEV 2>/dev/null || true; rm -rf $(MNT_DIR);' EXIT; \ \ echo "--- Using loop device: $$LOOP_DEV"; \ echo "--- Formatting EFI partition (FAT32)..."; \ sudo mkfs.vfat -F32 $${LOOP_DEV}p1; \ \ echo "--- Mounting partition..."; \ mkdir -p $(MNT_DIR); \ sudo mount $${LOOP_DEV}p1 $(MNT_DIR); \ \ echo "--- Copying EFI executable to EFI/BOOT/BOOTX64.EFI..."; \ sudo mkdir -p $(MNT_DIR)/EFI/BOOT; \ sudo cp $(EFI_FILE) $(MNT_DIR)/EFI/BOOT/BOOTX64.EFI; \ \ echo "--- Syncing filesystem..."; \ sync; @echo "\nSuccess! Bootable image created: $(IMG_FILE)" $(EFI_FILE): zig build-exe -OReleaseFast -target x86_64-uefi-msvc --name bootx64 main.zig # Rule to flash the image to a USB device. flash: $(IMG_FILE) @if [ "$(USB_DEV)" = "/dev/sdX" ]; then \ echo "\nERROR: USB_DEV is not set."; \ echo "Please specify the target device, e.g., 'make flash USB_DEV=/dev/sdb'"; \ exit 1; \ fi @echo "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" @echo "!! WARNING: This will ERASE ALL DATA on $(USB_DEV) !!" @echo "!! Verify that this is the correct device before proceeding. !!" @echo "!! Press Ctrl+C to cancel, or Enter to continue. !!" @echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" @read sudo dd if=$(IMG_FILE) of=$(USB_DEV) bs=4M status=progress conv=fsync # Rule to clean up all generated files and temporary directories. clean: @echo "--- Cleaning up..." @-sudo umount $(MNT_DIR) >/dev/null 2>&1 || true @-rm -rf $(MNT_DIR) @-if losetup -j $(IMG_FILE) > /dev/null 2>&1; then \ LOOP_DEV=$$(losetup -j $(IMG_FILE) | cut -d: -f1); \ echo "Detaching loop device $$LOOP_DEV..."; \ sudo losetup -d $$LOOP_DEV; \ fi @-rm -f $(IMG_FILE) @echo "Cleanup complete."