Exemplo n.º 1
0
        public static int Run(string[] args)
        {
            DebugHelper.HandleDebugSwitch(ref args);

            CommonCompilerOptions commonOptions       = null;
            AssemblyInfoOptions   assemblyInfoOptions = null;
            string tempOutDir = null;
            IReadOnlyList <string> references = Array.Empty <string>();
            IReadOnlyList <string> resources  = Array.Empty <string>();
            IReadOnlyList <string> sources    = Array.Empty <string>();
            string outputName = null;
            var    help       = false;
            var    returnCode = 0;
            string helpText   = null;

            try
            {
                ArgumentSyntax.Parse(args, syntax =>
                {
                    syntax.HandleHelp   = false;
                    syntax.HandleErrors = false;

                    commonOptions = CommonCompilerOptionsExtensions.Parse(syntax);

                    assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax);

                    syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory");

                    syntax.DefineOption("out", ref outputName, "Name of the output assembly");

                    syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference");

                    syntax.DefineOptionList("resource", ref resources, "Resources to embed");

                    syntax.DefineOption("h|help", ref help, "Help for compile native.");

                    syntax.DefineParameterList("source-files", ref sources, "Compilation sources");

                    helpText = syntax.GetHelpText();

                    if (tempOutDir == null)
                    {
                        syntax.ReportError("Option '--temp-output' is required");
                    }
                });
            }
            catch (ArgumentSyntaxException exception)
            {
                Console.Error.WriteLine(exception.Message);
                help       = true;
                returnCode = ExitFailed;
            }

            if (help)
            {
                Console.WriteLine(helpText);

                return(returnCode);
            }


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

            // 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 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(resources.Select(resource => $"--resource:{resource.Replace("\"", "")}"));

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

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

                //HACK we need default.win32manifest for exe
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    var win32manifestPath = Path.Combine(AppContext.BaseDirectory, "default.win32manifest");
                    allArgs.Add($"--win32manifest:{win32manifestPath}");
                }
            }

            if (commonOptions.SuppressWarnings != null)
            {
                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(sources, 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}"
            })
                         .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);
        }
Exemplo n.º 2
0
        public static int Main(string[] args)
        {
            DebugHelper.HandleDebugSwitch(ref args);

            CommonCompilerOptions commonOptions       = null;
            AssemblyInfoOptions   assemblyInfoOptions = null;
            string tempOutDir = null;
            IReadOnlyList <string> references = Array.Empty <string>();
            IReadOnlyList <string> resources  = Array.Empty <string>();
            IReadOnlyList <string> sources    = Array.Empty <string>();
            string outputName = null;
            var    help       = false;
            var    returnCode = 0;
            string helpText   = null;

            try
            {
                ArgumentSyntax.Parse(args, syntax =>
                {
                    syntax.HandleHelp   = false;
                    syntax.HandleErrors = false;

                    commonOptions = CommonCompilerOptionsExtensions.Parse(syntax);

                    assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax);

                    syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory");

                    syntax.DefineOption("out", ref outputName, "Name of the output assembly");

                    syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference");

                    syntax.DefineOptionList("resource", ref resources, "Resources to embed");

                    syntax.DefineOption("h|help", ref help, "Help for compile native.");

                    syntax.DefineParameterList("source-files", ref sources, "Compilation sources");

                    helpText = syntax.GetHelpText();

                    if (tempOutDir == null)
                    {
                        syntax.ReportError("Option '--temp-output' is required");
                    }
                });
            }
            catch (ArgumentSyntaxException exception)
            {
                Console.Error.WriteLine(exception.Message);
                help       = true;
                returnCode = ExitFailed;
            }

            if (help)
            {
                Console.WriteLine(helpText);

                return(returnCode);
            }

            var translated = TranslateCommonOptions(commonOptions, outputName);

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

            allArgs.AddRange(GetDefaultOptions());

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

            File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions));
            allArgs.Add($"\"{assemblyInfo}\"");

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

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

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

            allArgs.AddRange(references.Select(r => $"-r:\"{r}\""));
            allArgs.AddRange(resources.Select(resource => $"--resource:{resource}"));
            allArgs.AddRange(sources.Select(s => $"\"{s}\""));

            var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp");

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

            // Execute FSC!
            var result = RunFsc(string.Join(" ", allArgs))
                         .ForwardStdErr()
                         .ForwardStdOut()
                         .Execute();

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

            return(result.ExitCode);
        }
Exemplo n.º 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);
            }
        }