Switch Crossgen2 over to the new command-line parser (dotnet/coreclr#27489)
authorTomáš Rylek <trylek@microsoft.com>
Mon, 28 Oct 2019 15:11:49 +0000 (08:11 -0700)
committerGitHub <noreply@github.com>
Mon, 28 Oct 2019 15:11:49 +0000 (08:11 -0700)
With this change, Crossgen2 passes basic validation. If possible,
I would love to be able to merge this in ASAP as it's of paramount
importance for our repo consolidation efforts. I'll be happy to
follow up cleaning this change as necessary.

1) Update to a newer version of the System.CommandLine.Experimental
package enabling more general binding syntax needed for unambiguous
binding of multi-value arguments vs. options.

2) Explicitly specify arity for multi-value options as for whatever
reason the default maximum is 255 (lower than the number of reference
assemblies in Core_Root, for instance).

3) Reference paths cannot be bound to FileInfo[] as their syntax
supports wildcards.

Thanks

Tomas

Commit migrated from https://github.com/dotnet/coreclr/commit/627fb420a81ba83b711ca1b6c9db2eb8c4660e42

src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs
src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/crossgen2/Program.cs
src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj

index 6405bba..de83bb9 100644 (file)
@@ -46,7 +46,7 @@ namespace ILCompiler
         {
             var builder = new ArrayBuilder<KeyValuePair<string, string>>();
 
-            foreach (string param in options)
+            foreach (string param in options ?? Array.Empty<string>())
             {
                 int indexOfEquals = param.IndexOf('=');
 
diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs b/src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs
new file mode 100644 (file)
index 0000000..c943984
--- /dev/null
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.CommandLine;
+using System.IO;
+
+namespace ILCompiler
+{
+    public class CommandLineOptions
+    {
+        public FileInfo[] InputFilePaths { get; set; }
+        public string[] Reference { get; set; }
+        public FileInfo OutputFilePath { get; set; }
+        public bool Optimize { get; set; }
+        public bool OptimizeSpace { get; set; }
+        public bool OptimizeTime { get; set; }
+        public bool InputBubble { get; set; }
+        public bool CompileBubbleGenerics { get; set; }
+        public bool Verbose { get; set; }
+
+        public FileInfo DgmlLogFileName { get; set; }
+        public bool GenerateFullDgmlLog { get; set; }
+
+        public string TargetArch { get; set; }
+        public string TargetOS { get; set; }
+        public string JitPath { get; set; }
+        public string SystemModule { get; set; }
+        public bool WaitForDebugger { get; set; }
+        public bool Tuning { get; set; }
+        public bool Partial { get; set; }
+        public bool Resilient { get; set; }
+
+        public string SingleMethodTypeName { get; set; }
+        public string SingleMethodName { get; set; }
+        public string[] SingleMethodGenericArgs { get; set; }
+
+        public string[] CodegenOptions { get; set; }
+
+        public static Command RootCommand()
+        {
+            // For some reason, arity caps at 255 by default
+            ArgumentArity arbitraryArity = new ArgumentArity(0, 100000);
+
+            return new Command("Crossgen2Compilation")
+            {
+                new Argument<FileInfo[]>() 
+                { 
+                    Name = "input-file-paths", 
+                    Description = "Input file(s) to compile",
+                    Arity = arbitraryArity,
+                },
+                new Option(new[] { "--reference", "-r" }, "Reference file(s) for compilation")
+                { 
+                    Argument = new Argument<string[]>() 
+                    { 
+                        Arity = arbitraryArity
+                    } 
+                },
+                new Option(new[] { "--outputfilepath", "--out", "-o" }, "Output file path")
+                {
+                    Argument = new Argument<FileInfo>()
+                },
+                new Option(new[] { "--optimize", "-O" }, "Enable optimizations") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--optimize-space", "--Os" }, "Enable optimizations, favor code space") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--optimize-time", "--Ot" }, "Enable optimizations, favor code speed"),
+                new Option(new[] { "--inputbubble" }, "True when the entire input forms a version bubble (default = per-assembly bubble)"),
+                new Option(new[] { "--tuning" }, "Generate IBC tuning image") 
+                {
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--partial" }, "Generate partial image driven by profile") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--compilebubblegenerics" }, "Compile instantiations from reference modules used in the current module") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--dgml-log-file-name", "--dmgllog" }, "Save result of dependency analysis as DGML") 
+                { 
+                    Argument = new Argument<FileInfo>() 
+                },
+                new Option(new[] { "--generate-full-dmgl-log", "--fulllog" }, "Save detailed log of dependency analysis") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--verbose" }, "Enable verbose logging") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--systemmodule" }, "System module name (default: System.Private.CoreLib)") 
+                { 
+                    Argument = new Argument<string>() 
+                },
+                new Option(new[] { "--waitfordebugger" }, "Pause to give opportunity to attach debugger") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--codegen-options", "--codegenopt" }, "Define a codegen option") 
+                { 
+                    Argument = new Argument<string[]>()
+                    {
+                        Arity = arbitraryArity
+                    }
+                },
+                new Option(new[] { "--resilient" }, "Disable behavior where unexpected compilation failures cause overall compilation failure") 
+                { 
+                    Argument = new Argument<bool>() 
+                },
+                new Option(new[] { "--targetarch" }, "Target architecture for cross compilation") 
+                { 
+                    Argument = new Argument<string>() 
+                },
+                new Option(new[] { "--targetos" }, "Target OS for cross compilation") 
+                { 
+                    Argument = new Argument<string>() 
+                },
+                new Option(new[] { "--jitpath" }, "Path to JIT compiler library") 
+                { 
+                    Argument =  new Argument<string>() 
+                },
+                new Option(new[] { "--singlemethodtypename" }, "Single method compilation: name of the owning type") 
+                { 
+                    Argument = new Argument<string>() 
+                },
+                new Option(new[] { "--singlemethodname" }, "Single method compilation: generic arguments to the method") 
+                { 
+                    Argument = new Argument<string>() 
+                },
+                new Option(new[] { "--singlemethodgenericarg" }, "Single method compilation: generic arguments to the method") 
+                { 
+                    // We don't need to override arity here as 255 is the maximum number of generic arguments
+                    Argument = new Argument<string[]>()
+                },
+            };
+        }
+    }
+}
index ace2382..4979d23 100644 (file)
@@ -4,15 +4,19 @@
 
 using System;
 using System.Collections.Generic;
