Skip to content

Commit 18f77c5

Browse files
[One .NET] fixes for satellite assemblies
Context: #5040 In trying to enable our F# MSBuild tests, one fails with: GenerateCompressedAssembliesNativeSourceFiles Xamarin.Android.Common.targets(1933,3): error XAGCANSF7004: System.ArgumentException: An item with the same key has already been added. Key: [FSharp.Core.resources.dll, Xamarin.Android.Tasks.CompressedAssemblyInfo] at System.Collections.Generic.TreeSet`1.AddIfNotPresent(T item) at System.Collections.Generic.SortedDictionary`2.Add(TKey key, TValue value) at Xamarin.Android.Tasks.GenerateCompressedAssembliesNativeSourceFiles.GenerateCompressedAssemblySources() at Xamarin.Android.Tasks.GenerateCompressedAssembliesNativeSourceFiles.RunTask() at Xamarin.Android.Tasks.AndroidTask.Execute() Looking at some of the item groups earlier: C:\src\xamarin-android\packages\xamarin.android.fsharp.resourceprovider\1.0.1\lib\monoandroid81\Xamarin.Android.FSharp.ResourceProvider.Runtime.dll ... DestinationSubPath = Xamarin.Android.FSharp.ResourceProvider.Runtime.dll ... C:\src\xamarin-android\packages\fsharp.core\4.7.2\lib\netstandard2.0\cs\FSharp.Core.resources.dll ... DestinationSubDirectory = cs\ DestinationSubPath = cs\FSharp.Core.resources.dll ... C:\src\xamarin-android\packages\fsharp.core\4.7.2\lib\netstandard2.0\de\FSharp.Core.resources.dll ... DestinationSubDirectory = de\ DestinationSubPath = de\FSharp.Core.resources.dll ... Two instances of `FSharp.Core.resources.dll` is causing the above exception. Should we be using the `%(DestinationSubDirectory)` and `%(DestinationSubPath)` item metadata? Currently, we have some behavior for architecture-specific .NET assemblies: * `%(AbiDirectory)` is set for x86, armeabi-v7a, etc. * `%(IntermediateLinkerOutput)` is set to a full path taking `%(AbiDirectory)` into account. To clean things up here, we should just use `%(DestinationSubDirectory)` coming from dotnet/sdk and `%(DestinationSubPath)` and remove the item data that we invented. Other changes: * Usage of `%(AbiDirectory)` can use `%(DestinationSubDirectory)` or `%(DestinationSubPath)` where appropriate. * Any usage of `%(IntermediateLinkerOutput)` can use `$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)` instead. * The `<ResolveAssemblies/>` (legacy) and `<ProcessAssemblies/>` MSBuild tasks no longer need the `IntermediateAssemblyDirectory` property.
1 parent faf1d16 commit 18f77c5

File tree

7 files changed

+48
-44
lines changed

7 files changed

+48
-44
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ _ResolveAssemblies MSBuild target.
5757
<ProcessAssemblies
5858
InputAssemblies="@(_ResolvedAssemblyFiles)"
5959
ResolvedSymbols="@(_ResolvedSymbolFiles)"
60-
IntermediateAssemblyDirectory="$(MonoAndroidIntermediateAssemblyDir)"
6160
UseSharedRuntime="$(AndroidUseSharedRuntime)"
6261
LinkMode="$(AndroidLinkMode)">
6362
<Output TaskParameter="OutputAssemblies" ItemName="_ProcessedAssemblies" />
@@ -111,10 +110,10 @@ _ResolveAssemblies MSBuild target.
111110
<Target Name="_PrepareAssemblies"
112111
DependsOnTargets="$(_PrepareAssembliesDependsOnTargets)">
113112
<ItemGroup Condition=" '$(AndroidLinkMode)' == 'None' ">
114-
<_ResolvedAssemblies Include="@(ResolvedAssemblies->'%(IntermediateLinkerOutput)')" />
115-
<_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies->'%(IntermediateLinkerOutput)')" />
116-
<_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies->'%(IntermediateLinkerOutput)')" />
117-
<_ResolvedSymbols Include="@(ResolvedSymbols->'%(IntermediateLinkerOutput)')" />
113+
<_ResolvedAssemblies Include="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" />
114+
<_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" />
115+
<_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" />
116+
<_ResolvedSymbols Include="@(ResolvedSymbols->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" />
118117
<_ShrunkAssemblies Include="@(_ResolvedAssemblies)" />
119118
<_ShrunkUserAssemblies Include="@(_ResolvedUserAssemblies)" />
120119
<_ShrunkFrameworkAssemblies Include="@(_ResolvedFrameworkAssemblies)" />

