Files
nt-lite/code/build/build.c
T
maksw 73abd6f90d isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
2026-09-16 10:33:20 +02:00

701 lines
43 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
// 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 obj\\runtime\\native_exception.obj"
#define NATIVE_EXE_ENTRY_LITERAL "/ENTRY:NtlNativeStart"
#define USER_IMAGE_FLAGS_LITERAL "/DYNAMICBASE /HIGHENTROPYVA"
#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;
} 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_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\\kernel", "obj\\lwip", "obj\\ext4", "obj\\ntfs3g", "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\\named_queue_lifetime_smoke", "obj\\input_api_smoke", "obj\\input_model_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_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\\kernel", "obj\\lwip", "obj\\ext4", "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\\named_queue_lifetime_smoke", "obj\\input_api_smoke", "obj\\input_model_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_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);
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 /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 /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),
nob_temp_sprintf("cl %s /DNTL_POSIX_BUILD /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 " 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;
}
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\\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\\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\\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 /ENTRY:DriverEntry 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 /ENTRY:DriverEntry 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\\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\\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_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++) {
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");
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\\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\\named_queue_lifetime_smoke.exe",
"bin\\input_api_smoke.exe",
"bin\\input_model_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_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 (!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;
}