Improve crossgen2 help text (#55977)
authorDavid Wrighton <davidwr@microsoft.com>
Tue, 20 Jul 2021 02:29:13 +0000 (19:29 -0700)
committerGitHub <noreply@github.com>
Tue, 20 Jul 2021 02:29:13 +0000 (19:29 -0700)
- 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>
src/coreclr/tools/Common/CommandLine/ArgumentSyntax.cs
src/coreclr/tools/Common/CommandLine/HelpTextGenerator.cs
src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs
src/coreclr/tools/aot/crossgen2/Program.cs
src/coreclr/tools/aot/crossgen2/Properties/Resources.resx

index e4da81c..4cea120 100644 (file)
@@ -14,6 +14,8 @@ namespace Internal.CommandLine
         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;
@@ -452,5 +454,18 @@ namespace Internal.CommandLine
         {
             return HelpTextGenerator.Generate(this, maxWidth);
         }
+
+        public IReadOnlyList<string> ExtraHelpParagraphs
+        {
+            set
+            {
+                _extraHelpParagraphs.Clear();
+                _extraHelpParagraphs.AddRange(value);
+            }
+            get
+            {
+                return _extraHelpParagraphs.ToArray();
+            }
+        }
     }
 }
index 372cf05..afe1f0a 100644 (file)
@@ -27,6 +27,7 @@ namespace Internal.CommandLine
             public string ApplicationName;
             public IEnumerable<string> SyntaxElements;
             public IReadOnlyList<HelpRow> Rows;
+            public IReadOnlyList<string> ExtraParagraphs;
         }
 
         private struct HelpRow
@@ -47,6 +48,15 @@ namespace Internal.CommandLine
             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)
@@ -115,7 +125,8 @@ namespace Internal.CommandLine
             {
                 ApplicationName = argumentSyntax.ApplicationName,
                 SyntaxElements = GetGlobalSyntax(),
-                Rows = GetCommandRows(argumentSyntax).ToArray()
+                Rows = GetCommandRows(argumentSyntax).ToArray(),
+                ExtraParagraphs = argumentSyntax.ExtraHelpParagraphs
             };
         }
 
@@ -125,7 +136,8 @@ namespace Internal.CommandLine
             {
                 ApplicationName = argumentSyntax.ApplicationName,
                 SyntaxElements = GetCommandSyntax(argumentSyntax, command),
-                Rows = GetArgumentRows(argumentSyntax, command).ToArray()
+                Rows = GetArgumentRows(argumentSyntax, command).ToArray(),
+                ExtraParagraphs = argumentSyntax.ExtraHelpParagraphs
             };
         }
 
index c91e615..8f832d1 100644 (file)
@@ -5,8 +5,10 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
+using System.Text;
 
 using Internal.CommandLine;
+using Internal.TypeSystem;
 
 namespace ILCompiler
 {
@@ -88,6 +90,23 @@ namespace ILCompiler
             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();
@@ -157,6 +176,58 @@ namespace ILCompiler
 
             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();
             }
         }
index aeeb9f5..22e7b32 100644 (file)
@@ -46,36 +46,40 @@ namespace ILCompiler
         {
         }
 
-        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)
@@ -167,6 +171,26 @@ namespace ILCompiler
 
         }
 
+        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()
         {
             //
@@ -174,21 +198,7 @@ namespace ILCompiler
             //
             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)
             {
index 56fbb93..ab668d1 100644 (file)
   <data name="PerfMapFormatVersionOption" xml:space="preserve">
     <value>Explicitly request a particular PerfMap format version</value>
   </data>
-</root>
\ No newline at end of file
+  <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>