Summary
Microsoft.FSharp.NetSdk.props defaults the property ParallelCompilation to true:
<!-- sdk/<version>/FSharp/Microsoft.FSharp.NetSdk.props, line 53 -->
<ParallelCompilation Condition=" '$(ParallelCompilation)' == '' ">true</ParallelCompilation>
but Microsoft.FSharp.Targets passes the item @(ParallelCompilation) — which is always
empty — to the Fsc task inside CoreCompile:
<!-- sdk/<version>/FSharp/Microsoft.FSharp.Targets, line 384 -->
ParallelCompilation="@(ParallelCompilation)"
So the value never reaches the compiler. Parallel compilation (graph-based type checking,
etc.) is silently off for every F# project built through the .NET SDK, despite the props
default saying true — and even an explicit -p:ParallelCompilation=true is a no-op.
Verified in .NET SDK 10.0.204 and 10.0.301 (F# compiler 15.2.204.0 / 15.2.301.0);
both contain the identical props/targets lines.
Repro
-
Any F# project. Build with a binlog, explicitly opting in to be generous:
dotnet build MyProject.fsproj -p:ParallelCompilation=true -bl
-
Open msbuild.binlog and inspect the Fsc task invocation in CoreCompile.
Expected: the Fsc task receives ParallelCompilation=true and the generated
command line contains --parallelcompilation.
Actual: the Fsc task parameter list contains no ParallelCompilation entry at
all, and the fsc command line has no --parallelcompilation flag. (The binlog's
evaluation trace shows $(ParallelCompilation) = true as a property, confirming the
props default fires; it just never gets handed to the task.)
FSharp.Build.dll's Fsc task does support the parameter — its command-line builder
emits --parallelcompilation (visible in the task's string table and in
Fsc.fs) — so the
fix is a one-character-class change in the targets:
- ParallelCompilation="@(ParallelCompilation)"
+ ParallelCompilation="$(ParallelCompilation)"
Impact
- Graph-based type checking / parallel compilation is dead code for all SDK-style F#
builds; nobody building with dotnet build has it on, regardless of the props default
or any property they set.
- Anyone benchmarking
ParallelCompilation=true vs false measures zero difference and
draws wrong conclusions about the feature itself.
Workaround
Pass the flag through OtherFlags instead, e.g. in Directory.Build.props:
<PropertyGroup Condition="'$(FscParallel)' == 'true' And '$(MSBuildProjectExtension)' == '.fsproj'">
<OtherFlags>$(OtherFlags) --parallelcompilation</OtherFlags>
</PropertyGroup>
With that workaround the flag does reach fsc (confirmed via binlog), so only the
targets plumbing is broken, not the compiler option.
Environment
- .NET SDK 10.0.204 and 10.0.301, Windows 11 x64
Microsoft (R) F# Compiler version 15.2.204.0 / 15.2.301.0 for F# 10.0
Summary
Microsoft.FSharp.NetSdk.propsdefaults the propertyParallelCompilationtotrue:but
Microsoft.FSharp.Targetspasses the item@(ParallelCompilation)— which is alwaysempty — to the
Fsctask insideCoreCompile:<!-- sdk/<version>/FSharp/Microsoft.FSharp.Targets, line 384 --> ParallelCompilation="@(ParallelCompilation)"So the value never reaches the compiler. Parallel compilation (graph-based type checking,
etc.) is silently off for every F# project built through the .NET SDK, despite the props
default saying
true— and even an explicit-p:ParallelCompilation=trueis a no-op.Verified in .NET SDK 10.0.204 and 10.0.301 (F# compiler 15.2.204.0 / 15.2.301.0);
both contain the identical props/targets lines.
Repro
Any F# project. Build with a binlog, explicitly opting in to be generous:
Open
msbuild.binlogand inspect theFsctask invocation inCoreCompile.Expected: the
Fsctask receivesParallelCompilation=trueand the generatedcommand line contains
--parallelcompilation.Actual: the
Fsctask parameter list contains noParallelCompilationentry atall, and the fsc command line has no
--parallelcompilationflag. (The binlog'sevaluation trace shows
$(ParallelCompilation)=trueas a property, confirming theprops default fires; it just never gets handed to the task.)
FSharp.Build.dll'sFsctask does support the parameter — its command-line builderemits
--parallelcompilation(visible in the task's string table and inFsc.fs) — so thefix is a one-character-class change in the targets:
Impact
builds; nobody building with
dotnet buildhas it on, regardless of the props defaultor any property they set.
ParallelCompilation=truevsfalsemeasures zero difference anddraws wrong conclusions about the feature itself.
Workaround
Pass the flag through
OtherFlagsinstead, e.g. inDirectory.Build.props:With that workaround the flag does reach fsc (confirmed via binlog), so only the
targets plumbing is broken, not the compiler option.
Environment
Microsoft (R) F# Compiler version 15.2.204.0 / 15.2.301.0 for F# 10.0