Skip to content

Commit 910e1b3

Browse files
JanProvaznikCopilot
andcommitted
[vs17.14] Redistribute net472 dotnet/runtime 10.0.8 servicing wave (Nrbf + HashCode 6.0)
Redistribute the net472 dotnet/runtime 10.0.8 servicing wave to line up with the corresponding VS servicing event, without changing what MSBuild compiles or declares against. net472 downloads the 10.0.8 packages and swaps the copy-local assemblies into the application output after RAR, with matching binding redirects. - eng/Versions.props: introduce RuntimePackageVersion_CompileTime (9.0.0) and RuntimePackageVersion_VSDeploy (10.0.8); document the compile-vs-deploy split. - src/Directory.Build.targets: add ReplaceRuntimeAssembliesWithServicingVersions target gated on DeployRuntimeServicingAssemblies for net472. - src/MSBuild/MSBuild.csproj, src/MSBuild.Bootstrap/MSBuild.Bootstrap.csproj: opt in via DeployRuntimeServicingAssemblies. - src/MSBuild/app.config and app.amd64.config: binding redirects to the deployed assembly versions (10.0.0.8, Microsoft.Bcl.HashCode 6.0.0.0, System.Memory 4.0.5.0, System.Runtime.CompilerServices.Unsafe 6.0.3.0, System.Threading.Tasks.Extensions 4.2.4.0, System.Buffers 4.0.5.0, System.Numerics.Vectors 4.1.6.0). - src/Tasks/System.Resources.Extensions.pkgdef: redirect 10.0.0.3 -> 10.0.0.8. Ports internal PR DevDiv/DotNet-msbuild-Trusted!751025. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 32c970e commit 910e1b3

7 files changed

Lines changed: 239 additions & 71 deletions

File tree