src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -421,9 +421,9 @@ string CompressAssembly (ITaskItem assembly)
421421
if (compressedAssembliesInfo.TryGetValue (key, out CompressedAssemblyInfo info) && info != null) {
422422
EnsureCompressedAssemblyData (assembly.ItemSpec, info.DescriptorIndex);
423423
string assemblyOutputDir;
424-
string abiDirectory = assembly.GetMetadata ("AbiDirectory");
425-
if (!String.IsNullOrEmpty (abiDirectory))
426-
assemblyOutputDir = Path.Combine (compressedOutputDir, abiDirectory);
424+
string subDirectory = assembly.GetMetadata ("DestinationSubDirectory");
425+
if (!String.IsNullOrEmpty (subDirectory))
426+
assemblyOutputDir = Path.Combine (compressedOutputDir, subDirectory);
427427
else
428428
assemblyOutputDir = compressedOutputDir;
429429
AssemblyCompression.CompressionResult result = AssemblyCompression.Compress (compressedAssembly, assemblyOutputDir);
@@ -494,11 +494,13 @@ void AddAssemblyConfigEntry (ZipArchiveEx apk, string assemblyPath, string confi
494494
string GetAssemblyPath (ITaskItem assembly, bool frameworkAssembly)
495495
{
496496
var assembliesPath = AssembliesPath;
497-
var abiDirectory = assembly.GetMetadata ("AbiDirectory");
498-
if (!string.IsNullOrEmpty (abiDirectory)) {
499-
assembliesPath += abiDirectory + "/";
500-
}
501-
if (!frameworkAssembly && SatelliteAssembly.TryGetSatelliteCultureAndFileName (assembly.ItemSpec, out var culture, out _)) {
497+
var subDirectory = assembly.GetMetadata ("DestinationSubDirectory");
498+
if (!string.IsNullOrEmpty (subDirectory)) {
499+
assembliesPath += subDirectory.Replace ('\\', '/');
500+
if (!assembliesPath.EndsWith ("/", StringComparison.Ordinal)) {
501+
assembliesPath += "/";
502+
}
503+
} else if (!frameworkAssembly && SatelliteAssembly.TryGetSatelliteCultureAndFileName (assembly.ItemSpec, out var culture, out _)) {
502504
assembliesPath += culture + "/";
503505
}
504506
return assembliesPath;

src/Xamarin.Android.Build.Tasks/Tasks/ProcessAssemblies.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Xamarin.Android.Tasks
1515
/// Also sets some metadata:
1616
/// * %(FrameworkAssembly)=True to determine if framework or user assembly
1717
/// * %(HasMonoAndroidReference)=True for incremental build performance
18-
/// * %(AbiDirectory) if an assembly has an architecture-specific version
18+
/// * Modify %(DestinationSubDirectory) and %(DestinationSubPath) if an assembly has an architecture-specific version
1919
/// </summary>
2020
public class ProcessAssemblies : AndroidTask
2121
{
@@ -24,9 +24,6 @@ public class ProcessAssemblies : AndroidTask
2424
public bool UseSharedRuntime { get; set; }
2525

2626
public string LinkMode { get; set; }
27-
28-
[Required]
29-
public string IntermediateAssemblyDirectory { get; set; }
3027

3128
public ITaskItem [] InputAssemblies { get; set; }
3229

@@ -82,20 +79,22 @@ public override bool RunTask ()
8279
OutputAssemblies = output.Values.ToArray ();
8380
ResolvedSymbols = symbols.Values.ToArray ();
8481

85-
// Set %(AbiDirectory) for architecture-specific assemblies
82+
// Set %(DestinationSubDirectory) and %(DestinationSubPath) for architecture-specific assemblies
8683
var fileNames = new Dictionary<string, ITaskItem> (StringComparer.OrdinalIgnoreCase);
8784
foreach (var assembly in OutputAssemblies) {
8885
var fileName = Path.GetFileName (assembly.ItemSpec);
8986
symbols.TryGetValue (Path.ChangeExtension (assembly.ItemSpec, ".pdb"), out var symbol);
9087
if (fileNames.TryGetValue (fileName, out ITaskItem other)) {
91-
SetAbiDirectory (assembly, fileName, symbol);
88+
SetDestinationSubDirectory (assembly, fileName, symbol);
9289
symbols.TryGetValue (Path.ChangeExtension (other.ItemSpec, ".pdb"), out symbol);
93-
SetAbiDirectory (other, fileName, symbol);
90+
SetDestinationSubDirectory (other, fileName, symbol);
9491
} else {
9592
fileNames.Add (fileName, assembly);
96-
assembly.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, fileName));
97-
if (symbol != null) {
98-
symbol.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, Path.GetFileName (symbol.ItemSpec)));
93+
if (string.IsNullOrEmpty (assembly.GetMetadata ("DestinationSubPath"))) {
94+
assembly.SetMetadata ("DestinationSubPath", Path.GetFileName (assembly.ItemSpec));
95+
}
96+
if (symbol != null && string.IsNullOrEmpty (symbol.GetMetadata ("DestinationSubPath"))) {
97+
symbol.SetMetadata ("DestinationSubPath", Path.GetFileName (symbol.ItemSpec));
9998
}
10099
}
101100
}
@@ -115,24 +114,28 @@ public override bool RunTask ()
115114
}
116115

117116
/// <summary>
118-
/// Sets %(AbiDirectory) based on %(RuntimeIdentifier)
117+
/// Sets %(DestinationSubDirectory) and %(DestinationSubPath) based on %(RuntimeIdentifier)
119118
/// </summary>
120-
void SetAbiDirectory (ITaskItem assembly, string fileName, ITaskItem symbol)
119+
void SetDestinationSubDirectory (ITaskItem assembly, string fileName, ITaskItem symbol)
121120
{
122121
var rid = assembly.GetMetadata ("RuntimeIdentifier");
123122
var abi = MonoAndroidHelper.RuntimeIdentifierToAbi (rid);
124123
if (!string.IsNullOrEmpty (abi)) {
125-
assembly.SetMetadata ("AbiDirectory", abi);
126-
assembly.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, abi, fileName));
124+
string destination = Path.Combine (assembly.GetMetadata ("DestinationSubDirectory"), abi) + Path.DirectorySeparatorChar;
125+
assembly.SetMetadata ("DestinationSubDirectory", destination);
126+
assembly.SetMetadata ("DestinationSubPath", Path.Combine (destination, fileName));
127127
if (symbol != null) {
128-
symbol.SetMetadata ("AbiDirectory", abi);
129-
symbol.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, abi, Path.GetFileName (symbol.ItemSpec)));
128+
destination = Path.Combine (symbol.GetMetadata ("DestinationSubDirectory"), abi) + Path.DirectorySeparatorChar;
129+
symbol.SetMetadata ("DestinationSubDirectory", destination);
130+
symbol.SetMetadata ("DestinationSubPath", Path.Combine (destination, Path.GetFileName (symbol.ItemSpec)));
130131
}
131132
} else {
132133
Log.LogDebugMessage ($"Android ABI not found for: {assembly.ItemSpec}");
133-
assembly.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, fileName));
134-
if (symbol != null) {
135-
symbol.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, Path.GetFileName (symbol.ItemSpec)));
134+
if (string.IsNullOrEmpty (assembly.GetMetadata ("DestinationSubPath"))) {
135+
assembly.SetMetadata ("DestinationSubPath", Path.GetFileName (assembly.ItemSpec));
136+
}
137+
if (symbol != null && string.IsNullOrEmpty (symbol.GetMetadata ("DestinationSubPath"))) {
138+
symbol.SetMetadata ("DestinationSubPath", Path.GetFileName (symbol.ItemSpec));
136139
}
137140
}
138141
}

