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);