-using System.Reflection;
 using System.CommandLine;
+using System.CommandLine.Invocation;
+using System.Reflection;
 using System.Runtime.InteropServices;
+using System.Threading.Tasks;
 
 using Internal.IL;
 using Internal.TypeSystem;
 using Internal.TypeSystem.Ecma;
 
 using Internal.CommandLine;
+using System.Linq;
+using System.IO;
 
 namespace ILCompiler
 {
@@ -20,38 +24,16 @@ namespace ILCompiler
     {
         private const string DefaultSystemModule = "System.Private.CoreLib";
 
+        private CommandLineOptions _commandLineOptions;
+        public TargetOS _targetOS;
+        public TargetArchitecture _targetArchitecture;
+        public OptimizationMode _optimizationMode;
         private Dictionary<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
         private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
-        private string _outputFilePath;
-        private bool _isInputVersionBubble;
-        private bool _includeGenericsFromVersionBubble;
-        private bool _isVerbose;
-
-        private string _dgmlLogFileName;
-        private bool _generateFullDgmlLog;
-
-        private TargetArchitecture _targetArchitecture;
-        private string _targetArchitectureStr;
-        private TargetOS _targetOS;
-        private string _targetOSStr;
-        private string _jitPath;
-        private OptimizationMode _optimizationMode;
-        private string _systemModuleName = DefaultSystemModule;
-        private bool _tuning;
-        private bool _partial;
-        private bool _resilient;
-
-        private string _singleMethodTypeName;
-        private string _singleMethodName;
-        private IReadOnlyList<string> _singleMethodGenericArgs;
-
-        private IReadOnlyList<string> _codegenOptions = Array.Empty<string>();
-
-        private bool _help;
-
-        private Program()
+        private Program(CommandLineOptions commandLineOptions)
         {
+            _commandLineOptions = commandLineOptions;
         }
 
         private void Help(string helpText)
@@ -102,128 +84,78 @@ namespace ILCompiler
                 _targetArchitecture = TargetArchitecture.X64;
         }
 
-        private ArgumentSyntax ParseCommandLine(string[] args)
+        private void ProcessCommandLine()
         {
-            IReadOnlyList<string> inputFiles = Array.Empty<string>();
-            IReadOnlyList<string> referenceFiles = Array.Empty<string>();
-
-            bool optimize = false;
-            bool optimizeSpace = false;
-            bool optimizeTime = false;
-
-            bool waitForDebugger = false;
             AssemblyName name = typeof(Program).GetTypeInfo().Assembly.GetName();
-            ArgumentSyntax argSyntax = ArgumentSyntax.Parse(args, syntax =>
-            {
-                syntax.ApplicationName = name.Name.ToString();
-
-                // HandleHelp writes to error, fails fast with crash dialog and lacks custom formatting.
-                syntax.HandleHelp = false;
-                syntax.HandleErrors = true;
-
-                syntax.DefineOption("h|help", ref _help, "Help message for ILC");
-                syntax.DefineOptionList("r|reference", ref referenceFiles, "Reference file(s) for compilation");
-                syntax.DefineOption("o|out", ref _outputFilePath, "Output file path");
-                syntax.DefineOption("O", ref optimize, "Enable optimizations");
-                syntax.DefineOption("Os", ref optimizeSpace, "Enable optimizations, favor code space");
-                syntax.DefineOption("Ot", ref optimizeTime, "Enable optimizations, favor code speed");
-                syntax.DefineOption("inputbubble", ref _isInputVersionBubble, "True when the entire input forms a version bubble (default = per-assembly bubble)");
-                syntax.DefineOption("tuning", ref _tuning, "Generate IBC tuning image");
-                syntax.DefineOption("partial", ref _partial, "Generate partial image driven by profile");
-                syntax.DefineOption("compilebubblegenerics", ref _includeGenericsFromVersionBubble, "Compile instantiations from reference modules used in the current module");
-                syntax.DefineOption("dgmllog", ref _dgmlLogFileName, "Save result of dependency analysis as DGML");
-                syntax.DefineOption("fulllog", ref _generateFullDgmlLog, "Save detailed log of dependency analysis");
-                syntax.DefineOption("verbose", ref _isVerbose, "Enable verbose logging");
-                syntax.DefineOption("systemmodule", ref _systemModuleName, "System module name (default: System.Private.CoreLib)");
-                syntax.DefineOption("waitfordebugger", ref waitForDebugger, "Pause to give opportunity to attach debugger");
-                syntax.DefineOptionList("codegenopt", ref _codegenOptions, "Define a codegen option");
-                syntax.DefineOption("resilient", ref _resilient, "Disable behavior where unexpected compilation failures cause overall compilation failure");
-
-                syntax.DefineOption("targetarch", ref _targetArchitectureStr, "Target architecture for cross compilation");
-                syntax.DefineOption("targetos", ref _targetOSStr, "Target OS for cross compilation");
-                syntax.DefineOption("jitpath", ref _jitPath, "Path to JIT compiler library");
-
-                syntax.DefineOption("singlemethodtypename", ref _singleMethodTypeName, "Single method compilation: name of the owning type");
-                syntax.DefineOption("singlemethodname", ref _singleMethodName, "Single method compilation: name of the method");
-                syntax.DefineOptionList("singlemethodgenericarg", ref _singleMethodGenericArgs, "Single method compilation: generic arguments to the method");
-
-                syntax.DefineParameterList("in", ref inputFiles, "Input file(s) to compile");
-            });
-            if (waitForDebugger)
+
+            if (_commandLineOptions.WaitForDebugger)
             {
                 Console.WriteLine("Waiting for debugger to attach. Press ENTER to continue");
                 Console.ReadLine();
             }
 
-            if (_includeGenericsFromVersionBubble)
+            if (_commandLineOptions.CompileBubbleGenerics)
             {
-                if (!_isInputVersionBubble)
+                if (!_commandLineOptions.InputBubble)
                 {
                     Console.WriteLine("Warning: ignoring --compilebubblegenerics because --inputbubble was not specified");
-                    _includeGenericsFromVersionBubble = false;
+                    _commandLineOptions.CompileBubbleGenerics = false;
                 }
             }
 
             _optimizationMode = OptimizationMode.None;
-            if (optimizeSpace)
+            if (_commandLineOptions.OptimizeSpace)
             {
-                if (optimizeTime)
+                if (_commandLineOptions.OptimizeTime)
                     Console.WriteLine("Warning: overriding -Ot with -Os");
                 _optimizationMode = OptimizationMode.PreferSize;
             }
-            else if (optimizeTime)
+            else if (_commandLineOptions.OptimizeTime)
                 _optimizationMode = OptimizationMode.PreferSpeed;
-            else if (optimize)
+            else if (_commandLineOptions.Optimize)
                 _optimizationMode = OptimizationMode.Blended;
 
-            foreach (var input in inputFiles)
-                Helpers.AppendExpandedPaths(_inputFilePaths, input, true);
+            foreach (var input in _commandLineOptions.InputFilePaths ?? Enumerable.Empty<FileInfo>())
+                Helpers.AppendExpandedPaths(_inputFilePaths, input.FullName, true);
 
-            foreach (var reference in referenceFiles)
+            foreach (var reference in _commandLineOptions.Reference ?? Enumerable.Empty<string>())
                 Helpers.AppendExpandedPaths(_referenceFilePaths, reference, false);
-
-            return argSyntax;
         }
 
-        private int Run(string[] args)
+        private int Run()
         {
             InitializeDefaultOptions();
 
-            ArgumentSyntax syntax = ParseCommandLine(args);
-            if (_help)
-            {
-                Help(syntax.GetHelpText());
-                return 1;
-            }
+            ProcessCommandLine();
 
-            if (_outputFilePath == null)
+            if (_commandLineOptions.OutputFilePath == null)
                 throw new CommandLineException("Output filename must be specified (/out <file>)");
 
             //
             // Set target Architecture and OS
             //
-            if (_targetArchitectureStr != null)
+            if (_commandLineOptions.TargetArch != null)
             {
-                if (_targetArchitectureStr.Equals("x86", StringComparison.OrdinalIgnoreCase))
+                if (_commandLineOptions.TargetArch.Equals("x86", StringComparison.OrdinalIgnoreCase))
                     _targetArchitecture = TargetArchitecture.X86;
-                else if (_targetArchitectureStr.Equals("x64", StringComparison.OrdinalIgnoreCase))
+                else if (_commandLineOptions.TargetArch.Equals("x64", StringComparison.OrdinalIgnoreCase))
                     _targetArchitecture = TargetArchitecture.X64;
-                else if (_targetArchitectureStr.Equals("arm", StringComparison.OrdinalIgnoreCase))
+                else if (_commandLineOptions.TargetArch.Equals("arm", StringComparison.OrdinalIgnoreCase))
                     _targetArchitecture = TargetArchitecture.ARM;
-                else if (_targetArchitectureStr.Equals("armel", StringComparison.OrdinalIgnoreCase))
+                else if (_commandLineOptions.TargetArch.Equals("armel", StringComparison.OrdinalIgnoreCase))
                     _targetArchitecture = TargetArchitecture.ARM;
-                else if (_targetArchitectureStr.Equals("arm64", StringComparison.OrdinalIgnoreCase))
+                else if (_commandLineOptions.TargetArch.Equals("arm64", StringComparison.OrdinalIgnoreCase))
                     _targetArchitecture = TargetArchitecture.ARM64;
                 else
                     throw new CommandLineException("Target architecture is not supported");
             }
-            if (_targetOSStr != null)
+            if (_commandLineOptions.TargetOS != null)
             {
-                if (_targetOSStr.Equals("windows", StringComparison.OrdinalIgnoreCase))
+                if (_commandLineOptions.TargetOS.Equals("windows", StringComparison.OrdinalIgnoreCase))
                     _targetOS = TargetOS.Windows;
-                else if (_targetOSStr.Equals("linux", StringComparison.OrdinalIgnoreCase))
+                else if (_commandLineOptions.TargetOS.Equals("linux", StringComparison.OrdinalIgnoreCase))
                     _targetOS = TargetOS.Linux;
-                else if (_targetOSStr.Equals("osx", StringComparison.OrdinalIgnoreCase))
+                else if (_commandLineOptions.TargetOS.Equals("osx", StringComparison.OrdinalIgnoreCase))
                     _targetOS = TargetOS.OSX;
                 else
                     throw new CommandLineException("Target OS is not supported");
@@ -269,7 +201,8 @@ namespace ILCompiler
                     typeSystemContext.InputFilePaths = inputFilePaths;
                     typeSystemContext.ReferenceFilePaths = _referenceFilePaths;
 
-                    typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(_systemModuleName));
+                    string systemModuleName = _commandLineOptions.SystemModule ?? DefaultSystemModule;
+                    typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(systemModuleName));
 
                     if (typeSystemContext.InputFilePaths.Count == 0)
                         throw new CommandLineException("No input files specified");
@@ -281,7 +214,7 @@ namespace ILCompiler
                     // Single method mode?
                     MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(typeSystemContext);
 
-                    var logger = new Logger(Console.Out, _isVerbose);
+                    var logger = new Logger(Console.Out, _commandLineOptions.Verbose);
 
                     List<ModuleDesc> referenceableModules = new List<ModuleDesc>();
                     foreach (var inputFile in inputFilePaths)
@@ -336,7 +269,7 @@ namespace ILCompiler
                             compilationRoots.Add(new ReadyToRunRootProvider(module, profileDataManager));
                             inputModules.Add(module);
 
-                            if (!_isInputVersionBubble)
+                            if (!_commandLineOptions.InputBubble)
                             {
                                 break;
                             }
@@ -344,7 +277,7 @@ namespace ILCompiler
 
 
                         List<ModuleDesc> versionBubbleModules = new List<ModuleDesc>();
-                        if (_isInputVersionBubble)
+                        if (_commandLineOptions.InputBubble)
                         {
                             // In large version bubble mode add reference paths to the compilation group
                             foreach (string referenceFile in _referenceFilePaths.Values)
@@ -364,8 +297,8 @@ namespace ILCompiler
                         }
 
                         compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup(
-                            typeSystemContext, inputModules, versionBubbleModules, _includeGenericsFromVersionBubble,
-                            _partial ? profileDataManager : null);
+                            typeSystemContext, inputModules, versionBubbleModules, _commandLineOptions.CompileBubbleGenerics,
+                            _commandLineOptions.Partial ? profileDataManager : null);
                     }
 
                     //
