From d29392edce6bee3fb178ea6275222cc2ae69b18f Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 27 Mar 2026 12:40:14 +0000 Subject: [PATCH 1/2] Migrate remaining tools to modern commandline --- eng/build.yml | 2 +- src/AnalyzeAsm/AnalyzeAsm.csproj | 1 - src/Directory.Build.props | 15 ++ src/cijobs/CIJobsRootCommand.cs | 33 ++-- src/cijobs/Program.cs | 12 +- src/cijobs/cijobs.csproj | 3 - .../instructions-retired-explorer.csproj | 3 - src/jit-analyze/Program.cs | 7 +- src/jit-analyze/jit-analyze.csproj | 3 - src/jit-dasm-pmi/Program.cs | 7 +- src/jit-dasm-pmi/jit-dasm-pmi.csproj | 3 - src/jit-dasm/Program.cs | 7 +- src/jit-dasm/jit-dasm.csproj | 3 - .../jit-decisions-analyze.csproj | 3 - src/jit-diff/JitDiffRootCommand.cs | 149 ++++++++++++++++ src/jit-diff/jit-diff.cs | 168 ++++++++---------- src/jit-diff/jit-diff.csproj | 3 - src/jit-format/JitFormatRootCommand.cs | 65 +++++++ src/jit-format/jit-format.cs | 58 +++--- src/jit-format/jit-format.csproj | 3 - src/jit-include.props | 11 -- src/jit-rl-cse/MLCSE.csproj | 3 - src/jit-tp-analyze/Program.cs | 7 +- src/jit-tp-analyze/jit-tp-analyze.csproj | 3 - src/mutate-test/MutateTestRootCommand.cs | 32 ++-- src/mutate-test/Program.cs | 12 +- src/mutate-test/mutate-test.csproj | 3 - .../performance-explorer.csproj | 3 - src/pmi/pmi.csproj | 2 - src/superpmi/superpmicollect.csproj | 2 - src/target-framework.props | 9 - src/wasm-spmi-filter/wasm-spmi-filter.csproj | 1 - 32 files changed, 399 insertions(+), 237 deletions(-) create mode 100644 src/Directory.Build.props create mode 100644 src/jit-diff/JitDiffRootCommand.cs create mode 100644 src/jit-format/JitFormatRootCommand.cs delete mode 100644 src/jit-include.props delete mode 100644 src/target-framework.props diff --git a/eng/build.yml b/eng/build.yml index 9f7588ae..ba3779bb 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -13,7 +13,7 @@ jobs: displayName: 'Install .NET Core SDK' inputs: packageType: sdk - version: 8.x + version: 10.x installationPath: $(Agent.ToolsDirectory)/dotnet - ${{ if eq(parameters.agentOs, 'Windows_NT') }}: diff --git a/src/AnalyzeAsm/AnalyzeAsm.csproj b/src/AnalyzeAsm/AnalyzeAsm.csproj index 74954604..6a70a1ab 100644 --- a/src/AnalyzeAsm/AnalyzeAsm.csproj +++ b/src/AnalyzeAsm/AnalyzeAsm.csproj @@ -2,7 +2,6 @@ Exe - net6.0 diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000..0422e1b6 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,15 @@ + + + + net10.0 + + + + + + + + + + + diff --git a/src/cijobs/CIJobsRootCommand.cs b/src/cijobs/CIJobsRootCommand.cs index e566a403..df9c44af 100644 --- a/src/cijobs/CIJobsRootCommand.cs +++ b/src/cijobs/CIJobsRootCommand.cs @@ -5,38 +5,37 @@ using System; using System.Collections.Generic; using System.CommandLine; -using System.CommandLine.Invocation; using System.Threading.Tasks; namespace ManagedCodeGen { - internal sealed class CIJobsRootCommand : CliRootCommand + internal sealed class CIJobsRootCommand : RootCommand { - public CliOption Server { get; } = + public Option Server { get; } = new("--server", "-s") { Description = "Url of the server. Defaults to https://ci.dot.net/" }; - public CliOption JobName { get; } = + public Option JobName { get; } = new("--job", "-j") { Description = "Name of the job." }; - public CliOption BranchName { get; } = + public Option BranchName { get; } = new("--branch", "-b") { DefaultValueFactory = _ => "master", Description = "Name of the branch." }; - public CliOption RepoName { get; } = + public Option RepoName { get; } = new("--repo", "-r") { DefaultValueFactory = _ => "dotnet_coreclr", Description = "Name of the repo (e.g. dotnet_corefx or dotnet_coreclr)." }; - public CliOption MatchPattern { get; } = + public Option MatchPattern { get; } = new("--match", "-m") { Description = "Regex pattern used to select jobs output." }; - public CliOption JobNumber { get; } = + public Option JobNumber { get; } = new("--number", "-n") { Description = "Job number." }; - public CliOption ShowLastSuccessful { get; } = + public Option ShowLastSuccessful { get; } = new("--last-successful", "-l") { Description = "Show last successful build." }; - public CliOption Commit { get; } = + public Option Commit { get; } = new("--commit", "-c") { Description = "List build at this commit." }; - public CliOption ShowArtifacts { get; } = + public Option ShowArtifacts { get; } = new("--artifacts", "-a") { Description = "Show job artifacts on server." }; - public CliOption OutputPath { get; } = + public Option OutputPath { get; } = new("--output", "-o") { Description = "The path where output will be placed." }; - public CliOption OutputRoot { get; } = + public Option OutputRoot { get; } = new("--output-root") { Description = "The root directory where output will be placed. A subdirectory named by job and build number will be created within this to store the output." }; - public CliOption Unzip { get; } = + public Option Unzip { get; } = new("--unzip", "-u") { Description = "Unzip copied artifacts" }; - public CliOption ContentPath { get; } = + public Option ContentPath { get; } = new("--ContentPath", "-p") { Description = "Relative product zip path. Default is artifact/bin/Product/*zip*/Product.zip" }; public ParseResult Result; @@ -45,7 +44,7 @@ public CIJobsRootCommand(string[] args) : base("Continuous integration build job { List errors = new(); - CliCommand listCommand = new("list", "List jobs on ci.dot.net for the repo.") + Command listCommand = new("list", "List jobs on ci.dot.net for the repo.") { Server, JobName, @@ -104,7 +103,7 @@ public CIJobsRootCommand(string[] args) : base("Continuous integration build job Subcommands.Add(listCommand); - CliCommand copyCommand = new("copy", @"Copies job artifacts from ci.dot.net. This + Command copyCommand = new("copy", @"Copies job artifacts from ci.dot.net. This command copies a zip of artifacts from a repo (defaulted to dotnet_coreclr). The default location of the zips is the Product sub-directory, though that can be changed using the diff --git a/src/cijobs/Program.cs b/src/cijobs/Program.cs index 73b01e18..24626b0e 100755 --- a/src/cijobs/Program.cs +++ b/src/cijobs/Program.cs @@ -69,13 +69,13 @@ public async Task RunAsync(string name) return await CopyAsync(cic); } - private T Get(CliOption option) => _command.Result.GetValue(option); + private T Get(Option option) => _command.Result.GetValue(option); - private static Task Main(string[] args) => - new CliConfiguration(new CIJobsRootCommand(args).UseVersion()) - { - EnableParseErrorReporting = true - }.InvokeAsync(args); + private static Task Main(string[] args) + { + var command = new CIJobsRootCommand(args).UseVersion(); + return command.Parse(args).InvokeAsync(); + } // List jobs and their details from the given project on .NETCI Jenkins instance. // List functionality: diff --git a/src/cijobs/cijobs.csproj b/src/cijobs/cijobs.csproj index 036eb0f1..87773400 100644 --- a/src/cijobs/cijobs.csproj +++ b/src/cijobs/cijobs.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/instructions-retired-explorer/instructions-retired-explorer.csproj b/src/instructions-retired-explorer/instructions-retired-explorer.csproj index 4539b1d1..fc32fc7d 100644 --- a/src/instructions-retired-explorer/instructions-retired-explorer.csproj +++ b/src/instructions-retired-explorer/instructions-retired-explorer.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/jit-analyze/Program.cs b/src/jit-analyze/Program.cs index 2d334f85..cc791ca9 100644 --- a/src/jit-analyze/Program.cs +++ b/src/jit-analyze/Program.cs @@ -908,8 +908,11 @@ public static Dictionary DiffInText(string diffPath, string basePat private T Get(Option option) => _command.Result.GetValue(option); - private static int Main(string[] args) => - new CommandLineConfiguration(new JitAnalyzeRootCommand(args).UseVersion()).Invoke(args); + private static int Main(string[] args) + { + var command = new JitAnalyzeRootCommand(args).UseVersion(); + return command.Parse(args).Invoke(); + } public int Run() { diff --git a/src/jit-analyze/jit-analyze.csproj b/src/jit-analyze/jit-analyze.csproj index 036eb0f1..87773400 100644 --- a/src/jit-analyze/jit-analyze.csproj +++ b/src/jit-analyze/jit-analyze.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/jit-dasm-pmi/Program.cs b/src/jit-dasm-pmi/Program.cs index 16cf6c50..904bbba3 100644 --- a/src/jit-dasm-pmi/Program.cs +++ b/src/jit-dasm-pmi/Program.cs @@ -75,8 +75,11 @@ public int Run() private T Get(Option option) => _command.Result.GetValue(option); private T Get(Argument arg) => _command.Result.GetValue(arg); - private static int Main(string[] args) => - new CommandLineConfiguration(new JitDasmPmiRootCommand(args).UseVersion()).Invoke(args); + private static int Main(string[] args) + { + var command = new JitDasmPmiRootCommand(args).UseVersion(); + return command.Parse(args).Invoke(); + } public List GenerateAssemblyWorklist() { diff --git a/src/jit-dasm-pmi/jit-dasm-pmi.csproj b/src/jit-dasm-pmi/jit-dasm-pmi.csproj index 036eb0f1..87773400 100644 --- a/src/jit-dasm-pmi/jit-dasm-pmi.csproj +++ b/src/jit-dasm-pmi/jit-dasm-pmi.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/jit-dasm/Program.cs b/src/jit-dasm/Program.cs index dc24baa8..77755cd1 100644 --- a/src/jit-dasm/Program.cs +++ b/src/jit-dasm/Program.cs @@ -84,8 +84,11 @@ public int Run() private T Get(Option option) => _command.Result.GetValue(option); private T Get(Argument arg) => _command.Result.GetValue(arg); - private static int Main(string[] args) => - new CommandLineConfiguration(new JitDasmRootCommand(args).UseVersion()).Invoke(args); + private static int Main(string[] args) + { + var command = new JitDasmRootCommand(args).UseVersion(); + return command.Parse(args).Invoke(); + } public List GenerateAssemblyWorklist() { diff --git a/src/jit-dasm/jit-dasm.csproj b/src/jit-dasm/jit-dasm.csproj index 036eb0f1..87773400 100644 --- a/src/jit-dasm/jit-dasm.csproj +++ b/src/jit-dasm/jit-dasm.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/jit-decisions-analyze/jit-decisions-analyze.csproj b/src/jit-decisions-analyze/jit-decisions-analyze.csproj index 036eb0f1..87773400 100644 --- a/src/jit-decisions-analyze/jit-decisions-analyze.csproj +++ b/src/jit-decisions-analyze/jit-decisions-analyze.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/jit-diff/JitDiffRootCommand.cs b/src/jit-diff/JitDiffRootCommand.cs new file mode 100644 index 00000000..9048517e --- /dev/null +++ b/src/jit-diff/JitDiffRootCommand.cs @@ -0,0 +1,149 @@ +// 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.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Parsing; + +namespace ManagedCodeGen +{ + internal sealed class JitDiffRootCommand : RootCommand + { + public Option BasePath { get; } = + new("--base", "-b") { Description = "The base compiler directory or tag. Will use crossgen, corerun, or clrjit from this directory.", Arity = ArgumentArity.ZeroOrOne }; + public Option DiffPath { get; } = + new("--diff", "-d") { Description = "The diff compiler directory or tag. Will use crossgen, corerun, or clrjit from this directory.", Arity = ArgumentArity.ZeroOrOne }; + public Option CrossgenExe { get; } = + new("--crossgen") { Description = "The crossgen or crossgen2 compiler exe. When this is specified, will use clrjit from the --base and --diff directories with this crossgen." }; + public Option OutputPath { get; } = + new("--output", "-o") { Description = "The output path." }; + public Option NoAnalyze { get; } = + new("--noanalyze") { Description = "Do not analyze resulting base, diff dasm directories. (By default, the directories are analyzed for diffs.)" }; + public Option Sequential { get; } = + new("--sequential", "-s") { Description = "Run sequentially; don't do parallel compiles." }; + public Option Tag { get; } = + new("--tag", "-t") { Description = "Name of root in output directory. Allows for many sets of output." }; + public Option CoreLib { get; } = + new("--corelib", "-c") { Description = "Diff System.Private.CoreLib.dll." }; + public Option Frameworks { get; } = + new("--frameworks", "-f") { Description = "Diff frameworks." }; + public Option Metric { get; } = + new("--metrics", "-m") { Description = "Comma-separated metric to use for diff computations. Available metrics: CodeSize(default), PerfScore, PrologSize, InstrCount, AllocSize, ExtraAllocBytes, DebugClauseCount, DebugVarCount" }; + public Option Benchmarks { get; } = + new("--benchmarks") { Description = "Diff core benchmarks." }; + public Option Tests { get; } = + new("--tests") { Description = "Diff all tests." }; + public Option GCInfo { get; } = + new("--gcinfo") { Description = "Add GC info to the disasm output." }; + public Option DebugInfo { get; } = + new("--debuginfo") { Description = "Add Debug info to the disasm output." }; + public Option Verbose { get; } = + new("--verbose", "-v") { Description = "Enable verbose output." }; + public Option NoDiffable { get; } = + new("--nodiffable") { Description = "Generate non-diffable asm (pointer values will be left in output)." }; + public Option CoreRoot { get; } = + new("--core_root") { Description = "Path to test CORE_ROOT." }; + public Option TestRoot { get; } = + new("--test_root") { Description = "Path to test tree. Use with --benchmarks or --tests." }; + public Option BaseRoot { get; } = + new("--base_root") { Description = "Path to root of base dotnet/runtime repo." }; + public Option DiffRoot { get; } = + new("--diff_root") { Description = "Path to root of diff dotnet/runtime repo." }; + public Option Arch { get; } = + new("--arch") { Description = "Architecture to diff (x86, x64)." }; + public Option Build { get; } = + new("--build") { Description = "Build flavor to diff (Checked, Debug)." }; + public Option AltJit { get; } = + new("--altjit") { Description = "If set, the name of the altjit to use (e.g., clrjit_win_arm64_x64.dll)." }; + public Option Pmi { get; } = + new("--pmi") { Description = "Run asm diffs via pmi." }; + public Option Cctors { get; } = + new("--cctors") { Description = "With --pmi, jit and run cctors before jitting other methods" }; + public Option> AssemblyList { get; } = + new("--assembly") { Description = "Run asm diffs on a given set of assemblies. An individual item can be an assembly or a directory tree containing assemblies." }; + public Option Tsv { get; } = + new("--tsv") { Description = "Dump analysis data to diffs.tsv in output directory." }; + public Option Tier0 { get; } = + new("--tier0") { Description = "Diff tier0 codegen where possible." }; + public Option Count { get; } = + new("--count") { Description = "Provide the count parameter to jit-analyze (default 20)." }; + + public Option JobName { get; } = + new("--job", "-j") { Description = "Name of the job." }; + public Option Number { get; } = + new("--number", "-n") { Description = "Job number." }; + public Option LastSuccessful { get; } = + new("--last_successful", "-l") { Description = "Last successful build." }; + public Option BranchName { get; } = + new("--branch", "-b") { Description = "Name of branch." }; + + public ParseResult Result { get; private set; } + public jitdiff.Commands SelectedCommand { get; private set; } + + public JitDiffRootCommand(string[] args) : base("Managed codegen diff orchestrator") + { + Command diffCommand = new("diff", "Run asm diffs via crossgen.") + { + BasePath, DiffPath, CrossgenExe, OutputPath, NoAnalyze, Sequential, Tag, CoreLib, Frameworks, Metric, + Benchmarks, Tests, GCInfo, DebugInfo, Verbose, NoDiffable, CoreRoot, TestRoot, BaseRoot, DiffRoot, + Arch, Build, AltJit, Pmi, Cctors, AssemblyList, Tsv, Tier0, Count + }; + diffCommand.SetAction(result => Execute(result, jitdiff.Commands.Diff)); + Subcommands.Add(diffCommand); + + Command listCommand = new("list", "List defaults and available tools in config.json.") + { + Verbose + }; + listCommand.SetAction(result => Execute(result, jitdiff.Commands.List)); + Subcommands.Add(listCommand); + + Command installCommand = new("install", "Install tool in config.json.") + { + JobName, Number, LastSuccessful, BranchName, Verbose + }; + installCommand.SetAction(result => Execute(result, jitdiff.Commands.Install)); + Subcommands.Add(installCommand); + + Command uninstallCommand = new("uninstall", "Uninstall tool from config.json.") + { + Tag + }; + uninstallCommand.SetAction(result => Execute(result, jitdiff.Commands.Uninstall)); + Subcommands.Add(uninstallCommand); + } + + private int Execute(ParseResult result, jitdiff.Commands command) + { + Result = result; + SelectedCommand = command; + + try + { + jitdiff.Config config = new(this); + return config.DoCommand switch + { + jitdiff.Commands.Diff => jitdiff.DiffTool.DiffCommand(config), + jitdiff.Commands.PmiDiff => jitdiff.DiffTool.DiffCommand(config), + jitdiff.Commands.List => config.ListCommand(), + jitdiff.Commands.Install => jitdiff.InstallCommand(config), + jitdiff.Commands.Uninstall => jitdiff.UninstallCommand(config), + _ => 1, + }; + } + catch (Exception e) + { + Console.ResetColor(); + Console.ForegroundColor = ConsoleColor.Red; + + Console.Error.WriteLine("Error: " + e.Message); + Console.Error.WriteLine(e.ToString()); + + Console.ResetColor(); + return 1; + } + } + } +} diff --git a/src/jit-diff/jit-diff.cs b/src/jit-diff/jit-diff.cs index 9430d637..c395c112 100755 --- a/src/jit-diff/jit-diff.cs +++ b/src/jit-diff/jit-diff.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.CommandLine; +using System.CommandLine.Parsing; using System.IO; using System.Linq; using System.Text.Json; @@ -113,7 +114,6 @@ private static string GetConfigurationArtifactDir(string platformMoniker, string public class Config { - private ArgumentSyntax _syntaxResult; private Commands _command = Commands.Diff; private bool _baseSpecified = false; // True if user specified "--base" or "--base " or "--base " private bool _diffSpecified = false; // True if user specified "--diff" or "--diff " or "--diff " @@ -158,77 +158,80 @@ public class Config private bool _noJitUtilsRoot = false; private bool _validationError = false; - public Config(string[] args) + internal Config(JitDiffRootCommand command) { - // Get configuration values from JIT_UTILS_ROOT/config.json + // Get configuration values from JIT_UTILS_ROOT/config.json. LoadFileConfig(); - _syntaxResult = ArgumentSyntax.Parse(args, syntax => + ParseResult result = command.Result; + _command = command.SelectedCommand; + + bool IsSpecified(Option option) => result.GetResult(option) != null; + T Get(Option option) => result.GetValue(option); + + if (_command == Commands.Diff) { - // Diff command section. - syntax.DefineCommand("diff", ref _command, Commands.Diff, "Run asm diffs via crossgen."); - - var baseOption = syntax.DefineOption("b|base", ref _basePath, false, - "The base compiler directory or tag. Will use crossgen, corerun, or clrjit from this directory."); - var diffOption = syntax.DefineOption("d|diff", ref _diffPath, false, - "The diff compiler directory or tag. Will use crossgen, corerun, or clrjit from this directory."); - syntax.DefineOption("crossgen", ref _crossgenExe, - "The crossgen or crossgen2 compiler exe. When this is specified, will use clrjit from the --base and " + - "--diff directories with this crossgen."); - syntax.DefineOption("o|output", ref _outputPath, "The output path."); - syntax.DefineOption("noanalyze", ref _noanalyze, "Do not analyze resulting base, diff dasm directories. (By default, the directories are analyzed for diffs.)"); - syntax.DefineOption("s|sequential", ref _sequential, "Run sequentially; don't do parallel compiles."); - syntax.DefineOption("t|tag", ref _tag, "Name of root in output directory. Allows for many sets of output."); - syntax.DefineOption("c|corelib", ref _corelib, "Diff System.Private.CoreLib.dll."); - syntax.DefineOption("f|frameworks", ref _frameworks, "Diff frameworks."); - syntax.DefineOption("m|metrics", ref _metric, false, "Comma-separated metric to use for diff computations. Available metrics: CodeSize(default), PerfScore, PrologSize, InstrCount, AllocSize, ExtraAllocBytes, DebugClauseCount, DebugVarCount"); - syntax.DefineOption("benchmarks", ref _benchmarks, "Diff core benchmarks."); - syntax.DefineOption("tests", ref _tests, "Diff all tests."); - syntax.DefineOption("gcinfo", ref _gcinfo, "Add GC info to the disasm output."); - syntax.DefineOption("debuginfo", ref _debuginfo, "Add Debug info to the disasm output."); - syntax.DefineOption("v|verbose", ref _verbose, "Enable verbose output."); - syntax.DefineOption("nodiffable", ref _noDiffable, "Generate non-diffable asm (pointer values will be left in output)."); - syntax.DefineOption("core_root", ref _platformPath, "Path to test CORE_ROOT."); - syntax.DefineOption("test_root", ref _testPath, "Path to test tree. Use with --benchmarks or --tests."); - syntax.DefineOption("base_root", ref _baseRoot, "Path to root of base dotnet/runtime repo."); - syntax.DefineOption("diff_root", ref _diffRoot, "Path to root of diff dotnet/runtime repo."); - syntax.DefineOption("arch", ref _arch, "Architecture to diff (x86, x64)."); - syntax.DefineOption("build", ref _build, "Build flavor to diff (Checked, Debug)."); - syntax.DefineOption("altjit", ref _altjit, "If set, the name of the altjit to use (e.g., clrjit_win_arm64_x64.dll)."); - var pmiOption = syntax.DefineOption("pmi", ref _pmi, "Run asm diffs via pmi."); - syntax.DefineOption("cctors", ref _cctors, "With --pmi, jit and run cctors before jitting other methods"); - syntax.DefineOptionList("assembly", ref _assemblyList, "Run asm diffs on a given set of assemblies. An individual item can be an assembly or a directory tree containing assemblies."); - syntax.DefineOption("tsv", ref _tsv, "Dump analysis data to diffs.tsv in output directory."); - syntax.DefineOption("tier0", ref _tier0, "Diff tier0 codegen where possible."); - - // used by jit-analyze - syntax.DefineOption("count", ref _count, "provide the count parameter to jit-analyze (default 20)"); - - // List command section. - syntax.DefineCommand("list", ref _command, Commands.List, - "List defaults and available tools in " + s_configFileName + "."); - syntax.DefineOption("v|verbose", ref _verbose, "Enable verbose output."); - - // Install command section. - syntax.DefineCommand("install", ref _command, Commands.Install, "Install tool in " + s_configFileName + "."); - syntax.DefineOption("j|job", ref _jobName, "Name of the job."); - syntax.DefineOption("n|number", ref _number, "Job number."); - syntax.DefineOption("l|last_successful", ref _lastSuccessful, "Last successful build."); - syntax.DefineOption("b|branch", ref _branchName, "Name of branch."); - syntax.DefineOption("v|verbose", ref _verbose, "Enable verbose output."); - - // Uninstall command section.s - syntax.DefineCommand("uninstall", ref _command, Commands.Uninstall, "Uninstall tool from " + s_configFileName + "."); - syntax.DefineOption("t|tag", ref _tag, "Name of tool tag in config file."); - - _baseSpecified = baseOption.IsSpecified; - _diffSpecified = diffOption.IsSpecified; - - if (pmiOption.IsSpecified) + _baseSpecified = IsSpecified(command.BasePath); + if (_baseSpecified) + { + _basePath = Get(command.BasePath); + } + + _diffSpecified = IsSpecified(command.DiffPath); + if (_diffSpecified) + { + _diffPath = Get(command.DiffPath); + } + + if (IsSpecified(command.CrossgenExe)) _crossgenExe = Get(command.CrossgenExe); + if (IsSpecified(command.OutputPath)) _outputPath = Get(command.OutputPath); + if (IsSpecified(command.NoAnalyze)) _noanalyze = Get(command.NoAnalyze); + if (IsSpecified(command.Sequential)) _sequential = Get(command.Sequential); + if (IsSpecified(command.Tag)) _tag = Get(command.Tag); + if (IsSpecified(command.CoreLib)) _corelib = Get(command.CoreLib); + if (IsSpecified(command.Frameworks)) _frameworks = Get(command.Frameworks); + if (IsSpecified(command.Metric)) _metric = Get(command.Metric); + if (IsSpecified(command.Benchmarks)) _benchmarks = Get(command.Benchmarks); + if (IsSpecified(command.Tests)) _tests = Get(command.Tests); + if (IsSpecified(command.GCInfo)) _gcinfo = Get(command.GCInfo); + if (IsSpecified(command.DebugInfo)) _debuginfo = Get(command.DebugInfo); + if (IsSpecified(command.Verbose)) _verbose = Get(command.Verbose); + if (IsSpecified(command.NoDiffable)) _noDiffable = Get(command.NoDiffable); + if (IsSpecified(command.CoreRoot)) _platformPath = Get(command.CoreRoot); + if (IsSpecified(command.TestRoot)) _testPath = Get(command.TestRoot); + if (IsSpecified(command.BaseRoot)) _baseRoot = Get(command.BaseRoot); + if (IsSpecified(command.DiffRoot)) _diffRoot = Get(command.DiffRoot); + if (IsSpecified(command.Arch)) _arch = Get(command.Arch); + if (IsSpecified(command.Build)) _build = Get(command.Build); + if (IsSpecified(command.AltJit)) _altjit = Get(command.AltJit); + if (IsSpecified(command.Pmi)) _pmi = Get(command.Pmi); + if (IsSpecified(command.Cctors)) _cctors = Get(command.Cctors); + if (IsSpecified(command.AssemblyList)) _assemblyList = Get(command.AssemblyList); + if (IsSpecified(command.Tsv)) _tsv = Get(command.Tsv); + if (IsSpecified(command.Tier0)) _tier0 = Get(command.Tier0); + if (IsSpecified(command.Count)) _count = Get(command.Count); + + if (_pmi) { _command = Commands.PmiDiff; } - }); + } + else if (_command == Commands.List) + { + if (IsSpecified(command.Verbose)) _verbose = Get(command.Verbose); + } + else if (_command == Commands.Install) + { + if (IsSpecified(command.JobName)) _jobName = Get(command.JobName); + if (IsSpecified(command.Number)) _number = Get(command.Number); + if (IsSpecified(command.LastSuccessful)) _lastSuccessful = Get(command.LastSuccessful); + if (IsSpecified(command.BranchName)) _branchName = Get(command.BranchName); + if (IsSpecified(command.Verbose)) _verbose = Get(command.Verbose); + } + else if (_command == Commands.Uninstall) + { + if (IsSpecified(command.Tag)) _tag = Get(command.Tag); + } SetRID(); @@ -776,7 +779,8 @@ private void Validate() private void DisplayUsageMessage() { Console.Error.WriteLine(""); - Console.Error.Write(_syntaxResult.GetHelpText(100)); + Console.Error.WriteLine("Usage: jit-diff [options]"); + Console.Error.WriteLine("Run 'jit-diff --help' for command-specific options."); if (_command == Commands.Diff) { @@ -1348,36 +1352,8 @@ public int ListCommand() public static int Main(string[] args) { - Config config = new Config(args); - int ret = 0; - - switch (config.DoCommand) - { - case Commands.Diff: - case Commands.PmiDiff: - { - ret = DiffTool.DiffCommand(config); - } - break; - case Commands.List: - { - // List command: list loaded configuration - ret = config.ListCommand(); - } - break; - case Commands.Install: - { - ret = InstallCommand(config); - } - break; - case Commands.Uninstall: - { - ret = UninstallCommand(config); - } - break; - } - - return ret; + var command = new JitDiffRootCommand(args).UseVersion(); + return command.Parse(args).Invoke(); } } } diff --git a/src/jit-diff/jit-diff.csproj b/src/jit-diff/jit-diff.csproj index 7c7b258e..87773400 100644 --- a/src/jit-diff/jit-diff.csproj +++ b/src/jit-diff/jit-diff.csproj @@ -1,14 +1,11 @@  - - Exe - diff --git a/src/jit-format/JitFormatRootCommand.cs b/src/jit-format/JitFormatRootCommand.cs new file mode 100644 index 00000000..2d3c4d3d --- /dev/null +++ b/src/jit-format/JitFormatRootCommand.cs @@ -0,0 +1,65 @@ +// 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.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Parsing; + +namespace ManagedCodeGen +{ + internal sealed class JitFormatRootCommand : RootCommand + { + public Option Arch { get; } = + new("--arch", "-a") { Description = "The architecture of the build (options: arm64, x64, x86)" }; + public Option OS { get; } = + new("--os", "-o") { Description = "The operating system of the build (options: windows, osx, linux, etc.)" }; + public Option Build { get; } = + new("--build", "-b") { Description = "The build type of the build (options: Release, Checked, Debug)" }; + public Option RuntimePath { get; } = + new("--runtime", "-r") { Description = "Full path to runtime directory" }; + public Option CompileCommands { get; } = + new("--compile-commands") { Description = "Full path to compile_commands.json" }; + public Option Verbose { get; } = + new("--verbose") { Description = "Enable verbose output." }; + public Option Untidy { get; } = + new("--untidy") { Description = "Do not run clang-tidy" }; + public Option NoFormat { get; } = + new("--noformat") { Description = "Do not run clang-format" }; + public Option Cross { get; } = + new("--cross") { Description = "If on Linux, run the configure build as a cross build." }; + public Option Fix { get; } = + new("--fix", "-f") { Description = "Fix formatting errors discovered by clang-format and clang-tidy." }; + public Option IgnoreErrors { get; } = + new("--ignore-errors", "-i") { Description = "Ignore clang-tidy errors" }; + public Option> Projects { get; } = + new("--projects") { Description = "List of build projects clang-tidy should consider (e.g. dll, standalone, protojit, etc.). Default: dll" }; + public Argument> Filenames { get; } = + new("filenames") { Description = "Optional list of files that should be formatted." }; + + public ParseResult Result { get; private set; } + + public JitFormatRootCommand(string[] args) : base("JIT formatting tool") + { + Options.Add(Arch); + Options.Add(OS); + Options.Add(Build); + Options.Add(RuntimePath); + Options.Add(CompileCommands); + Options.Add(Verbose); + Options.Add(Untidy); + Options.Add(NoFormat); + Options.Add(Cross); + Options.Add(Fix); + Options.Add(IgnoreErrors); + Options.Add(Projects); + Arguments.Add(Filenames); + + SetAction(result => + { + Result = result; + return jitformat.Execute(this); + }); + } + } +} diff --git a/src/jit-format/jit-format.cs b/src/jit-format/jit-format.cs index 104017e8..4d7ca752 100644 --- a/src/jit-format/jit-format.cs +++ b/src/jit-format/jit-format.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.CommandLine; +using System.CommandLine.Parsing; using System.Diagnostics; using System.IO; using System.Linq; @@ -30,7 +31,6 @@ public class Config private static string s_configFileName = "config.json"; private static string s_configFileRootKey = "format"; - private ArgumentSyntax _syntaxResult; private string _arch = null; private string _os = null; private string _build = null; @@ -51,27 +51,29 @@ public class Config private JsonObject _jObj; private string _jitUtilsRoot = null; - public Config(string[] args) + internal Config(JitFormatRootCommand command) { LoadFileConfig(); - _syntaxResult = ArgumentSyntax.Parse(args, syntax => - { - syntax.DefineOption("a|arch", ref _arch, "The architecture of the build (options: arm64, x64, x86)"); - syntax.DefineOption("o|os", ref _os, "The operating system of the build (options: windows, osx, linux, etc.)"); - syntax.DefineOption("b|build", ref _build, "The build type of the build (options: Release, Checked, Debug)"); - syntax.DefineOption("r|runtime", ref _runtimePath, "Full path to runtime directory"); - syntax.DefineOption("compile-commands", ref _compileCommands, "Full path to compile_commands.json"); - syntax.DefineOption("v|verbose", ref _verbose, "Enable verbose output."); - syntax.DefineOption("untidy", ref _untidy, "Do not run clang-tidy"); - syntax.DefineOption("noformat", ref _noformat, "Do not run clang-format"); - syntax.DefineOption("cross", ref _cross, "If on Linux, run the configure build as a cross build."); - syntax.DefineOption("f|fix", ref _fix, "Fix formatting errors discovered by clang-format and clang-tidy."); - syntax.DefineOption("i|ignore-errors", ref _ignoreErrors, "Ignore clang-tidy errors"); - syntax.DefineOptionList("projects", ref _projects, "List of build projects clang-tidy should consider (e.g. dll, standalone, protojit, etc.). Default: dll"); - - syntax.DefineParameterList("filenames", ref _filenames, "Optional list of files that should be formatted."); - }); + ParseResult result = command.Result; + + bool IsSpecified(Option option) => result.GetResult(option) != null; + T Get(Option option) => result.GetValue(option); + List GetArgument(Argument> arg) => result.GetValue(arg); + + if (IsSpecified(command.Arch)) _arch = Get(command.Arch); + if (IsSpecified(command.OS)) _os = Get(command.OS); + if (IsSpecified(command.Build)) _build = Get(command.Build); + if (IsSpecified(command.RuntimePath)) _runtimePath = Get(command.RuntimePath); + if (IsSpecified(command.CompileCommands)) _compileCommands = Get(command.CompileCommands); + if (IsSpecified(command.Verbose)) _verbose = Get(command.Verbose); + if (IsSpecified(command.Untidy)) _untidy = Get(command.Untidy); + if (IsSpecified(command.NoFormat)) _noformat = Get(command.NoFormat); + if (IsSpecified(command.Cross)) _cross = Get(command.Cross); + if (IsSpecified(command.Fix)) _fix = Get(command.Fix); + if (IsSpecified(command.IgnoreErrors)) _ignoreErrors = Get(command.IgnoreErrors); + if (IsSpecified(command.Projects)) _projects = Get(command.Projects); + _filenames = GetArgument(command.Filenames); // Run validation code on parsed input to ensure we have a sensible scenario. @@ -241,7 +243,7 @@ private void validate() if (!_untidy && ((_arch == null) || (_os == null) || (_build == null))) { - _syntaxResult.ReportError("Specify --arch, --os, and --build for clang-tidy run."); + throw new Exception("Specify --arch, --os, and --build for clang-tidy run."); } if (_runtimePath == null) @@ -253,7 +255,7 @@ private void validate() _runtimePath = Utility.GetRepoRoot(_verbose); if (_runtimePath == null) { - _syntaxResult.ReportError("Specify --runtime"); + throw new Exception("Specify --runtime"); } else { @@ -265,12 +267,12 @@ private void validate() if (!Directory.Exists(_coreclrPath)) { // If _coreclrPath doesn't exist, it is an invalid path - _syntaxResult.ReportError("Invalid path to runtime directory. Specify with --runtime"); + throw new Exception("Invalid path to runtime directory. Specify with --runtime"); } else if (!File.Exists(Path.Combine(_coreclrPath, "build-runtime.cmd")) || !File.Exists(Path.Combine(_coreclrPath, "build-runtime.sh")) || !File.Exists(Path.Combine(_coreclrPath, "clr.featuredefines.props"))) { // Doesn't look like the coreclr directory. - _syntaxResult.ReportError("Invalid path to coreclr directory. Specify with --runtime"); + throw new Exception("Invalid path to coreclr directory. Specify with --runtime"); } // Check that we can find compile_commands.json on windows @@ -491,10 +493,10 @@ public CompileCommand(string dir, string cmd, string filename) } } - public static int Main(string[] args) + internal static int Execute(JitFormatRootCommand command) { // Parse and store comand line options. - var config = new Config(args); + var config = new Config(command); int returncode = 0; bool verbose = config.DoVerboseOutput; @@ -625,6 +627,12 @@ public static int Main(string[] args) return returncode; } + public static int Main(string[] args) + { + var command = new JitFormatRootCommand(args).UseVersion(); + return command.Parse(args).Invoke(); + } + // This method reads in a compile_command.json file, and writes a new json file with only the entries // commands for files found in the project specified. For example, if project is dll, it will write a // new compile_commands file (called compile_commands_dll.json) with only the entries whose directory diff --git a/src/jit-format/jit-format.csproj b/src/jit-format/jit-format.csproj index 7c7b258e..87773400 100644 --- a/src/jit-format/jit-format.csproj +++ b/src/jit-format/jit-format.csproj @@ -1,14 +1,11 @@  - - Exe - diff --git a/src/jit-include.props b/src/jit-include.props deleted file mode 100644 index e4a0fd5d..00000000 --- a/src/jit-include.props +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/jit-rl-cse/MLCSE.csproj b/src/jit-rl-cse/MLCSE.csproj index c5357bb9..65779695 100644 --- a/src/jit-rl-cse/MLCSE.csproj +++ b/src/jit-rl-cse/MLCSE.csproj @@ -1,8 +1,5 @@  - - - Exe enable diff --git a/src/jit-tp-analyze/Program.cs b/src/jit-tp-analyze/Program.cs index ae9acac5..2fdc5fae 100644 --- a/src/jit-tp-analyze/Program.cs +++ b/src/jit-tp-analyze/Program.cs @@ -124,8 +124,11 @@ private static double GetPercentageDiff(double baseValue, double diffValue) => private static string FormatPercentageDiff(double value, string precision = "00") => (value > 0 ? "+" : "") + value.ToString($"0.{precision}") + "%"; - private static void Main(string[] args) => - new CommandLineConfiguration(new JitTpAnalyzeRootCommand().UseVersion()).Invoke(args); + private static void Main(string[] args) + { + var command = new JitTpAnalyzeRootCommand().UseVersion(); + command.Parse(args).Invoke(); + } private struct FunctionDiff { diff --git a/src/jit-tp-analyze/jit-tp-analyze.csproj b/src/jit-tp-analyze/jit-tp-analyze.csproj index fe8dbbe8..6a70a1ab 100644 --- a/src/jit-tp-analyze/jit-tp-analyze.csproj +++ b/src/jit-tp-analyze/jit-tp-analyze.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/mutate-test/MutateTestRootCommand.cs b/src/mutate-test/MutateTestRootCommand.cs index e6ed26b5..bb14301c 100644 --- a/src/mutate-test/MutateTestRootCommand.cs +++ b/src/mutate-test/MutateTestRootCommand.cs @@ -7,35 +7,35 @@ namespace MutateTest { - internal sealed class MutateTestRootCommand : CliRootCommand + internal sealed class MutateTestRootCommand : RootCommand { - public CliArgument InputFilePath { get; } = - new("input-test-case") { Description = "Input test case file or directory (for --recursive)", Arity = ArgumentArity.OneOrMore }; - public CliOption EHStress { get; } = + public Argument InputFilePath { get; } = + new("input-test-case") { Description = "Input test case file or directory (for --recursive)", Arity = ArgumentArity.ExactlyOne }; + public Option EHStress { get; } = new("--ehStress") { Description = "Add EH to methods" }; - public CliOption StructStress { get; } = + public Option StructStress { get; } = new("--structStress") { Description = "Replace locals with structs" }; - public CliOption ShowResults { get; } = + public Option ShowResults { get; } = new("--showResults") { Description = "Add EH to methods" }; - public CliOption Verbose { get; } = + public Option Verbose { get; } = new("--verbose") { Description = "Describe each transformation" }; - public CliOption Quiet { get; } = + public Option Quiet { get; } = new("--quiet") { Description = "Produce minimal output" }; - public CliOption Recursive { get; } = + public Option Recursive { get; } = new("--recursive") { Description = "Process each file recursively" }; - public CliOption Seed { get; } = + public Option Seed { get; } = new("--seed") { DefaultValueFactory = _ => 42, Description = "Random seed" }; - public CliOption StopAtFirstFailure { get; } = + public Option StopAtFirstFailure { get; } = new("--stopAtFirstFailure") { Description = "Stop each test at first failure" }; - public CliOption EmptyBlocks { get; } = + public Option EmptyBlocks { get; } = new("--emptyBlocks") { Description = "Transform empty blocks" }; - public CliOption SizeLimit { get; } = + public Option SizeLimit { get; } = new("--sizeLimit") { DefaultValueFactory = _ => 10000, Description = "Don't process programs larger than this size" }; - public CliOption TimeLimit { get; } = + public Option TimeLimit { get; } = new("--timeLimit") { DefaultValueFactory = _ => 10000, Description = "Don't stress programs where compile + run takes more than this many milliseconds" }; - public CliOption Projects { get; } = + public Option Projects { get; } = new("--projects") { Description = "Look for .csproj files instead of .cs files when doing recursive exploration" }; - public CliOption OnlyFailures { get; } = + public Option OnlyFailures { get; } = new("--onlyFailures") { Description = "Only emit output for cases that fail at runtime" }; public ParseResult Result { get; private set; } diff --git a/src/mutate-test/Program.cs b/src/mutate-test/Program.cs index 212a8ba1..6006e466 100644 --- a/src/mutate-test/Program.cs +++ b/src/mutate-test/Program.cs @@ -232,13 +232,13 @@ public Program(MutateTestRootCommand command) private static bool isFirstRun = true; - private T Get(CliOption option) => _command.Result.GetValue(option); + private T Get(Option option) => _command.Result.GetValue(option); - private static int Main(string[] args) => - new CliConfiguration(new MutateTestRootCommand(args).UseVersion()) - { - EnableParseErrorReporting = true - }.Invoke(args); + private static int Main(string[] args) + { + var command = new MutateTestRootCommand(args).UseVersion(); + return command.Parse(args).Invoke(); + } public int Run() { diff --git a/src/mutate-test/mutate-test.csproj b/src/mutate-test/mutate-test.csproj index bd600f3a..c09eb2da 100644 --- a/src/mutate-test/mutate-test.csproj +++ b/src/mutate-test/mutate-test.csproj @@ -1,10 +1,7 @@  - - Exe - net6.0 Mutate Mutate diff --git a/src/performance-explorer/performance-explorer.csproj b/src/performance-explorer/performance-explorer.csproj index 036eb0f1..87773400 100644 --- a/src/performance-explorer/performance-explorer.csproj +++ b/src/performance-explorer/performance-explorer.csproj @@ -1,8 +1,5 @@  - - - Exe diff --git a/src/pmi/pmi.csproj b/src/pmi/pmi.csproj index 344ce4c0..89ff5527 100644 --- a/src/pmi/pmi.csproj +++ b/src/pmi/pmi.csproj @@ -4,8 +4,6 @@ Exe - - diff --git a/src/superpmi/superpmicollect.csproj b/src/superpmi/superpmicollect.csproj index 95fdbc0d..52e6553d 100644 --- a/src/superpmi/superpmicollect.csproj +++ b/src/superpmi/superpmicollect.csproj @@ -4,6 +4,4 @@ Exe - - diff --git a/src/target-framework.props b/src/target-framework.props deleted file mode 100644 index c5a6fefa..00000000 --- a/src/target-framework.props +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - net8.0 - - - diff --git a/src/wasm-spmi-filter/wasm-spmi-filter.csproj b/src/wasm-spmi-filter/wasm-spmi-filter.csproj index 19d1338a..553d71b4 100644 --- a/src/wasm-spmi-filter/wasm-spmi-filter.csproj +++ b/src/wasm-spmi-filter/wasm-spmi-filter.csproj @@ -2,7 +2,6 @@ Exe - net10.0 wasm_spmi_filter enable enable From 4c1ec85dd84e16cc4df69a5357804e203f9ac5cf Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Tue, 12 May 2026 12:43:21 +0000 Subject: [PATCH 2/2] Consolidate extended help for diff subcommand --- src/jit-diff/diff.cs | 6 +- src/jit-diff/jit-diff.cs | 133 ++++++++++++++++----------------- src/jit-format/jit-format.cs | 9 +-- src/util/CommandLineHelpers.cs | 45 +++++++++++ 4 files changed, 116 insertions(+), 77 deletions(-) diff --git a/src/jit-diff/diff.cs b/src/jit-diff/diff.cs index e9cd749c..7a671de8 100644 --- a/src/jit-diff/diff.cs +++ b/src/jit-diff/diff.cs @@ -432,14 +432,14 @@ private static int CompareFrameworkAssemblies(AssemblyInfo assemblyInfo1, Assemb { string assembly1 = assemblyInfo1.Path; - if (assembly1 == s_CoreLibAssembly) + if (assembly1 == CoreLibAssemblyName) { return -1; } string assembly2 = assemblyInfo2.Path; - if (assembly2 == s_CoreLibAssembly) + if (assembly2 == CoreLibAssemblyName) { return 1; } @@ -497,7 +497,7 @@ public static List GenerateAssemblyWorklist(Config config) if (config.CoreLib || config.DoFrameworks) { const bool recursive = false; - string searchPattern = config.DoFrameworks ? "*" : s_CoreLibAssembly; + string searchPattern = config.DoFrameworks ? "*" : CoreLibAssemblyName; List directoryAssemblyInfoList = IdentifyAssemblies(config.CoreRoot, config.CoreRoot, config, recursive, searchPattern); directoryAssemblyInfoList.Sort(CompareFrameworkAssemblies); diff --git a/src/jit-diff/jit-diff.cs b/src/jit-diff/jit-diff.cs index c395c112..a8fa8b7e 100755 --- a/src/jit-diff/jit-diff.cs +++ b/src/jit-diff/jit-diff.cs @@ -5,13 +5,10 @@ using System; using System.Collections.Generic; using System.CommandLine; -using System.CommandLine.Parsing; using System.IO; -using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Runtime.InteropServices; namespace ManagedCodeGen @@ -148,7 +145,7 @@ public class Config private string _platformName = null; private string _branchName = null; private bool _pmi = false; - private IReadOnlyList _assemblyList = Array.Empty(); + private IReadOnlyList _assemblyList = []; private bool _tsv; private bool _cctors; private int _count = 20; @@ -771,65 +768,11 @@ private void Validate() if (_validationError) { - DisplayUsageMessage(); + jitdiff.DisplayCommandHelp(_command); Environment.Exit(-1); } } - private void DisplayUsageMessage() - { - Console.Error.WriteLine(""); - Console.Error.WriteLine("Usage: jit-diff [options]"); - Console.Error.WriteLine("Run 'jit-diff --help' for command-specific options."); - - if (_command == Commands.Diff) - { - string[] diffExampleText = { - @"Examples:", - @"", - @" jit-diff diff --output c:\diffs --corelib --core_root c:\runtime\artifacts\tests\coreclr\windows.x64.Release\Tests\Core_Root --base c:\runtime_base\artifacts\bin\coreclr\windows.x64.Checked --diff c:\runtime\artifacts\bin\coreclr\windows.x86.Checked", - @" Generate diffs of prejitted code for System.Private.CoreLib.dll by specifying baseline and", - @" diff compiler directories explicitly.", - @"", - @" jit-diff diff --output c:\diffs --base c:\runtime_base\artifacts\bin\coreclr\windows.x64.Checked --diff", - @" If run within the c:\runtime git clone of dotnet/runtime, does the same", - @" as the prevous example, using defaults.", - @"", - @" jit-diff diff --output c:\diffs --base --base_root c:\runtime_base --diff", - @" Does the same as the prevous example, using -base_root to find the base", - @" directory (if run from c:\runtime tree).", - @"", - @" jit-diff diff --base --diff", - @" Does the same as the prevous example (if run from c:\runtime tree), but uses", - @" default c:\runtime\artifacts\diffs output directory, and `base_root` must be specified", - @" in the config.json file in the directory pointed to by the JIT_UTILS_ROOT", - @" environment variable.", - @"", - @" jit-diff diff --base --diff --pmi", - @" Does the same as the prevous example (if run from c:\runtime tree)", - @" but shows diffs for jitted code, via PMI", - @"", - @" jit-diff diff --diff", - @" Only generates asm using the diff JIT -- does not generate asm from a baseline compiler --", - @" using all computed defaults.", - @"", - @" jit-diff diff --diff --pmi --assembly test.exe", - @" Generates asm using the diff JIT, showing jitted code for all methods", - @" in the assembly test.exe", - @"", - @" jit-diff diff --diff --arch x86", - @" Generate diffs, but for x86, even if there is an x64 compiler available.", - @"", - @" jit-diff diff --diff --build Debug", - @" Generate diffs, but using a Debug build, even if there is a Checked build available." - }; - foreach (var line in diffExampleText) - { - Console.Error.WriteLine(line); - } - } - } - private void DisplayErrorMessage(string error) { Console.Error.WriteLine("error: {0}", error); @@ -976,11 +919,18 @@ public string GetToolPath(string tool, out bool found) // Extract set value for tool and see if we can find it // in the installed tools. var tools = (JsonArray)_jObj[s_configFileRootKey]["tools"]; - var path = tools.Where(x => (string)x["tag"] == tag) - .Select(x => (string)x["path"]); - // If the tag resolves to a tool return it, otherwise just return it - // as a posible path. - return path.Any() ? path.First() : tag; + foreach (JsonNode installedTool in tools) + { + if ((string)installedTool["tag"] == tag) + { + // If the tag resolves to a tool, return the resolved path. + return (string)installedTool["path"]; + } + } + + // If the tag doesn't resolve to an installed tool, return it as + // a possible path. + return tag; } found = false; @@ -1348,13 +1298,62 @@ public int ListCommand() "V8" }; - private static string s_CoreLibAssembly = "System.Private.CoreLib.dll"; + private const string CoreLibAssemblyName = "System.Private.CoreLib.dll"; + + private static RootCommand CreateRootCommand(string[] args) => + new JitDiffRootCommand(args) + .UseVersion() + .UseExtendedHelp(PrintExtendedHelp); + + internal static void DisplayCommandHelp(Commands command) + { + string[] helpArgs = command switch + { + Commands.Diff or Commands.PmiDiff => ["diff", "--help"], + Commands.List => ["list", "--help"], + Commands.Install => ["install", "--help"], + Commands.Uninstall => ["uninstall", "--help"], + _ => ["--help"] + }; + + CreateRootCommand([]).Parse(helpArgs).Invoke(); + } + + public static void PrintExtendedHelp(ParseResult parseResult) + { + if (!string.Equals(parseResult.CommandResult.Command.Name, "diff", StringComparison.OrdinalIgnoreCase)) + { + return; + } + + Console.WriteLine(""" + + Examples: + + jit-diff diff --output c:\diffs --corelib --core_root c:\runtime\artifacts\tests\coreclr\windows.x64.Release\Tests\Core_Root --base c:\runtime_base\artifacts\bin\coreclr\windows.x64.Checked --diff c:\runtime\artifacts\bin\coreclr\windows.x64.Checked + Generate corelib prejit diffs by specifying explicit baseline and diff compiler directories. + + jit-diff diff --output c:\diffs --base --base_root c:\runtime_base --diff + If run from a dotnet/runtime clone, infer the remaining paths and architecture/build defaults. + + jit-diff diff --base --diff + Same as above, but use the default output directory under artifacts\diffs. + + jit-diff diff --base --diff --pmi + Diff jitted code via PMI instead of prejitting with crossgen. + + jit-diff diff --diff --pmi --assembly test.exe + Diff all jitted methods for a specific assembly. + + jit-diff diff --diff --arch x86 + Force x86 diffs even when x64 defaults are available. + """); + } public static int Main(string[] args) { - var command = new JitDiffRootCommand(args).UseVersion(); + var command = CreateRootCommand(args); return command.Parse(args).Invoke(); } } } - diff --git a/src/jit-format/jit-format.cs b/src/jit-format/jit-format.cs index 4d7ca752..bf508d43 100644 --- a/src/jit-format/jit-format.cs +++ b/src/jit-format/jit-format.cs @@ -2,11 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/////////////////////////////////////////////////////////////////////////////// -// -// jit-format - -// - using System; using System.Collections.Generic; using System.CommandLine; @@ -36,8 +31,8 @@ public class Config private string _build = null; private string _runtimePath = null; private string _coreclrPath = null; - private IReadOnlyList _filenames = Array.Empty(); - private IReadOnlyList _projects = Array.Empty(); + private IReadOnlyList _filenames = []; + private IReadOnlyList _projects = []; private string _srcDirectory = null; private bool _untidy = false; private bool _noformat = false; diff --git a/src/util/CommandLineHelpers.cs b/src/util/CommandLineHelpers.cs index fd1793e5..d661cb15 100644 --- a/src/util/CommandLineHelpers.cs +++ b/src/util/CommandLineHelpers.cs @@ -2,7 +2,10 @@ // 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.CommandLine.Help; +using System.CommandLine.Invocation; using System.CommandLine.Parsing; using System.IO; @@ -22,6 +25,48 @@ public static RootCommand UseVersion(this RootCommand command) return command; } + public static RootCommand UseExtendedHelp(this RootCommand command, Action customizer) + { + ConfigureHelp(command, customizer); + return command; + } + + private static void ConfigureHelp(Command command, Action customizer) + { + foreach (Option option in command.Options) + { + if (option is HelpOption helpOption) + { + helpOption.Action = new CustomizedHelpAction(helpOption, customizer); + break; + } + } + + foreach (Command subcommand in command.Subcommands) + { + ConfigureHelp(subcommand, customizer); + } + } + + private sealed class CustomizedHelpAction : SynchronousCommandLineAction + { + private readonly HelpAction _helpAction; + private readonly Action _customizer; + + public CustomizedHelpAction(HelpOption helpOption, Action customizer) + { + _helpAction = (HelpAction)helpOption.Action; + _customizer = customizer; + } + + public override int Invoke(ParseResult parseResult) + { + int result = _helpAction.Invoke(parseResult); + _customizer(parseResult); + return result; + } + } + #nullable enable public static string? GetResolvedPath(ArgumentResult result) => result.Tokens.Count > 0 ? Path.GetFullPath(result.Tokens[0].Value) : null;