Files
nt-lite/code/build/build.c
T

538 lines
33 KiB
C

// 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_LITERAL "/nologo /W3 /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 KERNEL_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL " /Icode\\kernel\\include"
#define DRIVER_CFLAGS_LITERAL COMMON_CFLAGS_LITERAL
#define USER_CFLAGS_LITERAL COMMON_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.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 obj\\runtime\\native_exception.obj"
#define NATIVE_EXE_ENTRY_LITERAL "/ENTRY:NtlNativeStart"
#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 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)
const char *CommonCflags = COMMON_CFLAGS_LITERAL;
const char *KernelCflags = KERNEL_CFLAGS_LITERAL;
const char *UserCflags = USER_CFLAGS_LITERAL;
const char *BootCflags = BOOT_CFLAGS_LITERAL;
const char *LwipCflags = LWIP_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;
} Driver_Target;
#define DRIVER_TARGET(name_, obj_dir_, sources_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, "" }
#define DRIVER_TARGET_LIBS(name_, obj_dir_, sources_, libs_) { (name_), (obj_dir_), (sources_), DRIVER_CFLAGS_LITERAL, (libs_) }
#define DRIVER_TARGET_FLAGS(name_, obj_dir_, sources_, cflags_) { (name_), (obj_dir_), (sources_), (cflags_), "" }
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("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_mount.c"),
DRIVER_TARGET("ntfs", "obj\\drivers\\ntfs", "code\\drivers\\fs\\ntfs\\ntfs.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\\kernel", "obj\\lwip", "obj\\hal",
"obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix", "obj\\drivers", "obj\\init",
"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\\named_queue_lifetime_smoke", "obj\\input_api_smoke", "obj\\input_model_smoke", "obj\\timer_smoke", "obj\\stats_abi_smoke", "obj\\realpath_smoke", "obj\\file_lock_smoke", "obj\\process_protection_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_peb_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\\surface_smoke", "obj\\surface_invalid_rect", "obj\\surface_multithread_present", "obj\\net_irp_smoke", "obj\\module_load_smoke", "obj\\posix_module_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\\kernel", "obj\\lwip", "obj\\hal",
"obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix",
"obj\\init", "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\\named_queue_lifetime_smoke", "obj\\input_api_smoke", "obj\\input_model_smoke", "obj\\timer_smoke", "obj\\stats_abi_smoke", "obj\\realpath_smoke", "obj\\file_lock_smoke", "obj\\process_protection_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_peb_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\\surface_smoke", "obj\\surface_invalid_rect", "obj\\surface_multithread_present", "obj\\net_irp_smoke", "obj\\module_load_smoke", "obj\\posix_module_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");
}
// Utility to copy a 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);
}
// 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);
}
// 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 true;
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};
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);
if (!create_disk_vhd_if_missing()) return 1;
if (!create_usbfatroot_if_missing()) return 1;
create_layout();
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",
"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 code\\common\\ini_parser.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", UserCflags),
// Bootloader.
nob_temp_sprintf("cl %s /MP /c /Icode\\boot\\uefi\\include /Foobj\\boot\\ code\\boot\\uefi\\*.c && link %s /FORCE:MULTIPLE /SUBSYSTEM:EFI_APPLICATION /ENTRY:UefiMain /OUT:bin\\bootx64.efi obj\\libc.obj obj\\ini_parser.obj code\\boot\\uefi\\efilib.lib obj\\boot\\*.obj", BootCflags, LFLAGS),
// HAL.
nob_temp_sprintf("cl %s /MP /c /Foobj\\hal\\ code\\kernel\\hal\\*.c && link %s /DLL /OUT:bin\\hal.dll /ENTRY:HalInitialize /IGNORE:4216 obj\\printf.obj obj\\libc.obj obj\\hal\\*.obj", KernelCflags, LFLAGS),
// Kernel.
nob_temp_sprintf("cl %s /DKE_DISPLAY_BUILD /MP /c /Foobj\\kernel\\ code\\kernel\\*.c && link %s /SUBSYSTEM:NATIVE /ENTRY:KernelMain /OUT:bin\\kernel.exe bin\\hal.lib obj\\ini_parser.obj obj\\printf.obj obj\\libc.obj obj\\kernel\\*.obj", KernelCflags, LFLAGS),
// Subsystem DLLs.
"link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\syscall.dll obj\\syscall\\stubs.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 /OUT:bin\\win32.dll bin\\syscall.lib obj\\libc.obj obj\\win32\\*.obj", UserCflags),
nob_temp_sprintf("cl %s /DUSER_HEAP_EXPORTS /MP /c /Foobj\\posix\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\personalities\\posix\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\posix.dll bin\\syscall.lib obj\\libc.obj obj\\posix\\*.obj", UserCflags)
};
for (size_t i = 0; i < NOB_ARRAY_LEN(core_tasks); i++) {
if (!run_sync(core_tasks[i])) 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 /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.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 /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib %s obj\\libc.obj %s\\*.obj",
driver->cflags, driver->obj_dir, driver->sources, driver->name,
driver->libs ? driver->libs : "", driver->obj_dir
);
nob_da_append(&procs, run_async(cmd));
}
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 /ENTRY:DriverEntry bin\\hal.lib bin\\kernel.lib obj\\libc.obj obj\\lwip\\*.obj", LwipCflags, lwip_files.items)));
}
const char *apps[][4] = {
{"system\\init", NATIVE_INIT_LIBS_LITERAL, "init", "/ENTRY:_start"},
{"tests\\all_tests", NATIVE_EXE_LIBS_LITERAL, "all_tests", 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\\named_queue_lifetime_smoke", NATIVE_EXE_LIBS_LITERAL, "named_queue_lifetime_smoke", NATIVE_EXE_ENTRY_LITERAL},
{"tests\\input_api_smoke", NATIVE_EXE_LIBS_LITERAL, "input_api_smoke", NATIVE_EXE_ENTRY_LITERAL},
{"tests\\input_model_smoke", NATIVE_EXE_LIBS_LITERAL, "input_model_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\\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\\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_peb_smoke", NATIVE_EXE_LIBS_LITERAL, "cwd_peb_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_present", NATIVE_EXE_LIBS_LITERAL, "surface_multithread_present", 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++) {
const char *cmd = nob_temp_sprintf(
"cl %s /MP /c /Foobj\\%s\\ code\\user\\%s\\*.c && link %s /SUBSYSTEM:NATIVE %s /OUT:bin\\%s.exe /PDB:bin\\%s.pdb %s obj\\%s\\*.obj",
UserCflags, 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, "apps");
mmd_dir(VHD_PART1, "system");
mmd_dir(VHD_PART1, "drivers");
mmd_dir(VHD_PART1, "EFI");
mmd_dir(VHD_PART1, "EFI/BOOT");
mmd_dir(VHD_PART2, "tests");
const char *copies[][3] = {
{"bin\\bootx64.efi", VHD_PART1, "EFI/BOOT/bootx64.efi"},
{"bin\\kernel.exe", VHD_PART1, "system/colonel.exe"},
{"bin\\hal.dll", VHD_PART1, "system/hal.dll"},
{"bin\\syscall.dll", VHD_PART1, "system/syscall.dll"},
{"bin\\win32.dll", VHD_PART1, "system/win32.dll"},
{"bin\\posix.dll", VHD_PART1, "system/posix.dll"},
{"code\\settings.ini", VHD_PART1, "system/settings.ini"},
{"bin\\init.exe", VHD_PART1, "system/init.exe"},
{"bin\\pci.sys", VHD_PART1, "drivers/pci.sys"},
{"bin\\ps2.sys", VHD_PART1, "drivers/ps2.sys"},
{"bin\\serial.sys", VHD_PART1, "drivers/serial.sys"},
{"bin\\hda.sys", VHD_PART1, "drivers/hda.sys"},
{"bin\\ata.sys", VHD_PART1, "drivers/ata.sys"},
{"bin\\ahci.sys", VHD_PART1, "drivers/ahci.sys"},
{"bin\\fat.sys", VHD_PART1, "drivers/fat.sys"},
{"bin\\ntfs.sys", VHD_PART1, "drivers/ntfs.sys"},
{"bin\\vmwaresvga.sys", VHD_PART1, "drivers/vmwaresvga.sys"},
{"bin\\lwip.sys", VHD_PART1, "drivers/lwip.sys"},
{"bin\\usb.sys", VHD_PART1, "drivers/usb.sys"},
{"bin\\rtl816x.sys", VHD_PART1, "drivers/rtl816x.sys"},
{"bin\\rtl8139.sys", VHD_PART1, "drivers/rtl8139.sys"},
{"code\\drivers\\drivers.ini", VHD_PART1, "drivers/drivers.ini"},
{"code\\boot.ini", VHD_PART1, "boot.ini"},
{"bin\\shell_win32.exe", VHD_PART1, "apps/shell_win32.exe"},
{"bin\\shell_posix.exe", VHD_PART1, "apps/shell_posix.exe"},
{"bin\\shell_native.exe", VHD_PART1, "apps/shell_native.exe"},
{"bin\\edit.exe", VHD_PART1, "apps/edit.exe"},
{"bin\\httpget.exe", VHD_PART1, "apps/httpget.exe"},
{"bin\\tcpserve.exe", VHD_PART1, "apps/tcpserve.exe"},
{"bin\\udp.exe", VHD_PART1, "apps/udp.exe"},
{"bin\\resolve.exe", VHD_PART1, "apps/resolve.exe"},
{"bin\\ping.exe", VHD_PART1, "apps/ping.exe"},
{"bin\\doom.exe", VHD_PART1, "apps/doom.exe"},
{"bin\\video.exe", VHD_PART1, "apps/video.exe"},
{"bin\\memtop.exe", VHD_PART1, "apps/memtop.exe"},
// Partition 2 Apps
{"bin\\all_tests.exe", VHD_PART2, "tests/all_tests.exe"},
{"bin\\async_apc.exe", VHD_PART2, "tests/async_apc.exe"},
{"bin\\async_cancel.exe", VHD_PART2, "tests/async_cancel.exe"},
{"bin\\apc_return_smoke.exe", VHD_PART2, "tests/apc_return_smoke.exe"},
{"bin\\file_stat_smoke.exe", VHD_PART2, "tests/file_stat_smoke.exe"},
{"bin\\handle_dup_smoke.exe", VHD_PART2, "tests/handle_dup_smoke.exe"},
{"bin\\named_queue_lifetime_smoke.exe", VHD_PART2, "tests/named_queue_lifetime_smoke.exe"},
{"bin\\input_api_smoke.exe", VHD_PART2, "tests/input_api_smoke.exe"},
{"bin\\input_model_smoke.exe", VHD_PART2, "tests/input_model_smoke.exe"},
{"bin\\timer_smoke.exe", VHD_PART2, "tests/timer_smoke.exe"},
{"bin\\stats_abi_smoke.exe", VHD_PART2, "tests/stats_abi_smoke.exe"},
{"bin\\realpath_smoke.exe", VHD_PART2, "tests/realpath_smoke.exe"},
{"bin\\file_lock_smoke.exe", VHD_PART2, "tests/file_lock_smoke.exe"},
{"bin\\process_protection_smoke.exe", VHD_PART2, "tests/process_protection_smoke.exe"},
{"bin\\socket_addr_smoke.exe", VHD_PART2, "tests/socket_addr_smoke.exe"},
{"bin\\net_irp_smoke.exe", VHD_PART2, "tests/net_irp_smoke.exe"},
{"bin\\module_load_smoke.exe", VHD_PART2, "tests/module_load_smoke.exe"},
{"bin\\posix_module_smoke.exe", VHD_PART2, "tests/posix_module_smoke.exe"},
{"bin\\exception_dispatcher_smoke.exe", VHD_PART2, "tests/exception_dispatcher_smoke.exe"},
{"bin\\native_exception_runtime_smoke.exe", VHD_PART2, "tests/native_exception_runtime_smoke.exe"},
{"bin\\native_raise_exception_smoke.exe", VHD_PART2, "tests/native_raise_exception_smoke.exe"},
{"bin\\exception_smoke.exe", VHD_PART2, "tests/exception_smoke.exe"},
{"bin\\win32_exception_smoke.exe", VHD_PART2, "tests/win32_exception_smoke.exe"},
{"bin\\win32_seh_smoke.exe", VHD_PART2, "tests/win32_seh_smoke.exe"},
{"bin\\syscall_contract_smoke.exe", VHD_PART2, "tests/syscall_contract_smoke.exe"},
{"bin\\would_block_smoke.exe", VHD_PART2, "tests/would_block_smoke.exe"},
{"bin\\audio_stream_smoke.exe", VHD_PART2, "tests/audio_stream_smoke.exe"},
{"bin\\winmm_waveout_smoke.exe", VHD_PART2, "tests/winmm_waveout_smoke.exe"},
{"bin\\win32_condition_variable_smoke.exe", VHD_PART2, "tests/win32_condition_variable_smoke.exe"},
{"bin\\win32_mutex_smoke.exe", VHD_PART2, "tests/win32_mutex_smoke.exe"},
{"bin\\win32_thread_suspend_smoke.exe", VHD_PART2, "tests/win32_thread_suspend_smoke.exe"},
{"bin\\win32_module_lookup_smoke.exe", VHD_PART2, "tests/win32_module_lookup_smoke.exe"},
{"bin\\cwd_peb_smoke.exe", VHD_PART2, "tests/cwd_peb_smoke.exe"},
{"bin\\mmap_smoke.exe", VHD_PART2, "tests/mmap_smoke.exe"},
{"bin\\pcache_smoke.exe", VHD_PART2, "tests/pcache_smoke.exe"},
{"bin\\pcache_pressure.exe", VHD_PART2, "tests/pcache_pressure.exe"},
{"bin\\dirty_writeback.exe", VHD_PART2, "tests/dirty_writeback.exe"},
{"bin\\shared_mmap.exe", VHD_PART2, "tests/shared_mmap.exe"},
{"bin\\pcache_invalidate.exe", VHD_PART2, "tests/pcache_invalidate.exe"},
{"bin\\pcache_mmap_read_reuse.exe", VHD_PART2, "tests/pcache_mmap_read_reuse.exe"},
{"bin\\pcache_multithread.exe", VHD_PART2, "tests/pcache_multithread.exe"},
{"bin\\surface_smoke.exe", VHD_PART2, "tests/surface_smoke.exe"},
{"bin\\surface_invalid_rect.exe", VHD_PART2, "tests/surface_invalid_rect.exe"},
{"bin\\surface_multithread_present.exe", VHD_PART2, "tests/surface_multithread_present.exe"}
};
for (size_t i = 0; i < NOB_ARRAY_LEN(copies); i++) {
mcopy_file(copies[i][0], copies[i][1], copies[i][2]);
}
if (nob_file_exists("code\\user\\apps\\video\\bink2w64.dll")) mcopy_file("code\\user\\apps\\video\\bink2w64.dll", VHD_PART1, "apps/bink2w64.dll");
if (nob_file_exists("code\\user\\apps\\video\\video.bk2")) mcopy_file("code\\user\\apps\\video\\video.bk2", VHD_PART1, "apps/video.bk2");
if (nob_file_exists("code\\user\\apps\\doom\\doom1.wad")) mcopy_file("code\\user\\apps\\doom\\doom1.wad", VHD_PART1, "apps/doom1.wad");
nob_log(NOB_INFO, "Build complete!");
return 0;
}