eng/Versions.props

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the MIT license. See License.txt in the project root for full license information. -->
33
<Project>
44
<PropertyGroup>
5-
<VersionPrefix>17.14.50</VersionPrefix>
5+
<VersionPrefix>17.14.51</VersionPrefix>
66
<DotNetFinalVersionKind>release</DotNetFinalVersionKind>
77
<PackageValidationBaselineVersion>17.13.9</PackageValidationBaselineVersion>
88
<AssemblyVersion>15.1.0.0</AssemblyVersion>
99
<PreReleaseVersionLabel>servicing</PreReleaseVersionLabel>
10-
<!-- differentiate experimental insertions to avoid package id conflicts,
10+
<!-- differentiate experimental insertions to avoid package id conflicts,
1111
it has to be alphabetically after "preview" to avoid downgrade errors in VS -->
1212
<PreReleaseVersionLabel Condition="'$(IsExperimental)' == 'true'">test</PreReleaseVersionLabel>
1313
<DotNetUseShippingVersions>true</DotNetUseShippingVersions>
@@ -31,6 +31,18 @@
3131
As a result, we CONTINUE TO REFERENCE the old versions at build time, so those are the versions that get embedded into MSBuild assemblies.
3232
However, we can update, binding-redirect to, and distribute the newest version (that matches the VS-referenced versions) in order to get the benefits of updating.
3333
See uses of $(UseFrozenMaintenancePackageVersions) for details.
34+
35+
These referenced versions are deliberately NOT bumped to the servicing build that the
36+
net472 runtime wave ($(RuntimePackageVersion_VSDeploy)) was produced against: doing so
37+
would change what the .NET (Core) build references and pull in new source-build prebuilts.
38+
Instead, net472 redistributes the newer maintenance assemblies through the same
39+
$(DeployRuntimeServicingAssemblies) swap as the runtime packages (see
40+
src/Directory.Build.targets). Because their assembly versions move between servicing
41+
builds, the matching redirects in src/MSBuild/app.config and app.amd64.config point at the
42+
deployed assembly versions: System.Memory 4.6.3 -> 4.0.5.0,
43+
System.Runtime.CompilerServices.Unsafe 6.1.2 -> 6.0.3.0,
44+
System.Threading.Tasks.Extensions 4.6.3 -> 4.2.4.0, and the transitively redistributed
45+
System.Buffers 4.6.1 -> 4.0.5.0 and System.Numerics.Vectors 4.6.1 -> 4.1.6.0.
3446
-->
3547
<SystemMemoryVersion>4.6.0</SystemMemoryVersion>
3648
<SystemThreadingTasksExtensionsVersion>4.6.0</SystemThreadingTasksExtensionsVersion>
@@ -41,20 +53,39 @@
4153
</PropertyGroup>
4254
<PropertyGroup>
4355
<!-- dotnet/runtime packages -->
44-
<SystemCollectionsImmutableVersion>9.0.0</SystemCollectionsImmutableVersion>
45-
<SystemConfigurationConfigurationManagerVersion>9.0.0</SystemConfigurationConfigurationManagerVersion>
46-
<SystemDiagnosticsDiagnosticSourceVersion>9.0.0</SystemDiagnosticsDiagnosticSourceVersion>
47-
<SystemDiagnosticsEventLogVersion>9.0.0</SystemDiagnosticsEventLogVersion>
48-
<SystemFormatsAsn1Version>9.0.0</SystemFormatsAsn1Version>
49-
<SystemFormatsNrbfVersion>9.0.0</SystemFormatsNrbfVersion>
50-
<SystemReflectionMetadataVersion>9.0.0</SystemReflectionMetadataVersion>
51-
<SystemReflectionMetadataLoadContextVersion>9.0.0</SystemReflectionMetadataLoadContextVersion>
52-
<SystemResourcesExtensionsVersion>9.0.0</SystemResourcesExtensionsVersion>
53-
<SystemSecurityCryptographyProtectedDataVersion>9.0.0</SystemSecurityCryptographyProtectedDataVersion>
54-
<SystemTextEncodingCodePagesVersion>9.0.0</SystemTextEncodingCodePagesVersion>
55-
<SystemTextJsonVersion>9.0.0</SystemTextJsonVersion>
56-
<SystemThreadingChannelsVersion>9.0.0</SystemThreadingChannelsVersion>
57-
<SystemThreadingTasksDataflowVersion>9.0.0</SystemThreadingTasksDataflowVersion>
56+
<!--
57+
$(RuntimePackageVersion_CompileTime) is the version MSBuild COMPILES against and declares as its
58+
own NuGet package dependencies. It is deliberately the same for every target framework
59+
so that restore never sees a version downgrade: with central transitive pinning on, a
60+
TargetFramework-conditioned version here would leak the higher version into leaf
61+
packaging/test projects (which pin the unconditioned version directly) and fail with
62+
NU1109.
63+
64+
For net472 we additionally REDISTRIBUTE a newer servicing build of these assemblies to
65+
line up with a Visual Studio servicing event, WITHOUT changing what we compile or
66+
declare against. That is driven by $(RuntimePackageVersion_VSDeploy): the newer packages
67+
are downloaded and copied to the output in place of the compiled-against assemblies, and
68+
the net472 binding redirects (src/MSBuild/app.config and app.amd64.config) point at them.
69+
See the ReplaceRuntimeAssembliesWithServicingVersions target in src/Directory.Build.targets.
70+
This mirrors the $(UseFrozenMaintenancePackageVersions) mechanism in reverse (there we
71+
compile against an older build than we ship; here we ship a newer build than we compile).
72+
-->
73+
<RuntimePackageVersion_CompileTime>9.0.0</RuntimePackageVersion_CompileTime>
74+
<RuntimePackageVersion_VSDeploy>10.0.8</RuntimePackageVersion_VSDeploy>
75+
<SystemCollectionsImmutableVersion>$(RuntimePackageVersion_CompileTime)</SystemCollectionsImmutableVersion>
76+
<SystemConfigurationConfigurationManagerVersion>$(RuntimePackageVersion_CompileTime)</SystemConfigurationConfigurationManagerVersion>
77+
<SystemDiagnosticsDiagnosticSourceVersion>$(RuntimePackageVersion_CompileTime)</SystemDiagnosticsDiagnosticSourceVersion>
78+
<SystemDiagnosticsEventLogVersion>$(RuntimePackageVersion_CompileTime)</SystemDiagnosticsEventLogVersion>
79+
<SystemFormatsAsn1Version>$(RuntimePackageVersion_CompileTime)</SystemFormatsAsn1Version>
80+
<SystemFormatsNrbfVersion>$(RuntimePackageVersion_CompileTime)</SystemFormatsNrbfVersion>
81+
<SystemReflectionMetadataVersion>$(RuntimePackageVersion_CompileTime)</SystemReflectionMetadataVersion>
82+
<SystemReflectionMetadataLoadContextVersion>$(RuntimePackageVersion_CompileTime)</SystemReflectionMetadataLoadContextVersion>
83+
<SystemResourcesExtensionsVersion>$(RuntimePackageVersion_CompileTime)</SystemResourcesExtensionsVersion>
84+
<SystemSecurityCryptographyProtectedDataVersion>$(RuntimePackageVersion_CompileTime)</SystemSecurityCryptographyProtectedDataVersion>
85+
<SystemTextEncodingCodePagesVersion>$(RuntimePackageVersion_CompileTime)</SystemTextEncodingCodePagesVersion>
86+
<SystemTextJsonVersion>$(RuntimePackageVersion_CompileTime)</SystemTextJsonVersion>
87+
<SystemThreadingChannelsVersion>$(RuntimePackageVersion_CompileTime)</SystemThreadingChannelsVersion>
88+
<SystemThreadingTasksDataflowVersion>$(RuntimePackageVersion_CompileTime)</SystemThreadingTasksDataflowVersion>
5889
</PropertyGroup>
5990
<PropertyGroup>
6091
<!-- maintained in eng/dependabot/Packages.props -->

