Skip to content

Support multithreaded MSBuild in F# build tasks - #20506

Draft
T-Gro wants to merge 36 commits into
dotnet:mainfrom
T-Gro:t-gro-msbuild-task-multithreading
Draft

Support multithreaded MSBuild in F# build tasks#20506
T-Gro wants to merge 36 commits into
dotnet:mainfrom
T-Gro:t-gro-msbuild-task-multithreading

Conversation

@T-Gro

@T-Gro T-Gro commented Sep 10, 2026

Copy link
Copy Markdown
Member

Use MSBuild's per-task environment so concurrent SDK builds do not share working-directory or environment state. Enable MT in existing SDK CI jobs, with required MP/MT end-to-end coverage.

Generate ILLink substitutions before resource assignment so trimmed builds consume them, without recompiling unchanged projects.

perf-bundle and others added 30 commits September 8, 2026 16:18
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Deduplicate TaskEnvironment lifecycle scaffolding in the FSharp.Build task
tests by reusing FSharp.Test.ReflectionHelper.getPrivateInstanceMethod and
adding narrowly-scoped with* helpers, without altering any scenario or oracle.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Reduce comment bloat and duplication across the multithread-safe FSharp.Build
task migration without changing behavior:

- Extract the duplicated path-diagnostic helpers (replaceOrdinal,
  pathComparison, restoreOriginalPaths) shared verbatim by FSharpEmbedResXSource
  and FSharpEmbedResourceText into a single internal TaskEnvironmentPaths module.
- Condense war-story / step-narration comments in Fsc, Fsi, SubstituteText,
  CompilerLocation and the resource generators to concise why-only notes.
- Trim restated and overlong comments in the task tests while preserving every
  distinct regression scenario and mutation-killing assertion.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace duplicated path and compiler task tests with named data-driven matrices while preserving every regression oracle. Generalize the existing paired TaskEnvironment lifecycle fixture for compiler-bin isolation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the private PathScenario record and replace pathScenarios callbacks with
direct (name, input, expectation) tuples parameterized by directory. Fold
assertConcurrentSuccess into runConcurrently by adding a scenario parameter,
updating all four call sites. Drop the #nowarn trailing comment and the
MockEngine doc comment. Every non-Windows/Windows scenario, xUnit row,
task-specific oracle, and failure message is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Trim why-comments that restated code or duplicated across the migrated
MSBuild tasks (Fsc/Fsi tool-path normalization, rootedPath helpers,
try-block path recording, parameterless-ctor notes) without changing any
behavior, scenario, or test coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Share tool-path normalization, remove test-only production hooks and one-use helpers, deduplicate compiler task factories and assertions, and matrix the Linux CI variants while preserving both commands and failure policies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract the duplicated IMultiThreadableTask boilerplate (backing field,
parameterless fallback ctor, interface impl) and the rootedPath /
restoreOriginalPaths helpers from the five Task-derived multithreadable
FSharp.Build tasks into a shared MultiThreadableTask abstract base in
TaskEnvironmentPaths.fs. Each task keeps its own
[<MSBuildMultiThreadableTask>] attribute (asserted directly by the
task-is-marked test). Net -44 LOC, no behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the branch-added public task base and injected compiler-task constructors, restoring the original public inheritance and constructor shape. Share deferred compiler path resolution and retain per-task environment state through internal composition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refactor the branch-added FSharp.Build task path handling toward
expression-oriented F# without changing behavior:

- replaceOrdinal: replace the two mutable indices and while loop with a
  tail-recursive local scanning function that pattern matches on
  String.IndexOf, keeping the StringBuilder as the only local mutation.
- Resource tasks: accumulate the diagnostic originalPaths as an immutable
  list rebind (mutable let, still recorded inside the try) instead of a
  ResizeArray with Add/AddRange plus List.ofSeq at the failure handler.
- FSharpEmbedResourceText / FSharpEmbedResXSource: root each path once via
  local bindings and reuse them across the up-to-date checks, reads and
  writes rather than re-calling RootedPath at every use site.

Preserves evaluation order, exception boundaries, diagnostics, path
comparison semantics and the numbered up-to-date condition ladder. Fantomas
clean; 64 FSharp.Build unit tests pass (20/20 repeats); two deliberate
mutations in the touched code are caught by the suite. Net -3 LOC.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 378abfca-7dca-4612-9f0e-932807f85dec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
perf-bundle and others added 5 commits September 8, 2026 17:43
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 50c9b6ff-7645-415f-85e5-e59e3b4d0120
Use single resource errors, bounded barriers and independent regression rows. Preserve quoted filenames while restoring diagnostic paths, and cover incremental no-ops, generated-output failures and both substitution stages.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Run generation before AssignTargetPaths, retaining the CoreCompile hook for direct invocations. Avoid touching identical XML so the added embedded resource does not force no-op recompilation. The real SDK PublishTrimmed control now removes metadata only when substitutions are enabled.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Retain real SDK task-loading and routing probes, MP/MT parity and concurrency checks, incremental no-ops, isolated failures, and enabled/disabled trimmed-publish controls. Add explicit informational canaries without weakening the required Linux job.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
Use the existing Arcade opt-in and native SDK switch instead of extra jobs or a new global setting. Require SDK MP/MT integration in Linux and Windows EndToEndBuildTests. Keep MP controls explicit even when CI centrally enables MT.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

✅ No release notes required

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4e3e43-3404-456d-bbe6-dad204950074
@baronfel

Copy link
Copy Markdown
Member

@T-Gro you won't be able to consume it directly, but there's a Roslyn analyzer in the dotnet-public feed that flags categories of known-bad Task patterns. We have docs for it here that an agent should be able to consume and use to help guide the migration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

2 participants