Example #1
0
        public static int Main(string[] args)
        {
            DebugHelper.HandleDebugSwitch(ref args);

            CommandLineApplication app = new CommandLineApplication();

            app.Name                = "dotnet compile-vbc";
            app.FullName            = ".NET VB Compiler";
            app.Description         = "VB Compiler for the .NET Platform";
            app.HandleResponseFiles = true;
            app.HelpOption("-h|--help");

            CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app);
            AssemblyInfoOptionsCommandLine   assemblyInfoCommandLine   = AssemblyInfoOptionsCommandLine.AddOptions(app);

            CommandOption   tempOutput = app.Option("--temp-output <arg>", "Compilation temporary directory", CommandOptionType.SingleValue);
            CommandOption   outputName = app.Option("--out <arg>", "Name of the output assembly", CommandOptionType.SingleValue);
            CommandOption   references = app.Option("--reference <arg>...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue);
            CommandOption   analyzers  = app.Option("--analyzer <arg>...", "Path to an analyzer assembly", CommandOptionType.MultipleValue);
            CommandOption   resources  = app.Option("--resource <arg>...", "Resources to embed", CommandOptionType.MultipleValue);
            CommandArgument sources    = app.Argument("<source-files>...", "Compilation sources", multipleValues: true);

            app.OnExecute(() =>
            {
                if (!tempOutput.HasValue())
                {
                    Reporter.Error.WriteLine("Option '--temp-output' is required");
                    return(ExitFailed);
                }

                CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues();

                AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues();

                var translated = TranslateCommonOptions(commonOptions, outputName.Value());

                var allArgs = new List <string>(translated);
                allArgs.AddRange(GetDefaultOptions());

                // Generate assembly info

                /*DISABLED BECAUSE AssemblyInfoGenerator doesnt undertstand vb
                 * just add something like https://github.com/dotnet/cli/blob/04f40f906dce2678d80fb9787e68de76ee6bf57e/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoFileGenerator.cs#L19
                 *
                 * var assemblyInfo = Path.Combine(tempOutput.Value(), $"dotnet-compile.assemblyinfo.vb");
                 *
                 * File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources.Values));
                 *
                 * allArgs.Add($"\"{assemblyInfo}\"");
                 *
                 */

                if (outputName.HasValue())
                {
                    allArgs.Add($"-out:\"{outputName.Value()}\"");
                }

                allArgs.AddRange(analyzers.Values.Select(a => $"-a:\"{a}\""));
                allArgs.AddRange(references.Values.Select(r => $"-r:\"{r}\""));

                // Resource has two parts separated by a comma
                // Only the first should be quoted. This is handled
                // in dotnet-compile where the information is present.
                allArgs.AddRange(resources.Values.Select(resource => $"-resource:{resource}"));

                allArgs.AddRange(sources.Values.Select(s => $"\"{s}\""));

                var rsp = Path.Combine(tempOutput.Value(), "dotnet-compile-vbc.rsp");

                File.WriteAllLines(rsp, allArgs, Encoding.UTF8);

                // Execute VBC!
                var result = RunVbc(new string[] { $"-noconfig", "@" + $"{rsp}" })
                             .WorkingDirectory(Directory.GetCurrentDirectory())
                             .ForwardStdErr()
                             .ForwardStdOut()
                             .Execute();

                // RENAME things
                // This is currently necessary as the BUILD task of the dotnet executable expects (at this stage) a .DLL (not an EXE).
                var outExe = outputName.Value();
                outExe     = outExe + ".exe";
                if (!string.IsNullOrEmpty(outExe) && File.Exists(outExe))
                {
                    string outDll = outExe.Replace(".dll.exe", ".dll");
                    if (File.Exists(outDll))
                    {
                        File.Delete(outDll);
                    }
                    System.IO.File.Move(outExe, outDll);

                    string outPdbOrig = outExe.Replace(".dll.exe", ".dll.pdb");
                    string outPdb     = outPdbOrig.Replace(".dll.pdb", ".pdb");
                    if (File.Exists(outPdb))
                    {
                        File.Delete(outPdb);
                    }
                    System.IO.File.Move(outPdbOrig, outPdb);
                }

                return(result.ExitCode);
            });

            try
            {
                return(app.Execute(args));
            }
            catch (Exception ex)
            {
#if DEBUG
                Reporter.Error.WriteLine(ex.ToString());
#else
                Reporter.Error.WriteLine(ex.Message);
#endif
                return(ExitFailed);
            }
        }