src/Directory.Build.targets

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,118 @@
184184
</ItemGroup>
185185
</Target>
186186

187+
<!--
188+
net472 redistributes newer dotnet/runtime servicing assemblies than it compiles against,
189+
to line up with a Visual Studio servicing event. This mirrors the frozen maintenance-package
190+
mechanism above, in reverse: compile and restore stay at the referenced versions so there is
191+
no package downgrade (and so the .NET (Core) build, which shares these references, does not
192+
pull in new source-build prebuilts), while here we download the servicing build and copy those
193+
assemblies to the output in place of the compiled-against ones. The matching binding redirects
194+
live in src/MSBuild/app.config and src/MSBuild/app.amd64.config and must be kept in sync with
195+
%(_DeployedRuntimeAssembly.Version).
196+
197+
The dotnet/runtime 10.x wave is redistributed at $(RuntimePackageVersion_VSDeploy); the
198+
maintenance packages it binds to (System.Memory etc.) are redistributed at the matching
199+
servicing versions without changing their referenced ($(SystemMemoryVersion) etc.) versions.
200+
201+
This is opt-in per project ($(DeployRuntimeServicingAssemblies)) and intended only for the
202+
assemblies that Visual Studio actually loads (the MSBuild.exe output directory). Enabling it
203+
in a library project would make that project's output disagree with what every downstream
204+
project compiles against, producing spurious MSB3277 version-conflict warnings (errors under
205+
-warnAsError); the redistributed assemblies must therefore only appear in the final,
206+
non-referenced application output.
207+
-->
208+
<ItemGroup Condition="'$(TargetFramework)' == 'net472' and '$(DeployRuntimeServicingAssemblies)' == 'true'">
209+
<!-- dotnet/runtime 10.x servicing wave, redistributed at $(RuntimePackageVersion_VSDeploy). -->
210+
<_DeployedRuntimeAssembly Include="System.Collections.Immutable;System.Configuration.ConfigurationManager;System.Diagnostics.DiagnosticSource;System.Diagnostics.EventLog;System.Formats.Asn1;System.Formats.Nrbf;System.Reflection.Metadata;System.Reflection.MetadataLoadContext;System.Resources.Extensions;System.Security.Cryptography.ProtectedData;System.Text.Encoding.CodePages;System.Text.Json;System.Threading.Channels;System.Threading.Tasks.Dataflow">
211+
<Version>$(RuntimePackageVersion_VSDeploy)</Version>
212+
</_DeployedRuntimeAssembly>
213+
<!-- Transitive dependencies of the above (notably of System.Text.Json) that we also
214+
redistribute and that ship as part of the same wave. -->
215+
<_DeployedRuntimeAssembly Include="System.IO.Pipelines;System.Text.Encodings.Web;Microsoft.Bcl.AsyncInterfaces">
216+
<Version>$(RuntimePackageVersion_VSDeploy)</Version>
217+
</_DeployedRuntimeAssembly>
218+
<!-- Maintenance packages the wave binds to. Their assembly versions move between servicing
219+
builds (so the app.config / app.amd64.config redirects move with them); they are
220+
redistributed here without bumping their referenced versions. -->
221+
<_DeployedRuntimeAssembly Include="System.Memory">
222+
<Version>4.6.3</Version>
223+
</_DeployedRuntimeAssembly>
224+
<_DeployedRuntimeAssembly Include="System.Runtime.CompilerServices.Unsafe">
225+
<Version>6.1.2</Version>
226+
</_DeployedRuntimeAssembly>
227+
<_DeployedRuntimeAssembly Include="System.Threading.Tasks.Extensions">
228+
<Version>4.6.3</Version>
229+
</_DeployedRuntimeAssembly>
230+
<_DeployedRuntimeAssembly Include="System.Buffers">
231+
<Version>4.6.1</Version>
232+
</_DeployedRuntimeAssembly>
233+
<_DeployedRuntimeAssembly Include="System.Numerics.Vectors">
234+
<Version>4.6.1</Version>
235+
</_DeployedRuntimeAssembly>
236+
<!-- System.Formats.Nrbf in the 10.x wave binds to Microsoft.Bcl.HashCode 6.0.0.0 on net462,
237+
but the compile-time closure only brings in 1.0.0.0. Redistribute 6.0.0 so the shipped
238+
assembly matches the redirect (and the version Nrbf actually loads). -->
239+
<_DeployedRuntimeAssembly Include="Microsoft.Bcl.HashCode">
240+
<Version>6.0.0</Version>
241+
</_DeployedRuntimeAssembly>
242+
</ItemGroup>
243+
244+
<ItemGroup Condition="'$(TargetFramework)' == 'net472' and '$(DeployRuntimeServicingAssemblies)' == 'true'">
245+
<PackageDownload Include="@(_DeployedRuntimeAssembly)" Version="[%(Version)]" />
246+
</ItemGroup>
247+
248+
<PropertyGroup Condition="'$(TargetFramework)' == 'net472' and '$(DeployRuntimeServicingAssemblies)' == 'true'">
249+
<!-- RAR sees the net472 binding redirect to the deployed version but resolves the referenced
250+
version (the swap to the servicing build happens after RAR, and the compile references
251+
must stay on the packages so their .NET Framework type-forwards keep working), so it
252+
reports an unresolvable version conflict. That mismatch is intentional;
253+
ValidateMSBuildPackageDependencyVersions enforces that the shipped redirects match the
254+
assemblies actually in the output. -->
255+
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
256+
</PropertyGroup>
257+
258+
<!--
259+
Swap the runtime copy-local assemblies AFTER RAR, so the output directory contains the
260+
redistributed servicing build rather than the compiled-against one. We deliberately do NOT
261+
touch the compile-time references: the net462 reference assemblies type-forward into the
262+
.NET Framework (e.g. System.Configuration.ConfigurationManager forwards
263+
ConfigurationErrorsException to the GAC's System.Configuration), and substituting raw file
264+
references for the package references breaks those forwards. The build-time RAR
265+
version-conflict warning that results is suppressed (and the real guardrail is the
266+
ValidateMSBuildPackageDependencyVersions task) in the projects that opt in.
267+
-->
268+
<Target Name="ReplaceRuntimeAssembliesWithServicingVersions"
269+
AfterTargets="ResolveAssemblyReferences"
270+
Condition="'$(TargetFramework)' == 'net472' and '@(_DeployedRuntimeAssembly)' != ''">
271+
<PropertyGroup>
272+
<!-- Semicolon-delimited (and -bracketed) so membership tests can't match on a substring. -->
273+
<_DeployedRuntimeAssemblyIds>;@(_DeployedRuntimeAssembly);</_DeployedRuntimeAssemblyIds>
274+
<!-- The package ids that are actually copy-local in this project, so we only swap the
275+
assemblies it really redistributes (some of the wave is not referenced here). -->
276+
<_RuntimeCopyLocalIds>;@(ReferenceCopyLocalPaths->'%(NuGetPackageId)');</_RuntimeCopyLocalIds>
277+
</PropertyGroup>
278+
<ItemGroup>
279+
<!-- Precompute the servicing-build path per assembly (kept out of the transform below so
280+
that transform string stays free of nested quotes / property functions). -->
281+
<_DeployedRuntimeAssembly>
282+
<DeployedPath>$(NuGetPackageRoot)$([System.String]::Copy('%(Identity)').ToLowerInvariant())\%(Version)\lib\net462\%(Identity).dll</DeployedPath>
283+
</_DeployedRuntimeAssembly>
284+
</ItemGroup>
285+
<ItemGroup>
286+
<!-- Drop the compiled-against copies of the assemblies we redistribute... -->
287+
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)"
288+
Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and $(_DeployedRuntimeAssemblyIds.Contains(';%(ReferenceCopyLocalPaths.NuGetPackageId);'))" />
289+
290+
<!-- ...and add the servicing build, but only for assemblies this project actually copies. -->
291+
<ReferenceCopyLocalPaths Include="@(_DeployedRuntimeAssembly->'%(DeployedPath)')"
292+
Condition="$(_RuntimeCopyLocalIds.Contains(';%(_DeployedRuntimeAssembly.Identity);'))">
293+
<NuGetPackageId>%(_DeployedRuntimeAssembly.Identity)</NuGetPackageId>
294+
<NuGetPackageVersion>%(_DeployedRuntimeAssembly.Version)</NuGetPackageVersion>
295+
</ReferenceCopyLocalPaths>
296+
</ItemGroup>
297+
</Target>
298+
187299
<!-- Import parent targets -->
188300
<Import Project="..\Directory.Build.targets"/>
189301