src/Xamarin.Android.Build.Tasks/Tasks/ResolveAssemblies.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ public class ResolveAssemblies : AndroidAsyncTask
3434
[Required]
3535
public string ProjectFile { get; set; }
3636

37-
[Required]
38-
public string IntermediateAssemblyDirectory { get; set; }
39-
4037
public string ProjectAssetFile { get; set; }
4138

4239
public string TargetMoniker { get; set; }
@@ -141,7 +138,9 @@ void Execute (MetadataResolver resolver)
141138
} else {
142139
resolvedUserAssemblies.Add (assembly);
143140
}
144-
assembly.SetMetadata ("IntermediateLinkerOutput", Path.Combine (IntermediateAssemblyDirectory, Path.GetFileName (assembly.ItemSpec)));
141+
if (string.IsNullOrEmpty (assembly.GetMetadata ("DestinationSubPath"))) {
142+
assembly.SetMetadata ("DestinationSubPath", Path.GetFileName (assembly.ItemSpec));
143+
}
145144
}
146145
ResolvedAssemblies = resolvedAssemblies.ToArray ();
147146
ResolvedSymbols = resolvedSymbols.ToArray ();

src/Xamarin.Android.Build.Tasks/Utilities/CompressedAssemblyInfo.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ public static string GetKey (string projectFullPath)
2727