@@ -379,21 +312,21 @@ namespace ILCompiler
                         break;
                     }
                     CompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(typeSystemContext, compilationGroup, inputFilePath,
-                        ibcTuning: _tuning,
-                        resilient: _resilient);
+                        ibcTuning: _commandLineOptions.Tuning,
+                        resilient: _commandLineOptions.Resilient);
 
                     string compilationUnitPrefix = "";
                     builder.UseCompilationUnitPrefix(compilationUnitPrefix);
 
                     ILProvider ilProvider = new ReadyToRunILProvider();
 
-                    DependencyTrackingLevel trackingLevel = _dgmlLogFileName == null ?
-                        DependencyTrackingLevel.None : (_generateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
+                    DependencyTrackingLevel trackingLevel = _commandLineOptions.DgmlLogFileName == null ?
+                        DependencyTrackingLevel.None : (_commandLineOptions.GenerateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
 
                     builder
                         .UseILProvider(ilProvider)
-                        .UseJitPath(_jitPath)
-                        .UseBackendOptions(_codegenOptions)
+                        .UseJitPath(_commandLineOptions.JitPath)
+                        .UseBackendOptions(_commandLineOptions.CodegenOptions)
                         .UseLogger(logger)
                         .UseDependencyTracking(trackingLevel)
                         .UseCompilationRoots(compilationRoots)
@@ -402,10 +335,10 @@ namespace ILCompiler
                     compilation = builder.ToCompilation();
 
                 }
-                compilation.Compile(_outputFilePath);
+                compilation.Compile(_commandLineOptions.OutputFilePath.FullName);
 
-                if (_dgmlLogFileName != null)
-                    compilation.WriteDependencyLog(_dgmlLogFileName);
+                if (_commandLineOptions.DgmlLogFileName != null)
+                    compilation.WriteDependencyLog(_commandLineOptions.DgmlLogFileName.FullName);
             }
 
             return 0;