src/MSBuild.Bootstrap/MSBuild.Bootstrap.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212

1313
<!-- The output of this project is sort of an "executable" so it can get the latest versions of everything. -->
1414
<UseFrozenMaintenancePackageVersions>false</UseFrozenMaintenancePackageVersions>
15+
16+
<!-- This project's output is copied into the bootstrap MSBuild that tests run against, so it
17+
is a redistribution surface for the net472 dotnet/runtime servicing assemblies just like
18+
MSBuild.csproj. See the ReplaceRuntimeAssembliesWithServicingVersions target in
19+
src/Directory.Build.targets. -->
20+
<DeployRuntimeServicingAssemblies>true</DeployRuntimeServicingAssemblies>
1521
</PropertyGroup>
1622

1723
<ItemGroup>

src/MSBuild/MSBuild.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
redirect ValueTuple _down_ to match VS. -->
4141
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
4242

43+
<!-- This is the executable copy of MSBuild that Visual Studio loads, so its output is
44+
where we redistribute the newer dotnet/runtime servicing assemblies for net472 (the
45+
ones the net472 binding redirects in app.config / app.amd64.config point at). See the
46+
ReplaceRuntimeAssembliesWithServicingVersions target in src/Directory.Build.targets. -->
47+
<DeployRuntimeServicingAssemblies>true</DeployRuntimeServicingAssemblies>
48+
4349
<IsPackable>true</IsPackable>
4450
<ContentTargetFolders>contentFiles</ContentTargetFolders>
4551
<BuildOutputTargetFolder>contentFiles\any\</BuildOutputTargetFolder>

0 commit comments

Comments
 (0)