#!/usr/bin/env pwsh $ErrorActionPreference = "Stop"; $HOST_OS = &{ if ($IsWindows) { "windows" } elseif ($IsMacOS) { "macos"; } elseif ($IsLinux) { "linux"; } else { Write-Error "Unsupported host operating system"; } }; $HOST_ARCH = &{ switch ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) { "X86" { "x86" } "X64" { "x86_64" } "Arm" { "arm" } "Arm64" { "aarch64" } default { Write-Error "Unsupported host architecture"; } } } $OUT_DIR = "out"; $DEPS_DIR = "thirdparty"; $EXE_NAME = "p2601"; function Get-Ext($platform) { if ($platform -eq "windows") { return ".exe"; } if ($platform -eq "emscripten") { return ".o"; } return ""; } $ZIG_VERSION = "0.15.2"; $ZIG_SLUG = "zig-${HOST_ARCH}-${HOST_OS}-${ZIG_VERSION}"; $ZIG_DIR = Join-Path $DEPS_DIR $ZIG_SLUG $ZIG = Join-Path $ZIG_DIR "zig$(Get-Ext $HOST_OS)" $BLOCKS_RT_DIR = Join-Path $DEPS_DIR "blocksruntime"; $BLOCKS_RT_FLAGS = "-I$BLOCKS_RT_DIR -I$(Join-Path $BLOCKS_RT_DIR "BlocksRuntime")"; $BLOCKS_RT_RUNTIME = (Join-Path $BLOCKS_RT_DIR "BlocksRuntime" "runtime.c"); $BLOCKS_RT_DATA = (Join-Path $BLOCKS_RT_DIR "BlocksRuntime" "data.c"); $BLOCKS_RT_SOURCE = "$BLOCKS_RT_RUNTIME $BLOCKS_RT_DATA"; $EMSDK_REPO = "https://github.com/emscripten-core/emsdk.git"; $EMSDK_DIR = Join-Path $DEPS_DIR "emsdk"; $C_SOURCE = "source/main.c"; $C_INCLUDES = "-Isrc -I$DEPS_DIR"; $C_FLAGS = "-std=c23 -fblocks -g $C_INCLUDES"; $RELEASE_FLAGS = "-Ofast -Wno-everything -ffast-math"; $WINDOWS_FLAGS = "-ld3d11 -lgdi32"; $MACOS_FLAGS = "-x objective-c -lobjc -framework Foundation -framework Cocoa -framework CoreFoundation -framework CoreGraphics -framework QuartzCore -framework Metal -framework MetalKit"; $LINUX_FLAGS = "-lgl"; $WASM_FLAGS = "-c -fno-sanitize=address -fno-sanitize=undefined -isystem " + (Join-Path $EMSDK_DIR "upstream" "emscripten" "cache" "sysroot" "include"); # try vendoring zig if (-not (Test-Path $ZIG)) { $zig_ext = ""; if ($IsWindows) { $zig_ext = ".zip"; } else { $zig_ext = ".tar.xz"; } $zig_url = "https://ziglang.org/download/$ZIG_VERSION/$ZIG_SLUG$ZIG_EXT"; Write-Host ":: Downloading Zig $ZIG_VERSION ($HOST_OS/$HOST_ARCH)"; Write-Host $zig_url; if ($IsWindows) { $tmp = Join-Path $DEPS_DIR "zig-compiler$zig_ext"; Invoke-WebRequest -Uri $zig_url -OutFile $tmp -UseBasicParsing Expand-Archive -Path $tmp -DestinationPath $DEPS_DIR -Force Remove-Item $tmp } else { curl -sSfL $zig_url | tar -xJ -C $DEPS_DIR } } # try vendoring emsdk if (-not (Test-Path $EMSDK_DIR)) { git clone $EMSDK_REPO $EMSDK_DIR Set-Location $EMSDK_DIR if ($IsWindows) { &"./emsdk.bat" install latest &"./emsdk.bat" activate latest } else { &"./emsdk" install latest &"./emsdk" activate latest } } # ensure the out directory exists New-Item -ItemType Directory -Force -Path $OUT_DIR | Out-Null; # ............... function GetFlags($os, $release) { $flags = $C_FLAGS; switch ($os) { "windows" { $flags += " $WINDOWS_FLAGS $BLOCKS_RT_FLAGS -DPLATFORM_WINDOWS"; } "macos" { $flags += " $MACOS_FLAGS -DPLATFORM_MACOS"; } "linux" { $flags += " $LINUX_FLAGS $BLOCKS_RT_FLAGS -DPLATFORM_LINUX"; } "emscripten" { $flags += " $WASM_FLAGS $BLOCKS_RT_FLAGS -DPLATFORM_WASM -DARCH_32" } default { Write-Error "Unsupported operating system '$os'"; } } if ($release) { $flags += " $RELEASE_FLAGS"; } return $flags; } function GetSource($os) { $source = $C_SOURCE; switch ($os) { "macos" { # Do nothing here since macos already supports the blocks runtime # and our local copy conflicts with the one shipped. } "windows" { $source += " $BLOCKS_RT_SOURCE"; } "linux" { $source += " $BLOCKS_RT_SOURCE"; } "emscripten" { $source += " $BLOCKS_RT_SOURCE" } default { Write-Error "Unsupported operating system '$os'"; } } return $source; } function CompileCommand($target_os, $release) { return "$ZIG cc $(GetFlags $target_os $release) $(GetSource $target_os)"; } # .............. $command = $args[0]; $rest = $args[1..($args.Length-1)]; switch ($command) { {($_ -eq "build") -or ($_ -eq "b")} { $release = $rest[0] -eq "release" -or $rest[0] -eq "fast"; $cmd = "$(CompileCommand $HOST_OS $release) -o $(Join-Path $OUT_DIR $($EXE_NAME + (Get-Ext $HOST_OS)))"; Write-Host (":: Compiling natively" + $(if ($release) { " (release mode)" } else { "" })); Write-Host $cmd; Invoke-Expression $cmd | Write-Host; } {($_ -eq "build-cross") -or ($_ -eq "bc")} { $target = $rest[0]; $rest = $rest[1..($rest.Length-1)]; $release = $rest[0] -eq "release" -or $rest[0] -eq "fast"; $target_os = ($target -split "-")[1]; if ($null -eq $target_os) { Write-Error "Unsupported target '$target' - run list-targets to see possible targets"; } $out = Join-Path $OUT_DIR ($EXE_NAME + (Get-Ext $target_os)); $cmd = "$(CompileCommand $target_os $release) --target=$target -o $out"; Write-Host (":: Cross-compiling for $target" + $(if ($release) { " (release mode)" } else { "" })); Write-Host $cmd; Invoke-Expression $cmd | Write-Host; if ($target_os -eq "emscripten") { if (-not $IsWindows) { Set-Alias "python" "python3"; } [Environment]::SetEnvironmentVariable("EMSDK_QUIET", 1); & (Join-Path $EMSDK_DIR "emsdk_env.ps1"); $runtime_o = (Join-Path $OUT_DIR "p2601-blocks-runtime.o"); $cmd = "$ZIG cc $WASM_FLAGS $BLOCKS_RT_FLAGS --target=$target -c $BLOCKS_RT_RUNTIME -o $runtime_o"; Write-Host $cmd; Invoke-Expression $cmd | Write-Host; $data_o = (Join-Path $OUT_DIR "p2601-blocks-data.o"); $cmd = "$ZIG cc $WASM_FLAGS $BLOCKS_RT_FLAGS --target=$target -c $BLOCKS_RT_DATA -o $data_O"; Write-Host $cmd; Invoke-Expression $cmd | Write-Host; $binary = Join-Path $OUT_DIR ($EXE_NAME + (Get-Ext $HOST_OS)); $cmd = "emcc $out $runtime_o $data_o -sUSE_WEBGL2=1 -sFULL_ES3=1 -sALLOW_MEMORY_GROWTH -o " + (Join-Path $OUT_DIR ($EXE_NAME + ".html")); Write-Host $cmd; Invoke-Expression $cmd | Write-Host; } } {($_ -eq "run") -or ($_ -eq "r")} { $binary = Join-Path $OUT_DIR ($EXE_NAME + (Get-Ext $HOST_OS)); if (-not (Test-Path $binary)) { $release = $rest[0] -eq "release" -or $rest[0] -eq "fast"; &"./do.ps1" build if ($release) { "release" } else { "" }; } Invoke-Expression $binary | Write-Host; } {($_ -eq "run-wasm") -or ($_ -eq "rw")} { if (-not (Test-Path (Join-Path $OUT_DIR "p2601.wasm"))) { &"./do.ps1" build-cross wasm32-emscripten; } $cmd = "$ZIG run " + (Join-Path $DEPS_DIR "tinyhttp.zig"); Write-Host $cmd; Invoke-Expression $cmd | Write-Host; } {($_ -eq "clean") -or ($_ -eq "c")} { Write-Host ":: Cleaning up build artifacts..."; Remove-Item -Path (Join-Path $OUT_DIR ($EXE_NAME + "*")) -Force; } {($_ -eq "list") -or ($_ -eq "l")} { # zig target doesn't actually output json... Write-Host ":: Available cross-compilation targets"; Write-Host " x86_64-windows-gnu"; Write-Host " x86_64-linux-gnu"; Write-Host " wasm32-emscripten"; } default { Write-Host ":: Available things to do"; Write-Host " build (b) compiles the program natively"; Write-Host " build-cross (bc) cross-compiles the program for the target triple (ex. x86_64-windows-gnu)"; Write-Host " run (r) compiles and runs the native program"; Write-Host " run-wasm (rw) compiles and runs the wasm program"; Write-Host " clean (c) cleans up all build artifacts"; Write-Host " list-targets (lt) lists all cross-compliation targets"; return; } }