@@ -428,30 +361,30 @@ namespace ILCompiler
 
         private MethodDesc CheckAndParseSingleMethodModeArguments(CompilerTypeSystemContext context)
         {
-            if (_singleMethodName == null && _singleMethodTypeName == null && _singleMethodGenericArgs == null)
+            if (_commandLineOptions.SingleMethodName == null && _commandLineOptions.SingleMethodTypeName == null && _commandLineOptions.SingleMethodGenericArgs == null)
                 return null;
 
-            if (_singleMethodName == null || _singleMethodTypeName == null)
+            if (_commandLineOptions.SingleMethodName == null || _commandLineOptions.SingleMethodTypeName == null)
                 throw new CommandLineException("Both method name and type name are required parameters for single method mode");
 
-            TypeDesc owningType = FindType(context, _singleMethodTypeName);
+            TypeDesc owningType = FindType(context, _commandLineOptions.SingleMethodTypeName);
 
             // TODO: allow specifying signature to distinguish overloads
-            MethodDesc method = owningType.GetMethod(_singleMethodName, null);
+            MethodDesc method = owningType.GetMethod(_commandLineOptions.SingleMethodName, null);
             if (method == null)
-                throw new CommandLineException($"Method '{_singleMethodName}' not found in '{_singleMethodTypeName}'");
+                throw new CommandLineException($"Method '{_commandLineOptions.SingleMethodName}' not found in '{_commandLineOptions.SingleMethodTypeName}'");
 
-            if (method.HasInstantiation != (_singleMethodGenericArgs != null) ||
-                (method.HasInstantiation && (method.Instantiation.Length != _singleMethodGenericArgs.Count)))
+            if (method.HasInstantiation != (_commandLineOptions.SingleMethodGenericArgs != null) ||
+                (method.HasInstantiation && (method.Instantiation.Length != _commandLineOptions.SingleMethodGenericArgs.Length)))
             {
                 throw new CommandLineException(
-                    $"Expected {method.Instantiation.Length} generic arguments for method '{_singleMethodName}' on type '{_singleMethodTypeName}'");
+                    $"Expected {method.Instantiation.Length} generic arguments for method '{_commandLineOptions.SingleMethodName}' on type '{_commandLineOptions.SingleMethodTypeName}'");
             }
 
             if (method.HasInstantiation)
             {
                 List<TypeDesc> genericArguments = new List<TypeDesc>();
-                foreach (var argString in _singleMethodGenericArgs)
+                foreach (var argString in _commandLineOptions.SingleMethodGenericArgs)
                     genericArguments.Add(FindType(context, argString));
                 method = method.MakeInstantiatedMethod(genericArguments.ToArray());
             }
@@ -476,12 +409,19 @@ namespace ILCompiler
             return false;
         }
 
-        private static int Main(string[] args)
+        public static async Task<int> Main(string[] args)
+        {
+            var command = CommandLineOptions.RootCommand();
+            command.Handler = CommandHandler.Create<CommandLineOptions>((CommandLineOptions options) => InnerMain(options));
+            return await command.InvokeAsync(args);
+        }
+
+        private static int InnerMain(CommandLineOptions buildOptions)
         {
 #if DEBUG
             try
             {
-                return new Program().Run(args);
+                return new Program(buildOptions).Run();
             }
             catch (CodeGenerationFailedException ex) when (DumpReproArguments(ex))
             {
@@ -490,7 +430,7 @@ namespace ILCompiler
 #else
             try
             {
-                return new Program().Run(args);
+                return new Program(buildOptions).Run();
             }
             catch (Exception e)
             {
index a33cd3b..a8be30a 100644 (file)
@@ -29,8 +29,8 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="System.CommandLine">
-      <Version>0.1.0-e160119-1</Version>
+    <PackageReference Include="System.CommandLine.Experimental">
+      <Version>0.3.0-alpha.19525.2</Version>
     </PackageReference>
   </ItemGroup>
 </Project>