Skip to content

Commit

Permalink
Add SDK support for rooting subsets of inputs in a composite image. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Oct 24, 2024
1 parent c267ab6 commit 35acbef
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public class PrepareForReadyToRunCompilation : TaskBase

public string[] PublishReadyToRunCompositeExclusions { get; set; }

// When specified, only these assemblies will be fully compiled into the composite image.
// All other input (non-reference) assemblies will only have code compiled for methods
// called by a method in a rooted assembly (possibly transitively).
public string[] PublishReadyToRunCompositeRoots { get; set; }

public ITaskItem CrossgenTool { get; set; }
public ITaskItem Crossgen2Tool { get; set; }

Expand All @@ -50,6 +55,9 @@ public class PrepareForReadyToRunCompilation : TaskBase
[Output]
public ITaskItem[] ReadyToRunCompositeBuildInput => _r2rCompositeInput.ToArray();

[Output]
public ITaskItem[] ReadyToRunCompositeUnrootedBuildInput => _r2rCompositeUnrootedInput.ToArray();

private bool _crossgen2IsVersion5;
private int _perfmapFormatVersion;

Expand All @@ -59,6 +67,7 @@ public class PrepareForReadyToRunCompilation : TaskBase
private List<ITaskItem> _r2rReferences = new();
private List<ITaskItem> _r2rCompositeReferences = new();
private List<ITaskItem> _r2rCompositeInput = new();
private List<ITaskItem> _r2rCompositeUnrootedInput = new();

private bool IsTargetWindows
{
Expand Down Expand Up @@ -108,7 +117,7 @@ protected override void ExecuteCore()
!string.IsNullOrEmpty(diaSymReaderPath) && File.Exists(diaSymReaderPath);

// Process input lists of files
ProcessInputFileList(Assemblies, _compileList, _symbolsCompileList, _r2rFiles, _r2rReferences, _r2rCompositeReferences, _r2rCompositeInput, hasValidDiaSymReaderLib);
ProcessInputFileList(Assemblies, _compileList, _symbolsCompileList, _r2rFiles, _r2rReferences, _r2rCompositeReferences, _r2rCompositeInput, _r2rCompositeUnrootedInput, hasValidDiaSymReaderLib);
}

