Skip to content

Commit

Permalink
Adapt System.CommandLine (v2) in more places (#72082)
Browse files Browse the repository at this point in the history
* Switch ilc to use System.CommandLine

* Switch cg2 to use System.CommandLine

* Fix release build

* Fix test build

* ilc: --insructionset, crossgen2: --instruction-set 🥲

* Fix a couple of defaults

* Fix repro package arguments for cg2

* ilc: rename --instructionset to --instruction-set

* Remove 'Microsoft (R)' from tools' banner

* Merge conflict typo fix

* Add -v alias for version (to match old behavior)
  • Loading branch information
am11 committed Sep 23, 2022
1 parent 0acd508 commit d0559e6
Show file tree
Hide file tree
Showing 12 changed files with 1,370 additions and 1,196 deletions.
291 changes: 291 additions & 0 deletions src/coreclr/tools/Common/CommandLineHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.CommandLine.Binding;
using System.CommandLine.Parsing;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;

using Internal.TypeSystem;

namespace System.CommandLine
{
internal sealed class CommandLineException : Exception
{
public CommandLineException(string message) : base(message) { }
}

//
// Helpers for command line processing
//
internal static class Helpers
{
public const string DefaultSystemModule = "System.Private.CoreLib";

public static Dictionary<string, string> BuildPathDictionay(IReadOnlyList<Token> tokens, bool strict)
{
Dictionary<string, string> dictionary = new(StringComparer.OrdinalIgnoreCase);

foreach (Token token in tokens)
{
AppendExpandedPaths(dictionary, token.Value, strict);
}

return dictionary;
}

public static TargetOS GetTargetOS(string token)
{
if(string.IsNullOrEmpty(token))
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return TargetOS.Windows;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return TargetOS.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return TargetOS.OSX;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
return TargetOS.FreeBSD;

throw new NotImplementedException();
}

if (token.Equals("windows", StringComparison.OrdinalIgnoreCase))
return TargetOS.Windows;
else if (token.Equals("linux", StringComparison.OrdinalIgnoreCase))
return TargetOS.Linux;
else if (token.Equals("osx", StringComparison.OrdinalIgnoreCase))
return TargetOS.OSX;

throw new CommandLineException($"Target OS '{token}' is not supported");
}

public static TargetArchitecture GetTargetArchitecture(string token)
{
if(string.IsNullOrEmpty(token))
{
return RuntimeInformation.ProcessArchitecture switch
{
Architecture.X86 => TargetArchitecture.X86,
Architecture.X64 => TargetArchitecture.X64,
Architecture.Arm => TargetArchitecture.ARM,
Architecture.Arm64 => TargetArchitecture.ARM64,
Architecture.LoongArch64 => TargetArchitecture.LoongArch64,
_ => throw new NotImplementedException()
};
}

if (token.Equals("x86", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.X86;
else if (token.Equals("x64", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.X64;
else if (token.Equals("arm", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.ARM;
else if (token.Equals("arm64", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.ARM64;
else if (token.Equals("loongarch64", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.LoongArch64;

throw new CommandLineException($"Target architecture '{token}' is not supported");
}

public static void MakeReproPackage(string makeReproPath, string outputFilePath, string[] args, ParseResult res, IEnumerable<string> inputOptions)
{
Directory.CreateDirectory(makeReproPath);

List<string> details = new List<string>();
details.Add("Tool version");
try
{
details.Add(Environment.GetCommandLineArgs()[0]);
}
catch { }
try
{
details.Add(System.Diagnostics.FileVersionInfo.GetVersionInfo(Environment.GetCommandLineArgs()[0]).ToString());
}
catch { }

details.Add("------------------------");
details.Add("Actual Command Line Args");
details.Add("------------------------");
details.AddRange(args);
foreach (string arg in args)
{
if (arg.StartsWith('@'))
{
string rspFileName = arg.Substring(1);
details.Add("------------------------");
details.Add(rspFileName);
details.Add("------------------------");
try
{
details.AddRange(File.ReadAllLines(rspFileName));
}
catch { }
}
}

HashCode hashCodeOfArgs = default;
foreach (string s in details)
hashCodeOfArgs.Add(s);

string zipFileName = ((uint)hashCodeOfArgs.ToHashCode()).ToString();

if (outputFilePath != null)
zipFileName = zipFileName + "_" + Path.GetFileName(outputFilePath);

zipFileName = Path.Combine(makeReproPath, Path.ChangeExtension(zipFileName, ".zip"));

Console.WriteLine($"Creating {zipFileName}");
using (var archive = ZipFile.Open(zipFileName, ZipArchiveMode.Create))
{
ZipArchiveEntry commandEntry = archive.CreateEntry("command.txt");
using (StreamWriter writer = new StreamWriter(commandEntry.Open()))
{
foreach (string s in details)
writer.WriteLine(s);
}

HashSet<string> inputOptionNames = new HashSet<string>(inputOptions);
Dictionary<string, string> inputToReproPackageFileName = new();

List<string> rspFile = new List<string>();
foreach (var option in res.CommandResult.Command.Options)
{
if (!res.HasOption(option) || option.Name == "make-repro-path")
{
continue;
}

IValueDescriptor descriptor = option;
object val = res.CommandResult.GetValueForOption(option);
if (val is not null && !(descriptor.HasDefaultValue && descriptor.GetDefaultValue().Equals(val)))
{
if (val is IEnumerable<string> values)
{
if (inputOptionNames.Contains(option.Name))
{
Dictionary<string, string> dictionary = new();
foreach (string optInList in values)
{
Helpers.AppendExpandedPaths(dictionary, optInList, false);
}
foreach (string inputFile in dictionary.Values)
{
rspFile.Add($"--{option.Name}:{ConvertFromInputPathToReproPackagePath(inputFile)}");
}
}
else
{
foreach (string optInList in values)
{
rspFile.Add($"--{option.Name}:{optInList}");
}
}
}
else
{
rspFile.Add($"--{option.Name}:{val}");
}
}
}

foreach (var argument in res.CommandResult.Command.Arguments)
{
object val = res.CommandResult.GetValueForArgument(argument);
if (val is IEnumerable<string> values)
{
foreach (string optInList in values)
{
rspFile.Add($"{ConvertFromInputPathToReproPackagePath((string)optInList)}");
}
}
else
{
rspFile.Add($"{ConvertFromInputPathToReproPackagePath((string)val)}");
}
}

ZipArchiveEntry rspEntry = archive.CreateEntry("repro.rsp");
using (StreamWriter writer = new StreamWriter(rspEntry.Open()))
{
foreach (string s in rspFile)
writer.WriteLine(s);
}

string ConvertFromInputPathToReproPackagePath(string inputPath)
{
if (inputToReproPackageFileName.TryGetValue(inputPath, out string reproPackagePath))
{
return reproPackagePath;
}

try
{
string inputFileDir = inputToReproPackageFileName.Count.ToString();
reproPackagePath = Path.Combine(inputFileDir, Path.GetFileName(inputPath));
archive.CreateEntryFromFile(inputPath, reproPackagePath);
inputToReproPackageFileName.Add(inputPath, reproPackagePath);

return reproPackagePath;
}
catch
{
return inputPath;
}
}
}
}

// Helper to create a collection of paths unique in their simple names.
private static void AppendExpandedPaths(Dictionary<string, string> dictionary, string pattern, bool strict)
{
bool empty = true;
string directoryName = Path.GetDirectoryName(pattern);
string searchPattern = Path.GetFileName(pattern);

if (directoryName == "")
directoryName = ".";

if (Directory.Exists(directoryName))
{
foreach (string fileName in Directory.EnumerateFiles(directoryName, searchPattern))
{
string fullFileName = Path.GetFullPath(fileName);

string simpleName = Path.GetFileNameWithoutExtension(fileName);

if (dictionary.ContainsKey(simpleName))
{
if (strict)
{
throw new CommandLineException("Multiple input files matching same simple name " +
fullFileName + " " + dictionary[simpleName]);
}
}
else
{
dictionary.Add(simpleName, fullFileName);
}

empty = false;
}
}

if (empty)
{
if (strict)
{
throw new CommandLineException("No files matching " + pattern);
}
else
{
Console.WriteLine("Warning: No files matching " + pattern);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void TestDependencyGraphInvariants(EcmaMethod method)
new FullyBlockedMetadataBlockingPolicy(), new FullyBlockedManifestResourceBlockingPolicy(),
null, new NoStackTraceEmissionPolicy(), new NoDynamicInvokeThunkGenerationPolicy(),
new ILLink.Shared.TrimAnalysis.FlowAnnotations(Logger.Null, ilProvider, compilerGeneratedState), UsageBasedMetadataGenerationOptions.None,
Logger.Null, Array.Empty<KeyValuePair<string, bool>>(), Array.Empty<string>(), Array.Empty<string>());
Logger.Null, Array.Empty<KeyValuePair<string, bool>>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>());

CompilationBuilder builder = new RyuJitCompilationBuilder(context, compilationGroup)
.UseILProvider(ilProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public UsageBasedMetadataManager(
Logger logger,
IEnumerable<KeyValuePair<string, bool>> featureSwitchValues,
IEnumerable<string> rootEntireAssembliesModules,
IEnumerable<string> additionalRootedAssemblies,
IEnumerable<string> trimmedAssemblies)
: base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy)
{
Expand All @@ -92,6 +93,7 @@ public UsageBasedMetadataManager(
FeatureSwitches = new Dictionary<string, bool>(featureSwitchValues);

_rootEntireAssembliesModules = new HashSet<string>(rootEntireAssembliesModules);
_rootEntireAssembliesModules.UnionWith(additionalRootedAssemblies);
_trimmedAssemblies = new HashSet<string>(trimmedAssemblies);
}

Expand Down
21 changes: 2 additions & 19 deletions src/coreclr/tools/aot/ILCompiler/ILCompiler.props
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,11 @@
</ItemGroup>

<ItemGroup>
<Compile Include="..\..\Common\CommandLine\Argument.cs" />
<Compile Include="..\..\Common\CommandLine\Argument_1.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentCommand.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentCommand_1.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentLexer.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentList_1.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentParser.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentSyntax.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentSyntax_Definers.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentSyntaxException.cs" />
<Compile Include="..\..\Common\CommandLine\ArgumentToken.cs" />
<Compile Include="..\..\Common\CommandLine\CommandLineException.cs" />
<Compile Include="..\..\Common\CommandLine\CommandLineHelpers.cs" />
<Compile Include="..\..\Common\CommandLine\Enumerable.cs" />
<Compile Include="..\..\Common\CommandLine\HelpTextGenerator.cs" />
<Compile Include="..\..\Common\CommandLineHelpers.cs" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="..\..\Common\CommandLine\Resources\Strings.resx">
<GenerateSource>true</GenerateSource>
<ClassName>Internal.CommandLine.Strings</ClassName>
</EmbeddedResource>
<PackageReference Include="System.CommandLine" Version="$(SystemCommandLineVersion)" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit d0559e6

Please sign in to comment.