Skip to content

Commit

Permalink
Improve crossgen2 help text (#55977)
Browse files Browse the repository at this point in the history
- Add handling of "-?" and no command line arguments.
- Print out default values for --targetos and --targetarch
- Describe behavior of response files
- Describe the behavior of the -- switch
- Describe in much greater detail the valid values for the --instruction-set switch

Fix #47486

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
davidwrighton and jkotas authored Jul 20, 2021
1 parent 16359b2 commit eb1e55e
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 28 deletions.
15 changes: 15 additions & 0 deletions src/coreclr/tools/Common/CommandLine/ArgumentSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public sealed partial class ArgumentSyntax
private readonly List<Argument> _options = new List<Argument>();
private readonly List<Argument> _parameters = new List<Argument>();

private readonly List<string> _extraHelpParagraphs = new List<string>();

private ArgumentParser _parser;
private ArgumentCommand _definedCommand;
private ArgumentCommand _activeCommand;
Expand Down Expand Up @@ -452,5 +454,18 @@ public string GetHelpText(int maxWidth)
{
return HelpTextGenerator.Generate(this, maxWidth);
}

public IReadOnlyList<string> ExtraHelpParagraphs
{
set
{
_extraHelpParagraphs.Clear();
_extraHelpParagraphs.AddRange(value);
}
get
{
return _extraHelpParagraphs.ToArray();
}
}
}
}
16 changes: 14 additions & 2 deletions src/coreclr/tools/Common/CommandLine/HelpTextGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ private struct HelpPage
public string ApplicationName;
public IEnumerable<string> SyntaxElements;
public IReadOnlyList<HelpRow> Rows;
public IReadOnlyList<string> ExtraParagraphs;
}

private struct HelpRow
Expand All @@ -47,6 +48,15 @@ private static void WriteHelpPage(this StringBuilder sb, HelpPage page, int maxW
sb.WriteRows(page.Rows, maxWidth);

sb.AppendLine();

if (page.ExtraParagraphs != null)
{
foreach (string text in page.ExtraParagraphs)
{
var words = SplitWords(text);
sb.WriteWordWrapped(words, 0, maxWidth);
}
}
}

private static void WriteUsage(this StringBuilder sb, string applicationName, IEnumerable<string> syntaxElements, int maxWidth)
Expand Down Expand Up @@ -115,7 +125,8 @@ private static HelpPage GetCommandListHelp(ArgumentSyntax argumentSyntax)
{
ApplicationName = argumentSyntax.ApplicationName,
SyntaxElements = GetGlobalSyntax(),
Rows = GetCommandRows(argumentSyntax).ToArray()
Rows = GetCommandRows(argumentSyntax).ToArray(),
ExtraParagraphs = argumentSyntax.ExtraHelpParagraphs
};
}

Expand All @@ -125,7 +136,8 @@ private static HelpPage GetCommandHelp(ArgumentSyntax argumentSyntax, ArgumentCo
{
ApplicationName = argumentSyntax.ApplicationName,
SyntaxElements = GetCommandSyntax(argumentSyntax, command),
Rows = GetArgumentRows(argumentSyntax, command).ToArray()
Rows = GetArgumentRows(argumentSyntax, command).ToArray(),
ExtraParagraphs = argumentSyntax.ExtraHelpParagraphs
};
}

Expand Down
71 changes: 71 additions & 0 deletions src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;

using Internal.CommandLine;
using Internal.TypeSystem;

