Example #1
0
        public static CommandLineBuilder Build()
        {
            var parser = new CommandLineBuilder()
                         .AddCommand(CompileFolder())
                         .AddCommand(CompileSubtree())
                         .AddCommand(CompileFramework())
                         .AddCommand(CompileNugetPackages())
                         .AddCommand(CompileSerp());

            return(parser);

            Command CreateCommand(string name, string description, Option[] options, Func <BuildOptions, int> action)
            {
                Command command = new Command(name, description);

                foreach (var option in GetCommonOptions())
                {
                    command.AddOption(option);
                }
                foreach (var option in options)
                {
                    command.AddOption(option);
                }
                command.Handler = CommandHandler.Create <BuildOptions>(action);
                return(command);
            }

            Option[] GetCommonOptions() => new[] { CoreRootDirectory(), DotNetCli() };

            Command CompileFolder() =>
            CreateCommand("compile-directory", "Compile all assemblies in directory",
                          new Option[]
            {
                InputDirectory(),
                OutputDirectory(),
                Crossgen(),
                CrossgenPath(),
                Crossgen2Path(),
                TargetArch(),
                VerifyTypeAndFieldLayout(),
                NoJit(),
                NoCrossgen2(),
                Exe(),
                NoExe(),
                NoEtw(),
                NoCleanup(),
                Map(),
                DegreeOfParallelism(),
                Sequential(),
                Framework(),
                UseFramework(),
                Release(),
                LargeBubble(),
                Composite(),
                Crossgen2Parallelism(),
                Crossgen2JitPath(),
                ReferencePath(),
                IssuesPath(),
                CompilationTimeoutMinutes(),
                ExecutionTimeoutMinutes(),
                R2RDumpPath(),
                MeasurePerf(),
                InputFileSearchString(),
            },
                          CompileDirectoryCommand.CompileDirectory);

            Command CompileSubtree() =>
            CreateCommand("compile-subtree", "Build each directory in a given subtree containing any managed assemblies as a separate app",
                          new Option[]
            {
                InputDirectory(),
                OutputDirectory(),
                Crossgen(),
                CrossgenPath(),
                Crossgen2Path(),
                TargetArch(),
                VerifyTypeAndFieldLayout(),
                NoJit(),
                NoCrossgen2(),
                Exe(),
                NoExe(),
                NoEtw(),
                NoCleanup(),
                Map(),
                DegreeOfParallelism(),
                Sequential(),
                Framework(),
                UseFramework(),
                Release(),
                LargeBubble(),
                Composite(),
                Crossgen2Parallelism(),
                Crossgen2JitPath(),
                ReferencePath(),
                IssuesPath(),
                CompilationTimeoutMinutes(),
                ExecutionTimeoutMinutes(),
                R2RDumpPath(),
                GCStress(),
            },
                          CompileSubtreeCommand.CompileSubtree);

            Command CompileFramework() =>
            CreateCommand("compile-framework", "Compile managed framework assemblies in Core_Root",
                          new Option[]
            {
                Crossgen(),
                CrossgenPath(),
                Crossgen2Path(),
                TargetArch(),
                VerifyTypeAndFieldLayout(),
                NoCrossgen2(),
                NoCleanup(),
                Crossgen2Parallelism(),
                Crossgen2JitPath(),
                DegreeOfParallelism(),
                Sequential(),
                Release(),
                LargeBubble(),
                Composite(),
                ReferencePath(),
                IssuesPath(),
                CompilationTimeoutMinutes(),
                R2RDumpPath(),
                MeasurePerf(),
                InputFileSearchString(),
                OutputDirectory(),
            },
                          CompileFrameworkCommand.CompileFramework);

            Command CompileNugetPackages() =>
            CreateCommand("compile-nuget", "Restore a list of Nuget packages into an empty console app, publish, and optimize with Crossgen / CPAOT",
                          new Option[]
            {
                R2RDumpPath(),
                InputDirectory(),
                OutputDirectory(),
                PackageList(),
                Crossgen(),
                NoCleanup(),
                DegreeOfParallelism(),
                CompilationTimeoutMinutes(),
                ExecutionTimeoutMinutes(),
            },
                          CompileNugetCommand.CompileNuget);

            Command CompileSerp() =>
            CreateCommand("compile-serp", "Compile existing application",
                          new Option[]
            {
                InputDirectory(),
                DegreeOfParallelism(),
                AspNetPath(),
                CompositeScenario()
            },
                          options =>
            {
                var compileSerp = new CompileSerpCommand(options);
                return(compileSerp.CompileSerpAssemblies());
            });

            // Todo: Input / Output directories should be required arguments to the command when they're made available to handlers
            // https://github.com/dotnet/command-line-api/issues/297
            Option InputDirectory() =>
            new Option <DirectoryInfo>(new[] { "--input-directory", "-in" }, "Folder containing assemblies to optimize").ExistingOnly();

            Option OutputDirectory() =>
            new Option <DirectoryInfo>(new[] { "--output-directory", "-out" }, "Folder to emit compiled assemblies").LegalFilePathsOnly();

            Option CoreRootDirectory() =>
            new Option <DirectoryInfo>(new[] { "--core-root-directory", "-cr" }, "Location of the CoreCLR CORE_ROOT folder")
            {
                Required = true
            }.ExistingOnly();

            Option ReferencePath() =>
            new Option <DirectoryInfo[]>(new[] { "--reference-path", "-r" }, "Folder containing assemblies to reference during compilation")
            { Argument = new Argument <DirectoryInfo[]>()
              {
                  Arity = ArgumentArity.ZeroOrMore
              }.ExistingOnly() };

            Option Crossgen() =>
            new Option <bool>(new[] { "--crossgen" }, "Compile the apps using Crossgen in the CORE_ROOT folder");

            Option CrossgenPath() =>
            new Option <FileInfo>(new[] { "--crossgen-path", "-cp" }, "Explicit Crossgen path (useful for cross-targeting)").ExistingOnly();

            Option Crossgen2Path() =>
            new Option <FileInfo>(new[] { "--crossgen2-path", "-c2p" }, "Explicit Crossgen2 path (useful for cross-targeting)").ExistingOnly();

            Option VerifyTypeAndFieldLayout() =>
            new Option <bool>(new[] { "--verify-type-and-field-layout" }, "Verify that struct type layout and field offsets match between compile time and runtime. Use only for diagnostic purposes.");

            Option NoJit() =>
            new Option <bool>(new[] { "--nojit" }, "Don't run tests in JITted mode");

            Option NoCrossgen2() =>
            new Option <bool>(new[] { "--nocrossgen2" }, "Don't run tests in Crossgen2 mode");

            Option Exe() =>
            new Option <bool>(new[] { "--exe" }, "Don't compile tests, just execute them");

            Option NoExe() =>
            new Option <bool>(new[] { "--noexe" }, "Compilation-only mode (don't execute the built apps)");

            Option NoEtw() =>
            new Option <bool>(new[] { "--noetw" }, "Don't capture jitted methods using ETW");

            Option NoCleanup() =>
            new Option <bool>(new[] { "--nocleanup" }, "Don't clean up compilation artifacts after test runs");

            Option Map() =>
            new Option <bool>(new[] { "--map" }, "Generate a map file (Crossgen2)");

            Option DegreeOfParallelism() =>
            new Option <int>(new[] { "--degree-of-parallelism", "-dop" }, "Override default compilation / execution DOP (default = logical processor count)");

            Option Sequential() =>
            new Option <bool>(new[] { "--sequential" }, "Run tests sequentially");

            Option Framework() =>
            new Option <bool>(new[] { "--framework" }, "Precompile and use native framework");

            Option UseFramework() =>
            new Option <bool>(new[] { "--use-framework" }, "Use native framework (don't precompile, assume previously compiled)");

            Option Release() =>
            new Option <bool>(new[] { "--release" }, "Build the tests in release mode");

            Option LargeBubble() =>
            new Option <bool>(new[] { "--large-bubble" }, "Assume all input files as part of one version bubble");

            Option Composite() =>
            new Option <bool>(new[] { "--composite" }, "Compile tests in composite R2R mode");

            Option Crossgen2Parallelism() =>
            new Option <int>(new[] { "--crossgen2-parallelism" }, "Max number of threads to use in Crossgen2 (default = logical processor count)");

            Option Crossgen2JitPath() =>
            new Option <FileInfo>(new[] { "--crossgen2-jitpath" }, "Jit path to use for crossgen2");

            Option IssuesPath() =>
            new Option <FileInfo[]>(new[] { "--issues-path", "-ip" }, "Path to issues.targets")
            { Argument = new Argument <FileInfo[]>()
              {
                  Arity = ArgumentArity.ZeroOrMore
              } };

            Option CompilationTimeoutMinutes() =>
            new Option <int>(new[] { "--compilation-timeout-minutes", "-ct" }, "Compilation timeout (minutes)");

            Option ExecutionTimeoutMinutes() =>
            new Option <int>(new[] { "--execution-timeout-minutes", "-et" }, "Execution timeout (minutes)");

            Option R2RDumpPath() =>
            new Option <FileInfo>(new[] { "--r2r-dump-path", "-r2r" }, "Path to R2RDump.exe/dll").ExistingOnly();;

            Option MeasurePerf() =>
            new Option <bool>(new[] { "--measure-perf" }, "Print out compilation time");

            Option InputFileSearchString() =>
            new Option <string>(new[] { "--input-file-search-string", "-input-file" }, "Search string for input files in the input directory");

            Option GCStress() =>
            new Option <string>(new[] { "--gcstress" }, "Run tests with the specified GC stress level enabled (the argument value is in hex)");

            Option DotNetCli() =>
            new Option <string>(new [] { "--dotnet-cli", "-cli" }, "For dev box testing, point at .NET 5 dotnet.exe or <repo>/dotnet.cmd.");

            Option TargetArch() =>
            new Option <string>(new[] { "--target-arch" }, "Target architecture for crossgen2");

            //
            // compile-nuget specific options
            //
            Option PackageList() =>
            new Option <FileInfo>(new[] { "--package-list", "-pl" }, "Text file containing a package name on each line").ExistingOnly();;

            //
            // compile-serp specific options
            //
            Option AspNetPath() =>
            new Option <DirectoryInfo>(new[] { "--asp-net-path", "-asp" }, "Path to SERP's ASP.NET Core folder").ExistingOnly();

            Option CompositeScenario() =>
            new Option <SerpCompositeScenario>(new [] { "--composite-scenario", "-cs" }, "Specifies which layers of a shared framework application are compiled as composite");
        }
        R2RTestRootCommand()
        {
            CreateCommand("compile-directory", "Compile all assemblies in directory",
                          new Option[]
            {
                InputDirectory,
                OutputDirectory,
                Crossgen2Path,
                TargetArch,
                VerifyTypeAndFieldLayout,
                NoJit,
                NoCrossgen2,
                Exe,
                NoExe,
                NoEtw,
                NoCleanup,
                Map,
                Pdb,
                Perfmap,
                PerfmapFormatVersion,
                DegreeOfParallelism,
                Sequential,
                Iterations,
                Framework,
                UseFramework,
                Release,
                LargeBubble,
                Composite,
                Crossgen2Parallelism,
                Crossgen2JitPath,
                ReferencePath,
                IssuesPath,
                CompilationTimeoutMinutes,
                ExecutionTimeoutMinutes,
                R2RDumpPath,
                MeasurePerf,
                InputFileSearchString,
                MibcPath,
            },
                          CompileDirectoryCommand.CompileDirectory);

            CreateCommand("compile-subtree", "Build each directory in a given subtree containing any managed assemblies as a separate app",
                          new Option[]
            {
                InputDirectory,
                OutputDirectory,
                Crossgen2Path,
                TargetArch,
                VerifyTypeAndFieldLayout,
                NoJit,
                NoCrossgen2,
                Exe,
                NoExe,
                NoEtw,
                NoCleanup,
                Map,
                Pdb,
                Perfmap,
                PerfmapFormatVersion,
                DegreeOfParallelism,
                Sequential,
                Iterations,
                Framework,
                UseFramework,
                Release,
                LargeBubble,
                Composite,
                Crossgen2Parallelism,
                Crossgen2JitPath,
                ReferencePath,
                IssuesPath,
                CompilationTimeoutMinutes,
                ExecutionTimeoutMinutes,
                R2RDumpPath,
                GCStress,
                MibcPath,
            },
                          CompileSubtreeCommand.CompileSubtree);

            CreateCommand("compile-framework", "Compile managed framework assemblies in Core_Root",
                          new Option[]
            {
                Crossgen2Path,
                TargetArch,
                VerifyTypeAndFieldLayout,
                NoCrossgen2,
                NoCleanup,
                Map,
                Pdb,
                Perfmap,
                PerfmapFormatVersion,
                Crossgen2Parallelism,
                Crossgen2JitPath,
                DegreeOfParallelism,
                Sequential,
                Iterations,
                Release,
                LargeBubble,
                Composite,
                ReferencePath,
                IssuesPath,
                CompilationTimeoutMinutes,
                R2RDumpPath,
                MeasurePerf,
                InputFileSearchString,
                OutputDirectory,
                MibcPath,
            },
                          CompileFrameworkCommand.CompileFramework);

            CreateCommand("compile-nuget", "Restore a list of Nuget packages into an empty console app, publish, and optimize with Crossgen / CPAOT",
                          new Option[]
            {
                R2RDumpPath,
                InputDirectory,
                OutputDirectory,
                PackageList,
                NoCleanup,
                Map,
                Pdb,
                Perfmap,
                PerfmapFormatVersion,
                DegreeOfParallelism,
                CompilationTimeoutMinutes,
                ExecutionTimeoutMinutes,
                MibcPath,
            },
                          CompileNugetCommand.CompileNuget);

            CreateCommand("compile-serp", "Compile existing application",
                          new Option[]
            {
                InputDirectory,
                DegreeOfParallelism,
                AspNetPath,
                Composite,
                Map,
                Pdb,
                Perfmap,
                PerfmapFormatVersion,
                CompilationTimeoutMinutes,
                Crossgen2Path,
                MibcPath,
            },
                          options =>
            {
                var compileSerp = new CompileSerpCommand(options);
                return(compileSerp.CompileSerpAssemblies());
            });
        }