private void ProcessInputFileList(
Expand All @@ -119,6 +128,7 @@ private void ProcessInputFileList(
List<ITaskItem> r2rReferenceList,
List<ITaskItem> r2rCompositeReferenceList,
List<ITaskItem> r2rCompositeInputList,
List<ITaskItem> r2rCompositeUnrootedInput,
bool hasValidDiaSymReaderLib)
{
if (inputFiles == null)
Expand All @@ -128,10 +138,11 @@ private void ProcessInputFileList(

var exclusionSet = ExcludeList == null || Crossgen2Composite ? null : new HashSet<string>(ExcludeList, StringComparer.OrdinalIgnoreCase);
var compositeExclusionSet = PublishReadyToRunCompositeExclusions == null || !Crossgen2Composite ? null : new HashSet<string>(PublishReadyToRunCompositeExclusions, StringComparer.OrdinalIgnoreCase);
var compositeRootSet = PublishReadyToRunCompositeRoots == null || !Crossgen2Composite ? null : new HashSet<string>(PublishReadyToRunCompositeRoots, StringComparer.OrdinalIgnoreCase);

foreach (var file in inputFiles)
{
var eligibility = GetInputFileEligibility(file, Crossgen2Composite, exclusionSet, compositeExclusionSet);
var eligibility = GetInputFileEligibility(file, Crossgen2Composite, exclusionSet, compositeExclusionSet, compositeRootSet);

if (eligibility.NoEligibility)
{
Expand Down Expand Up @@ -205,6 +216,10 @@ private void ProcessInputFileList(
r2rCompilationEntry.RemoveMetadata(MetadataKeys.OriginalItemSpec);
imageCompilationList.Add(r2rCompilationEntry);
}
else if (eligibility.CompileUnrootedIntoCompositeImage)
{
r2rCompositeUnrootedInput.Add(file);
}
else if (eligibility.CompileIntoCompositeImage)
{
r2rCompositeInputList.Add(file);
Expand Down Expand Up @@ -334,6 +349,7 @@ private enum EligibilityEnum
HideReferenceFromComposite = 2,
CompileSeparately = 4,
CompileIntoCompositeImage = 8,
CompileUnrootedIntoCompositeImage = 16,
}

private readonly EligibilityEnum _flags;
Expand All @@ -344,8 +360,9 @@ private enum EligibilityEnum
public bool IsReference => (_flags & EligibilityEnum.Reference) == EligibilityEnum.Reference;
public bool ReferenceHiddenFromCompositeBuild => (_flags & EligibilityEnum.HideReferenceFromComposite) == EligibilityEnum.HideReferenceFromComposite;
public bool CompileIntoCompositeImage => (_flags & EligibilityEnum.CompileIntoCompositeImage) == EligibilityEnum.CompileIntoCompositeImage;
public bool CompileUnrootedIntoCompositeImage => (_flags & EligibilityEnum.CompileUnrootedIntoCompositeImage) == EligibilityEnum.CompileUnrootedIntoCompositeImage;
public bool CompileSeparately => (_flags & EligibilityEnum.CompileSeparately) == EligibilityEnum.CompileSeparately;
public bool Compile => CompileIntoCompositeImage || CompileSeparately;
public bool Compile => CompileIntoCompositeImage || CompileUnrootedIntoCompositeImage || CompileSeparately;

private Eligibility(EligibilityEnum flags)
{
Expand All @@ -360,12 +377,14 @@ public static Eligibility CreateReferenceEligibility(bool hideFromCompositeBuild
return new Eligibility(EligibilityEnum.Reference);
}

public static Eligibility CreateCompileEligibility(bool doNotBuildIntoComposite)
public static Eligibility CreateCompileEligibility(bool doNotBuildIntoComposite, bool rootedInComposite)
{
if (doNotBuildIntoComposite)
return new Eligibility(EligibilityEnum.Reference | EligibilityEnum.HideReferenceFromComposite | EligibilityEnum.CompileSeparately);
else
else if (rootedInComposite)
return new Eligibility(EligibilityEnum.Reference | EligibilityEnum.CompileIntoCompositeImage);
else
return new Eligibility(EligibilityEnum.Reference | EligibilityEnum.CompileUnrootedIntoCompositeImage);
}
};

Expand All @@ -388,7 +407,7 @@ private static bool IsNonCompositeReadyToRunImage(PEReader peReader)
}
}

private static Eligibility GetInputFileEligibility(ITaskItem file, bool compositeCompile, HashSet<string> exclusionSet, HashSet<string> r2rCompositeExclusionSet)
private static Eligibility GetInputFileEligibility(ITaskItem file, bool compositeCompile, HashSet<string> exclusionSet, HashSet<string> r2rCompositeExclusionSet, HashSet<string> r2rCompositeRootSet)
{
// Check to see if this is a valid ILOnly image that we can compile
if (!file.ItemSpec.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) && !file.ItemSpec.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -423,6 +442,10 @@ private static Eligibility GetInputFileEligibility(ITaskItem file, bool composit
bool excludeFromR2R = (exclusionSet != null && exclusionSet.Contains(Path.GetFileName(file.ItemSpec)));
bool excludeFromComposite = (r2rCompositeExclusionSet != null && r2rCompositeExclusionSet.Contains(Path.GetFileName(file.ItemSpec))) || excludeFromR2R;

// Default to rooting all assemblies.
// If a root set is specified, only root if in the set.
bool rootedInComposite = (r2rCompositeRootSet == null || r2rCompositeRootSet.Contains(Path.GetFileName(file.ItemSpec)));

if ((pereader.PEHeaders.CorHeader.Flags & CorFlags.ILOnly) != CorFlags.ILOnly)
{
// This can happen due to C++/CLI binaries or due to previously R2R compiled binaries.
Expand Down Expand Up @@ -460,7 +483,7 @@ private static Eligibility GetInputFileEligibility(ITaskItem file, bool composit
return Eligibility.CreateReferenceEligibility(excludeFromComposite);
}

return Eligibility.CreateCompileEligibility(!compositeCompile || excludeFromComposite);
return Eligibility.CreateCompileEligibility(!compositeCompile || excludeFromComposite, rootedInComposite);
}
}
catch (BadImageFormatException)
Expand Down
9 changes: 9 additions & 0 deletions src/Tasks/Microsoft.NET.Build.Tasks/RunReadyToRunCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class RunReadyToRunCompiler : ToolTask
public ITaskItem[] ImplementationAssemblyReferences { get; set; }
public ITaskItem[] ReadyToRunCompositeBuildReferences { get; set; }
public ITaskItem[] ReadyToRunCompositeBuildInput { get; set; }
public ITaskItem[] ReadyToRunCompositeUnrootedBuildInput { get; set; }
public bool ShowCompilerWarnings { get; set; }
public bool UseCrossgen2 { get; set; }
public string Crossgen2ExtraCommandLineArgs { get; set; }
Expand Down Expand Up @@ -365,6 +366,14 @@ private string GenerateCrossgen2ResponseFile()
{
result.AppendLine(reference.ItemSpec);
}

if (ReadyToRunCompositeUnrootedBuildInput != null)
{
foreach (var unrooted in ReadyToRunCompositeUnrootedBuildInput)
{
result.AppendLine($"-u:\"{unrooted.ItemSpec}\"");
}
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ Copyright (c) .NET Foundation. All rights reserved.
IncludeSymbolsInSingleFile="$(IncludeSymbolsInSingleFile)"
ReadyToRunUseCrossgen2="$(PublishReadyToRunUseCrossgen2)"
Crossgen2Composite="$(PublishReadyToRunComposite)"
PublishReadyToRunCompositeExclusions="@(PublishReadyToRunCompositeExclusions)">
PublishReadyToRunCompositeExclusions="@(PublishReadyToRunCompositeExclusions)"
PublishReadyToRunCompositeRoots="@(PublishReadyToRunCompositeRoots)">

<Output TaskParameter="ReadyToRunCompileList" ItemName="_ReadyToRunCompileList" />
<Output TaskParameter="ReadyToRunSymbolsCompileList" ItemName="_ReadyToRunSymbolsCompileList" />
Expand All @@ -430,6 +431,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<Output TaskParameter="ReadyToRunAssembliesToReference" ItemName="_ReadyToRunAssembliesToReference" />
<Output TaskParameter="ReadyToRunCompositeBuildReferences" ItemName="_ReadyToRunCompositeBuildReferences" />
<Output TaskParameter="ReadyToRunCompositeBuildInput" ItemName="_ReadyToRunCompositeBuildInput" />
<Output TaskParameter="ReadyToRunCompositeUnrootedBuildInput" ItemName="_ReadyToRunCompositeUnrootedBuildInput" />

</PrepareForReadyToRunCompilation>
</Target>
Expand Down Expand Up @@ -472,7 +474,8 @@ Copyright (c) .NET Foundation. All rights reserved.
CompilationEntry="@(_ReadyToRunCompileList)"
ContinueOnError="ErrorAndContinue"
ReadyToRunCompositeBuildReferences="@(_ReadyToRunCompositeBuildReferences)"
ReadyToRunCompositeBuildInput="@(_ReadyToRunCompositeBuildInput)">
ReadyToRunCompositeBuildInput="@(_ReadyToRunCompositeBuildInput)"
ReadyToRunCompositeUnrootedBuildInput="@(_ReadyToRunCompositeUnrootedBuildInput)">
<Output TaskParameter="ExitCode" PropertyName="_ReadyToRunCompilerExitCode" />
<Output TaskParameter="WarningsDetected" PropertyName="_ReadyToRunWarningsDetected" />
</RunReadyToRunCompiler>
Expand Down

2 comments on commit 35acbef

@am11
Copy link
Member

@am11 am11 commented on 35acbef Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkoritzinsky, do we need to apply these changes in https://github.com/dotnet/runtime/tree/d450d9c9ee4dd5a98812981dac06d2f92bdb8213/src/tasks/Crossgen2Tasks or is that copy a deadcode? Maybe we can just delete it if it's the latter. :)

@jkoritzinsky
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should. That code is used when we introduce a new feature into crossgen2 that we want to consume within the runtime repo before an SDK flow. It's quite out of date as we needed that capability once or twice when onboarding Crossgen2.

Please sign in to comment.