[CmdletBinding()]
param(
[ValidateSet('Desktop','Console')][string]$Edition='Desktop',
[switch]$BootstrapOnly,
[string[]]$RuntimeObjects = @(),
[string]$RuntimePortReceipt,
[string]$MathReceipt,
[string]$ToolsRoot
)
$ErrorActionPreference = 'Stop'
$Edition=if($Edition -eq 'Console'){'Console'}else{'Desktop'}
if($BootstrapOnly -and $Edition -eq 'Console'){throw 'BootstrapOnly cannot build the complete console edition.'}
$taskRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ToolsRoot) { $ToolsRoot = Join-Path $taskRoot '.tools' }
$ToolsRoot = [IO.Path]::GetFullPath($ToolsRoot)
$sourceRoot = Join-Path $taskRoot 'Source/XFESystem.NativeKernel'
$buildId = 'Build-' + $Edition + '-' + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() + '-' + [Guid]::NewGuid().ToString('N').Substring(0,8)
$outputRoot = Join-Path $taskRoot ('build/IndependentKernel/' + $buildId)
[void][IO.Directory]::CreateDirectory($outputRoot)
$receipt = [ordered]@{ Kind='XfeIndependentKernelBuild'; Target='x86_64-none'; Edition=$Edition; Passed=$false;
ContainsCosmos=$false; BootstrapOnly=[bool]$BootstrapOnly; FullDotNet10=$false;
Stage='preflight'; SourceSha256=[ordered]@{}; ToolSha256=[ordered]@{}; Commands=@(); OutputRoot=$outputRoot }
function Get-TaskHash([string]$Path) { (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() }
function Invoke-TaskTool([string]$Tool, [string[]]$Arguments, [string]$Name) {
$receipt.Commands += [ordered]@{Executable=$Tool;Arguments=$Arguments}
$savedAction=$ErrorActionPreference
try {
$ErrorActionPreference='Continue'
& $Tool @Arguments 2>&1 | Tee-Object -FilePath (Join-Path $outputRoot ($Name+'.log'))
$taskExit=$LASTEXITCODE
} finally { $ErrorActionPreference=$savedAction }
if ($taskExit -ne 0) { throw ($Name+' failed with exit code '+$taskExit) }
}
$previousLib=[Environment]::GetEnvironmentVariable('BFLAT_LIB','Process')
$previousLd=[Environment]::GetEnvironmentVariable('BFLAT_LD','Process')
Push-Location $taskRoot
try {
$compiler=Join-Path $ToolsRoot 'bflat-8.0.2/bflat.exe'
$clang=Join-Path $ToolsRoot 'llvm/bin/clang.exe'
$linker=Join-Path $ToolsRoot 'llvm/bin/ld.lld.exe'
$nm=Join-Path $ToolsRoot 'llvm/bin/llvm-nm.exe'
$objcopy=Join-Path $ToolsRoot 'llvm/bin/llvm-objcopy.exe'
$compilerLock=Get-Content -LiteralPath (Join-Path $taskRoot 'Tools/CSharpBoot/BflatToolchain.json') -Raw -Encoding UTF8 | ConvertFrom-Json
foreach($tool in @($compiler,$clang,$linker,$nm,$objcopy)) {
if (!(Test-Path -LiteralPath $tool)) { throw ('Required compiler tool is missing: '+$tool) }
$receipt.ToolSha256[$tool]=Get-TaskHash $tool
}
if ((Get-TaskHash $compiler) -cne $compilerLock.ToolSha256.'bflat.exe') { throw 'The locked bflat compiler differs.' }
$zero=Join-Path $ToolsRoot 'bflat-8.0.2/lib/linux/x64/zerolib.dll'
$receipt.ToolSha256[$zero]=Get-TaskHash $zero
$csharp=@(Get-ChildItem -LiteralPath $sourceRoot -File -Filter '*.cs' | Sort-Object Name | Select-Object -ExpandProperty FullName)
$csharp+=Join-Path $taskRoot 'Source/XFESystem.Boot/GpuContracts.cs'
$native=@(Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'Native') -File | Where-Object {$_.Extension -in '.c','.s'} | Sort-Object Name | Select-Object -ExpandProperty FullName)
if ($BootstrapOnly) {
$native+=Join-Path $taskRoot 'Source/XFESystem.NativeRuntime/Native/BasicLibc.c'
$native+=Join-Path $taskRoot 'Source/XFESystem.NativeRuntime/Native/Stdio.c'
}
$script=Join-Path $sourceRoot 'linker.ld'
if ($csharp.Count -eq 0 -or $native.Count -eq 0 -or !(Test-Path -LiteralPath $script)) { throw 'Independent kernel source files are incomplete.' }
$headers=@(Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'Native') -File -Filter '*.h' | Select-Object -ExpandProperty FullName)
$profilePath=Join-Path $sourceRoot 'KernelProfile.json'
$profile=Get-Content -LiteralPath $profilePath -Raw -Encoding UTF8 | ConvertFrom-Json
if ($profile.Kind -cne 'XfeIndependentKernelConfiguration' -or $profile.Architecture -cne 'x86_64' -or
$profile.ContainsCosmos -or $profile.ExecutingCpuCount -ne 1 -or
!((($profile.RamOnly -eq $true) -and ($profile.StorageEnabled -eq $false)) -or
(($profile.RamOnly -eq $false) -and ($profile.StorageEnabled -eq $true) -and $profile.StorageBackend -ceq 'BootUsbBotFat32DualBankWorkspaceV1' -and $profile.RamFallbackWhenBootUsbUnavailable -eq $true))) {
throw 'Unsupported independent kernel configuration.'
}
$receipt.Configuration=$profile
$boundFiles=@($csharp)+@($native)+@($headers)+@($script,$PSCommandPath,$profilePath)+@(
(Join-Path $taskRoot 'Tools/BuildBootLogo.py'),
(Join-Path $taskRoot 'assets/branding/console/icon.rgba'),
(Join-Path $taskRoot 'assets/branding/console/xfe-mono.bin'))
$receipt.BootVisualPolicy='XfeBrandedBootVisualV1'
foreach($path in $boundFiles) {
$relative=$path.Substring($taskRoot.Length+1).Replace('\','/')
$receipt.SourceSha256[$relative]=Get-TaskHash $path
if ([IO.File]::ReadAllText($path) -match '(?m)^\s*(using\s+Cosmos\.|#\s*include\s*[<"]Cosmos|<PackageReference\s+Include="Cosmos)') {
throw ('Independent kernel has a Cosmos dependency: '+$relative)
}
}
if (!$BootstrapOnly) {
if (!$RuntimePortReceipt -and $RuntimeObjects.Count -eq 1) {
$RuntimePortReceipt=Join-Path (Split-Path -Parent $RuntimeObjects[0]) 'PortReceipt.json'
}
if (!$RuntimePortReceipt) { throw 'A source-bound native runtime port receipt is required.' }
$port=Get-Content -LiteralPath $RuntimePortReceipt -Raw -Encoding UTF8 | ConvertFrom-Json
if ($port.Schema -cne 'XfeIndependentNativeRuntimePort1' -or $port.CosmosReferenced -or
!$port.NativePortCompilationPassed -or !$port.RelocatableRuntimeLinkPassed -or
$port.MicrosoftRuntimeVersion -cne '10.0.12' -or !$port.SourceSha256 -or
(Get-TaskHash $port.CombinedObjectPath) -cne $port.CombinedObjectSha256 -or
!$port.FinalLinkInputs -or !$port.FinalLinkInputsSha256) {
throw 'Runtime objects must match the exact independently compiled source-bound port.'
}
if ($RuntimeObjects.Count -eq 1 -and [IO.Path]::GetFullPath($RuntimeObjects[0]) -ieq [IO.Path]::GetFullPath($port.CombinedObjectPath)) {
# ld -r is useful for symbol inventory, but merged COMDAT unwind
# sections must not become the final executable input. Link the
# exact original managed/native objects and archives once.
$RuntimeObjects=@($port.FinalLinkInputs)
}
if($RuntimeObjects.Count -ne $port.FinalLinkInputs.Count){throw 'Runtime link input count differs from its receipt.'}
for($inputIndex=0;$inputIndex -lt $RuntimeObjects.Count;$inputIndex++) {
$inputPath=[IO.Path]::GetFullPath($RuntimeObjects[$inputIndex])
if($inputPath -ine [IO.Path]::GetFullPath($port.FinalLinkInputs[$inputIndex]) -or
(Get-TaskHash $inputPath) -cne $port.FinalLinkInputsSha256.PSObject.Properties[$port.FinalLinkInputs[$inputIndex]].Value) {
throw ('Runtime final link input differs: '+$inputPath)
}
}
foreach($property in $port.SourceSha256.PSObject.Properties) {
$path=[IO.Path]::GetFullPath((Join-Path $taskRoot $property.Name))
if (!$path.StartsWith($taskRoot+[IO.Path]::DirectorySeparatorChar,[StringComparison]::OrdinalIgnoreCase) -or
(Get-TaskHash $path) -cne $property.Value) { throw ('Runtime source changed: '+$property.Name) }
$receipt.SourceSha256[$property.Name]=$property.Value
}
$consoleProject='Source/XFESystem.NativeRuntime/ConsoleApplication/ConsoleApplication.csproj'
$desktopProject='Source/XFESystem.NativeRuntime/Application/NativeApplication.csproj'
if($Edition -eq 'Console') {
if(!$port.SourceSha256.PSObject.Properties[$consoleProject] -or $port.SourceSha256.PSObject.Properties[$desktopProject]) {
throw 'The console edition requires the standalone ConsoleApplication project, without the desktop application.'
}
foreach($entry in $port.SourceSha256.PSObject.Properties) {
if($entry.Name -match '^Source/XFESystem[.](Browser|Documents)/' -or
($entry.Name -match '^Source/XFESystem[.]Desktop/' -and $entry.Name -cne 'Source/XFESystem.Desktop/TerminalShell.cs')) {
throw ('Graphical application source is not allowed in the console edition: '+$entry.Name)
}
}
} elseif($port.SourceSha256.PSObject.Properties[$consoleProject]) {
throw 'The desktop edition cannot link the console entry application.'
}
foreach($map in @($port.AssemblySha256,$port.RuntimeLibrariesSha256,$port.NativeObjectsSha256)) {
if (!$map) { continue }
foreach($property in $map.PSObject.Properties) {
if ((Get-TaskHash $property.Name) -cne $property.Value) { throw ('Runtime input changed: '+$property.Name) }
}
}
$receipt.ManagedRuntimeLinked=$true
$receipt.RuntimePortReceipt=[ordered]@{Path=$RuntimePortReceipt;Sha256=(Get-TaskHash $RuntimePortReceipt);
MicrosoftRuntimeVersion=$port.MicrosoftRuntimeVersion;MicrosoftSourceCommit=$port.MicrosoftSourceCommit;
CombinedObjectSha256=$port.CombinedObjectSha256;RuntimeLibrariesSha256=$port.RuntimeLibrariesSha256;
FinalLinkInputsSha256=$port.FinalLinkInputsSha256;RelocatableObjectUsedForFinalLink=$false}
}
Remove-Item Env:BFLAT_LIB -ErrorAction SilentlyContinue
Remove-Item Env:BFLAT_LD -ErrorAction SilentlyContinue
$receipt.Stage='compile-csharp'
$managedObject=Join-Path $outputRoot 'KernelCoreRaw.o'
$arguments=@('build')+$csharp+@('--os:linux','--arch:x64','--stdlib:zero','--target:Shared','--deterministic','--no-debug-info','-Ot','-c','-x',('-o:'+$managedObject),'-i:xfe_native')
if (!$BootstrapOnly) { $arguments+=@('--define','XFE_DOTNET_RUNTIME') }
Invoke-TaskTool $compiler $arguments 'CSharpCompile'
# Zero has deliberately minimal Rhp helpers. Isolate every one of its
# symbols and metadata sections so the full Microsoft runtime can never
# accidentally resolve to those helpers or register the Zero module.
$defined=@(& $nm --defined-only --extern-only --just-symbol-name $managedObject)
if($LASTEXITCODE -ne 0){throw 'Cannot inspect bootstrap exports.'}
$undefined=@(& $nm --undefined-only --just-symbol-name $managedObject)
if($LASTEXITCODE -ne 0){throw 'Cannot inspect bootstrap imports.'}
$prefixed=Join-Path $outputRoot 'KernelCorePrefixed.o'
Invoke-TaskTool $objcopy @('--prefix-symbols=XfeZero_','--rename-section','__modules=__xfe_zero_modules','--rename-section','__managedcode=__xfe_zero_managedcode','--rename-section','__unbox=__xfe_zero_unbox',$managedObject,$prefixed) 'IsolateZeroRuntime'
$renames=Join-Path $outputRoot 'BootstrapSymbols.txt'
$restored=@($defined+$undefined | Where-Object {$_ -match '^(xfe_|XfeKernelMain$|XfeHandleInterrupt$|XfeRuntimeStart$)'} | Sort-Object -Unique | ForEach-Object {'XfeZero_'+$_+' '+$_})
$restored+=@('XfeZero_SystemNative_Abort xfe_zero_abort','XfeZero_SystemNative_Malloc xfe_zero_malloc')
# Large value-only GPU discovery records generate compiler libc intrinsics.
# Bind byte-range operations to our freestanding C implementation, never to
# an isolated managed helper or to an OS libc. No object ABI crosses here.
$restored+=@('XfeZero_memcpy memcpy','XfeZero_memset memset','XfeZero_memmove memmove')
$restored | Set-Content -LiteralPath $renames -Encoding ASCII
$isolated=Join-Path $outputRoot 'KernelCore.o'
Invoke-TaskTool $objcopy @(('--redefine-syms='+$renames),$prefixed,$isolated) 'RestoreKernelAbi'
$objects=@($isolated)
$receipt.Stage='compile-native'
foreach($path in $native) {
$object=Join-Path $outputRoot ([IO.Path]::GetFileName($path)+'.o')
$arguments=@('--target=x86_64-unknown-none-elf','-ffreestanding','-fno-builtin','-fno-stack-protector','-fasynchronous-unwind-tables','-fno-pic','-fno-pie','-mno-red-zone','-mcmodel=kernel','-O2','-g','-c',$path,'-o',$object)
Invoke-TaskTool $clang $arguments ([IO.Path]::GetFileName($path))
$objects+=$object
}
if (!$BootstrapOnly -and $RuntimeObjects.Count -eq 0) { throw 'A complete native runtime bridge is required. BootstrapOnly is an explicit, limited diagnostic build, not the desktop system.' }
foreach($path in $RuntimeObjects) {
$runtimeObject=[IO.Path]::GetFullPath($path)
if (!(Test-Path -LiteralPath $runtimeObject)) { throw ('Runtime object missing: '+$runtimeObject) }
$objects+=$runtimeObject
$receipt.ToolSha256[$runtimeObject]=Get-TaskHash $runtimeObject
}
if (!$MathReceipt) {
$latestMath=Get-ChildItem -LiteralPath (Join-Path $taskRoot 'build/IndependentKernel') -Directory -Filter 'Math-*' |
Sort-Object Name -Descending | Where-Object {Test-Path -LiteralPath (Join-Path $_.FullName 'BuildReceipt.json')} | Select-Object -First 1
if (!$latestMath) { throw 'Build the pinned external mathematical library with Tools/IndependentKernel/Runtime/BuildMath.py first.' }
$MathReceipt=Join-Path $latestMath.FullName 'BuildReceipt.json'
}
$math=Get-Content -LiteralPath $MathReceipt -Raw -Encoding UTF8 | ConvertFrom-Json
if ($math.Kind -cne 'XfeExternalMathLibraryBuild' -or !$math.Passed -or $math.ContainsCosmos -or
$math.ContainsMuslOperatingSystemCode -or $math.ArchiveSha256 -cne 'a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4' -or
(Get-TaskHash $math.LibraryPath) -cne $math.LibrarySha256) { throw 'Invalid external math build receipt.' }
if ($objects -notcontains $math.LibraryPath) { $objects+=$math.LibraryPath }
$receipt.ExternalMath=[ordered]@{Version=$math.Version;ArchiveUrl=$math.ArchiveUrl;ArchiveSha256=$math.ArchiveSha256;
LibrarySha256=$math.LibrarySha256;ReceiptSha256=(Get-TaskHash $MathReceipt);ContainsOperatingSystemCode=$false}
$receipt.SourceSha256['Tools/IndependentKernel/Runtime/BuildMath.py']=Get-TaskHash (Join-Path $taskRoot 'Tools/IndependentKernel/Runtime/BuildMath.py')
$receipt.Stage='link'
$kernel=Join-Path $outputRoot 'Kernel.elf'
Invoke-TaskTool $linker (@('-m','elf_x86_64','-nostdlib','-static','--gc-sections','--eh-frame-hdr','--error-limit=0','-z','max-page-size=4096','-T',$script)+$objects+@('-o',$kernel)) 'Link'
$symbols=@(& $nm --undefined-only $kernel)
if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect kernel imports.' }
$optionalBootstrap=@('XfeRuntimeDetachThread','XfeRuntimeTlsCreate','XfeRuntimeTlsRelease','XfeRuntimeTryHijack','XfeRuntimeDispatchHardwareFault')
$invalidImports=@($symbols | Where-Object {
-not ($BootstrapOnly -and $_ -match '^\s+w\s+(\S+)\s*$' -and $optionalBootstrap -contains $Matches[1])
})
if ($invalidImports.Count) { throw ('The freestanding kernel has unresolved imports: '+($invalidImports -join ', ')) }
$receipt.OptionalAbsentRuntimeServices=@($symbols)
& $nm --defined-only $kernel | Set-Content -LiteralPath (Join-Path $outputRoot 'Symbols.txt') -Encoding UTF8
if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect final kernel symbols.' }
if ([IO.File]::ReadAllText((Join-Path $outputRoot 'Symbols.txt')) -match 'Cosmos[._]') { throw 'Final kernel symbols contain Cosmos.' }
$bytes=[IO.File]::ReadAllBytes($kernel)
if ($bytes.Length -lt 64 -or $bytes[0] -ne 127 -or $bytes[1] -ne 69 -or $bytes[2] -ne 76 -or $bytes[3] -ne 70 -or
$bytes[4] -ne 2 -or [BitConverter]::ToUInt16($bytes,16) -ne 2 -or [BitConverter]::ToUInt16($bytes,18) -ne 62) { throw 'Expected an executable x86_64 ELF.' }
foreach($entry in $receipt.SourceSha256.GetEnumerator()) {
if ((Get-TaskHash (Join-Path $taskRoot $entry.Key)) -cne $entry.Value) { throw ('Source changed during compilation: '+$entry.Key) }
}
$receipt.KernelPath=$kernel
$receipt.KernelSha256=Get-TaskHash $kernel
$receipt.StandardLibrary=if($BootstrapOnly){'bflat Zero 8.0.2 (MIT), bootstrap-only diagnostic'}else{'bflat Zero 8.0.2 for the isolated kernel core; Microsoft .NET NativeAOT 10.0.12 GC/BCL through the independently implemented PAL. Full API compatibility is not claimed.'}
$receipt.Stage='built';$receipt.Passed=$true
$receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath ($kernel+'.json') -Encoding UTF8
$receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $outputRoot 'BuildReceipt.json') -Encoding UTF8
Write-Host ('Independent kernel build: '+$kernel)
} catch {
$receipt.Error=$_.Exception.Message
$receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $outputRoot 'Failure.json') -Encoding UTF8
throw
} finally {
[Environment]::SetEnvironmentVariable('BFLAT_LIB',$previousLib,'Process')
[Environment]::SetEnvironmentVariable('BFLAT_LD',$previousLd,'Process')
Pop-Location
}
[CmdletBinding()]
param(
[ValidateSet('Desktop','Console')][string]$Edition='Desktop',
[switch]$BootstrapOnly,
[string[]]$RuntimeObjects = @(),
[string]$RuntimePortReceipt,
[string]$MathReceipt,
[string]$ToolsRoot
)
$ErrorActionPreference = 'Stop'
$Edition=if($Edition -eq 'Console'){'Console'}else{'Desktop'}
if($BootstrapOnly -and $Edition -eq 'Console'){throw 'BootstrapOnly cannot build the complete console edition.'}
$taskRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ToolsRoot) { $ToolsRoot = Join-Path $taskRoot '.tools' }
$ToolsRoot = [IO.Path]::GetFullPath($ToolsRoot)
$sourceRoot = Join-Path $taskRoot 'Source/XFESystem.NativeKernel'
$buildId = 'Build-' + $Edition + '-' + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() + '-' + [Guid]::NewGuid().ToString('N').Substring(0,8)
$outputRoot = Join-Path $taskRoot ('build/IndependentKernel/' + $buildId)
[void][IO.Directory]::CreateDirectory($outputRoot)
$receipt = [ordered]@{ Kind='XfeIndependentKernelBuild'; Target='x86_64-none'; Edition=$Edition; Passed=$false;
ContainsCosmos=$false; BootstrapOnly=[bool]$BootstrapOnly; FullDotNet10=$false;
Stage='preflight'; SourceSha256=[ordered]@{}; ToolSha256=[ordered]@{}; Commands=@(); OutputRoot=$outputRoot }
function Get-TaskHash([string]$Path) { (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() }
function Invoke-TaskTool([string]$Tool, [string[]]$Arguments, [string]$Name) {
$receipt.Commands += [ordered]@{Executable=$Tool;Arguments=$Arguments}
$savedAction=$ErrorActionPreference
try {
$ErrorActionPreference='Continue'
& $Tool @Arguments 2>&1 | Tee-Object -FilePath (Join-Path $outputRoot ($Name+'.log'))
$taskExit=$LASTEXITCODE
} finally { $ErrorActionPreference=$savedAction }
if ($taskExit -ne 0) { throw ($Name+' failed with exit code '+$taskExit) }
}
$previousLib=[Environment]::GetEnvironmentVariable('BFLAT_LIB','Process')
$previousLd=[Environment]::GetEnvironmentVariable('BFLAT_LD','Process')
Push-Location $taskRoot
try {
$compiler=Join-Path $ToolsRoot 'bflat-8.0.2/bflat.exe'
$clang=Join-Path $ToolsRoot 'llvm/bin/clang.exe'
$linker=Join-Path $ToolsRoot 'llvm/bin/ld.lld.exe'
$nm=Join-Path $ToolsRoot 'llvm/bin/llvm-nm.exe'
$objcopy=Join-Path $ToolsRoot 'llvm/bin/llvm-objcopy.exe'
$compilerLock=Get-Content -LiteralPath (Join-Path $taskRoot 'Tools/CSharpBoot/BflatToolchain.json') -Raw -Encoding UTF8 | ConvertFrom-Json
foreach($tool in @($compiler,$clang,$linker,$nm,$objcopy)) {
if (!(Test-Path -LiteralPath $tool)) { throw ('Required compiler tool is missing: '+$tool) }
$receipt.ToolSha256[$tool]=Get-TaskHash $tool
}
if ((Get-TaskHash $compiler) -cne $compilerLock.ToolSha256.'bflat.exe') { throw 'The locked bflat compiler differs.' }
$zero=Join-Path $ToolsRoot 'bflat-8.0.2/lib/linux/x64/zerolib.dll'
$receipt.ToolSha256[$zero]=Get-TaskHash $zero
$csharp=@(Get-ChildItem -LiteralPath $sourceRoot -File -Filter '*.cs' | Sort-Object Name | Select-Object -ExpandProperty FullName)
$csharp+=Join-Path $taskRoot 'Source/XFESystem.Boot/GpuContracts.cs'
$native=@(Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'Native') -File | Where-Object {$_.Extension -in '.c','.s'} | Sort-Object Name | Select-Object -ExpandProperty FullName)
if ($BootstrapOnly) {
$native+=Join-Path $taskRoot 'Source/XFESystem.NativeRuntime/Native/BasicLibc.c'
$native+=Join-Path $taskRoot 'Source/XFESystem.NativeRuntime/Native/Stdio.c'
}
$script=Join-Path $sourceRoot 'linker.ld'
if ($csharp.Count -eq 0 -or $native.Count -eq 0 -or !(Test-Path -LiteralPath $script)) { throw 'Independent kernel source files are incomplete.' }
$headers=@(Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'Native') -File -Filter '*.h' | Select-Object -ExpandProperty FullName)
$profilePath=Join-Path $sourceRoot 'KernelProfile.json'
$profile=Get-Content -LiteralPath $profilePath -Raw -Encoding UTF8 | ConvertFrom-Json
if ($profile.Kind -cne 'XfeIndependentKernelConfiguration' -or $profile.Architecture -cne 'x86_64' -or
$profile.ContainsCosmos -or $profile.ExecutingCpuCount -ne 1 -or
!((($profile.RamOnly -eq $true) -and ($profile.StorageEnabled -eq $false)) -or
(($profile.RamOnly -eq $false) -and ($profile.StorageEnabled -eq $true) -and $profile.StorageBackend -ceq 'BootUsbBotFat32DualBankWorkspaceV1' -and $profile.RamFallbackWhenBootUsbUnavailable -eq $true))) {
throw 'Unsupported independent kernel configuration.'
}
$receipt.Configuration=$profile
$boundFiles=@($csharp)+@($native)+@($headers)+@($script,$PSCommandPath,$profilePath)+@(
(Join-Path $taskRoot 'Tools/BuildBootLogo.py'),
(Join-Path $taskRoot 'assets/branding/console/icon.rgba'),
(Join-Path $taskRoot 'assets/branding/console/xfe-mono.bin'))
$receipt.BootVisualPolicy='XfeBrandedBootVisualV1'
foreach($path in $boundFiles) {
$relative=$path.Substring($taskRoot.Length+1).Replace('\','/')
$receipt.SourceSha256[$relative]=Get-TaskHash $path
if ([IO.File]::ReadAllText($path) -match '(?m)^\s*(using\s+Cosmos\.|#\s*include\s*[<"]Cosmos|<PackageReference\s+Include="Cosmos)') {
throw ('Independent kernel has a Cosmos dependency: '+$relative)
}
}
if (!$BootstrapOnly) {
if (!$RuntimePortReceipt -and $RuntimeObjects.Count -eq 1) {
$RuntimePortReceipt=Join-Path (Split-Path -Parent $RuntimeObjects[0]) 'PortReceipt.json'
}
if (!$RuntimePortReceipt) { throw 'A source-bound native runtime port receipt is required.' }
$port=Get-Content -LiteralPath $RuntimePortReceipt -Raw -Encoding UTF8 | ConvertFrom-Json
if ($port.Schema -cne 'XfeIndependentNativeRuntimePort1' -or $port.CosmosReferenced -or
!$port.NativePortCompilationPassed -or !$port.RelocatableRuntimeLinkPassed -or
$port.MicrosoftRuntimeVersion -cne '10.0.12' -or !$port.SourceSha256 -or
(Get-TaskHash $port.CombinedObjectPath) -cne $port.CombinedObjectSha256 -or
!$port.FinalLinkInputs -or !$port.FinalLinkInputsSha256) {
throw 'Runtime objects must match the exact independently compiled source-bound port.'
}
if ($RuntimeObjects.Count -eq 1 -and [IO.Path]::GetFullPath($RuntimeObjects[0]) -ieq [IO.Path]::GetFullPath($port.CombinedObjectPath)) {
# ld -r is useful for symbol inventory, but merged COMDAT unwind
# sections must not become the final executable input. Link the
# exact original managed/native objects and archives once.
$RuntimeObjects=@($port.FinalLinkInputs)
}
if($RuntimeObjects.Count -ne $port.FinalLinkInputs.Count){throw 'Runtime link input count differs from its receipt.'}
for($inputIndex=0;$inputIndex -lt $RuntimeObjects.Count;$inputIndex++) {
$inputPath=[IO.Path]::GetFullPath($RuntimeObjects[$inputIndex])
if($inputPath -ine [IO.Path]::GetFullPath($port.FinalLinkInputs[$inputIndex]) -or
(Get-TaskHash $inputPath) -cne $port.FinalLinkInputsSha256.PSObject.Properties[$port.FinalLinkInputs[$inputIndex]].Value) {
throw ('Runtime final link input differs: '+$inputPath)
}
}
foreach($property in $port.SourceSha256.PSObject.Properties) {
$path=[IO.Path]::GetFullPath((Join-Path $taskRoot $property.Name))
if (!$path.StartsWith($taskRoot+[IO.Path]::DirectorySeparatorChar,[StringComparison]::OrdinalIgnoreCase) -or
(Get-TaskHash $path) -cne $property.Value) { throw ('Runtime source changed: '+$property.Name) }
$receipt.SourceSha256[$property.Name]=$property.Value
}
$consoleProject='Source/XFESystem.NativeRuntime/ConsoleApplication/ConsoleApplication.csproj'
$desktopProject='Source/XFESystem.NativeRuntime/Application/NativeApplication.csproj'
if($Edition -eq 'Console') {
if(!$port.SourceSha256.PSObject.Properties[$consoleProject] -or $port.SourceSha256.PSObject.Properties[$desktopProject]) {
throw 'The console edition requires the standalone ConsoleApplication project, without the desktop application.'
}
foreach($entry in $port.SourceSha256.PSObject.Properties) {
if($entry.Name -match '^Source/XFESystem[.](Browser|Documents)/' -or
($entry.Name -match '^Source/XFESystem[.]Desktop/' -and $entry.Name -cne 'Source/XFESystem.Desktop/TerminalShell.cs')) {
throw ('Graphical application source is not allowed in the console edition: '+$entry.Name)
}
}
} elseif($port.SourceSha256.PSObject.Properties[$consoleProject]) {
throw 'The desktop edition cannot link the console entry application.'
}
foreach($map in @($port.AssemblySha256,$port.RuntimeLibrariesSha256,$port.NativeObjectsSha256)) {
if (!$map) { continue }
foreach($property in $map.PSObject.Properties) {
if ((Get-TaskHash $property.Name) -cne $property.Value) { throw ('Runtime input changed: '+$property.Name) }
}
}
$receipt.ManagedRuntimeLinked=$true
$receipt.RuntimePortReceipt=[ordered]@{Path=$RuntimePortReceipt;Sha256=(Get-TaskHash $RuntimePortReceipt);
MicrosoftRuntimeVersion=$port.MicrosoftRuntimeVersion;MicrosoftSourceCommit=$port.MicrosoftSourceCommit;
CombinedObjectSha256=$port.CombinedObjectSha256;RuntimeLibrariesSha256=$port.RuntimeLibrariesSha256;
FinalLinkInputsSha256=$port.FinalLinkInputsSha256;RelocatableObjectUsedForFinalLink=$false}
}
Remove-Item Env:BFLAT_LIB -ErrorAction SilentlyContinue
Remove-Item Env:BFLAT_LD -ErrorAction SilentlyContinue
$receipt.Stage='compile-csharp'
$managedObject=Join-Path $outputRoot 'KernelCoreRaw.o'
$arguments=@('build')+$csharp+@('--os:linux','--arch:x64','--stdlib:zero','--target:Shared','--deterministic','--no-debug-info','-Ot','-c','-x',('-o:'+$managedObject),'-i:xfe_native')
if (!$BootstrapOnly) { $arguments+=@('--define','XFE_DOTNET_RUNTIME') }
Invoke-TaskTool $compiler $arguments 'CSharpCompile'
# Zero has deliberately minimal Rhp helpers. Isolate every one of its
# symbols and metadata sections so the full Microsoft runtime can never
# accidentally resolve to those helpers or register the Zero module.
$defined=@(& $nm --defined-only --extern-only --just-symbol-name $managedObject)
if($LASTEXITCODE -ne 0){throw 'Cannot inspect bootstrap exports.'}
$undefined=@(& $nm --undefined-only --just-symbol-name $managedObject)
if($LASTEXITCODE -ne 0){throw 'Cannot inspect bootstrap imports.'}
$prefixed=Join-Path $outputRoot 'KernelCorePrefixed.o'
Invoke-TaskTool $objcopy @('--prefix-symbols=XfeZero_','--rename-section','__modules=__xfe_zero_modules','--rename-section','__managedcode=__xfe_zero_managedcode','--rename-section','__unbox=__xfe_zero_unbox',$managedObject,$prefixed) 'IsolateZeroRuntime'
$renames=Join-Path $outputRoot 'BootstrapSymbols.txt'
$restored=@($defined+$undefined | Where-Object {$_ -match '^(xfe_|XfeKernelMain$|XfeHandleInterrupt$|XfeRuntimeStart$)'} | Sort-Object -Unique | ForEach-Object {'XfeZero_'+$_+' '+$_})
$restored+=@('XfeZero_SystemNative_Abort xfe_zero_abort','XfeZero_SystemNative_Malloc xfe_zero_malloc')
# Large value-only GPU discovery records generate compiler libc intrinsics.
# Bind byte-range operations to our freestanding C implementation, never to
# an isolated managed helper or to an OS libc. No object ABI crosses here.
$restored+=@('XfeZero_memcpy memcpy','XfeZero_memset memset','XfeZero_memmove memmove')
$restored | Set-Content -LiteralPath $renames -Encoding ASCII
$isolated=Join-Path $outputRoot 'KernelCore.o'
Invoke-TaskTool $objcopy @(('--redefine-syms='+$renames),$prefixed,$isolated) 'RestoreKernelAbi'
$objects=@($isolated)
$receipt.Stage='compile-native'
foreach($path in $native) {
$object=Join-Path $outputRoot ([IO.Path]::GetFileName($path)+'.o')
$arguments=@('--target=x86_64-unknown-none-elf','-ffreestanding','-fno-builtin','-fno-stack-protector','-fasynchronous-unwind-tables','-fno-pic','-fno-pie','-mno-red-zone','-mcmodel=kernel','-O2','-g','-c',$path,'-o',$object)
Invoke-TaskTool $clang $arguments ([IO.Path]::GetFileName($path))
$objects+=$object
}
if (!$BootstrapOnly -and $RuntimeObjects.Count -eq 0) { throw 'A complete native runtime bridge is required. BootstrapOnly is an explicit, limited diagnostic build, not the desktop system.' }
foreach($path in $RuntimeObjects) {
$runtimeObject=[IO.Path]::GetFullPath($path)
if (!(Test-Path -LiteralPath $runtimeObject)) { throw ('Runtime object missing: '+$runtimeObject) }
$objects+=$runtimeObject
$receipt.ToolSha256[$runtimeObject]=Get-TaskHash $runtimeObject
}
if (!$MathReceipt) {
$latestMath=Get-ChildItem -LiteralPath (Join-Path $taskRoot 'build/IndependentKernel') -Directory -Filter 'Math-*' |
Sort-Object Name -Descending | Where-Object {Test-Path -LiteralPath (Join-Path $_.FullName 'BuildReceipt.json')} | Select-Object -First 1
if (!$latestMath) { throw 'Build the pinned external mathematical library with Tools/IndependentKernel/Runtime/BuildMath.py first.' }
$MathReceipt=Join-Path $latestMath.FullName 'BuildReceipt.json'
}
$math=Get-Content -LiteralPath $MathReceipt -Raw -Encoding UTF8 | ConvertFrom-Json
if ($math.Kind -cne 'XfeExternalMathLibraryBuild' -or !$math.Passed -or $math.ContainsCosmos -or
$math.ContainsMuslOperatingSystemCode -or $math.ArchiveSha256 -cne 'a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4' -or
(Get-TaskHash $math.LibraryPath) -cne $math.LibrarySha256) { throw 'Invalid external math build receipt.' }
if ($objects -notcontains $math.LibraryPath) { $objects+=$math.LibraryPath }
$receipt.ExternalMath=[ordered]@{Version=$math.Version;ArchiveUrl=$math.ArchiveUrl;ArchiveSha256=$math.ArchiveSha256;
LibrarySha256=$math.LibrarySha256;ReceiptSha256=(Get-TaskHash $MathReceipt);ContainsOperatingSystemCode=$false}
$receipt.SourceSha256['Tools/IndependentKernel/Runtime/BuildMath.py']=Get-TaskHash (Join-Path $taskRoot 'Tools/IndependentKernel/Runtime/BuildMath.py')
$receipt.Stage='link'
$kernel=Join-Path $outputRoot 'Kernel.elf'
Invoke-TaskTool $linker (@('-m','elf_x86_64','-nostdlib','-static','--gc-sections','--eh-frame-hdr','--error-limit=0','-z','max-page-size=4096','-T',$script)+$objects+@('-o',$kernel)) 'Link'
$symbols=@(& $nm --undefined-only $kernel)
if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect kernel imports.' }
$optionalBootstrap=@('XfeRuntimeDetachThread','XfeRuntimeTlsCreate','XfeRuntimeTlsRelease','XfeRuntimeTryHijack','XfeRuntimeDispatchHardwareFault')
$invalidImports=@($symbols | Where-Object {
-not ($BootstrapOnly -and $_ -match '^\s+w\s+(\S+)\s*$' -and $optionalBootstrap -contains $Matches[1])
})
if ($invalidImports.Count) { throw ('The freestanding kernel has unresolved imports: '+($invalidImports -join ', ')) }
$receipt.OptionalAbsentRuntimeServices=@($symbols)
& $nm --defined-only $kernel | Set-Content -LiteralPath (Join-Path $outputRoot 'Symbols.txt') -Encoding UTF8
if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect final kernel symbols.' }
if ([IO.File]::ReadAllText((Join-Path $outputRoot 'Symbols.txt')) -match 'Cosmos[._]') { throw 'Final kernel symbols contain Cosmos.' }
$bytes=[IO.File]::ReadAllBytes($kernel)
if ($bytes.Length -lt 64 -or $bytes[0] -ne 127 -or $bytes[1] -ne 69 -or $bytes[2] -ne 76 -or $bytes[3] -ne 70 -or
$bytes[4] -ne 2 -or [BitConverter]::ToUInt16($bytes,16) -ne 2 -or [BitConverter]::ToUInt16($bytes,18) -ne 62) { throw 'Expected an executable x86_64 ELF.' }
foreach($entry in $receipt.SourceSha256.GetEnumerator()) {
if ((Get-TaskHash (Join-Path $taskRoot $entry.Key)) -cne $entry.Value) { throw ('Source changed during compilation: '+$entry.Key) }
}
$receipt.KernelPath=$kernel
$receipt.KernelSha256=Get-TaskHash $kernel
$receipt.StandardLibrary=if($BootstrapOnly){'bflat Zero 8.0.2 (MIT), bootstrap-only diagnostic'}else{'bflat Zero 8.0.2 for the isolated kernel core; Microsoft .NET NativeAOT 10.0.12 GC/BCL through the independently implemented PAL. Full API compatibility is not claimed.'}
$receipt.Stage='built';$receipt.Passed=$true
$receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath ($kernel+'.json') -Encoding UTF8
$receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $outputRoot 'BuildReceipt.json') -Encoding UTF8
Write-Host ('Independent kernel build: '+$kernel)
} catch {
$receipt.Error=$_.Exception.Message
$receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $outputRoot 'Failure.json') -Encoding UTF8
throw
} finally {
[Environment]::SetEnvironmentVariable('BFLAT_LIB',$previousLib,'Process')
[Environment]::SetEnvironmentVariable('BFLAT_LD',$previousLd,'Process')
Pop-Location
}