namespace ILCompiler
{
Expand Down Expand Up @@ -88,6 +90,23 @@ public CommandLineOptions(string[] args)
Parallelism = Environment.ProcessorCount;
SingleMethodGenericArg = null;

bool forceHelp = false;
if (args.Length == 0)
{
forceHelp = true;
}

foreach (string arg in args)
{
if (arg == "-?")
forceHelp = true;
}

if (forceHelp)
{
args = new string[] {"--help"};
}

ArgumentSyntax argSyntax = ArgumentSyntax.Parse(args, syntax =>
{
syntax.ApplicationName = typeof(Program).Assembly.GetName().Name.ToString();
Expand Down Expand Up @@ -157,6 +176,58 @@ public CommandLineOptions(string[] args)

if (Help)
{
List<string> extraHelp = new List<string>();
extraHelp.Add(SR.OptionPassingHelp);
extraHelp.Add("");
extraHelp.Add(SR.DashDashHelp);
extraHelp.Add("");

string[] ValidArchitectures = new string[] {"arm", "armel", "arm64", "x86", "x64"};
string[] ValidOS = new string[] {"windows", "linux", "osx"};
TargetOS defaultOs;
TargetArchitecture defaultArch;
Program.ComputeDefaultOptions(out defaultOs, out defaultArch);

extraHelp.Add(String.Format(SR.SwitchWithDefaultHelp, "--targetos", String.Join("', '", ValidOS), defaultOs.ToString().ToLowerInvariant()));

extraHelp.Add("");

extraHelp.Add(String.Format(SR.SwitchWithDefaultHelp, "--targetarch", String.Join("', '", ValidArchitectures), defaultArch.ToString().ToLowerInvariant()));

extraHelp.Add("");

extraHelp.Add(SR.InstructionSetHelp);
foreach (string arch in ValidArchitectures)
{
StringBuilder archString = new StringBuilder();

archString.Append(arch);
archString.Append(": ");

TargetArchitecture targetArch = Program.GetTargetArchitectureFromArg(arch, out _);
bool first = true;
foreach (var instructionSet in Internal.JitInterface.InstructionSetFlags.ArchitectureToValidInstructionSets(targetArch))
{
// Only instruction sets with are specifiable should be printed to the help text
if (instructionSet.Specifiable)
{
if (first)
{
first = false;
}
else
{
archString.Append(", ");
}
archString.Append(instructionSet.Name);
}
}

extraHelp.Add(archString.ToString());
}

argSyntax.ExtraHelpParagraphs = extraHelp;

HelpText = argSyntax.GetHelpText();
}
}
Expand Down
60 changes: 35 additions & 25 deletions src/coreclr/tools/aot/crossgen2/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,36 +46,40 @@ private Program()
{
}

private void InitializeDefaultOptions()
public static void ComputeDefaultOptions(out TargetOS os, out TargetArchitecture arch)
{
// We could offer this as a command line option, but then we also need to
// load a different RyuJIT, so this is a future nice to have...
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
_targetOS = TargetOS.Windows;
os = TargetOS.Windows;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
_targetOS = TargetOS.Linux;
os = TargetOS.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
_targetOS = TargetOS.OSX;
os = TargetOS.OSX;
else
throw new NotImplementedException();

switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.X86:
_targetArchitecture = TargetArchitecture.X86;
arch = TargetArchitecture.X86;
break;
case Architecture.X64:
_targetArchitecture = TargetArchitecture.X64;
arch = TargetArchitecture.X64;
break;
case Architecture.Arm:
_targetArchitecture = TargetArchitecture.ARM;
arch = TargetArchitecture.ARM;
break;
case Architecture.Arm64:
_targetArchitecture = TargetArchitecture.ARM64;
arch = TargetArchitecture.ARM64;
break;
default:
throw new NotImplementedException();
}

}

private void InitializeDefaultOptions()
{
ComputeDefaultOptions(out _targetOS, out _targetArchitecture);
}

private void ProcessCommandLine(string[] args)
Expand Down Expand Up @@ -167,28 +171,34 @@ private void ProcessCommandLine(string[] args)

}

public static TargetArchitecture GetTargetArchitectureFromArg(string archArg, out bool armelAbi)
{
armelAbi = false;
if (archArg.Equals("x86", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.X86;
else if (archArg.Equals("x64", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.X64;
else if (archArg.Equals("arm", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.ARM;
else if (archArg.Equals("armel", StringComparison.OrdinalIgnoreCase))
{
armelAbi = true;
return TargetArchitecture.ARM;
}
else if (archArg.Equals("arm64", StringComparison.OrdinalIgnoreCase))
return TargetArchitecture.ARM64;
else
throw new CommandLineException(SR.TargetArchitectureUnsupported);
}

private void ConfigureTarget()
{
//
// Set target Architecture and OS
//
if (_commandLineOptions.TargetArch != null)
{
if (_commandLineOptions.TargetArch.Equals("x86", StringComparison.OrdinalIgnoreCase))
_targetArchitecture = TargetArchitecture.X86;
else if (_commandLineOptions.TargetArch.Equals("x64", StringComparison.OrdinalIgnoreCase))
_targetArchitecture = TargetArchitecture.X64;
else if (_commandLineOptions.TargetArch.Equals("arm", StringComparison.OrdinalIgnoreCase))
_targetArchitecture = TargetArchitecture.ARM;
else if (_commandLineOptions.TargetArch.Equals("armel", StringComparison.OrdinalIgnoreCase))
{
_targetArchitecture = TargetArchitecture.ARM;
_armelAbi = true;
}
else if (_commandLineOptions.TargetArch.Equals("arm64", StringComparison.OrdinalIgnoreCase))
_targetArchitecture = TargetArchitecture.ARM64;
else
throw new CommandLineException(SR.TargetArchitectureUnsupported);
_targetArchitecture = GetTargetArchitectureFromArg(_commandLineOptions.TargetArch, out _armelAbi);
}
if (_commandLineOptions.TargetOS != null)
{
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/tools/aot/crossgen2/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,16 @@
<data name="PerfMapFormatVersionOption" xml:space="preserve">
<value>Explicitly request a particular PerfMap format version</value>
</data>
</root>
<data name="OptionPassingHelp" xml:space="preserve">
<value>Options may be passed on the command line, or via response file. On the command line switch values may be specified by passing the option followed by a space followed by the value of the option, or by specifying a : between option and switch value. A response file is specified by passing the @ symbol before the response file name. In a response file all options must be specified on their own lines, and only the : syntax for switches is supported.</value>
</data>
<data name="DashDashHelp" xml:space="preserve">
<value>Use the '--' option to disambiguate between input files that have begin with -- and options. After a '--' option, all arguments are considered to be input files. If no input files begin with '--' then this option is not necessary.</value>
</data>
<data name="SwitchWithDefaultHelp" xml:space="preserve">
<value>Valid switches for {0} are: '{1}'. The default value is '{2}'.</value>
</data>
<data name="InstructionSetHelp" xml:space="preserve">
<value>The allowable values for the --instruction-set option are described in the table below. Each architecture has a different set of valid instruction sets, and multiple instruction sets may be specified by separating the instructions sets by a ','. For example 'avx2,bmi,lzcnt'</value>
</data>
</root>

0 comments on commit eb1e55e

Please sign in to comment.