Example #2
0
        public static int Run(string[] args)
        {
            DebugHelper.HandleDebugSwitch(ref args);

            CommandLineApplication app = new CommandLineApplication();

            app.Name        = "dotnet compile-csc-linq-rewrite";
            app.FullName    = ".NET C# Compiler with LINQ rewrite";
            app.Description = "C# Compiler for the .NET Platform with LINQ rewrite optimizations";

            app.HandleResponseFiles = true;
            app.HelpOption("-h|--help");

            CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app);
            AssemblyInfoOptionsCommandLine   assemblyInfoCommandLine   = AssemblyInfoOptionsCommandLine.AddOptions(app);

            CommandOption   tempOutput = app.Option("--temp-output <arg>", "Compilation temporary directory", CommandOptionType.SingleValue);
            CommandOption   outputName = app.Option("--out <arg>", "Name of the output assembly", CommandOptionType.SingleValue);
            CommandOption   references = app.Option("--reference <arg>...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue);
            CommandOption   analyzers  = app.Option("--analyzer <arg>...", "Path to an analyzer assembly", CommandOptionType.MultipleValue);
            CommandOption   resources  = app.Option("--resource <arg>...", "Resources to embed", CommandOptionType.MultipleValue);
            CommandArgument sources    = app.Argument("<source-files>...", "Compilation sources", multipleValues: true);

            app.OnExecute(() =>
            {
                if (!tempOutput.HasValue())
                {
                    Reporter.Error.WriteLine("Option '--temp-output' is required");
                    return(ExitFailed);
                }

                CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues();

                AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues();

                var translated = TranslateCommonOptions(commonOptions, outputName.Value());

                var allArgs = new List <string>(translated);
                allArgs.AddRange(GetDefaultOptions());

                // Generate assembly info
                var assemblyInfo = Path.Combine(tempOutput.Value(), $"dotnet-compile.assemblyinfo.cs");

                File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources.Values));

                allArgs.Add($"\"{assemblyInfo}\"");

                if (outputName.HasValue())
                {
                    allArgs.Add($"-out:\"{outputName.Value()}\"");
                }

                allArgs.AddRange(analyzers.Values.Select(a => $"-a:\"{a}\""));
                allArgs.AddRange(references.Values.Select(r => $"-r:\"{r}\""));

                // Resource has two parts separated by a comma
                // Only the first should be quoted. This is handled
                // in dotnet-compile where the information is present.
                allArgs.AddRange(resources.Values.Select(resource => $"-resource:{resource}"));

                allArgs.AddRange(sources.Values.Select(s => $"\"{s}\""));

                var rsp = Path.Combine(tempOutput.Value(), "dotnet-compile-csc.rsp");

                File.WriteAllLines(rsp, allArgs, Encoding.UTF8);

                // Execute CSC!

                return(Microsoft.CodeAnalysis.CSharp.CommandLine.ProgramLinqRewrite.MainInternal(new string[] { $"-noconfig", "@" + $"{rsp}" }));
            });

            try
            {
                return(app.Execute(args));
            }
            catch (Exception ex)
            {
//#if DEBUG
                Reporter.Error.WriteLine(ex.ToString());
//#else
//                Reporter.Error.WriteLine(ex.Message);
///#endif
                return(ExitFailed);
            }
        }
