diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index 16345416419c..b4321d8e7e6a 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -475,6 +475,7 @@
@(_AotArguments -> 'AOTArgument=%(Identity)')
AOTCompiler=$(_XamarinAOTCompiler)
AOTOutputDirectory=$(_AOTOutputDirectory)
+ DedupAssembly=$(_DedupAssembly)
AppBundleManifestPath=$(_AppBundleManifestPath)
CacheDirectory=$(_LinkerCacheDirectory)
@(_BundlerDlsym -> 'Dlsym=%(Identity)')
@@ -918,6 +919,8 @@
<_AOTInputDirectory>$(_IntermediateNativeLibraryDir)aot-input/
<_AOTOutputDirectory>$(_IntermediateNativeLibraryDir)aot-output/
+ <_IsDedupEnabled Condition="'$(_IsDedupEnabled)' == ''">true
+ <_DedupAssembly Condition="'$(_RunAotCompiler)' == 'true' And '$(IsMacEnabled)' == 'true' And '$(_IsDedupEnabled)' == 'true'">$(IntermediateOutputPath)aot-instances.dll
<_LibMonoLinkMode Condition="'$(_LibMonoLinkMode)' == '' And ('$(ComputedPlatform)' != 'iPhone' Or '$(_PlatformName)' == 'macOS')">dylib
<_LibMonoLinkMode Condition="'$(_LibMonoLinkMode)' == ''">static
@@ -1022,6 +1025,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
<_AOTCompileDependsOn>
$(_AOTCompileDependsOn);
@@ -1030,6 +1056,7 @@
_DetectAppManifest;
_ReadAppManifest;
_WriteAppManifest;
+ _CreateAOTDedupAssembly;
{
diff --git a/tools/common/Application.cs b/tools/common/Application.cs
index d6c60f20b83d..7fe7053a4182 100644
--- a/tools/common/Application.cs
+++ b/tools/common/Application.cs
@@ -1495,13 +1495,13 @@ public bool IsAOTCompiled (string assembly)
public IList GetAotArguments (string filename, Abi abi, string outputDir, string outputFile, string llvmOutputFile, string dataFile)
{
- GetAotArguments (filename, abi, outputDir, outputFile, llvmOutputFile, dataFile, out var processArguments, out var aotArguments);
+ GetAotArguments (filename, abi, outputDir, outputFile, llvmOutputFile, dataFile, null, out var processArguments, out var aotArguments);
processArguments.Add (string.Join (",", aotArguments));
processArguments.Add (filename);
return processArguments;
}
- public void GetAotArguments (string filename, Abi abi, string outputDir, string outputFile, string llvmOutputFile, string dataFile, out List processArguments, out List aotArguments, string llvm_path = null)
+ public void GetAotArguments (string filename, Abi abi, string outputDir, string outputFile, string llvmOutputFile, string dataFile, bool? isDedupAssembly, out List processArguments, out List aotArguments, string llvm_path = null)
{
string fname = Path.GetFileName (filename);
processArguments = new List ();
@@ -1536,6 +1536,18 @@ public void GetAotArguments (string filename, Abi abi, string outputDir, string
aotArguments.Add ($"data-outfile={dataFile}");
aotArguments.Add ("static");
aotArguments.Add ("asmonly");
+ // This method is used in legacy build as well, where dedup is not supported.
+ // Variable isDedupAssembly could have the following values:
+ // - NULL means that dedup is not enabled
+ // - FALSE means that dedup-skip flag should be passed for all assemblies except a container assemblt
+ // - TRUE means that dedup-include flag should be passed for the container assembly
+ if (isDedupAssembly.HasValue) {
+ if (isDedupAssembly.Value) {
+ aotArguments.Add ($"dedup-include={fname}");
+ } else {
+ aotArguments.Add ($"dedup-skip");
+ }
+ }
if (app.LibMonoLinkMode == AssemblyBuildTarget.StaticObject || !Driver.IsDotNet)
aotArguments.Add ("direct-icalls");
aotArguments.AddRange (app.AotArguments);
diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs
index 6cf3b44e7f2e..37a94046eed4 100644
--- a/tools/dotnet-linker/LinkerConfiguration.cs
+++ b/tools/dotnet-linker/LinkerConfiguration.cs
@@ -21,6 +21,7 @@ public class LinkerConfiguration {
public List Abis;
public string AOTCompiler;
public string AOTOutputDirectory;
+ public string DedupAssembly;
public string CacheDirectory { get; private set; }
public Version DeploymentTarget { get; private set; }
public HashSet FrameworkAssemblies { get; private set; } = new HashSet ();
@@ -125,6 +126,9 @@ public static LinkerConfiguration GetInstance (LinkContext context, bool createI
case "AOTOutputDirectory":
AOTOutputDirectory = value;
break;
+ case "DedupAssembly":
+ DedupAssembly = value;
+ break;
case "CacheDirectory":
CacheDirectory = value;
break;
@@ -386,6 +390,7 @@ public void Write ()
Console.WriteLine ($" ABIs: {string.Join (", ", Abis.Select (v => v.AsArchString ()))}");
Console.WriteLine ($" AOTArguments: {string.Join (", ", Application.AotArguments)}");
Console.WriteLine ($" AOTOutputDirectory: {AOTOutputDirectory}");
+ Console.WriteLine ($" DedupAssembly: {DedupAssembly}");
Console.WriteLine ($" AppBundleManifestPath: {Application.InfoPListPath}");
Console.WriteLine ($" AreAnyAssembliesTrimmed: {Application.AreAnyAssembliesTrimmed}");
Console.WriteLine ($" AssemblyName: {Application.AssemblyName}");
diff --git a/tools/dotnet-linker/Steps/ComputeAOTArguments.cs b/tools/dotnet-linker/Steps/ComputeAOTArguments.cs
index 8d13589e3cf8..3d3e043ab305 100644
--- a/tools/dotnet-linker/Steps/ComputeAOTArguments.cs
+++ b/tools/dotnet-linker/Steps/ComputeAOTArguments.cs
@@ -19,6 +19,8 @@ protected override void TryEndProcess ()
var app = Configuration.Application;
var outputDirectory = Configuration.AOTOutputDirectory;
+ var dedupFileName = Path.GetFileName (Configuration.DedupAssembly);
+ var isDedupEnabled = Configuration.Target.Assemblies.Any (asm => Path.GetFileName (asm.FullPath) == dedupFileName);
foreach (var asm in Configuration.Target.Assemblies) {
var isAOTCompiled = asm.IsAOTCompiled;
@@ -30,6 +32,10 @@ protected override void TryEndProcess ()
};
var input = asm.FullPath;
+ bool? isDedupAssembly = null;
+ if (isDedupEnabled) {
+ isDedupAssembly = Path.GetFileName (input) == dedupFileName;
+ }
var abis = app.Abis.Select (v => v.AsString ()).ToArray ();
foreach (var abi in app.Abis) {
var abiString = abi.AsString ();
@@ -38,7 +44,7 @@ protected override void TryEndProcess ()
var aotData = Path.Combine (outputDirectory, arch, Path.GetFileNameWithoutExtension (input) + ".aotdata");
var llvmFile = Configuration.Application.IsLLVM ? Path.Combine (outputDirectory, arch, Path.GetFileName (input) + ".llvm.o") : string.Empty;
var objectFile = Path.Combine (outputDirectory, arch, Path.GetFileName (input) + ".o");
- app.GetAotArguments (asm.FullPath, abi, outputDirectory, aotAssembly, llvmFile, aotData, out var processArguments, out var aotArguments, Path.GetDirectoryName (Configuration.AOTCompiler));
+ app.GetAotArguments (asm.FullPath, abi, outputDirectory, aotAssembly, llvmFile, aotData, isDedupAssembly, out var processArguments, out var aotArguments, Path.GetDirectoryName (Configuration.AOTCompiler));
item.Metadata.Add ("Arguments", StringUtils.FormatArguments (aotArguments));
item.Metadata.Add ("ProcessArguments", StringUtils.FormatArguments (processArguments));
item.Metadata.Add ("Abi", abiString);
@@ -47,6 +53,8 @@ protected override void TryEndProcess ()
item.Metadata.Add ("AOTAssembly", aotAssembly);
item.Metadata.Add ("LLVMFile", llvmFile);
item.Metadata.Add ("ObjectFile", objectFile);
+ if (isDedupAssembly.HasValue && isDedupAssembly.Value)
+ item.Metadata.Add ("IsDedupAssembly", isDedupAssembly.Value.ToString ());
}
assembliesToAOT.Add (item);