// Project build orchestrator. This file describes the Windows/MSVC build graph and keeps driver dependencies explicit. #define NOB_IMPLEMENTATION #include "nob.h" // Compiler and linker flags stay in macros so they can be used in file-scope aggregate initializers. // MSVC C rejects initializing a static object from another object, even when the source object is const. // Drivers and user binaries do not inherit kernel include paths so private dependencies fail at compile time. #define COMMON_CFLAGS_BASE_LITERAL "/nologo /WX /O2 /GS- /Gs999999 /Gz /Gy /EHsc- /GR- /Oi- /Z7 /std:c17 /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /Icode\\public /Icode\\common\\include" #define COMMON_CFLAGS_LITERAL COMMON_CFLAGS_BASE_LITERAL " /W3" #define KERNEL_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL " /Icode\\kernel\\include" #define DRIVER_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL #define USER_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL // POSIX targets own their standard C/POSIX headers; /X prevents the host UCRT from entering the target ABI. #define POSIX_USER_CFLAGS_LITERAL "/X /Icode\\public\\posix /Icode\\public\\freestanding " USER_CFLAGS_LITERAL #define BOOT_CFLAGS_LITERAL KERNEL_CFLAGS_LITERAL #define USER_HEAP_OBJS_LITERAL "obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj" #define NATIVE_RUNTIME_OBJS_LITERAL "obj\\runtime\\native_exception.obj obj\\runtime\\native_start.obj" #define NATIVE_EXE_LIBS_LITERAL "bin\\syscall.lib obj\\libc.obj " USER_HEAP_OBJS_LITERAL " " NATIVE_RUNTIME_OBJS_LITERAL #define NATIVE_INIT_LIBS_LITERAL "bin\\syscall_s.lib obj\\libc.obj obj\\runtime\\native_exception.obj" #define NATIVE_SERVICE_LIBS_LITERAL "bin\\syscall_s.lib obj\\libc.obj " USER_HEAP_OBJS_LITERAL " obj\\runtime\\native_exception.obj" #define WIN32_EXE_LIBS_LITERAL "bin\\win32.lib bin\\syscall.lib obj\\libc.obj obj\\runtime\\native_start.obj" #define POSIX_EXE_LIBS_LITERAL "bin\\posix.lib bin\\syscall.lib obj\\libc.obj obj\\runtime\\posix_start.obj" #define NATIVE_EXE_ENTRY_LITERAL "/ENTRY:NtlNativeStart" #define USER_IMAGE_FLAGS_LITERAL "/DYNAMICBASE /HIGHENTROPYVA" #define ACPICA_CFLAGS_LITERAL COMMON_CFLAGS_BASE_LITERAL " /W0 /DACPI_NTLITE /Icode\\drivers\\platform\\acpi\\third_party\\acpica\\include /wd4100 /wd4101 /wd4127 /wd4214 /wd4244 /wd4267 /wd4706 /wd4702" #define LWIP_CFLAGS_LITERAL DRIVER_CFLAGS_LITERAL " /Icode\\drivers\\net\\lwip\\include /Icode\\drivers\\net\\lwip\\third_party\\lwip\\src\\include /wd4005 /wd4100 /wd4103 /wd4127 /wd4244 /wd4267 /wd4706" #define EXT4_CFLAGS_LITERAL DRIVER_CFLAGS_LITERAL " /Icode\\drivers\\fs\\ext4\\include /Icode\\drivers\\fs\\ext4\\third_party\\lwext4\\include /DCONFIG_USE_DEFAULT_CFG=1 /DCONFIG_HAVE_OWN_ERRNO=1 /DCONFIG_DEBUG_PRINTF=0 /DCONFIG_DEBUG_ASSERT=0 /DCONFIG_BLOCK_DEV_ENABLE_STATS=0 /DCONFIG_EXT4_BLOCKDEVS_COUNT=8 /DCONFIG_EXT4_MOUNTPOINTS_COUNT=8 /wd4005 /wd4100 /wd4101 /wd4103 /wd4127 /wd4244 /wd4267 /wd4706 /wd4996" #define NTFS3G_CFLAGS_LITERAL DRIVER_CFLAGS_LITERAL " /Icode\\drivers\\fs\\ntfs\\ntfs3g\\include /Icode\\drivers\\fs\\ntfs\\ntfs3g\\third_party\\ntfs-3g\\include /Icode\\drivers\\fs\\ntfs\\ntfs3g\\third_party\\ntfs-3g\\include\\ntfs-3g /DHAVE_CONFIG_H=1 /DNO_NTFS_DEVICE_DEFAULT_IO_OPS=1 /wd4005 /wd4018 /wd4100 /wd4101 /wd4103 /wd4127 /wd4133 /wd4146 /wd4244 /wd4267 /wd4305 /wd4311 /wd4312 /wd4706 /wd4996" #define LFLAGS_LITERAL "/nologo /NODEFAULTLIB /DEBUG" // Partition offsets inside disk.vhd #define VHD_PART1 "disk.vhd@@1M" // ESP / Partition 1 (Offset 1MB) #define VHD_PART2 "disk.vhd@@65M" // Test/Data / Partition 2 (Offset 65MB) #define DEFAULT_VHD_DISK_SIGNATURE 0x4E544C31u const char* CommonCflags = COMMON_CFLAGS_LITERAL; const char* KernelCflags = KERNEL_CFLAGS_LITERAL; const char* UserCflags = USER_CFLAGS_LITERAL; const char* PosixUserCflags = POSIX_USER_CFLAGS_LITERAL; const char* BootCflags = BOOT_CFLAGS_LITERAL; const char* LwipCflags = LWIP_CFLAGS_LITERAL; const char* Ext4Cflags = EXT4_CFLAGS_LITERAL; const char* Ntfs3gCflags = NTFS3G_CFLAGS_LITERAL; const char* LFLAGS = LFLAGS_LITERAL; typedef struct Driver_Target { const char* name; const char* obj_dir; const char* sources; const char* cflags; const char* libs; const char* entry_flag; } Driver_Target; #define DRIVER_TARGET(name_, obj_dir_, sources_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, "", "/NOENTRY" } #define DRIVER_TARGET_LIBS(name_, obj_dir_, sources_, libs_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, (libs_), "/NOENTRY" } #define DRIVER_TARGET_FLAGS(name_, obj_dir_, sources_, cflags_) { (name_), (obj_dir_), (sources_), (cflags_), "", "/NOENTRY" } #define DRIVER_TARGET_DECLARATIVE(name_, obj_dir_, sources_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, "", "/NOENTRY" } static const Driver_Target PCI_BUS_DRIVER = DRIVER_TARGET_FLAGS("pci", "obj\\drivers\\pci", "code\\drivers\\bus\\pci\\pci.c", DRIVER_CFLAGS_LITERAL " /DPCI_SYS_BUILD"); static const Driver_Target STANDALONE_DRIVERS[] = { DRIVER_TARGET("ps2", "obj\\drivers\\ps2", "code\\drivers\\input\\ps2\\ps2.c code\\drivers\\input\\ps2\\ps2_i8042.c"), DRIVER_TARGET_DECLARATIVE("serial", "obj\\drivers\\serial", "code\\drivers\\input\\serial\\serial.c"), DRIVER_TARGET_LIBS("hda", "obj\\drivers\\hda", "code\\drivers\\audio\\hda\\hda.c code\\drivers\\audio\\hda\\hda_transport.c code\\drivers\\audio\\hda\\hda_codec.c", "bin\\pci.lib"), DRIVER_TARGET_LIBS("ata", "obj\\drivers\\ata", "code\\drivers\\storage\\ata\\ata.c", "bin\\pci.lib"), DRIVER_TARGET_LIBS("ahci", "obj\\drivers\\ahci", "code\\drivers\\storage\\ahci\\ahci.c code\\drivers\\storage\\ahci\\ahci_port.c", "bin\\pci.lib"), DRIVER_TARGET("fat", "obj\\drivers\\fat", "code\\drivers\\fs\\fat\\fat.c code\\drivers\\fs\\fat\\fat_directory.c code\\drivers\\fs\\fat\\fat_file.c code\\drivers\\fs\\fat\\fat_async.c code\\drivers\\fs\\fat\\fat_driver.c code\\drivers\\fs\\fat\\fat_mount.c"), DRIVER_TARGET_LIBS("vmwaresvga", "obj\\drivers\\vmwaresvga", "code\\drivers\\display\\vmwaresvga\\vmwaresvga.c", "bin\\pci.lib"), DRIVER_TARGET_LIBS("usb", "obj\\drivers\\usb", "code\\drivers\\bus\\usb\\usb.c code\\drivers\\bus\\usb\\usb_bus.c code\\drivers\\bus\\usb\\usb_composite.c code\\drivers\\bus\\usb\\usb_core.c code\\drivers\\bus\\usb\\usb_xhci.c code\\drivers\\bus\\usb\\usb_hid.c code\\drivers\\bus\\usb\\usb_storage.c code\\drivers\\bus\\usb\\usb_hub.c", "bin\\pci.lib"), DRIVER_TARGET_LIBS("rtl816x", "obj\\drivers\\rtl816x", "code\\drivers\\net\\rtl816x\\rtl816x.c", "bin\\pci.lib"), DRIVER_TARGET_LIBS("rtl8139", "obj\\drivers\\rtl8139", "code\\drivers\\net\\rtl8139\\rtl8139.c", "bin\\pci.lib"), }; // Creates layout. void create_layout() { const char* dirs[] = { "obj", "bin", "obj\\boot", "obj\\ddk", "obj\\kernel", "obj\\lwip", "obj\\ext4", "obj\\ntfs3g", "obj\\acpica", "obj\\hal", "obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix", "obj\\drivers", "obj\\init", "obj\\rssrv", "obj\\posixsrv", "obj\\dwm", "obj\\shell_win32", "obj\\shell_posix", "obj\\shell_native", "obj\\async_apc", "obj\\async_cancel", "obj\\apc_return_smoke", "obj\\edit", "obj\\httpget", "obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping", "obj\\doom", "obj\\video", "obj\\memtop", "obj\\file_stat_smoke", "obj\\handle_dup_smoke", "obj\\security_smoke", "obj\\port_ipc_smoke", "obj\\resource_service_smoke", "obj\\anonymous_queue_smoke", "obj\\input_service_smoke", "obj\\console_service_smoke", "obj\\desktop_smoke", "obj\\timer_smoke", "obj\\stats_abi_smoke", "obj\\realpath_smoke", "obj\\file_lock_smoke", "obj\\process_protection_smoke", "obj\\process_exit_multithread_smoke", "obj\\thread_name_smoke", "obj\\process_builder_smoke", "obj\\socket_addr_smoke", "obj\\syscall_contract_smoke", "obj\\would_block_smoke", "obj\\audio_stream_smoke", "obj\\winmm_waveout_smoke", "obj\\win32_condition_variable_smoke", "obj\\win32_mutex_smoke", "obj\\win32_thread_suspend_smoke", "obj\\win32_module_lookup_smoke", "obj\\cwd_userspace_smoke", "obj\\mmap_smoke", "obj\\pcache_smoke", "obj\\pcache_pressure", "obj\\dirty_writeback", "obj\\shared_mmap", "obj\\pcache_invalidate", "obj\\pcache_mmap_read_reuse", "obj\\pcache_multithread", "obj\\all_tests", "obj\\posix_service_smoke", "obj\\surface_smoke", "obj\\surface_invalid_rect", "obj\\surface_multithread_commit", "obj\\surface_cross_process_smoke", "obj\\net_irp_smoke", "obj\\module_load_smoke", "obj\\posix_module_smoke", "obj\\posix_runtime_smoke", "obj\\posix_fd_smoke", "obj\\posix_process_smoke", "obj\\posix_signal_smoke", "obj\\posix_pipe_smoke", "obj\\exception_dispatcher_smoke", "obj\\native_exception_runtime_smoke", "obj\\native_raise_exception_smoke", "obj\\exception_smoke", "obj\\win32_exception_smoke", "obj\\win32_seh_smoke" }; for (size_t i = 0; i < NOB_ARRAY_LEN(dirs); i++) nob_mkdir_if_not_exists(dirs[i]); nob_mkdir_if_not_exists(PCI_BUS_DRIVER.obj_dir); for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) nob_mkdir_if_not_exists(STANDALONE_DRIVERS[i].obj_dir); } // Runs a shell command and waits for it to finish. bool run_sync(const char* cmd_str) { Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cmd.exe", "/c", cmd_str); bool ok = nob_cmd_run_sync(cmd); nob_cmd_free(cmd); return ok; } // Launches a shell command while the build graph continues. Nob_Proc run_async(const char* cmd_str) { Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cmd.exe", "/c", cmd_str); Nob_Proc proc = nob_cmd_run_async(cmd); nob_cmd_free(cmd); return proc; } // Deletes stale object files from a target directory before compiling into it. bool clean_object_directory(const char* obj_dir) { const char* cmd = nob_temp_sprintf("if exist %s\\*.obj del /q %s\\*.obj", obj_dir, obj_dir); return run_sync(cmd); } // Cleans object directories that are linked through wildcards. bool clean_build_object_directories(void) { const char* dirs[] = { "obj\\boot", "obj\\ddk", "obj\\kernel", "obj\\lwip", "obj\\ext4", "obj\\acpica", "obj\\hal", "obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix", "obj\\init", "obj\\rssrv", "obj\\posixsrv", "obj\\dwm", "obj\\shell_win32", "obj\\shell_posix", "obj\\shell_native", "obj\\async_apc", "obj\\async_cancel", "obj\\apc_return_smoke", "obj\\edit", "obj\\httpget", "obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping", "obj\\doom", "obj\\video", "obj\\memtop", "obj\\file_stat_smoke", "obj\\handle_dup_smoke", "obj\\security_smoke", "obj\\port_ipc_smoke", "obj\\resource_service_smoke", "obj\\anonymous_queue_smoke", "obj\\input_service_smoke", "obj\\console_service_smoke", "obj\\desktop_smoke", "obj\\timer_smoke", "obj\\stats_abi_smoke", "obj\\realpath_smoke", "obj\\file_lock_smoke", "obj\\process_protection_smoke", "obj\\process_exit_multithread_smoke", "obj\\thread_name_smoke", "obj\\process_builder_smoke", "obj\\socket_addr_smoke", "obj\\syscall_contract_smoke", "obj\\would_block_smoke", "obj\\audio_stream_smoke", "obj\\winmm_waveout_smoke", "obj\\win32_condition_variable_smoke", "obj\\win32_mutex_smoke", "obj\\win32_thread_suspend_smoke", "obj\\win32_module_lookup_smoke", "obj\\cwd_userspace_smoke", "obj\\mmap_smoke", "obj\\pcache_smoke", "obj\\pcache_pressure", "obj\\dirty_writeback", "obj\\shared_mmap", "obj\\pcache_invalidate", "obj\\pcache_mmap_read_reuse", "obj\\pcache_multithread", "obj\\all_tests", "obj\\posix_service_smoke", "obj\\surface_smoke", "obj\\surface_invalid_rect", "obj\\surface_multithread_commit", "obj\\surface_cross_process_smoke", "obj\\net_irp_smoke", "obj\\module_load_smoke", "obj\\posix_module_smoke", "obj\\posix_runtime_smoke", "obj\\posix_fd_smoke", "obj\\posix_process_smoke", "obj\\posix_signal_smoke", "obj\\posix_pipe_smoke", "obj\\exception_dispatcher_smoke", "obj\\native_exception_runtime_smoke", "obj\\native_raise_exception_smoke", "obj\\exception_smoke", "obj\\win32_exception_smoke", "obj\\win32_seh_smoke" }; for (size_t i = 0; i < NOB_ARRAY_LEN(dirs); i++) { if (!clean_object_directory(dirs[i])) return false; } if (!clean_object_directory(PCI_BUS_DRIVER.obj_dir)) return false; for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) { if (!clean_object_directory(STANDALONE_DRIVERS[i].obj_dir)) return false; } return true; } // Creates the USB fat root once and leaves its contents alone between builds. bool create_usbfatroot_if_missing(void) { return nob_mkdir_if_not_exists("usbfatroot"); } // Copies one local file into a FAT image using mcopy without admin rights. bool mcopy_file(const char* src, const char* vhd_target, const char* dst_path) { const char* cmd = nob_temp_sprintf("mcopy -o -i %s %s ::%s", vhd_target, src, dst_path); return run_sync(cmd); } // Copies several same-name files into one FAT directory with a single mcopy process. bool mcopy_files_to_dir(const char* vhd_target, const char* dst_dir, const char* const* sources, size_t source_count) { if (!vhd_target || !dst_dir || (!sources && source_count)) return false; if (!source_count) return true; Nob_String_Builder command = {0}; nob_sb_appendf(&command, "mcopy -o -i %s", vhd_target); for (size_t i = 0; i < source_count; ++i) nob_sb_appendf(&command, " %s", sources[i]); nob_sb_appendf(&command, " ::%s", dst_dir); nob_sb_append_null(&command); bool ok = run_sync(command.items); nob_sb_free(command); return ok; } // Utility to create a directory in a FAT image using mmd. bool mmd_dir(const char* vhd_target, const char* dir_path) { const char* cmd = nob_temp_sprintf("mmd -i %s ::%s 2>nul", vhd_target, dir_path); run_sync(cmd); return true; } // Writes a 512-byte Connectix VHD Fixed Disk Footer at the end of the file. static void write_vpc_footer(FILE* f, uint64_t disk_size_bytes) { uint8_t footer[512] = {0}; memcpy(&footer[0], "conectix", 8); // Features: 0x00000002 (Big Endian) footer[11] = 0x02; // File Format Version: 0x00010000 footer[13] = 0x01; // Data Offset: 0xFFFFFFFFFFFFFFFF (Fixed disk) memset(&footer[16], 0xFF, 8); // Creator Application: "qemu" memcpy(&footer[28], "qemu", 4); // Creator Version: 0x00020000 footer[33] = 0x02; // Creator Host OS: "Wi2k" memcpy(&footer[36], "Wi2k", 4); // Original & Current Size (uint64_t Big Endian) for (int i = 0; i < 8; i++) { uint8_t b = (uint8_t)(disk_size_bytes >> ((7 - i) * 8)); footer[40 + i] = b; footer[48 + i] = b; } // Geometry for 512MB: 1024 Cylinders (0x0400), 16 Heads, 63 Sectors/Track footer[56] = 0x04; footer[57] = 0x00; footer[58] = 16; footer[59] = 63; // Disk Type: 2 (Fixed Hard Disk) footer[63] = 0x02; // Unique ID GUID static const uint8_t guid[16] = { 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }; memcpy(&footer[68], guid, 16); // Checksum: 1's complement sum of all bytes in footer with checksum cleared uint32_t sum = 0; for (int i = 0; i < 512; i++) { sum += footer[i]; } uint32_t checksum = ~sum; footer[64] = (uint8_t)(checksum >> 24); footer[65] = (uint8_t)(checksum >> 16); footer[66] = (uint8_t)(checksum >> 8); footer[67] = (uint8_t)(checksum & 0xFF); fseek(f, (long)disk_size_bytes, SEEK_SET); fwrite(footer, 1, 512, f); } // Ensures the managed development VHD carries the stable identity used by boot.ini. static bool ensure_disk_vhd_signature(void) { FILE* f = fopen("disk.vhd", "r+b"); if (!f) return false; uint32_t signature = DEFAULT_VHD_DISK_SIGNATURE; if (fseek(f, 440, SEEK_SET) != 0 || fwrite(&signature, sizeof(signature), 1, f) != 1) { fclose(f); return false; } fclose(f); return true; } // Creates a 512 MB partitioned disk.vhd image with a valid VPC footer. bool create_disk_vhd_if_missing(void) { if (nob_file_exists("disk.vhd")) return ensure_disk_vhd_signature(); nob_log(NOB_INFO, "disk.vhd missing, creating new 512 MB fixed VHD image..."); const uint64_t disk_size = (uint64_t)512 * 1024 * 1024; // 512 MB Payload FILE* f = fopen("disk.vhd", "wb"); if (!f) { nob_log(NOB_ERROR, "Failed to create disk.vhd file!"); return false; } // Expand file to 512MB payload if (fseek(f, (long)(disk_size - 1), SEEK_SET) != 0) { fclose(f); return false; } fputc(0, f); // Build standard MBR partition table (Sector 0) uint8_t mbr[512] = {0}; uint32_t disk_signature = DEFAULT_VHD_DISK_SIGNATURE; memcpy(&mbr[440], &disk_signature, sizeof(disk_signature)); mbr[510] = 0x55; mbr[511] = 0xAA; // Partition 1 Entry: 64MB FAT32 @ LBA 2048 (1MB offset) uint8_t* p1 = &mbr[0x01BE]; p1[0] = 0x80; // Active / Bootable p1[1] = 0x00; p1[2] = 0x02; p1[3] = 0x00; // CHS Start p1[4] = 0x0C; // FAT32 LBA p1[5] = 0xFE; p1[6] = 0xFF; p1[7] = 0xFF; // CHS End (LBA boundary) uint32_t p1_lba = 2048; uint32_t p1_sectors = 131072; // 64 MB memcpy(&p1[8], &p1_lba, 4); memcpy(&p1[12], &p1_sectors, 4); // Partition 2 Entry: 256MB FAT32 @ LBA 133120 (65MB offset) uint8_t* p2 = &mbr[0x01CE]; p2[0] = 0x00; // Inactive p2[1] = 0x00; p2[2] = 0x01; p2[3] = 0x08; // CHS Start p2[4] = 0x0C; // FAT32 LBA p2[5] = 0xFE; p2[6] = 0xFF; p2[7] = 0xFF; // CHS End (LBA boundary) uint32_t p2_lba = 133120; uint32_t p2_sectors = 524288; // 256 MB memcpy(&p2[8], &p2_lba, 4); memcpy(&p2[12], &p2_sectors, 4); // Write Sector 0 fseek(f, 0, SEEK_SET); fwrite(mbr, 1, 512, f); // Append 512-byte Connectix VPC Footer write_vpc_footer(f, disk_size); fclose(f); nob_log(NOB_INFO, "Formatting disk.vhd partitions with mformat..."); if (!run_sync("mformat -i " VHD_PART1 " -F")) return false; if (!run_sync("mformat -i " VHD_PART2 " -F")) return false; return true; } // Runs the requested operation. int main(int argc, char** argv) { NOB_GO_REBUILD_URSELF(argc, argv); bool with_tests = argc == 2 && strcmp(argv[1], "--with-tests") == 0; if (argc != 1 && !with_tests) { nob_log(NOB_ERROR, "Usage: build.exe [--with-tests]"); return 1; } if (!create_disk_vhd_if_missing()) return 1; if (!create_usbfatroot_if_missing()) return 1; create_layout(); if (!nob_file_exists("code\\drivers\\fs\\ext4\\third_party\\lwext4\\src\\ext4.c")) { nob_log(NOB_ERROR, "lwext4 is not vendored. Run: powershell -ExecutionPolicy Bypass -File code\\drivers\\fs\\ext4\\vendor_lwext4.ps1"); return 1; } if (!nob_file_exists("code\\drivers\\fs\\ntfs\\ntfs3g\\third_party\\ntfs-3g\\libntfs-3g\\volume.c")) { nob_log(NOB_ERROR, "ntfs-3g is not vendored. Run: powershell -ExecutionPolicy Bypass -File code\\drivers\\fs\\ntfs\\ntfs3g\\vendor_ntfs3g.ps1"); return 1; } if (!clean_build_object_directories()) return 1; nob_log(NOB_INFO, "--- Building Core Subsystems ---"); const char* core_tasks[] = { "ml64 /nologo /c /Foobj\\kernel\\ke_switch.obj code\\kernel\\ke_switch.asm", "ml64 /nologo /c /Foobj\\kernel\\ke_syscall_asm.obj code\\kernel\\ke_syscall.asm", "ml64 /nologo /c /Foobj\\kernel\\ke_gdt_reload.obj code\\kernel\\ke_gdt_reload.asm", "ml64 /nologo /c /Foobj\\syscall\\stubs.obj code\\user\\syscall\\syscall_stubs.asm", "ml64 /nologo /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\stubs_s.obj code\\user\\syscall\\syscall_stubs.asm", nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\pe_loader.obj code\\user\\syscall\\pe_loader.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\pe_loader_s.obj code\\user\\syscall\\pe_loader.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\module_loader.obj code\\user\\syscall\\module_loader.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\module_loader_s.obj code\\user\\syscall\\module_loader.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\process_loader.obj code\\user\\syscall\\process_loader.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\process_loader_s.obj code\\user\\syscall\\process_loader.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\resource.obj code\\user\\syscall\\resource.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\resource_s.obj code\\user\\syscall\\resource.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\input_service.obj code\\user\\syscall\\input_service.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\input_service_s.obj code\\user\\syscall\\input_service.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\console_service.obj code\\user\\syscall\\console_service.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\console_service_s.obj code\\user\\syscall\\console_service.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\desktop.obj code\\user\\syscall\\desktop.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\desktop_s.obj code\\user\\syscall\\desktop.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_BUILD /c /Foobj\\syscall\\path.obj code\\user\\syscall\\path.c", UserCflags), nob_temp_sprintf("cl %s /DNTL_SYSCALL_STATIC /c /Foobj\\syscall\\path_s.obj code\\user\\syscall\\path.c", UserCflags), "for %f in (code\\boot\\uefi\\*.asm) do ml64 /nologo /c /Fo\"obj\\boot\\%~nf.obj\" \"%f\"", nob_temp_sprintf("cl %s /MP /c /Foobj\\ code\\common\\printf.c", CommonCflags), "cl /nologo /c /Foobj\\libc.obj code\\common\\libc.c", nob_temp_sprintf("cl %s /c /Foobj\\runtime\\user_heap.obj code\\user\\runtime\\heap.c", UserCflags), nob_temp_sprintf("cl %s /c /Foobj\\runtime\\user_heap_exports.obj code\\user\\runtime\\heap_exports.c", UserCflags), nob_temp_sprintf("cl %s /c /Foobj\\runtime\\native_exception.obj code\\user\\runtime\\native_exception.c", UserCflags), nob_temp_sprintf("cl %s /c /Foobj\\runtime\\native_start.obj code\\user\\runtime\\native_start.c", UserCflags), nob_temp_sprintf("cl %s /c /Foobj\\runtime\\posix_start.obj code\\user\\runtime\\posix_start.c", PosixUserCflags), // Bootloader. nob_temp_sprintf("cl %s /MP /c /Icode\\boot\\uefi\\include /Foobj\\boot\\ code\\boot\\uefi\\*.c code\\common\\boot_volume_selector.c && link %s /FORCE:MULTIPLE /SUBSYSTEM:EFI_APPLICATION /ENTRY:UefiMain /OUT:bin\\bootx64.efi obj\\libc.obj code\\boot\\uefi\\efilib.lib obj\\boot\\*.obj", BootCflags, LFLAGS), // HAL. nob_temp_sprintf("cl %s /DNTL_HAL_BUILD /MP /c /Foobj\\hal\\ code\\kernel\\hal\\*.c && link %s /DLL /FIXED /DYNAMICBASE:NO /HIGHENTROPYVA:NO /RELEASE /BASE:0xFFFF800010000000 /OUT:bin\\hal.dll /NOENTRY /IGNORE:4216 obj\\printf.obj obj\\libc.obj obj\\hal\\*.obj", KernelCflags, LFLAGS), // Kernel. nob_temp_sprintf("cl %s /DNTL_KERNEL_BUILD /DKE_DISPLAY_BUILD /MP /c /Foobj\\kernel\\ code\\kernel\\*.c code\\common\\boot_volume_selector.c && link %s /SUBSYSTEM:NATIVE /FIXED /DYNAMICBASE:NO /HIGHENTROPYVA:NO /RELEASE /BASE:0xFFFF800000000000 /ENTRY:KernelMain /MAP:bin\\kernel.map /OUT:bin\\kernel.exe bin\\hal.lib obj\\printf.obj obj\\libc.obj obj\\kernel\\*.obj", KernelCflags, LFLAGS), // Subsystem DLLs. "link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL " USER_IMAGE_FLAGS_LITERAL " /OUT:bin\\syscall.dll obj\\syscall\\stubs.obj obj\\syscall\\pe_loader.obj obj\\syscall\\module_loader.obj obj\\syscall\\process_loader.obj obj\\syscall\\resource.obj obj\\syscall\\input_service.obj obj\\syscall\\console_service.obj obj\\syscall\\desktop.obj obj\\syscall\\path.obj obj\\libc.obj", "lib /nologo /OUT:bin\\syscall_s.lib obj\\syscall\\stubs_s.obj obj\\syscall\\pe_loader_s.obj obj\\syscall\\module_loader_s.obj obj\\syscall\\process_loader_s.obj obj\\syscall\\resource_s.obj obj\\syscall\\input_service_s.obj obj\\syscall\\console_service_s.obj obj\\syscall\\desktop_s.obj obj\\syscall\\path_s.obj", nob_temp_sprintf("cl %s /DUSER_HEAP_EXPORTS /DNTL_EXCEPTION_EXPORTS /MP /c /Foobj\\win32\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\runtime\\native_exception.c code\\user\\personalities\\win32\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL " USER_IMAGE_FLAGS_LITERAL " /OUT:bin\\win32.dll bin\\syscall.lib obj\\libc.obj obj\\win32\\*.obj", UserCflags), "ml64 /nologo /Icode\\user\\syscall /c /Foobj\\posix\\posix_vfork_asm.obj code\\user\\personalities\\posix\\posix_vfork.asm", nob_temp_sprintf("cl %s /DNTL_POSIX_BUILD /DUSER_HEAP_EXPORTS /DNTL_EXCEPTION_EXPORTS /MP /c /Foobj\\posix\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\runtime\\native_exception.c code\\user\\personalities\\posix\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL " USER_IMAGE_FLAGS_LITERAL " /OUT:bin\\posix.dll bin\\syscall.lib obj\\libc.obj obj\\posix\\*.obj", PosixUserCflags) }; for (size_t i = 0; i < NOB_ARRAY_LEN(core_tasks); i++) { if (!run_sync(core_tasks[i])) return 1; } // The support library contains only driver-side helpers, never kernel policy. if (!run_sync(nob_temp_sprintf( "cl %s /MP /c /Foobj\\ddk\\ code\\ddk\\*.c && lib /nologo /OUT:bin\\ntlddk.lib obj\\ddk\\*.obj", DRIVER_CFLAGS_LITERAL))) return 1; nob_log(NOB_INFO, "--- Building Bus Drivers ---"); const char* pci_cmd = nob_temp_sprintf( "cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys /IMPLIB:bin\\%s.lib /NOENTRY bin\\kernel.lib bin\\ntlddk.lib obj\\printf.obj obj\\libc.obj %s\\*.obj", PCI_BUS_DRIVER.cflags, PCI_BUS_DRIVER.obj_dir, PCI_BUS_DRIVER.sources, PCI_BUS_DRIVER.name, PCI_BUS_DRIVER.name, PCI_BUS_DRIVER.obj_dir ); if (!run_sync(pci_cmd)) return 1; nob_log(NOB_INFO, "--- Compiling Drivers and Apps in Parallel ---"); Nob_Procs procs = {0}; for (size_t i = 0; i < NOB_ARRAY_LEN(STANDALONE_DRIVERS); i++) { const Driver_Target* driver = &STANDALONE_DRIVERS[i]; const char* cmd = nob_temp_sprintf( "cl %s /MP /c /Fo%s\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\%s.sys %s bin\\kernel.lib %s obj\\libc.obj %s\\*.obj", driver->cflags, driver->obj_dir, driver->sources, driver->name, driver->entry_flag, driver->libs ? driver->libs : "", driver->obj_dir ); nob_da_append(&procs, run_async(cmd)); } // Compile the pinned ACPICA interpreter from its reproducible source manifest. Nob_String_Builder acpi_manifest = {0}, acpi_files = {0}; if (!nob_read_entire_file("code\\drivers\\platform\\acpi\\acpica_sources.txt", &acpi_manifest)) return 1; Nob_String_View acpi_view = nob_sv_from_parts(acpi_manifest.items, acpi_manifest.count); while (acpi_view.count > 0) { Nob_String_View line = nob_sv_trim(nob_sv_chop_by_delim(&acpi_view, '\n')); if (!line.count || line.data[0] == '#') continue; nob_sb_append_cstr(&acpi_files, "code\\"); for (size_t i = 0; i < line.count; i++) { char ch = line.data[i] == '/' ? '\\' : line.data[i]; nob_sb_append_buf(&acpi_files, &ch, 1); } nob_sb_append_cstr(&acpi_files, " "); } if (!nob_write_entire_file("obj\\acpica\\sources.rsp", acpi_files.items, acpi_files.count)) return 1; nob_da_append(&procs, run_async(nob_temp_sprintf( "cl %s /MP /c /Foobj\\acpica\\ code\\drivers\\platform\\acpi\\acpi.c code\\drivers\\platform\\acpi\\acpi_osl.c code\\drivers\\platform\\acpi\\acpi_ec.c @obj\\acpica\\sources.rsp && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /NOENTRY /OUT:bin\\acpi.sys bin\\kernel.lib obj\\acpica\\*.obj", ACPICA_CFLAGS_LITERAL))); Nob_String_Builder sb = {0}, lwip_files = {0}; if (nob_read_entire_file("code\\drivers\\net\\lwip\\lwip_sources.txt", &sb)) { Nob_String_View sv = nob_sv_from_parts(sb.items, sb.count); while (sv.count > 0) { Nob_String_View line = nob_sv_trim(nob_sv_chop_by_delim(&sv, '\n')); if (line.count > 0 && line.data[0] != '#') { nob_sb_append_cstr(&lwip_files, "code\\"); for (size_t i = 0; i < line.count; i++) nob_sb_append_buf(&lwip_files, &(char){line.data[i] == '/' ? '\\' : line.data[i]}, 1); nob_sb_append_cstr(&lwip_files, " "); } } nob_sb_append_null(&lwip_files); nob_da_append(&procs, run_async(nob_temp_sprintf("cl %s /MP /c /Foobj\\lwip\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\lwip.sys /NOENTRY bin\\kernel.lib obj\\libc.obj obj\\lwip\\*.obj", LwipCflags, lwip_files.items))); } Nob_String_Builder ext4_sb = {0}, ext4_files = {0}; if (nob_read_entire_file("code\\drivers\\fs\\ext4\\lwext4_sources.txt", &ext4_sb)) { Nob_String_View sv = nob_sv_from_parts(ext4_sb.items, ext4_sb.count); while (sv.count > 0) { Nob_String_View line = nob_sv_trim(nob_sv_chop_by_delim(&sv, '\n')); if (line.count > 0 && line.data[0] != '#') { nob_sb_append_cstr(&ext4_files, "code\\"); for (size_t i = 0; i < line.count; i++) nob_sb_append_buf(&ext4_files, &(char){line.data[i] == '/' ? '\\' : line.data[i]}, 1); nob_sb_append_cstr(&ext4_files, " "); } } nob_sb_append_null(&ext4_files); nob_da_append(&procs, run_async(nob_temp_sprintf("cl %s /MP /c /Foobj\\ext4\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\ext4.sys /NOENTRY bin\\kernel.lib obj\\libc.obj obj\\ext4\\*.obj", Ext4Cflags, ext4_files.items))); } Nob_String_Builder ntfs3g_sb = {0}, ntfs3g_files = {0}; if (nob_read_entire_file("code\\drivers\\fs\\ntfs\\ntfs3g\\ntfs3g_sources.txt", &ntfs3g_sb)) { Nob_String_View sv = nob_sv_from_parts(ntfs3g_sb.items, ntfs3g_sb.count); while (sv.count > 0) { Nob_String_View line = nob_sv_trim(nob_sv_chop_by_delim(&sv, '\n')); if (line.count > 0 && line.data[0] != '#') { nob_sb_append_cstr(&ntfs3g_files, "code\\"); for (size_t i = 0; i < line.count; i++) nob_sb_append_buf(&ntfs3g_files, &(char){line.data[i] == '/' ? '\\' : line.data[i]}, 1); nob_sb_append_cstr(&ntfs3g_files, " "); } } nob_sb_append_null(&ntfs3g_files); nob_da_append(&procs, run_async(nob_temp_sprintf("cl %s /MP /c /Foobj\\ntfs3g\\ %s && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\ntfs.sys /NOENTRY bin\\kernel.lib obj\\printf.obj obj\\libc.obj obj\\ntfs3g\\*.obj", Ntfs3gCflags, ntfs3g_files.items))); } const char* apps[][4] = { {"system\\init", NATIVE_INIT_LIBS_LITERAL, "init", "/ENTRY:_start"}, {"system\\rssrv", NATIVE_SERVICE_LIBS_LITERAL, "rssrv", "/ENTRY:_start"}, {"system\\posixsrv", NATIVE_SERVICE_LIBS_LITERAL, "posixsrv", "/ENTRY:_start"}, {"system\\dwm", NATIVE_SERVICE_LIBS_LITERAL, "dwm", "/ENTRY:_start"}, {"tests\\all_tests", NATIVE_EXE_LIBS_LITERAL, "all_tests", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\posix_service_smoke", NATIVE_EXE_LIBS_LITERAL, "posix_service_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\shell_win32", WIN32_EXE_LIBS_LITERAL, "shell_win32", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\shell_posix", POSIX_EXE_LIBS_LITERAL, "shell_posix", "/ENTRY:PosixStart"}, {"apps\\shell_native", NATIVE_EXE_LIBS_LITERAL, "shell_native", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\async_apc", NATIVE_EXE_LIBS_LITERAL, "async_apc", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\apc_return_smoke", NATIVE_EXE_LIBS_LITERAL, "apc_return_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\async_cancel", NATIVE_EXE_LIBS_LITERAL, "async_cancel", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\file_stat_smoke", NATIVE_EXE_LIBS_LITERAL, "file_stat_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\handle_dup_smoke", NATIVE_EXE_LIBS_LITERAL, "handle_dup_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\security_smoke", NATIVE_EXE_LIBS_LITERAL, "security_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\port_ipc_smoke", NATIVE_EXE_LIBS_LITERAL, "port_ipc_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\resource_service_smoke", NATIVE_EXE_LIBS_LITERAL, "resource_service_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\anonymous_queue_smoke", NATIVE_EXE_LIBS_LITERAL, "anonymous_queue_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\input_service_smoke", NATIVE_EXE_LIBS_LITERAL, "input_service_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\console_service_smoke", NATIVE_EXE_LIBS_LITERAL, "console_service_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\desktop_smoke", NATIVE_EXE_LIBS_LITERAL, "desktop_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\timer_smoke", NATIVE_EXE_LIBS_LITERAL, "timer_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\stats_abi_smoke", NATIVE_EXE_LIBS_LITERAL, "stats_abi_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\realpath_smoke", NATIVE_EXE_LIBS_LITERAL, "realpath_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\file_lock_smoke", NATIVE_EXE_LIBS_LITERAL, "file_lock_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\process_protection_smoke", NATIVE_EXE_LIBS_LITERAL, "process_protection_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\process_exit_multithread_smoke", NATIVE_EXE_LIBS_LITERAL, "process_exit_multithread_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\thread_name_smoke", NATIVE_EXE_LIBS_LITERAL, "thread_name_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\process_builder_smoke", "bin\\syscall_s.lib obj\\libc.obj " NATIVE_RUNTIME_OBJS_LITERAL, "process_builder_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\socket_addr_smoke", NATIVE_EXE_LIBS_LITERAL, "socket_addr_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\net_irp_smoke", NATIVE_EXE_LIBS_LITERAL, "net_irp_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\module_load_smoke", NATIVE_EXE_LIBS_LITERAL, "module_load_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\posix_module_smoke", POSIX_EXE_LIBS_LITERAL, "posix_module_smoke", "/ENTRY:PosixStart"}, {"tests\\posix_runtime_smoke", POSIX_EXE_LIBS_LITERAL, "posix_runtime_smoke", "/ENTRY:PosixStart"}, {"tests\\posix_fd_smoke", POSIX_EXE_LIBS_LITERAL, "posix_fd_smoke", "/ENTRY:PosixStart"}, {"tests\\posix_process_smoke", POSIX_EXE_LIBS_LITERAL, "posix_process_smoke", "/ENTRY:PosixStart"}, {"tests\\posix_signal_smoke", POSIX_EXE_LIBS_LITERAL, "posix_signal_smoke", "/ENTRY:PosixStart"}, {"tests\\posix_pipe_smoke", POSIX_EXE_LIBS_LITERAL, "posix_pipe_smoke", "/ENTRY:PosixStart"}, {"tests\\exception_dispatcher_smoke", NATIVE_EXE_LIBS_LITERAL, "exception_dispatcher_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\native_exception_runtime_smoke", NATIVE_EXE_LIBS_LITERAL, "native_exception_runtime_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\native_raise_exception_smoke", NATIVE_EXE_LIBS_LITERAL, "native_raise_exception_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\exception_smoke", NATIVE_EXE_LIBS_LITERAL, "exception_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\win32_exception_smoke", WIN32_EXE_LIBS_LITERAL, "win32_exception_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\win32_seh_smoke", WIN32_EXE_LIBS_LITERAL, "win32_seh_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\syscall_contract_smoke", NATIVE_EXE_LIBS_LITERAL, "syscall_contract_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\would_block_smoke", NATIVE_EXE_LIBS_LITERAL, "would_block_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\audio_stream_smoke", NATIVE_EXE_LIBS_LITERAL, "audio_stream_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\winmm_waveout_smoke", WIN32_EXE_LIBS_LITERAL, "winmm_waveout_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\win32_condition_variable_smoke", WIN32_EXE_LIBS_LITERAL, "win32_condition_variable_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\win32_mutex_smoke", WIN32_EXE_LIBS_LITERAL, "win32_mutex_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\win32_thread_suspend_smoke", WIN32_EXE_LIBS_LITERAL, "win32_thread_suspend_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\win32_module_lookup_smoke", WIN32_EXE_LIBS_LITERAL, "win32_module_lookup_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\cwd_userspace_smoke", NATIVE_EXE_LIBS_LITERAL, "cwd_userspace_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\mmap_smoke", NATIVE_EXE_LIBS_LITERAL, "mmap_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\pcache_smoke", NATIVE_EXE_LIBS_LITERAL, "pcache_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\pcache_pressure", NATIVE_EXE_LIBS_LITERAL, "pcache_pressure", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\dirty_writeback", NATIVE_EXE_LIBS_LITERAL, "dirty_writeback", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\shared_mmap", NATIVE_EXE_LIBS_LITERAL, "shared_mmap", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\pcache_invalidate", NATIVE_EXE_LIBS_LITERAL, "pcache_invalidate", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\pcache_mmap_read_reuse", NATIVE_EXE_LIBS_LITERAL, "pcache_mmap_read_reuse", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\pcache_multithread", NATIVE_EXE_LIBS_LITERAL, "pcache_multithread", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\surface_smoke", NATIVE_EXE_LIBS_LITERAL, "surface_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\surface_invalid_rect", NATIVE_EXE_LIBS_LITERAL, "surface_invalid_rect", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\surface_multithread_commit", NATIVE_EXE_LIBS_LITERAL, "surface_multithread_commit", NATIVE_EXE_ENTRY_LITERAL}, {"tests\\surface_cross_process_smoke", NATIVE_EXE_LIBS_LITERAL, "surface_cross_process_smoke", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\edit", NATIVE_EXE_LIBS_LITERAL, "edit", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\httpget", NATIVE_EXE_LIBS_LITERAL, "httpget", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\tcpserve", NATIVE_EXE_LIBS_LITERAL, "tcpserve", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\udp", NATIVE_EXE_LIBS_LITERAL, "udp", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\resolve", NATIVE_EXE_LIBS_LITERAL, "resolve", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\ping", NATIVE_EXE_LIBS_LITERAL, "ping", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\doom", NATIVE_EXE_LIBS_LITERAL, "doom", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\video", "bin\\syscall.lib obj\\libc.obj " NATIVE_RUNTIME_OBJS_LITERAL " code\\user\\apps\\video\\bink2w64.lib", "video", NATIVE_EXE_ENTRY_LITERAL}, {"apps\\memtop", NATIVE_EXE_LIBS_LITERAL, "memtop", NATIVE_EXE_ENTRY_LITERAL} }; for (size_t i = 0; i < NOB_ARRAY_LEN(apps); i++) { if (!with_tests && strncmp(apps[i][0], "tests\\", 6) == 0) continue; const char* appCflags = strcmp(apps[i][3], "/ENTRY:PosixStart") == 0 ? PosixUserCflags : UserCflags; const char* cmd = nob_temp_sprintf( "cl %s /MP /c /Foobj\\%s\\ code\\user\\%s\\*.c && link %s /SUBSYSTEM:NATIVE " USER_IMAGE_FLAGS_LITERAL " %s /OUT:bin\\%s.exe /PDB:bin\\%s.pdb %s obj\\%s\\*.obj", appCflags, apps[i][2], apps[i][0], LFLAGS, apps[i][3], apps[i][2], apps[i][2], apps[i][1], apps[i][2] ); nob_da_append(&procs, run_async(cmd)); } if (!nob_procs_wait(procs)) { nob_log(NOB_ERROR, "One or more parallel build jobs failed!"); return 1; } // 4. Formatting and Packing VHD via mtools (No Admin, Fast). nob_log(NOB_INFO, "--- Formatting & Packing disk.vhd with mtools ---"); run_sync("mformat -i " VHD_PART1 " -F"); run_sync("mformat -i " VHD_PART2 " -F"); mmd_dir(VHD_PART1, "EFI"); mmd_dir(VHD_PART1, "EFI/BOOT"); mmd_dir(VHD_PART1, "EFI/NTLite"); mmd_dir(VHD_PART1, "EFI/NTLite/fs"); mmd_dir(VHD_PART2, "apps"); mmd_dir(VHD_PART2, "system"); mmd_dir(VHD_PART2, "drivers"); if (with_tests) mmd_dir(VHD_PART2, "tests"); // The ESP is only the boot anchor; the configured system volume carries the OS payload. if (!mcopy_file("bin\\bootx64.efi", VHD_PART1, "EFI/BOOT/bootx64.efi")) return 1; if (!mcopy_file("code\\boot.ini", VHD_PART1, "boot.ini")) return 1; if (!run_sync("if exist code\\boot\\uefi\\fs\\*.efi mcopy -o -i " VHD_PART1 " code\\boot\\uefi\\fs\\*.efi ::EFI/NTLite/fs/")) return 1; if (!mcopy_file("bin\\kernel.exe", VHD_PART2, "system/colonel.exe")) return 1; const char* system_files[] = { "bin\\hal.dll", "bin\\syscall.dll", "bin\\win32.dll", "bin\\posix.dll", "code\\settings.ini", "code\\services.ini", "bin\\init.exe", "bin\\rssrv.exe", "bin\\posixsrv.exe", "bin\\dwm.exe", }; if (!mcopy_files_to_dir(VHD_PART2, "system/", system_files, NOB_ARRAY_LEN(system_files))) return 1; const char* driver_files[] = { "bin\\pci.sys", "bin\\ps2.sys", "bin\\hda.sys", "bin\\ata.sys", "bin\\ahci.sys", "bin\\fat.sys", "bin\\ntfs.sys", "bin\\ext4.sys", "bin\\vmwaresvga.sys", "bin\\lwip.sys", "bin\\usb.sys", "bin\\acpi.sys", "bin\\rtl816x.sys", "bin\\rtl8139.sys", "code\\drivers\\drivers.ini", }; if (!mcopy_files_to_dir(VHD_PART2, "drivers/", driver_files, NOB_ARRAY_LEN(driver_files))) return 1; // The build artifact keeps the descriptive target name; the installed serial driver gets the cereal joke. if (!mcopy_file("bin\\serial.sys", VHD_PART2, "drivers/cereal.sys")) return 1; const char* app_files[] = { "bin\\shell_win32.exe", "bin\\shell_posix.exe", "bin\\shell_native.exe", "bin\\edit.exe", "bin\\httpget.exe", "bin\\tcpserve.exe", "bin\\udp.exe", "bin\\resolve.exe", "bin\\ping.exe", "bin\\doom.exe", "bin\\video.exe", "bin\\memtop.exe", }; if (!mcopy_files_to_dir(VHD_PART2, "apps/", app_files, NOB_ARRAY_LEN(app_files))) return 1; const char* test_files[] = { "bin\\all_tests.exe", "bin\\posix_service_smoke.exe", "bin\\async_apc.exe", "bin\\async_cancel.exe", "bin\\apc_return_smoke.exe", "bin\\file_stat_smoke.exe", "bin\\handle_dup_smoke.exe", "bin\\security_smoke.exe", "bin\\port_ipc_smoke.exe", "bin\\resource_service_smoke.exe", "bin\\anonymous_queue_smoke.exe", "bin\\input_service_smoke.exe", "bin\\console_service_smoke.exe", "bin\\desktop_smoke.exe", "bin\\timer_smoke.exe", "bin\\stats_abi_smoke.exe", "bin\\realpath_smoke.exe", "bin\\file_lock_smoke.exe", "bin\\process_protection_smoke.exe", "bin\\process_exit_multithread_smoke.exe", "bin\\thread_name_smoke.exe", "bin\\process_builder_smoke.exe", "bin\\socket_addr_smoke.exe", "bin\\net_irp_smoke.exe", "bin\\module_load_smoke.exe", "bin\\posix_module_smoke.exe", "bin\\posix_runtime_smoke.exe", "bin\\posix_fd_smoke.exe", "bin\\posix_process_smoke.exe", "bin\\posix_signal_smoke.exe", "bin\\posix_pipe_smoke.exe", "bin\\exception_dispatcher_smoke.exe", "bin\\native_exception_runtime_smoke.exe", "bin\\native_raise_exception_smoke.exe", "bin\\exception_smoke.exe", "bin\\win32_exception_smoke.exe", "bin\\win32_seh_smoke.exe", "bin\\syscall_contract_smoke.exe", "bin\\would_block_smoke.exe", "bin\\audio_stream_smoke.exe", "bin\\winmm_waveout_smoke.exe", "bin\\win32_condition_variable_smoke.exe", "bin\\win32_mutex_smoke.exe", "bin\\win32_thread_suspend_smoke.exe", "bin\\win32_module_lookup_smoke.exe", "bin\\cwd_userspace_smoke.exe", "bin\\mmap_smoke.exe", "bin\\pcache_smoke.exe", "bin\\pcache_pressure.exe", "bin\\dirty_writeback.exe", "bin\\shared_mmap.exe", "bin\\pcache_invalidate.exe", "bin\\pcache_mmap_read_reuse.exe", "bin\\pcache_multithread.exe", "bin\\surface_smoke.exe", "bin\\surface_invalid_rect.exe", "bin\\surface_multithread_commit.exe", "bin\\surface_cross_process_smoke.exe", }; if (with_tests && !mcopy_files_to_dir(VHD_PART2, "tests/", test_files, NOB_ARRAY_LEN(test_files))) return 1; const char* optional_app_files[3]; size_t optional_app_count = 0; if (nob_file_exists("code\\user\\apps\\video\\bink2w64.dll")) optional_app_files[optional_app_count++] = "code\\user\\apps\\video\\bink2w64.dll"; if (nob_file_exists("code\\user\\apps\\video\\video.bk2")) optional_app_files[optional_app_count++] = "code\\user\\apps\\video\\video.bk2"; if (nob_file_exists("code\\user\\apps\\doom\\doom1.wad")) optional_app_files[optional_app_count++] = "code\\user\\apps\\doom\\doom1.wad"; if (!mcopy_files_to_dir(VHD_PART2, "apps/", optional_app_files, optional_app_count)) return 1; nob_log(NOB_INFO, "Build complete!"); return 0; }