2828
public static string GetDictionaryKey (ITaskItem assembly)
2929
{
30-
var key = Path.GetFileName (assembly.ItemSpec);
31-
var abiDirectory = assembly.GetMetadata ("AbiDirectory");
32-
if (!string.IsNullOrEmpty (abiDirectory)) {
33-
key = abiDirectory + "/" + key;
30+
// Prefer %(DestinationSubPath) if set
31+
var path = assembly.GetMetadata ("DestinationSubPath");
32+
if (!string.IsNullOrEmpty (path)) {
33+
return path;
3434
}
35-
return key;
35+
// MSBuild sometimes only sets %(DestinationSubDirectory)
36+
var subDirectory = assembly.GetMetadata ("DestinationSubDirectory");
37+
return Path.Combine (subDirectory, Path.GetFileName (assembly.ItemSpec));
3638
}
3739
}
3840
}

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,11 +1376,11 @@ because xbuild doesn't support framework reference assemblies.
13761376
DependsOnTargets="_LinkAssembliesNoShrinkInputs"
13771377
Condition="'$(AndroidLinkMode)' == 'None'"
13781378
Inputs="@(ResolvedAssemblies);$(_AndroidBuildPropertiesCache)"
1379-
Outputs="@(ResolvedAssemblies->'%(IntermediateLinkerOutput)')">
1379+
Outputs="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')">
13801380
<LinkAssembliesNoShrink
13811381
ResolvedAssemblies="@(_AllResolvedAssemblies)"
13821382
SourceFiles="@(ResolvedAssemblies)"
1383-
DestinationFiles="@(ResolvedAssemblies->'%(IntermediateLinkerOutput)')"
1383+
DestinationFiles="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')"
13841384
Deterministic="$(Deterministic)"
13851385
/>
13861386
<ItemGroup>

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ projects. .NET 5 projects will not import this file.
284284
TargetFrameworkVersion="$(TargetFrameworkVersion)"
285285
ProjectAssetFile="$(ProjectLockFile)"
286286
TargetMoniker="$(NuGetTargetMoniker)"
287-
IntermediateAssemblyDirectory="$(MonoAndroidIntermediateAssemblyDir)"
288287
ReferenceAssembliesDirectory="$(TargetFrameworkDirectory)">
289288
<Output TaskParameter="ResolvedAssemblies" ItemName="ResolvedAssemblies" />
290289
<Output TaskParameter="ResolvedUserAssemblies" ItemName="ResolvedUserAssemblies" />

0 commit comments

Comments
 (0)