diff --git a/src/Tasks/Common/MetadataKeys.cs b/src/Tasks/Common/MetadataKeys.cs
index aa0522eb3718..5569d9a584ed 100644
--- a/src/Tasks/Common/MetadataKeys.cs
+++ b/src/Tasks/Common/MetadataKeys.cs
@@ -129,6 +129,8 @@ internal static class MetadataKeys
public const string IsVersion5 = "IsVersion5";
public const string CreateCompositeImage = "CreateCompositeImage";
public const string PerfmapFormatVersion = "PerfmapFormatVersion";
+ public const string RequiresNativeLink = "RequiresNativeLink";
+ public const string NativeLinkerInputPath = "NativeLinkerInputPath";
// Debug symbols
public const string RelatedProperty = "related";
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/PrepareForReadyToRunCompilation.cs b/src/Tasks/Microsoft.NET.Build.Tasks/PrepareForReadyToRunCompilation.cs
index b990120d246e..423e5e6e1aea 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/PrepareForReadyToRunCompilation.cs
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/PrepareForReadyToRunCompilation.cs
@@ -20,6 +20,7 @@ public class PrepareForReadyToRunCompilation : TaskBase
public bool EmitSymbols { get; set; }
public bool ReadyToRunUseCrossgen2 { get; set; }
public bool Crossgen2Composite { get; set; }
+ public string Crossgen2ContainerFormat { get; set; }
[Required]
public string OutputPath { get; set; }
@@ -278,7 +279,21 @@ private void ProcessInputFileList(
var compositeR2RImageRelativePath = MainAssembly.GetMetadata(MetadataKeys.RelativePath);
compositeR2RImageRelativePath = Path.ChangeExtension(compositeR2RImageRelativePath, "r2r" + Path.GetExtension(compositeR2RImageRelativePath));
+
+ // For non-PE formats, we may need to do a post-processing step to get the final R2R image
+ // after running crossgen2. In this case, compositeR2RImageRelativePath is the intermediate file
+ // produced by crossgen2, and compositeR2RFinalImageRelativePath is the final file to be published
+ // by any post-crossgen2 linking steps and used at runtime.
+ var compositeR2RFinalImageRelativePath = compositeR2RImageRelativePath;
+
+ if (Crossgen2ContainerFormat == "macho")
+ {
+ compositeR2RImageRelativePath = Path.ChangeExtension(compositeR2RImageRelativePath, ".o");
+ compositeR2RFinalImageRelativePath = Path.ChangeExtension(compositeR2RImageRelativePath, ".dylib");
+ }
+
var compositeR2RImage = Path.Combine(OutputPath, compositeR2RImageRelativePath);
+ var compositeR2RImageFinal = Path.Combine(OutputPath, compositeR2RFinalImageRelativePath);
TaskItem r2rCompilationEntry = new(MainAssembly)
{
@@ -333,10 +348,17 @@ private void ProcessInputFileList(
// Publish it
TaskItem compositeR2RFileToPublish = new(MainAssembly)
{
- ItemSpec = compositeR2RImage
+ ItemSpec = compositeR2RImageFinal
};
compositeR2RFileToPublish.RemoveMetadata(MetadataKeys.OriginalItemSpec);
- compositeR2RFileToPublish.SetMetadata(MetadataKeys.RelativePath, compositeR2RImageRelativePath);
+ compositeR2RFileToPublish.SetMetadata(MetadataKeys.RelativePath, compositeR2RFinalImageRelativePath);
+
+ if (compositeR2RImageFinal != compositeR2RImage)
+ {
+ compositeR2RFileToPublish.SetMetadata(MetadataKeys.RequiresNativeLink, "true");
+ compositeR2RFileToPublish.SetMetadata(MetadataKeys.NativeLinkerInputPath, compositeR2RImage);
+ }
+
r2rFilesPublishList.Add(compositeR2RFileToPublish);
}
}
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/RunReadyToRunCompiler.cs b/src/Tasks/Microsoft.NET.Build.Tasks/RunReadyToRunCompiler.cs
index feca628b33d5..c5c7523099e7 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/RunReadyToRunCompiler.cs
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/RunReadyToRunCompiler.cs
@@ -24,6 +24,7 @@ public class RunReadyToRunCompiler : ToolTask
public bool UseCrossgen2 { get; set; }
public string Crossgen2ExtraCommandLineArgs { get; set; }
public ITaskItem[] Crossgen2PgoFiles { get; set; }
+ public string Crossgen2ContainerFormat { get; set; }
[Output]
public bool WarningsDetected { get; set; }
@@ -342,6 +343,11 @@ private string GenerateCrossgen2ResponseFile()
}
}
+ if (!string.IsNullOrEmpty(Crossgen2ContainerFormat))
+ {
+ result.AppendLine($"--obj-format:{Crossgen2ContainerFormat}");
+ }
+
if (!string.IsNullOrEmpty(Crossgen2ExtraCommandLineArgs))
{
foreach (string extraArg in Crossgen2ExtraCommandLineArgs.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets
index 60115b373731..8bd49dd1839b 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets
@@ -25,6 +25,14 @@ Copyright (c) .NET Foundation. All rights reserved.
true
1
false
+ pe
+
+ false
+ false
+ false
+ false
+ false
+ false
+ <_IgnoreLinkerWarnings Condition="'$(_XcodeVersion)' == '16'">true
+
+
+
+
+
+
+
+ @rpath/%(_ReadyToRunNativeObjectOutputs.Filename)%(_ReadyToRunNativeObjectOutputs.Extension)
+
+
+
+ <_MachLinkerArg Include="-Wl,-install_name,"$(SharedLibraryInstallName)"" />
+ <_MachLinkerArg Include="%(_ReadyToRunNativeObjectOutputs.NativeLinkerInputPath)" />
+ <_MachLinkerArg Include="-o %(_ReadyToRunNativeObjectOutputs.Identity)" />
+
+
+
+
+
+
+
+
+
+
+