Example #3
0
        public static int Main(string[] args)
        {
            DebugHelper.HandleDebugSwitch(ref args);

            CommandLineApplication app = new CommandLineApplication();

            app.Name                = "dotnet compile-fsc";
            app.FullName            = ".NET F# Compiler";
            app.Description         = "F# Compiler for the .NET Platform";
            app.HandleResponseFiles = true;
            app.HelpOption("-h|--help");

            CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app);
            AssemblyInfoOptionsCommandLine   assemblyInfoCommandLine   = AssemblyInfoOptionsCommandLine.AddOptions(app);

            CommandOption   tempOutputOption = app.Option("--temp-output <arg>", "Compilation temporary directory", CommandOptionType.SingleValue);
            CommandOption   outputNameOption = app.Option("--out <arg>", "Name of the output assembly", CommandOptionType.SingleValue);
            CommandOption   referencesOption = app.Option("--reference <arg>...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue);
            CommandOption   resourcesOption  = app.Option("--resource <arg>...", "Resources to embed", CommandOptionType.MultipleValue);
            CommandArgument sourcesArgument  = app.Argument("<source-files>...", "Compilation sources", multipleValues: true);

            app.OnExecute(() =>
            {
                if (!tempOutputOption.HasValue())
                {
                    Reporter.Error.WriteLine("Option '--temp-output' is required");
                    return(ExitFailed);
                }

                CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues();

                AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues();

                // TODO less hacky
                bool targetNetCore =
                    commonOptions.Defines.Contains("DNXCORE50") ||
                    commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARDAPP1_")).Any() ||
                    commonOptions.Defines.Where(d => d.StartsWith("NETCOREAPP1_")).Any() ||
                    commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any();

                // Get FSC Path upfront to use it for win32manifest path
                string tempOutDir  = tempOutputOption.Value();
                var fscCommandSpec = ResolveFsc(null, tempOutDir);
                var fscExeFile     = fscCommandSpec.FscExeFile;
                var fscExeDir      = fscCommandSpec.FscExeDir;

                // FSC arguments
                var allArgs = new List <string>();

                //HACK fsc raise error FS0208 if target exe doesnt have extension .exe
                bool hackFS0208 = targetNetCore && commonOptions.EmitEntryPoint == true;

                string outputName      = outputNameOption.Value();
                var originalOutputName = outputName;

                if (outputName != null)
                {
                    if (hackFS0208)
                    {
                        outputName = Path.ChangeExtension(outputName, ".exe");
                    }

                    allArgs.Add($"--out:{outputName}");
                }

                //let's pass debugging type only if options.DebugType is specified, until
                //portablepdb are confirmed to work.
                //so it's possibile to test portable pdb without breaking existing build
                if (string.IsNullOrEmpty(commonOptions.DebugType))
                {
                    //debug info (only windows pdb supported, not portablepdb)
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        allArgs.Add("--debug");
                        //TODO check if full or pdbonly
                        allArgs.Add("--debug:pdbonly");
                    }
                    else
                    {
                        allArgs.Add("--debug-");
                    }
                }
                else
                {
                    allArgs.Add("--debug");
                    allArgs.Add($"--debug:{commonOptions.DebugType}");
                }

                // Default options
                allArgs.Add("--noframework");
                allArgs.Add("--nologo");
                allArgs.Add("--simpleresolution");
                allArgs.Add("--nocopyfsharpcore");

                // project.json compilationOptions
                if (commonOptions.Defines != null)
                {
                    allArgs.AddRange(commonOptions.Defines.Select(def => $"--define:{def}"));
                }

                if (commonOptions.GenerateXmlDocumentation == true)
                {
                    allArgs.Add($"--doc:{Path.ChangeExtension(outputName, "xml")}");
                }

                if (commonOptions.KeyFile != null)
                {
                    allArgs.Add($"--keyfile:{commonOptions.KeyFile}");
                }

                if (commonOptions.Optimize == true)
                {
                    allArgs.Add("--optimize+");
                }

                //--resource doesnt expect "
                //bad: --resource:"path/to/file",name
                //ok:  --resource:path/to/file,name
                allArgs.AddRange(resourcesOption.Values.Select(resource => $"--resource:{resource.Replace("\"", "")}"));

                allArgs.AddRange(referencesOption.Values.Select(r => $"-r:{r}"));

                if (commonOptions.EmitEntryPoint != true)
                {
                    allArgs.Add("--target:library");
                }
                else
                {
                    allArgs.Add("--target:exe");

                    //HACK we need default.win32manifest for exe
                    var win32manifestPath = Path.Combine(fscExeDir, "..", "..", "runtimes", "any", "native", "default.win32manifest");
                    allArgs.Add($"--win32manifest:{win32manifestPath}");
                }

                if (commonOptions.SuppressWarnings != null && commonOptions.SuppressWarnings.Any())
                {
                    allArgs.Add("--nowarn:" + string.Join(",", commonOptions.SuppressWarnings.ToArray()));
                }

                if (commonOptions.LanguageVersion != null)
                {
                    // Not used in fsc
                }

                if (commonOptions.Platform != null)
                {
                    allArgs.Add($"--platform:{commonOptions.Platform}");
                }

                if (commonOptions.AllowUnsafe == true)
                {
                }

                if (commonOptions.WarningsAsErrors == true)
                {
                    allArgs.Add("--warnaserror");
                }

                //set target framework
                if (targetNetCore)
                {
                    allArgs.Add("--targetprofile:netcore");
                }

                if (commonOptions.DelaySign == true)
                {
                    allArgs.Add("--delaysign+");
                }

                if (commonOptions.PublicSign == true)
                {
                }

                if (commonOptions.AdditionalArguments != null)
                {
                    // Additional arguments are added verbatim
                    allArgs.AddRange(commonOptions.AdditionalArguments);
                }

                // Generate assembly info
                var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.fs");
                File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions));

                //source files + assemblyInfo
                allArgs.AddRange(GetSourceFiles(sourcesArgument.Values, assemblyInfo).ToArray());

                //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration

                var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp");
                File.WriteAllLines(rsp, allArgs, Encoding.UTF8);

                // Execute FSC!
                var result = RunFsc(new List <string> {
                    $"@{rsp}"
                }, tempOutDir)
                             .ForwardStdErr()
                             .ForwardStdOut()
                             .Execute();

                bool successFsc = result.ExitCode == 0;

                if (hackFS0208 && File.Exists(outputName))
                {
                    if (File.Exists(originalOutputName))
                    {
                        File.Delete(originalOutputName);
                    }
                    File.Move(outputName, originalOutputName);
                }

                //HACK dotnet build require a pdb (crash without), fsc atm cant generate a portable pdb, so an empty pdb is created
                string pdbPath = Path.ChangeExtension(outputName, ".pdb");
                if (successFsc && !File.Exists(pdbPath))
                {
                    File.WriteAllBytes(pdbPath, Array.Empty <byte>());
                }

                return(result.ExitCode);
            });

            try
            {
                return(app.Execute(args));
            }
            catch (Exception ex)
            {
#if DEBUG
                Reporter.Error.WriteLine(ex.ToString());
#else
                Reporter.Error.WriteLine(ex.Message);
#endif
                return(ExitFailed);
            }
        }