-
Notifications
You must be signed in to change notification settings - Fork 390
Expand file tree
/
Copy pathWorkarounds.targets
More file actions
383 lines (327 loc) · 16.5 KB
/
Copy pathWorkarounds.targets
File metadata and controls
383 lines (327 loc) · 16.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->
<Project InitialTargets="NormalizeNetCoreSdkRootCasing">
<!-- Workaround for https://github.com/Microsoft/msbuild/issues/1310 -->
<Target Name="ForceGenerationOfBindingRedirects"
AfterTargets="ResolveAssemblyReferences"
BeforeTargets="GenerateBindingRedirects"
Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
<PropertyGroup>
<!-- Needs to be set in a target because it has to be set after the initial evaluation in the common targets -->
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
</Target>
<!--
WPF temp project sets OutDir, which makes the SDK create an empty directory for it,
polluting the output dir. Avoid creating these directories.
https://github.com/dotnet/sdk/issues/1367
-->
<PropertyGroup Condition="'$(IsWpfTempProject)' == 'true'">
<OutDir/>
</PropertyGroup>
<!--
Workaround to fix that Visual Studio sometimes uses a special MSBuild evaluation
mode where all common conditions (e.g., inside ItemGroup) are ignored.
-->
<Choose>
<When Condition=" '$(IsWpfTempProject)' == 'true' and '$(TargetFrameworkIdentifier)' == '.NETFramework' ">
<ItemGroup>
<Reference Include="mscorlib" Pack="false" />
</ItemGroup>
</When>
</Choose>
<!--
Portable PDBs are not included in .nupkg by default. Include them unless the project produces symbol packages.
Remove this once we migrate to .snupkg. See https://github.com/dotnet/arcade/issues/1959.
-->
<PropertyGroup Condition="'$(DebugType)' == 'portable' and '$(IncludeSymbols)' != 'true'">
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<!--
Workarounds for insufficient support for tools packages by NuGet Pack: https://github.com/NuGet/Home/issues/6321.
Project that produce tools packages use .nuspec file in order to include all the needed dependencies.
This target translates common msbuild properties to NuSpec properties.
-->
<Target Name="InitializeStandardNuspecProperties"
BeforeTargets="GenerateNuspec"
DependsOnTargets="_InitializeNuspecRepositoryInformationPropertiesWorkaround"
Condition="'$(IsPackable)' == 'true'">
<PropertyGroup>
<PackageId Condition="'$(NuspecPackageId)' != ''">$(NuspecPackageId)</PackageId>
<PackageProjectUrl Condition="'$(PackageProjectUrl)' == ''">$(RepositoryUrl)</PackageProjectUrl>
</PropertyGroup>
<Error Text="PackageDescription must be specified" Condition="'$(PackageDescription)' == ''"/>
<Error Text="PackageProjectUrl must be specified" Condition="'$(PackageProjectUrl)' == ''"/>
<Error Text="RepositoryUrl must be specified" Condition="'$(RepositoryUrl)' == ''"/>
<Error Text="RepositoryCommit must be specified" Condition="'$(RepositoryCommit)' == ''"/>
<Error Text="RepositoryType must be specified" Condition="'$(RepositoryType)' == ''"/>
<Error Text="Either PackageLicenseExpression or PackageLicenseFile must be specified" Condition="'$(PackageLicenseExpression)' == '' and '$(PackageLicenseFile)' == ''"/>
<PropertyGroup Condition="'$(NuspecFile)' != '' and '$(NuspecProperties)' == ''">
<_LicenseElement/>
<_LicenseElement Condition="'$(PackageLicenseExpression)' != ''">
<license type="expression">$(PackageLicenseExpression)</license>
</_LicenseElement>
<_LicenseElement Condition="'$(PackageLicenseFile)' != ''">
<license type="file">$(PackageLicenseFile)</license>
</_LicenseElement>
<_LicenseFileElement/>
<_LicenseFileElement Condition="'$(PackageLicenseFile)' != ''">
<file src="$(PackageLicenseFullPath)" target="$(PackageLicenseFile)" />
</_LicenseFileElement>
<_TagsElement/>
<_TagsElement Condition="'$(PackageTags)' != ''">
<tags>$(PackageTags.Replace(';', ' '))</tags>
</_TagsElement>
<_IconUrlElement/>
<_IconUrlElement Condition="'$(PackageIcon)' == '' and '$(PackageIconUrl)' != ''">
<iconUrl>$(PackageIconUrl)</iconUrl>
</_IconUrlElement>
<_IconElement/>
<_IconElement Condition="'$(PackageIcon)' != ''">
<icon>$(PackageIcon)</icon>
</_IconElement>
<_IconFileElement/>
<_IconFileElement Condition="'$(PackageIcon)' != ''">
<file src="$(PackageIconFullPath)" target="$(PackageIcon)" />
</_IconFileElement>
<_ReleaseNotesElement/>
<_ReleaseNotesElement Condition="'$(PackageReleaseNotes)' != ''">
<releaseNotes>$(PackageReleaseNotes)</releaseNotes>
</_ReleaseNotesElement>
<_CommonMetadataElements>
<id>$(PackageId)</id>
<description>$(PackageDescription)</description>
<version>$(PackageVersion)</version>
<authors>$(Authors)</authors>
<requireLicenseAcceptance>$(PackageRequireLicenseAcceptance)</requireLicenseAcceptance>
$(_TagsElement)
$(_LicenseElement)
$(_IconElement)
$(_IconUrlElement)
$(_ReleaseNotesElement)
<projectUrl>$(PackageProjectUrl)</projectUrl>
<copyright>$(Copyright)</copyright>
<developmentDependency>$(DevelopmentDependency)</developmentDependency>
<serviceable>$(Serviceable)</serviceable>
<repository type="$(RepositoryType)" url="$(RepositoryUrl)" commit="$(RepositoryCommit)" />
</_CommonMetadataElements>
<_CommonFileElements>
$(_IconFileElement)
$(_LicenseFileElement)
</_CommonFileElements>
</PropertyGroup>
<ItemGroup Condition="'$(NuspecFile)' != '' and '$(NuspecProperties)' == ''">
<NuspecProperty Include="CommonMetadataElements=$(_CommonMetadataElements)"/>
<NuspecProperty Include="CommonFileElements=$(_CommonFileElements)"/>
<NuspecProperty Include="PackageId=$(PackageId)"/>
<NuspecProperty Include="Version=$(PackageVersion)"/>
<NuspecProperty Include="ProjectDirectory=$(MSBuildProjectDirectory)"/>
</ItemGroup>
<PropertyGroup Condition="'$(NuspecFile)' != '' and '$(NuspecProperties)' == ''">
<NuspecProperties>@(NuspecProperty, ';')</NuspecProperties>
</PropertyGroup>
</Target>
<!--
Initialize Repository* properties from properties set by a source control package, if available in the project.
-->
<Target Name="_InitializeNuspecRepositoryInformationPropertiesWorkaround"
DependsOnTargets="InitializeSourceControlInformation"
Condition="'$(SourceControlInformationFeatureSupported)' == 'true'">
<PropertyGroup>
<!-- The project must specify PublishRepositoryUrl=true in order to publish the URL, in order to prevent inadvertent leak of internal URL. -->
<RepositoryUrl Condition="'$(RepositoryUrl)' == '' and '$(PublishRepositoryUrl)' == 'true'">$(PrivateRepositoryUrl)</RepositoryUrl>
<RepositoryCommit Condition="'$(RepositoryCommit)' == ''">$(SourceRevisionId)</RepositoryCommit>
</PropertyGroup>
</Target>
<!--
NuGet Restore uses PackageId and project name in the same namespace, so that project reference can be interchanged with a package reference.
This causes issues however for leaf packages that are not to be referenced (such as analyzer or tools packages) when we want to name the package
the same as an existing project in the solution. In that case we set PackageId to an invalid but unique value for Restore and override it for Pack
with the desired name stored in $(NuspecPackageId).
-->
<PropertyGroup Condition="'$(NuspecPackageId)' != ''">
<PackageId>*$(MSBuildProjectName)*</PackageId>
</PropertyGroup>
<!--
Source packaging helpers.
-->
<PropertyGroup Condition="'$(IsPackable)' == 'true' and '$(IsSourcePackage)' == 'true'">
<TargetsForTfmSpecificContentInPackage Condition="'$(NuspecFile)' == ''">$(TargetsForTfmSpecificContentInPackage);_AddSourceFilesToSourcePackage</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<Target Name="_AddSourceFilesToSourcePackage">
<PropertyGroup>
<!-- TODO: language to dir name mapping (https://github.com/Microsoft/msbuild/issues/2101) -->
<_LanguageDirName>$(DefaultLanguageSourceExtension.TrimStart('.'))</_LanguageDirName>
</PropertyGroup>
<ItemGroup>
<_File Remove="@(_File)"/>
<_File Include="$(MSBuildProjectDirectory)\**\*$(DefaultLanguageSourceExtension)" TargetDir="contentFiles/$(_LanguageDirName)/$(TargetFramework)" BuildAction="Compile" />
<TfmSpecificPackageFile Include="@(_File)" PackagePath="%(_File.TargetDir)/%(_File.RecursiveDir)%(_File.FileName)%(_File.Extension)"/>
</ItemGroup>
</Target>
<!--
==========================================================================
TEMPORARY WORKAROUND for https://github.com/dotnet/msbuild/issues/14026
==========================================================================
Problem
-------
The .NET task host handshake "salt" is a case-sensitive hash of the SDK
tools directory. The two sides derive that directory string differently:
* Host (.NET Framework MSBuild, e.g. VS): hashes the $(NetCoreSdkRoot)
property. Its drive-letter casing is propagated verbatim from the
environment (e.g. the Azure DevOps "D:\a\_work\1\s" sources path via
Arcade's DOTNET_ROOT / SDK resolver) and is NEVER canonicalized,
because managed Path.* APIs preserve the caller's drive casing.
* Child (.NET task host / SDK apphost): resolves its own path via
Environment.ProcessPath, which is GetModuleFileNameW(NULL) under the
hood and reports the volume's *canonical* on-disk drive-letter casing.
When those casings differ (observed: host "D:" vs child "d:") the salts
differ and the handshake fails with:
error MSB4216: Could not run the "..." task because MSBuild could not
create or connect to a task host with runtime "NET" ...
Fix
---
Rewrite ONLY the drive letter of $(NetCoreSdkRoot) to the SAME canonical
casing the child's Environment.ProcessPath will report, so the host computes
the same salt the child will. We splice just the drive letter onto the
original path so we do not resolve junctions/symlinks or alter the casing of
any other path component.
HOW WE MATCH Environment.ProcessPath EXACTLY
--------------------------------------------
Environment.ProcessPath is implemented as GetModuleFileNameW(NULL) for the
current process. We obtain the identical canonicalization in-process, WITHOUT
launching the SDK, by:
LoadLibraryEx(<apphost on the SDK volume>, LOAD_LIBRARY_AS_DATAFILE)
GetModuleFileNameW(hModule)
Empirically (verified on Windows), GetModuleFileNameW IGNORES the drive
casing passed to LoadLibraryEx and returns the volume's canonical casing -
the exact same value Environment.ProcessPath yields for a process launched
from that volume. The canonical drive-letter casing is a property of the
volume mount, not of the individual file, so loading MSBuild.exe (or, if the
apphost is absent, MSBuild.dll) from $(NetCoreSdkRoot) yields the same drive
letter the child task host will see.
This is Windows-only, idempotent, and a safe no-op when no loadable image is
found under $(NetCoreSdkRoot).
Remove this workaround once BOTH the VS MSBuild host and the .NET SDK task
host carry the bilateral salt-casing normalization from #14026.
Wiring
------
This workaround is implemented in Workarounds.targets and is imported automatically
by Microsoft.DotNet.Arcade.Sdk (see sdk/Sdk.targets). No additional wiring is
required for Arcade SDK consumers.
InitialTargets on this <Project> aggregates into the importing project's InitialTargets,
so the target runs early in the build (before the first .NET task host is launched).
NetCoreSdkRoot is defined during evaluation, so it is available by the time the target runs.
==========================================================================
-->
<UsingTask TaskName="NormalizeSdkRootDriveCasing"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"
Condition="'$(MSBuildRuntimeType)' == 'Full' and '$(NetCoreSdkRoot)' != ''">
<ParameterGroup>
<SdkRoot ParameterType="System.String" Required="true" />
<Result ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Class" Language="cs"><![CDATA[
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class NormalizeSdkRootDriveCasing : Task
{
[Required]
public string SdkRoot { get; set; }
[Output]
public string Result { get; set; }
private const uint LOAD_LIBRARY_AS_DATAFILE = 0x2;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr LoadLibraryExW(string lpFileName, IntPtr hFile, uint dwFlags);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern uint GetModuleFileNameW(IntPtr hModule, StringBuilder lpFilename, uint nSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeLibrary(IntPtr hModule);
public override bool Execute()
{
// Best-effort: never fail the build over a casing tweak. Default to a no-op.
Result = SdkRoot;
try
{
// Only handle local "X:\..." drive paths.
if (string.IsNullOrEmpty(SdkRoot) || SdkRoot.Length < 2 || SdkRoot[1] != ':')
{
return true;
}
// Load any PE image that lives on the SDK volume. The canonical drive
// letter is volume-wide, so the specific file does not matter; we prefer
// the apphost (the exact image the child task host runs as).
string image = null;
foreach (string candidate in new[] { "MSBuild.exe", "MSBuild.dll" })
{
string p = Path.Combine(SdkRoot, candidate);
if (File.Exists(p))
{
image = p;
break;
}
}
if (image == null)
{
return true;
}
IntPtr module = LoadLibraryExW(image, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
if (module == IntPtr.Zero)
{
return true;
}
try
{
var sb = new StringBuilder(1024);
uint len = GetModuleFileNameW(module, sb, (uint)sb.Capacity);
if (len == 0)
{
return true;
}
// GetModuleFileNameW returns the same canonical path Environment.ProcessPath
// would report. Splice ONLY its drive letter onto the original SDK root.
string canonical = sb.ToString();
if (canonical.Length >= 2 && canonical[1] == ':')
{
char canonicalDrive = canonical[0];
if (canonicalDrive != SdkRoot[0])
{
Result = canonicalDrive + SdkRoot.Substring(1);
Log.LogMessage(
MessageImportance.Low,
"Normalized NetCoreSdkRoot drive casing '{0}' -> '{1}' to match Environment.ProcessPath (#14026 workaround).",
SdkRoot[0],
canonicalDrive);
}
}
}
finally
{
FreeLibrary(module);
}
}
catch (Exception ex)
{
// Swallow: a casing mismatch is the only thing we're trying to fix, and
// we must not regress builds where this best-effort probe cannot run.
Log.LogMessage(MessageImportance.Low, "NormalizeSdkRootDriveCasing skipped: {0}", ex.Message);
}
return true;
}
}
]]></Code>
</Task>
</UsingTask>
<Target Name="NormalizeNetCoreSdkRootCasing"
Condition="'$(MSBuildRuntimeType)' == 'Full' and '$(NetCoreSdkRoot)' != ''">
<NormalizeSdkRootDriveCasing SdkRoot="$(NetCoreSdkRoot)">
<Output TaskParameter="Result" PropertyName="NetCoreSdkRoot" />
</NormalizeSdkRootDriveCasing>
</Target>
</Project>