Skip to content

Restore runtime bootstrapper handling for binary modules#309

Merged
PrzemyslawKlys merged 4 commits intomainfrom
fix/runtime-bootstrapper
Apr 7, 2026
Merged

Restore runtime bootstrapper handling for binary modules#309
PrzemyslawKlys merged 4 commits intomainfrom
fix/runtime-bootstrapper

Conversation

@PrzemyslawKlys
Copy link
Copy Markdown
Member

Summary

  • carry the runtime-handling flag through the PowerForge build plan and build spec
  • emit Windows runtime PATH bootstrap code when binary modules request runtime handling
  • cover the restored behavior with generator and planning tests

Testing

  • dotnet test PowerForge.Tests/PowerForge.Tests.csproj --nologo --filter "FullyQualifiedNameModuleBootstrapperGeneratorTests|FullyQualifiedNameModulePipelineExportAssemblyInferenceTests"

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95e4ca589f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

string moduleName,
ExportSet exports,
IReadOnlyList<string>? exportAssemblies,
bool handleRuntimes = false)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass handleRuntimes in every bootstrapper regeneration path

The new optional parameter defaults handleRuntimes to false, which lets older call sites silently compile without propagating runtime handling. ModulePipelineRunner.TryRegenerateBootstrapperFromManifest still calls ModuleBootstrapperGenerator.Generate(buildResult.StagingPath, moduleName, exports, exportAssemblies) (without the new argument), so in runs where that manifest-phase regeneration executes (for example when merge is disabled), it overwrites the earlier bootstrapper and drops the runtime PATH block even when NETHandleRuntimes was requested.

Useful? React with 👍 / 👎.

new[]
{
"# Ensure native runtime libraries are discoverable on Windows",
"if ($IsWindows -and $LibFolder) {",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace $IsWindows gate in runtime bootstrap block

The generated runtime handler is guarded by if ($IsWindows -and $LibFolder), but $IsWindows is only built-in on PowerShell Core. In Windows PowerShell 5.1 this evaluates as undefined/false (and can error under strict mode), so NETHandleRuntimes does not actually prepend the native runtime folder to PATH on Desktop hosts, which is exactly where net472 binary modules may still need native dependency resolution.

Useful? React with 👍 / 👎.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 7, 2026

Clarifying Review

A prior automated review (also attributed to "claude") was posted with some inaccurate observations. I want to correct the record before those points cause unnecessary churn.

Corrections to the previous review

Point 1 (PATH substring match)incorrect. The actual code at ModuleBootstrapperGenerator.cs:270 does NOT use -notlike "*$NativePath*". It correctly uses an exact-membership check after splitting on PathSeparator:

$PathEntries = if ([string]::IsNullOrWhiteSpace($env:PATH)) { @() } else { @($env:PATH -split [IO.Path]::PathSeparator) }
if ((Test-Path -LiteralPath $NativePath) -and ($PathEntries -notcontains $NativePath)) {

This is already the robust approach the previous review recommended adding.

Point 4 (silent fallback architecture)incorrect. The Default switch branch already emits a Write-Warning:

Default {
    Write-Warning -Message ("Unknown Windows architecture. Falling back to win-x64 native runtime probing.")
    'win-x64'
}

This is also verified by the test: Assert.Contains("Unknown Windows architecture", bootstrapper).

Actual assessment

The implementation is solid. A few genuine observations:

1. LibFolder empty-string guard works correctly. When only a Core-layout exists and the module loads on Desktop edition, $FrameworkNet is empty string, making $LibFolder falsy. The if ($IsWindowsPlatform -and $LibFolder) guard silently skips the runtime PATH block — this is intentional and documented in the generated code comment.

2. BuildRuntimeHandlerBlock is inline C# code, not a template file. All other bootstrapper scripts use embedded .ps1 template files (BinaryLoader.Template.ps1, ScriptLoader.Template.ps1). This block is hardcoded in a C# string array. Functional, but slightly inconsistent with the pattern. Could be extracted to a RuntimeHandler.Template.ps1 if the block grows.

3. Process-wide PATH modification is expected. Prepending to $env:PATH affects the entire PowerShell session. Multiple modules with HandleRuntimes each prepend their own native path — the deduplication check prevents double-adding the same path, so repeated imports are safe. The existing inline comment documents the intent well.

4. Test coverage is thorough. The four generator tests and Plan_CarriesHandleRuntimes_IntoBuildSpec cover the key scenarios: with/without runtime block, binary vs. script-only layout, and CsprojRequiredReasons assertion. The DoesNotContain assertion on double-newlines is a good guard against whitespace regressions.

Summary

The flag propagation chain is consistent with DoNotCopyLibrariesRecursively and other existing flags. The generated PowerShell is correct and well-tested. No blocking issues found.

@PrzemyslawKlys PrzemyslawKlys merged commit bc0ce3a into main Apr 7, 2026
6 checks passed
@PrzemyslawKlys PrzemyslawKlys deleted the fix/runtime-bootstrapper branch April 7, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant