Remove System.CommandLine dependency.

Also removed the dependency on Microsoft.Extensions.CommandLineUtils.Sources NuGet package and instead just checking the source files into our repo as internal classes.

Fix #2526
This commit is contained in:
Eric Erhardt 2016-04-19 22:51:32 -05:00
parent d06418509d
commit 44483ddc98
41 changed files with 1411 additions and 840 deletions

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED2FE3E2-F7E7-4389-8231-B65123F2076F}"
EndProject
@ -101,6 +101,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestPackages", "TestPackage
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-dependency-tool-invoker", "TestAssets\TestPackages\dotnet-dependency-tool-invoker\dotnet-dependency-tool-invoker.xproj", "{C26A48BB-193F-450C-AB09-4D3324C78188}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Compiler.Common.Tests", "test\Microsoft.DotNet.Compiler.Common.Tests\Microsoft.DotNet.Compiler.Common.Tests.xproj", "{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -705,6 +707,22 @@ Global
{C26A48BB-193F-450C-AB09-4D3324C78188}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{C26A48BB-193F-450C-AB09-4D3324C78188}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{C26A48BB-193F-450C-AB09-4D3324C78188}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|x64.ActiveCfg = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|x64.Build.0 = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|Any CPU.Build.0 = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|x64.ActiveCfg = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|x64.Build.0 = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -752,5 +770,6 @@ Global
{ADA7052B-884B-4776-8B8D-D04191D0AA70} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{1AB5B24B-B317-4142-A5D1-A6E84F15BA34} = {ADA7052B-884B-4776-8B8D-D04191D0AA70}
{C26A48BB-193F-450C-AB09-4D3324C78188} = {1AB5B24B-B317-4142-A5D1-A6E84F15BA34}
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
EndGlobalSection
EndGlobal

View file

@ -1,15 +1,11 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using NuGet.Frameworks;
using static System.Int32;
namespace Microsoft.DotNet.Tools.DependencyInvoker
{

View file

@ -3,6 +3,10 @@
"compilationOptions": {
"emitEntryPoint": true
},
"compile": [
"**/*.cs",
"../../../src/dotnet/CommandLine/*.cs"
],
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
@ -10,12 +14,7 @@
},
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
"Microsoft.Extensions.CommandLineUtils.Sources": {
"type": "build",
"version": "1.0.0-rc2-16453"
},
"System.CommandLine": "0.1.0-e160323-1"
"Microsoft.DotNet.Compiler.Common": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {

View file

@ -3,30 +3,29 @@
using Microsoft.DotNet.ProjectModel;
using System.Collections.Generic;
using System.CommandLine;
using NuGet.Frameworks;
namespace Microsoft.DotNet.Cli.Compiler.Common
{
public class AssemblyInfoOptions
{
private const string TitleOptionName = "title";
public static readonly string TitleOptionName = "title";
private const string DescriptionOptionName = "description";
public static readonly string DescriptionOptionName = "description";
private const string CopyrightOptionName = "copyright";
public static readonly string CopyrightOptionName = "copyright";
private const string AssemblyFileVersionOptionName = "file-version";
public static readonly string AssemblyFileVersionOptionName = "file-version";
private const string AssemblyVersionOptionName = "version";
public static readonly string AssemblyVersionOptionName = "version";
private const string InformationalVersionOptionName = "informational-version";
public static readonly string InformationalVersionOptionName = "informational-version";
private const string CultureOptionName = "culture";
public static readonly string CultureOptionName = "culture";
private const string NeutralCultureOptionName = "neutral-language";
public static readonly string NeutralCultureOptionName = "neutral-language";
private const string TargetFrameworkOptionName = "target-framework";
public static readonly string TargetFrameworkOptionName = "target-framework";
public string Title { get; set; }
@ -73,49 +72,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
};
}
public static AssemblyInfoOptions Parse(ArgumentSyntax syntax)
{
string version = null;
string informationalVersion = null;
string fileVersion = null;
string title = null;
string description = null;
string copyright = null;
string culture = null;
string neutralCulture = null;
string targetFramework = null;
syntax.DefineOption(AssemblyVersionOptionName, ref version, UnescapeNewlines, "Assembly version");
syntax.DefineOption(TitleOptionName, ref title, UnescapeNewlines, "Assembly title");
syntax.DefineOption(DescriptionOptionName, ref description, UnescapeNewlines, "Assembly description");
syntax.DefineOption(CopyrightOptionName, ref copyright, UnescapeNewlines, "Assembly copyright");
syntax.DefineOption(NeutralCultureOptionName, ref neutralCulture, UnescapeNewlines, "Assembly neutral culture");
syntax.DefineOption(CultureOptionName, ref culture, UnescapeNewlines, "Assembly culture");
syntax.DefineOption(InformationalVersionOptionName, ref informationalVersion, UnescapeNewlines, "Assembly informational version");
syntax.DefineOption(AssemblyFileVersionOptionName, ref fileVersion, UnescapeNewlines, "Assembly title");
syntax.DefineOption(TargetFrameworkOptionName, ref targetFramework, UnescapeNewlines, "Assembly target framework");
return new AssemblyInfoOptions()
{
AssemblyFileVersion = fileVersion,
AssemblyVersion = version,
Copyright = copyright,
NeutralLanguage = neutralCulture,
Description = description,
InformationalVersion = informationalVersion,
Title = title,
TargetFramework = targetFramework
};
}
public static IEnumerable<string> SerializeToArgs(AssemblyInfoOptions assemblyInfoOptions)
{
var options = new List<string>();
@ -165,10 +121,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
return $"--{optionName}:{EscapeNewlines(value)}";
}
private static string UnescapeNewlines(string text)
{
return text.Replace("\\r", "\r").Replace("\\n", "\n");
}
private static string EscapeNewlines(string text)
{
return text.Replace("\r", "\\r").Replace("\n", "\\n");

View file

@ -1,9 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.Linq;
using Microsoft.DotNet.ProjectModel;
@ -12,115 +10,51 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
{
public static class CommonCompilerOptionsExtensions
{
internal static readonly OptionTemplate s_definesTemplate = new OptionTemplate("define");
public static readonly string DefineOptionName = "define";
public static readonly string SuppressWarningOptionName = "suppress-warning";
public static readonly string LanguageVersionOptionName = "language-version";
public static readonly string PlatformOptionName = "platform";
public static readonly string AllowUnsafeOptionName = "allow-unsafe";
public static readonly string WarningsAsErrorsOptionName = "warnings-as-errors";
public static readonly string OptimizeOptionName = "optimize";
public static readonly string KeyFileOptionName = "key-file";
public static readonly string DelaySignOptionName = "delay-sign";
public static readonly string PublicSignOptionName = "public-sign";
public static readonly string DebugTypeOptionName = "debug-type";
public static readonly string EmitEntryPointOptionName = "emit-entry-point";
public static readonly string GenerateXmlDocumentationOptionName = "generate-xml-documentation";
public static readonly string AdditionalArgumentsOptionName = "additional-argument";
public static readonly string OutputNameOptionName = "output-name";
internal static readonly OptionTemplate s_suppressWarningTemplate = new OptionTemplate("suppress-warning");
internal static readonly OptionTemplate s_definesTemplate = new OptionTemplate(DefineOptionName);
internal static readonly OptionTemplate s_languageVersionTemplate = new OptionTemplate("language-version");
internal static readonly OptionTemplate s_suppressWarningTemplate = new OptionTemplate(SuppressWarningOptionName);
internal static readonly OptionTemplate s_platformTemplate = new OptionTemplate("platform");
internal static readonly OptionTemplate s_languageVersionTemplate = new OptionTemplate(LanguageVersionOptionName);
internal static readonly OptionTemplate s_allowUnsafeTemplate = new OptionTemplate("allow-unsafe");
internal static readonly OptionTemplate s_platformTemplate = new OptionTemplate(PlatformOptionName);
internal static readonly OptionTemplate s_warningsAsErrorsTemplate = new OptionTemplate("warnings-as-errors");
internal static readonly OptionTemplate s_allowUnsafeTemplate = new OptionTemplate(AllowUnsafeOptionName);
internal static readonly OptionTemplate s_optimizeTemplate = new OptionTemplate("optimize");
internal static readonly OptionTemplate s_warningsAsErrorsTemplate = new OptionTemplate(WarningsAsErrorsOptionName);
internal static readonly OptionTemplate s_keyFileTemplate = new OptionTemplate("key-file");
internal static readonly OptionTemplate s_optimizeTemplate = new OptionTemplate(OptimizeOptionName);
internal static readonly OptionTemplate s_delaySignTemplate = new OptionTemplate("delay-sign");
internal static readonly OptionTemplate s_keyFileTemplate = new OptionTemplate(KeyFileOptionName);
internal static readonly OptionTemplate s_publicSignTemplate = new OptionTemplate("public-sign");
internal static readonly OptionTemplate s_delaySignTemplate = new OptionTemplate(DelaySignOptionName);
internal static readonly OptionTemplate s_debugTypeTemplate = new OptionTemplate("debug-type");
internal static readonly OptionTemplate s_publicSignTemplate = new OptionTemplate(PublicSignOptionName);
internal static readonly OptionTemplate s_emitEntryPointTemplate = new OptionTemplate("emit-entry-point");
internal static readonly OptionTemplate s_debugTypeTemplate = new OptionTemplate(DebugTypeOptionName);
internal static readonly OptionTemplate s_generateXmlDocumentation = new OptionTemplate("generate-xml-documentation");
internal static readonly OptionTemplate s_emitEntryPointTemplate = new OptionTemplate(EmitEntryPointOptionName);
internal static readonly OptionTemplate s_additionalArgumentsTemplate = new OptionTemplate("additional-argument");
internal static readonly OptionTemplate s_generateXmlDocumentation = new OptionTemplate(GenerateXmlDocumentationOptionName);
internal static readonly OptionTemplate s_outputNameTemplate = new OptionTemplate("output-name");
internal static readonly OptionTemplate s_additionalArgumentsTemplate = new OptionTemplate(AdditionalArgumentsOptionName);
public static CommonCompilerOptions Parse(ArgumentSyntax syntax)
{
IReadOnlyList<string> defines = null;
IReadOnlyList<string> suppressWarnings = null;
string languageVersion = null;
string platform = null;
string debugType = null;
bool? allowUnsafe = null;
bool? warningsAsErrors = null;
bool? optimize = null;
string keyFile = null;
bool? delaySign = null;
bool? publicSign = null;
bool? emitEntryPoint = null;
bool? generateXmlDocumentation = null;
string outputName = null;
IReadOnlyList<string> additionalArguments = null;
Func<string, bool?> nullableBoolConverter = v => bool.Parse(v);
syntax.DefineOptionList(s_definesTemplate.LongName, ref defines, "Preprocessor definitions");
syntax.DefineOptionList(s_suppressWarningTemplate.LongName, ref suppressWarnings, "Suppresses the specified warning");
syntax.DefineOptionList(s_additionalArgumentsTemplate.LongName, ref additionalArguments, "Pass the additional argument directly to the compiler");
syntax.DefineOption(s_debugTypeTemplate.LongName, ref debugType, "The type of PDB to emit: portable or full");
syntax.DefineOption(s_languageVersionTemplate.LongName, ref languageVersion,
"The version of the language used to compile");
syntax.DefineOption(s_platformTemplate.LongName, ref platform,
"The target platform");
syntax.DefineOption(s_allowUnsafeTemplate.LongName, ref allowUnsafe,
nullableBoolConverter, "Allow unsafe code");
syntax.DefineOption(s_warningsAsErrorsTemplate.LongName, ref warningsAsErrors,
nullableBoolConverter, "Turn all warnings into errors");
syntax.DefineOption(s_optimizeTemplate.LongName, ref optimize,
nullableBoolConverter, "Enable compiler optimizations");
syntax.DefineOption(s_keyFileTemplate.LongName, ref keyFile,
"Path to file containing the key to strong-name sign the output assembly");
syntax.DefineOption(s_delaySignTemplate.LongName, ref delaySign,
nullableBoolConverter, "Delay-sign the output assembly");
syntax.DefineOption(s_publicSignTemplate.LongName, ref publicSign,
nullableBoolConverter, "Public-sign the output assembly");
syntax.DefineOption(s_emitEntryPointTemplate.LongName, ref emitEntryPoint,
nullableBoolConverter, "Output an executable console program");
syntax.DefineOption(s_generateXmlDocumentation.LongName, ref generateXmlDocumentation,
nullableBoolConverter, "Generate XML documentation file");
syntax.DefineOption(s_outputNameTemplate.LongName, ref outputName, "Output assembly name");
return new CommonCompilerOptions
{
Defines = defines,
SuppressWarnings = suppressWarnings,
LanguageVersion = languageVersion,
Platform = platform,
AllowUnsafe = allowUnsafe,
WarningsAsErrors = warningsAsErrors,
Optimize = optimize,
KeyFile = keyFile,
DelaySign = delaySign,
PublicSign = publicSign,
DebugType = debugType,
EmitEntryPoint = emitEntryPoint,
GenerateXmlDocumentation = generateXmlDocumentation,
OutputName = outputName,
AdditionalArguments = additionalArguments
};
}
internal static readonly OptionTemplate s_outputNameTemplate = new OptionTemplate(OutputNameOptionName);
public static IEnumerable<string> SerializeToArgs(this CommonCompilerOptions options)
{

View file

@ -7,8 +7,7 @@
"Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160410-01 ",
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",
"Microsoft.DotNet.Files": "1.0.0-*",
"System.CommandLine": "0.1.0-e160323-1"
"Microsoft.DotNet.Files": "1.0.0-*"
},
"frameworks": {
"netstandard1.5": {

View file

@ -2,19 +2,17 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.CommandLine;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Resolution;
using NuGet.Frameworks;
using System.Reflection;
namespace Microsoft.DotNet.Tools.Compiler.Fsc
{
@ -25,240 +23,228 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc
{
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;
CommandLineApplication app = new CommandLineApplication();
app.Name = "dotnet compile-fsc";
app.FullName = ".NET F# Compiler";
app.Description = "F# Compiler for the .NET Platform";
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
{
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");
}
});
return app.Execute(args);
}
catch (ArgumentSyntaxException exception)
catch (Exception ex)
{
Console.Error.WriteLine(exception.Message);
help = true;
returnCode = ExitFailed;
#if DEBUG
Reporter.Error.WriteLine(ex.ToString());
#else
Reporter.Error.WriteLine(ex.Message);
#endif
return 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("NETCOREAPP1_")).Any() ||
commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any();
// Get FSC Path upfront to use it for win32manifest path
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;
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(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
var win32manifestPath = Path.Combine(fscExeDir, "..", "..", "runtimes", "any", "native", "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}" }, 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;
}
// The assembly info must be in the last minus 1 position because:

View file

@ -3,9 +3,14 @@
"compilationOptions": {
"emitEntryPoint": true
},
"compile": [
"**/*.cs",
"../dotnet/CommandLine/*.cs",
"../dotnet/commands/dotnet-compile-csc/AssemblyInfoOptionsCommandLine.cs",
"../dotnet/commands/dotnet-compile-csc/CommonCompilerOptionsCommandLine.cs"
],
"dependencies": {
"Microsoft.FSharp.Compiler.netcore": "1.0.0-alpha-160318",
"System.CommandLine": "0.1.0-e160323-1",
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",

View file

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandArgument
{
public CommandArgument()
{
Values = new List<string>();
}
public string Name { get; set; }
public string Description { get; set; }
public List<string> Values { get; private set; }
public bool MultipleValues { get; set; }
public string Value
{
get
{
return Values.FirstOrDefault();
}
}
}
}

View file

@ -0,0 +1,530 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandLineApplication
{
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
private readonly bool _throwOnUnexpectedArg;
public CommandLineApplication(bool throwOnUnexpectedArg = true)
{
_throwOnUnexpectedArg = throwOnUnexpectedArg;
Options = new List<CommandOption>();
Arguments = new List<CommandArgument>();
Commands = new List<CommandLineApplication>();
RemainingArguments = new List<string>();
Invoke = () => 0;
}
public CommandLineApplication Parent { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public string Syntax { get; set; }
public string Description { get; set; }
public List<CommandOption> Options { get; private set; }
public CommandOption OptionHelp { get; private set; }
public CommandOption OptionVersion { get; private set; }
public List<CommandArgument> Arguments { get; private set; }
public List<string> RemainingArguments { get; private set; }
public bool IsShowingInformation { get; protected set; } // Is showing help or version?
public Func<int> Invoke { get; set; }
public Func<string> LongVersionGetter { get; set; }
public Func<string> ShortVersionGetter { get; set; }
public List<CommandLineApplication> Commands { get; private set; }
public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
bool throwOnUnexpectedArg = true)
{
var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this };
Commands.Add(command);
configuration(command);
return command;
}
public CommandOption Option(string template, string description, CommandOptionType optionType)
{
return Option(template, description, optionType, _ => { });
}
public CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration)
{
var option = new CommandOption(template, optionType) { Description = description };
Options.Add(option);
configuration(option);
return option;
}
public CommandArgument Argument(string name, string description, bool multipleValues = false)
{
return Argument(name, description, _ => { }, multipleValues);
}
public CommandArgument Argument(string name, string description, Action<CommandArgument> configuration, bool multipleValues = false)
{
var lastArg = Arguments.LastOrDefault();
if (lastArg != null && lastArg.MultipleValues)
{
var message = string.Format("The last argument '{0}' accepts multiple values. No more argument can be added.",
lastArg.Name);
throw new InvalidOperationException(message);
}
var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues };
Arguments.Add(argument);
configuration(argument);
return argument;
}
public void OnExecute(Func<int> invoke)
{
Invoke = invoke;
}
public void OnExecute(Func<Task<int>> invoke)
{
Invoke = () => invoke().Result;
}
public int Execute(params string[] args)
{
CommandLineApplication command = this;
CommandOption option = null;
IEnumerator<CommandArgument> arguments = null;
for (var index = 0; index < args.Length; index++)
{
var arg = args[index];
var processed = false;
if (!processed && option == null)
{
string[] longOption = null;
string[] shortOption = null;
if (arg.StartsWith("--"))
{
longOption = arg.Substring(2).Split(new[] { ':', '=' }, 2);
}
else if (arg.StartsWith("-"))
{
shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
}
if (longOption != null)
{
processed = true;
option = command.Options.SingleOrDefault(opt => string.Equals(opt.LongName, longOption[0], StringComparison.Ordinal));
if (option == null)
{
HandleUnexpectedArg(command, args, index, argTypeName: "option");
break;
}
// If we find a help/version option, show information and stop parsing
if (command.OptionHelp == option)
{
command.ShowHelp();
return 0;
}
else if (command.OptionVersion == option)
{
command.ShowVersion();
return 0;
}
if (longOption.Length == 2)
{
if (!option.TryParse(longOption[1]))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{longOption[1]}' for option '{option.LongName}'");
}
option = null;
}
else if (option.OptionType == CommandOptionType.NoValue)
{
// No value is needed for this option
option.TryParse(null);
option = null;
}
}
if (shortOption != null)
{
processed = true;
option = command.Options.SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal));
// If not a short option, try symbol option
if (option == null)
{
option = command.Options.SingleOrDefault(opt => string.Equals(opt.SymbolName, shortOption[0], StringComparison.Ordinal));
}
if (option == null)
{
HandleUnexpectedArg(command, args, index, argTypeName: "option");
break;
}
// If we find a help/version option, show information and stop parsing
if (command.OptionHelp == option)
{
command.ShowHelp();
return 0;
}
else if (command.OptionVersion == option)
{
command.ShowVersion();
return 0;
}
if (shortOption.Length == 2)
{
if (!option.TryParse(shortOption[1]))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{shortOption[1]}' for option '{option.LongName}'");
}
option = null;
}
else if (option.OptionType == CommandOptionType.NoValue)
{
// No value is needed for this option
option.TryParse(null);
option = null;
}
}
}
if (!processed && option != null)
{
processed = true;
if (!option.TryParse(arg))
{
command.ShowHint();
throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{option.LongName}'");
}
option = null;
}
if (!processed && arguments == null)
{
var currentCommand = command;
foreach (var subcommand in command.Commands)
{
if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
{
processed = true;
command = subcommand;
break;
}
}
// If we detect a subcommand
if (command != currentCommand)
{
processed = true;
}
}
if (!processed)
{
if (arguments == null)
{
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
}
if (arguments.MoveNext())
{
processed = true;
arguments.Current.Values.Add(arg);
}
}
if (!processed)
{
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
break;
}
}
if (option != null)
{
command.ShowHint();
throw new CommandParsingException(command, $"Missing value for option '{option.LongName}'");
}
return command.Invoke();
}
// Helper method that adds a help option
public CommandOption HelpOption(string template)
{
// Help option is special because we stop parsing once we see it
// So we store it separately for further use
OptionHelp = Option(template, "Show help information", CommandOptionType.NoValue);
return OptionHelp;
}
public CommandOption VersionOption(string template,
string shortFormVersion,
string longFormVersion = null)
{
if (longFormVersion == null)
{
return VersionOption(template, () => shortFormVersion);
}
else
{
return VersionOption(template, () => shortFormVersion, () => longFormVersion);
}
}
// Helper method that adds a version option
public CommandOption VersionOption(string template,
Func<string> shortFormVersionGetter,
Func<string> longFormVersionGetter = null)
{
// Version option is special because we stop parsing once we see it
// So we store it separately for further use
OptionVersion = Option(template, "Show version information", CommandOptionType.NoValue);
ShortVersionGetter = shortFormVersionGetter;
LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter;
return OptionVersion;
}
// Show short hint that reminds users to use help option
public void ShowHint()
{
if (OptionHelp != null)
{
Console.WriteLine(string.Format("Specify --{0} for a list of available options and commands.", OptionHelp.LongName));
}
}
// Show full help
public void ShowHelp(string commandName = null)
{
var headerBuilder = new StringBuilder("Usage:");
for (var cmd = this; cmd != null; cmd = cmd.Parent)
{
cmd.IsShowingInformation = true;
headerBuilder.Insert(6, string.Format(" {0}", cmd.Name));
}
CommandLineApplication target;
if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase))
{
target = this;
}
else
{
target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase));
if (target != null)
{
headerBuilder.AppendFormat(" {0}", commandName);
}
else
{
// The command name is invalid so don't try to show help for something that doesn't exist
target = this;
}
}
var optionsBuilder = new StringBuilder();
var commandsBuilder = new StringBuilder();
var argumentsBuilder = new StringBuilder();
if (target.Arguments.Any())
{
headerBuilder.Append(" [arguments]");
argumentsBuilder.AppendLine();
argumentsBuilder.AppendLine("Arguments:");
var maxArgLen = MaxArgumentLength(target.Arguments);
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxArgLen + 2);
foreach (var arg in target.Arguments)
{
argumentsBuilder.AppendFormat(outputFormat, arg.Name, arg.Description);
argumentsBuilder.AppendLine();
}
}
if (target.Options.Any())
{
headerBuilder.Append(" [options]");
optionsBuilder.AppendLine();
optionsBuilder.AppendLine("Options:");
var maxOptLen = MaxOptionTemplateLength(target.Options);
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxOptLen + 2);
foreach (var opt in target.Options)
{
optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description);
optionsBuilder.AppendLine();
}
}
if (target.Commands.Any())
{
headerBuilder.Append(" [command]");
commandsBuilder.AppendLine();
commandsBuilder.AppendLine("Commands:");
var maxCmdLen = MaxCommandLength(target.Commands);
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxCmdLen + 2);
foreach (var cmd in target.Commands.OrderBy(c => c.Name))
{
commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description);
commandsBuilder.AppendLine();
}
if (OptionHelp != null)
{
commandsBuilder.AppendLine();
commandsBuilder.AppendFormat("Use \"{0} [command] --help\" for more information about a command.", Name);
commandsBuilder.AppendLine();
}
}
headerBuilder.AppendLine();
var nameAndVersion = new StringBuilder();
nameAndVersion.AppendLine(GetFullNameAndVersion());
nameAndVersion.AppendLine();
Console.Write("{0}{1}{2}{3}{4}", nameAndVersion, headerBuilder, argumentsBuilder, optionsBuilder, commandsBuilder);
}
public void ShowVersion()
{
for (var cmd = this; cmd != null; cmd = cmd.Parent)
{
cmd.IsShowingInformation = true;
}
Console.WriteLine(FullName);
Console.WriteLine(LongVersionGetter());
}
public string GetFullNameAndVersion()
{
return ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter());
}
public void ShowRootCommandFullNameAndVersion()
{
var rootCmd = this;
while (rootCmd.Parent != null)
{
rootCmd = rootCmd.Parent;
}
Console.WriteLine(rootCmd.GetFullNameAndVersion());
Console.WriteLine();
}
private int MaxOptionTemplateLength(IEnumerable<CommandOption> options)
{
var maxLen = 0;
foreach (var opt in options)
{
maxLen = opt.Template.Length > maxLen ? opt.Template.Length : maxLen;
}
return maxLen;
}
private int MaxCommandLength(IEnumerable<CommandLineApplication> commands)
{
var maxLen = 0;
foreach (var cmd in commands)
{
maxLen = cmd.Name.Length > maxLen ? cmd.Name.Length : maxLen;
}
return maxLen;
}
private int MaxArgumentLength(IEnumerable<CommandArgument> arguments)
{
var maxLen = 0;
foreach (var arg in arguments)
{
maxLen = arg.Name.Length > maxLen ? arg.Name.Length : maxLen;
}
return maxLen;
}
private void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
{
if (command._throwOnUnexpectedArg)
{
command.ShowHint();
throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
}
else
{
// All remaining arguments are stored for further use
command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
}
}
private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
{
private readonly IEnumerator<CommandArgument> _enumerator;
public CommandArgumentEnumerator(IEnumerator<CommandArgument> enumerator)
{
_enumerator = enumerator;
}
public CommandArgument Current
{
get
{
return _enumerator.Current;
}
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public void Dispose()
{
_enumerator.Dispose();
}
public bool MoveNext()
{
if (Current == null || !Current.MultipleValues)
{
return _enumerator.MoveNext();
}
// If current argument allows multiple values, we don't move forward and
// all later values will be added to current CommandArgument.Values
return true;
}
public void Reset()
{
_enumerator.Reset();
}
}
}
}

View file

@ -0,0 +1,106 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandOption
{
public CommandOption(string template, CommandOptionType optionType)
{
Template = template;
OptionType = optionType;
Values = new List<string>();
foreach (var part in Template.Split(new[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries))
{
if (part.StartsWith("--"))
{
LongName = part.Substring(2);
}
else if (part.StartsWith("-"))
{
var optName = part.Substring(1);
// If there is only one char and it is not an English letter, it is a symbol option (e.g. "-?")
if (optName.Length == 1 && !IsEnglishLetter(optName[0]))
{
SymbolName = optName;
}
else
{
ShortName = optName;
}
}
else if (part.StartsWith("<") && part.EndsWith(">"))
{
ValueName = part.Substring(1, part.Length - 2);
}
else
{
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
}
}
if (string.IsNullOrEmpty(LongName) && string.IsNullOrEmpty(ShortName) && string.IsNullOrEmpty(SymbolName))
{
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
}
}
public string Template { get; set; }
public string ShortName { get; set; }
public string LongName { get; set; }
public string SymbolName { get; set; }
public string ValueName { get; set; }
public string Description { get; set; }
public List<string> Values { get; private set; }
public CommandOptionType OptionType { get; private set; }
public bool TryParse(string value)
{
switch (OptionType)
{
case CommandOptionType.MultipleValue:
Values.Add(value);
break;
case CommandOptionType.SingleValue:
if (Values.Any())
{
return false;
}
Values.Add(value);
break;
case CommandOptionType.NoValue:
if (value != null)
{
return false;
}
// Add a value to indicate that this option was specified
Values.Add("on");
break;
default:
break;
}
return true;
}
public bool HasValue()
{
return Values.Any();
}
public string Value()
{
return HasValue() ? Values[0] : null;
}
private bool IsEnglishLetter(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
}
}

View file

@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.DotNet.Cli.CommandLine
{
internal enum CommandOptionType
{
MultipleValue,
SingleValue,
NoValue
}
}

View file

@ -0,0 +1,18 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Microsoft.DotNet.Cli.CommandLine
{
internal class CommandParsingException : Exception
{
public CommandParsingException(CommandLineApplication command, string message)
: base(message)
{
Command = command;
}
public CommandLineApplication Command { get; }
}
}

View file

@ -0,0 +1,79 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Compiler.Common;
using static Microsoft.DotNet.Cli.Compiler.Common.AssemblyInfoOptions;
namespace Microsoft.DotNet.Tools.Compiler
{
internal class AssemblyInfoOptionsCommandLine
{
private const string ArgTemplate = "<arg>";
public CommandOption VersionOption { get; set; }
public CommandOption TitleOption { get; set; }
public CommandOption DescriptionOption { get; set; }
public CommandOption CopyrightOption { get; set; }
public CommandOption NeutralCultureOption { get; set; }
public CommandOption CultureOption { get; set; }
public CommandOption InformationalVersionOption { get; set; }
public CommandOption FileVersionOption { get; set; }
public CommandOption TargetFrameworkOption { get; set; }
public static AssemblyInfoOptionsCommandLine AddOptions(CommandLineApplication app)
{
AssemblyInfoOptionsCommandLine commandLineOptions = new AssemblyInfoOptionsCommandLine();
commandLineOptions.VersionOption =
app.Option($"{AssemblyVersionOptionName} {ArgTemplate}", "Assembly version", CommandOptionType.SingleValue);
commandLineOptions.TitleOption =
app.Option($"{TitleOptionName} {ArgTemplate}", "Assembly title", CommandOptionType.SingleValue);
commandLineOptions.DescriptionOption =
app.Option($"{DescriptionOptionName} {ArgTemplate}", "Assembly description", CommandOptionType.SingleValue);
commandLineOptions.CopyrightOption =
app.Option($"{CopyrightOptionName} {ArgTemplate}", "Assembly copyright", CommandOptionType.SingleValue);
commandLineOptions.NeutralCultureOption =
app.Option($"{NeutralCultureOptionName} {ArgTemplate}", "Assembly neutral culture", CommandOptionType.SingleValue);
commandLineOptions.CultureOption =
app.Option($"{CultureOptionName} {ArgTemplate}", "Assembly culture", CommandOptionType.SingleValue);
commandLineOptions.InformationalVersionOption =
app.Option($"{InformationalVersionOptionName} {ArgTemplate}", "Assembly informational version", CommandOptionType.SingleValue);
commandLineOptions.FileVersionOption =
app.Option($"{AssemblyFileVersionOptionName} {ArgTemplate}", "Assembly file version", CommandOptionType.SingleValue);
commandLineOptions.TargetFrameworkOption =
app.Option($"{TargetFrameworkOptionName} {ArgTemplate}", "Assembly target framework", CommandOptionType.SingleValue);
return commandLineOptions;
}
public AssemblyInfoOptions GetOptionValues()
{
return new AssemblyInfoOptions()
{
AssemblyVersion = UnescapeNewlines(VersionOption.Value()),
Title = UnescapeNewlines(TitleOption.Value()),
Description = UnescapeNewlines(DescriptionOption.Value()),
Copyright = UnescapeNewlines(CopyrightOption.Value()),
NeutralLanguage = UnescapeNewlines(NeutralCultureOption.Value()),
Culture = UnescapeNewlines(CultureOption.Value()),
InformationalVersion = UnescapeNewlines(InformationalVersionOption.Value()),
AssemblyFileVersion = UnescapeNewlines(FileVersionOption.Value()),
TargetFramework = UnescapeNewlines(TargetFrameworkOption.Value()),
};
}
private static string UnescapeNewlines(string text)
{
return text.Replace("\\r", "\r").Replace("\\n", "\n");
}
}
}

View file

@ -0,0 +1,104 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.ProjectModel;
using static Microsoft.DotNet.Cli.Compiler.Common.CommonCompilerOptionsExtensions;
namespace Microsoft.DotNet.Tools.Compiler
{
internal class CommonCompilerOptionsCommandLine
{
private const string ArgTemplate = "<arg>";
public CommandOption DefineOption { get; set; }
public CommandOption SuppressWarningOption { get; set; }
public CommandOption LanguageVersionOption { get; set; }
public CommandOption PlatformOption { get; set; }
public CommandOption AllowUnsafeOption { get; set; }
public CommandOption WarningsAsErrorsOption { get; set; }
public CommandOption OptimizeOption { get; set; }
public CommandOption KeyFileOption { get; set; }
public CommandOption DelaySignOption { get; set; }
public CommandOption PublicSignOption { get; set; }
public CommandOption DebugTypeOption { get; set; }
public CommandOption EmitEntryPointOption { get; set; }
public CommandOption GenerateXmlDocumentationOption { get; set; }
public CommandOption AdditionalArgumentsOption { get; set; }
public CommandOption OutputNameOption { get; set; }
public static CommonCompilerOptionsCommandLine AddOptions(CommandLineApplication app)
{
CommonCompilerOptionsCommandLine commandLineOptions = new CommonCompilerOptionsCommandLine();
commandLineOptions.DefineOption =
app.Option($"{DefineOptionName} {ArgTemplate}...", "Preprocessor definitions", CommandOptionType.MultipleValue);
commandLineOptions.SuppressWarningOption =
app.Option($"{SuppressWarningOptionName} {ArgTemplate}...", "Suppresses the specified warning", CommandOptionType.MultipleValue);
commandLineOptions.LanguageVersionOption =
app.Option($"{LanguageVersionOptionName} {ArgTemplate}", "The version of the language used to compile", CommandOptionType.SingleValue);
commandLineOptions.PlatformOption =
app.Option($"{PlatformOptionName} {ArgTemplate}", "The target platform", CommandOptionType.SingleValue);
commandLineOptions.AllowUnsafeOption =
app.Option($"{AllowUnsafeOptionName} {ArgTemplate}", "Allow unsafe code", CommandOptionType.SingleValue);
commandLineOptions.WarningsAsErrorsOption =
app.Option($"{WarningsAsErrorsOptionName} {ArgTemplate}", "Turn all warnings into errors", CommandOptionType.SingleValue);
commandLineOptions.OptimizeOption =
app.Option($"{OptimizeOptionName} {ArgTemplate}", "Enable compiler optimizations", CommandOptionType.SingleValue);
commandLineOptions.KeyFileOption =
app.Option($"{KeyFileOptionName} {ArgTemplate}", "Path to file containing the key to strong-name sign the output assembly", CommandOptionType.SingleValue);
commandLineOptions.DelaySignOption =
app.Option($"{DelaySignOptionName} {ArgTemplate}", "Delay-sign the output assembly", CommandOptionType.SingleValue);
commandLineOptions.PublicSignOption =
app.Option($"{PublicSignOptionName} {ArgTemplate}", "Public-sign the output assembly", CommandOptionType.SingleValue);
commandLineOptions.DebugTypeOption =
app.Option($"{DebugTypeOptionName} {ArgTemplate}", "The type of PDB to emit: portable or full", CommandOptionType.SingleValue);
commandLineOptions.EmitEntryPointOption =
app.Option($"{EmitEntryPointOptionName} {ArgTemplate}", "Output an executable console program", CommandOptionType.SingleValue);
commandLineOptions.GenerateXmlDocumentationOption =
app.Option($"{GenerateXmlDocumentationOptionName} {ArgTemplate}", "Generate XML documentation file", CommandOptionType.SingleValue);
commandLineOptions.AdditionalArgumentsOption =
app.Option($"{AdditionalArgumentsOptionName} {ArgTemplate}...", "Pass the additional argument directly to the compiler", CommandOptionType.MultipleValue);
commandLineOptions.OutputNameOption =
app.Option($"{OutputNameOptionName} {ArgTemplate}", "Output assembly name", CommandOptionType.SingleValue);
return commandLineOptions;
}
public CommonCompilerOptions GetOptionValues()
{
return new CommonCompilerOptions()
{
Defines = DefineOption.Values,
SuppressWarnings = SuppressWarningOption.Values,
LanguageVersion = LanguageVersionOption.Value(),
Platform = PlatformOption.Value(),
AllowUnsafe = bool.Parse(AllowUnsafeOption.Value()),
WarningsAsErrors = bool.Parse(WarningsAsErrorsOption.Value()),
Optimize = bool.Parse(OptimizeOption.Value()),
KeyFile = KeyFileOption.Value(),
DelaySign = bool.Parse(DelaySignOption.Value()),
PublicSign = bool.Parse(PublicSignOption.Value()),
DebugType = DebugTypeOption.Value(),
EmitEntryPoint = bool.Parse(EmitEntryPointOption.Value()),
GenerateXmlDocumentation = bool.Parse(GenerateXmlDocumentationOption.Value()),
AdditionalArguments = AdditionalArgumentsOption.Values,
OutputName = OutputNameOption.Value(),
};
}
}
}

View file

@ -2,13 +2,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.CommandLine;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
@ -23,103 +22,87 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc
{
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>();
IReadOnlyList<string> analyzers = Array.Empty<string>();
string outputName = null;
var help = false;
var returnCode = 0;
string helpText = null;
CommandLineApplication app = new CommandLineApplication();
app.Name = "dotnet compile-csc";
app.FullName = ".NET C# Compiler";
app.Description = "C# Compiler for the .NET Platform";
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!
var result = RunCsc(new string[] { $"-noconfig", "@" + $"{rsp}" })
.ForwardStdErr()
.ForwardStdOut()
.Execute();
return result.ExitCode;
});
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("analyzer", ref analyzers, "Path to an analyzer assembly");
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");
}
});
return app.Execute(args);
}
catch (ArgumentSyntaxException exception)
catch (Exception ex)
{
Console.Error.WriteLine(exception.Message);
help = true;
returnCode = ExitFailed;
#if DEBUG
Reporter.Error.WriteLine(ex.ToString());
#else
Reporter.Error.WriteLine(ex.Message);
#endif
return 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.cs");
File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources));
allArgs.Add($"\"{assemblyInfo}\"");
if (outputName != null)
{
allArgs.Add($"-out:\"{outputName}\"");
}
allArgs.AddRange(analyzers.Select(a => $"-a:\"{a}\""));
allArgs.AddRange(references.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.Select(resource => $"-resource:{resource}"));
allArgs.AddRange(sources.Select(s => $"\"{s}\""));
var rsp = Path.Combine(tempOutDir, "dotnet-compile-csc.rsp");
File.WriteAllLines(rsp, allArgs, Encoding.UTF8);
// Execute CSC!
var result = RunCsc(new string[] { $"-noconfig", "@" + $"{rsp}" })
.ForwardStdErr()
.ForwardStdOut()
.Execute();
return result.ExitCode;
}
// TODO: Review if this is the place for default options

View file

@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.Linq;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
@ -9,146 +10,115 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
{
internal static ArgValues Parse(IEnumerable<string> args)
{
string inputAssembly = null;
string outputDirectory = null;
string temporaryOutputDirectory = null;
string configuration = null;
BuildConfiguration? buildConfiguration = null;
string mode = null;
NativeIntermediateMode? nativeMode = null;
IReadOnlyList<string> ilcArgs = Array.Empty<string>();
IEnumerable<string> unquotIlcArgs = Array.Empty<string>();
string ilcPath = null;
string ilcSdkPath = null;
string appDepSdk = null;
string logPath = null;
var help = false;
string helpText = null;
var returnCode = 0;
string cppCompilerFlags = null;
CommandLineApplication app = new CommandLineApplication();
app.HelpOption("-h|--help");
IReadOnlyList<string> references = Array.Empty<string>();
IReadOnlyList<string> linklib = Array.Empty<string>();
CommandOption output = app.Option("--output <arg>", "Output Directory for native executable.", CommandOptionType.SingleValue);
CommandOption tempOutput = app.Option("--temp-output <arg>", "Directory for intermediate files.", CommandOptionType.SingleValue);
CommandOption configuration = app.Option("--configuration <arg>", "debug/release build configuration. Defaults to debug.", CommandOptionType.SingleValue);
CommandOption mode = app.Option("--mode <arg>", "Code Generation mode. Defaults to ryujit.", CommandOptionType.SingleValue);
CommandOption reference = app.Option("--reference <arg>...", "Use to specify Managed DLL references of the app.", CommandOptionType.MultipleValue);
// Custom Extensibility Points to support CoreRT workflow TODO better descriptions
CommandOption ilcarg = app.Option("--ilcarg <arg>...", "Use to specify custom arguments for the IL Compiler.", CommandOptionType.MultipleValue);
CommandOption ilcpath = app.Option("--ilcpath <arg>", "Use to specify a custom build of IL Compiler.", CommandOptionType.SingleValue);
CommandOption ilcsdkpath = app.Option("ilcsdkpath <arg>", "Use to specify a custom build of IL Compiler SDK", CommandOptionType.SingleValue);
CommandOption linklib = app.Option("--linklib <arg>...", "Use to link in additional static libs", CommandOptionType.MultipleValue);
// TEMPORARY Hack until CoreRT compatible Framework Libs are available
CommandOption appdepsdk = app.Option("--appdepsdk <arg>", "Use to plug in custom appdepsdk path", CommandOptionType.SingleValue);
// Optional Log Path
CommandOption logpath = app.Option("--logpath <arg>", "Use to dump Native Compilation Logs to a file.", CommandOptionType.SingleValue);
// Optional flags to be passed to the native compiler
CommandOption cppcompilerflags = app.Option("--cppcompilerflags <arg>", "Additional flags to be passed to the native compiler.", CommandOptionType.SingleValue);
CommandArgument inputAssembly = app.Argument("INPUT_ASSEMBLY", "The managed input assembly to compile to native.");
ArgValues argValues = new ArgValues();
app.OnExecute(() =>
{
if (string.IsNullOrEmpty(inputAssembly.Value))
{
Reporter.Error.WriteLine("Input Assembly is a required parameter.");
return 1;
}
if (configuration.HasValue())
{
try
{
argValues.BuildConfiguration = EnumExtensions.Parse<BuildConfiguration>(configuration.Value());
}
catch (ArgumentException)
{
Reporter.Error.WriteLine($"Invalid Configuration Option: {configuration}");
return 1;
}
}
if (mode.HasValue())
{
try
{
argValues.NativeMode = EnumExtensions.Parse<NativeIntermediateMode>(mode.Value());
}
catch (ArgumentException)
{
Reporter.Error.WriteLine($"Invalid Mode Option: {mode}");
return 1;
}
}
argValues.InputManagedAssemblyPath = inputAssembly.Value;
argValues.OutputDirectory = output.Value();
argValues.IntermediateDirectory = tempOutput.Value();
argValues.Architecture = ArchitectureMode.x64;
argValues.ReferencePaths = reference.Values;
argValues.IlcArgs = ilcarg.Values.Select(s =>
{
if (!s.StartsWith("\"") || !s.EndsWith("\""))
{
throw new ArgumentException("--ilcarg must be specified in double quotes", "ilcarg");
}
return s.Substring(1, s.Length - 2);
});
argValues.IlcPath = ilcpath.Value();
argValues.IlcSdkPath = ilcsdkpath.Value();
argValues.LinkLibPaths = linklib.Values;
argValues.AppDepSDKPath = appdepsdk.Value();
argValues.LogPath = logpath.Value();
argValues.CppCompilerFlags = cppcompilerflags.Value();
Reporter.Output.WriteLine($"Input Assembly: {inputAssembly}");
return 0;
});
try
{
ArgumentSyntax.Parse(args, syntax =>
{
syntax.HandleHelp = false;
syntax.HandleErrors = false;
syntax.DefineOption("output", ref outputDirectory, "Output Directory for native executable.");
syntax.DefineOption("temp-output", ref temporaryOutputDirectory, "Directory for intermediate files.");
syntax.DefineOption("configuration", ref configuration,
"debug/release build configuration. Defaults to debug.");
syntax.DefineOption("mode", ref mode, "Code Generation mode. Defaults to ryujit.");
syntax.DefineOptionList("reference", ref references,
"Use to specify Managed DLL references of the app.");
// Custom Extensibility Points to support CoreRT workflow TODO better descriptions
syntax.DefineOptionList("ilcarg", ref ilcArgs, "Use to specify custom arguments for the IL Compiler.");
syntax.DefineOption("ilcpath", ref ilcPath, "Use to specify a custom build of IL Compiler.");
syntax.DefineOption("ilcsdkpath", ref ilcSdkPath, "Use to specify a custom build of IL Compiler SDK");
syntax.DefineOptionList("linklib", ref linklib, "Use to link in additional static libs");
// TEMPORARY Hack until CoreRT compatible Framework Libs are available
syntax.DefineOption("appdepsdk", ref appDepSdk, "Use to plug in custom appdepsdk path");
// Optional Log Path
syntax.DefineOption("logpath", ref logPath, "Use to dump Native Compilation Logs to a file.");
// Optional flags to be passed to the native compiler
syntax.DefineOption("cppcompilerflags", ref cppCompilerFlags, "Additional flags to be passed to the native compiler.");
syntax.DefineOption("h|help", ref help, "Help for compile native.");
syntax.DefineParameter("INPUT_ASSEMBLY", ref inputAssembly,
"The managed input assembly to compile to native.");
helpText = syntax.GetHelpText();
if (string.IsNullOrWhiteSpace(inputAssembly))
{
syntax.ReportError("Input Assembly is a required parameter.");
help = true;
}
if (!string.IsNullOrEmpty(configuration))
{
try
{
buildConfiguration = EnumExtensions.Parse<BuildConfiguration>(configuration);
}
catch (ArgumentException)
{
syntax.ReportError($"Invalid Configuration Option: {configuration}");
help = true;
}
}
if (!string.IsNullOrEmpty(mode))
{
try
{
nativeMode = EnumExtensions.Parse<NativeIntermediateMode>(mode);
}
catch (ArgumentException)
{
syntax.ReportError($"Invalid Mode Option: {mode}");
help = true;
}
}
unquotIlcArgs = ilcArgs.Select(s =>
{
if (!s.StartsWith("\"") || !s.EndsWith("\""))
{
throw new ArgumentSyntaxException("--ilcarg must be specified in double quotes");
}
return s.Substring(1, s.Length - 2);
});
});
argValues.ReturnCode = app.Execute(args.ToArray());
}
catch (ArgumentSyntaxException exception)
catch (Exception ex)
{
Console.Error.WriteLine(exception.Message);
help = true;
returnCode = 1;
#if DEBUG
Console.Error.WriteLine(ex);
#else
Console.Error.WriteLine(ex.Message);
#endif
argValues.ReturnCode = 1;
}
if (help)
if (argValues.ReturnCode != 0)
{
Console.WriteLine(helpText);
return new ArgValues
{
IsHelp = help,
ReturnCode = returnCode
};
argValues.IsHelp = true;
}
Console.WriteLine($"Input Assembly: {inputAssembly}");
return new ArgValues
{
InputManagedAssemblyPath = inputAssembly,
OutputDirectory = outputDirectory,
IntermediateDirectory = temporaryOutputDirectory,
Architecture = ArchitectureMode.x64,
BuildConfiguration = buildConfiguration,
NativeMode = nativeMode,
ReferencePaths = references,
IlcArgs = unquotIlcArgs,
IlcPath = ilcPath,
IlcSdkPath = ilcSdkPath,
LinkLibPaths = linklib,
AppDepSDKPath = appDepSdk,
LogPath = logPath,
CppCompilerFlags = cppCompilerFlags
};
return argValues;
}
}
}

View file

@ -1,15 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
public static class DirectoryExtensions

View file

@ -1,16 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
public interface IPlatformNativeStep
public interface IPlatformNativeStep
{
int Invoke();
string DetermineOutputFile(NativeCompileSettings config);

View file

@ -1,16 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
public class IntermediateCompiler
public class IntermediateCompiler
{
public static IntermediateCompiler Create(NativeCompileSettings config)
{

View file

@ -1,12 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{

View file

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{

View file

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{

View file

@ -1,14 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
@ -22,6 +12,5 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
return IntPtr.Size == 8 ? ArchitectureMode.x64 : ArchitectureMode.x86;
#endif
}
}
}

View file

@ -1,14 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Common;
namespace Microsoft.DotNet.Tools.Compiler.Native
{

View file

@ -54,17 +54,12 @@ namespace Microsoft.DotNet.Tools.Compiler
{
if (ResourceUtility.IsResxFile(resgenFile.InputFile))
{
var arguments = new[]
{
$"{resgenFile.InputFile}",
$"-o:{resgenFile.OutputFile}",
$"-v:{project.Version.Version}"
};
var rsp = Path.Combine(intermediateOutputPath, $"dotnet-resgen-resx.rsp");
File.WriteAllLines(rsp, arguments);
var result = Resgen.ResgenCommand.Run(new[] { $"@{rsp}" });
var result = Resgen.ResgenCommand.Run(
new[] { resgenFile.InputFile },
culture: null,
outputFile: resgenFile.OutputFile,
version: project.Version.Version.ToString(),
compilationReferences: null);
if (result != 0)
{
@ -85,11 +80,9 @@ namespace Microsoft.DotNet.Tools.Compiler
protected static bool GenerateCultureResourceAssemblies(
Project project,
List<LibraryExport> dependencies,
string intermediateOutputPath,
string outputPath)
{
var referencePaths = CompilerUtil.GetReferencePathsForCultureResgen(dependencies);
var resgenReferenceArgs = referencePaths.Select(path => $"-r:{path}").ToList();
var cultureResgenFiles = CompilerUtil.GetCultureResources(project, outputPath);
foreach (var resgenFile in cultureResgenFiles)
@ -101,17 +94,13 @@ namespace Microsoft.DotNet.Tools.Compiler
Directory.CreateDirectory(resourceOutputPath);
}
var arguments = new List<string>();
var result = Resgen.ResgenCommand.Run(
resgenFile.InputFileToMetadata.Select(fileToMetadata => $"{fileToMetadata.Key},{fileToMetadata.Value}"),
resgenFile.Culture,
resgenFile.OutputFile,
project.Version.Version.ToString(),
referencePaths);
arguments.AddRange(resgenReferenceArgs);
arguments.Add($"-o:{resgenFile.OutputFile}");
arguments.Add($"-c:{resgenFile.Culture}");
arguments.Add($"-v:{project.Version.Version}");
arguments.AddRange(resgenFile.InputFileToMetadata.Select(fileToMetadata => $"{fileToMetadata.Key},{fileToMetadata.Value}"));
var rsp = Path.Combine(intermediateOutputPath, $"dotnet-resgen.rsp");
File.WriteAllLines(rsp, arguments);
var result = Resgen.ResgenCommand.Run(new[] { $"@{rsp}" });
if (result != 0)
{
return false;

View file

@ -207,7 +207,7 @@ namespace Microsoft.DotNet.Tools.Compiler
if (success)
{
success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, intermediateOutputPath, outputPath);
success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath);
}
return PrintSummary(diagnostics, sw, success);

View file

@ -1,4 +1,4 @@
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using System;
using System.Collections.Generic;

View file

@ -4,9 +4,9 @@
using System;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Tools.Pack;
namespace Microsoft.DotNet.Tools.Compiler

View file

@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.Extensions.Logging;
namespace Microsoft.DotNet.ProjectModel.Server

View file

@ -1,10 +1,10 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using System;
using System.IO;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Publish
{

View file

@ -3,9 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using System.Linq;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using NuGet.Frameworks;

View file

@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Repl

View file

@ -2,61 +2,29 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.CommandLine;
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Resgen
{
public partial class ResgenCommand
{
public static int Run(string[] args)
public static int Run(IEnumerable<string> inputFiles, string culture, string outputFile, string version, IEnumerable<string> compilationReferences)
{
DebugHelper.HandleDebugSwitch(ref args);
var help = false;
string helpText = null;
var returnCode = 0;
var resgenCommand = new ResgenCommand();
try
{
ArgumentSyntax.Parse(args, syntax =>
{
syntax.ApplicationName = "Resource compiler";
syntax.HandleHelp = false;
syntax.HandleErrors = false;
syntax.DefineOption("o|output", ref resgenCommand.OutputFileName, "Output file name");
syntax.DefineOption("c|culture", ref resgenCommand.AssemblyCulture, "Ouput assembly culture");
syntax.DefineOption("v|version", ref resgenCommand.AssemblyVersion, "Ouput assembly version");
syntax.DefineOption("h|help", ref help, "Help for compile native.");
syntax.DefineOptionList("r", ref resgenCommand.CompilationReferences, "Compilation references");
syntax.DefineParameterList("args", ref resgenCommand.Args, "Input files");
helpText = syntax.GetHelpText();
});
}
catch (ArgumentSyntaxException exception)
{
Console.Error.WriteLine(exception.Message);
help = true;
returnCode = 1;
}
if (resgenCommand.Args.Count == 0)
if (!inputFiles.Any())
{
Reporter.Error.WriteLine("No input files specified");
help = true;
returnCode = 1;
return 1;
}
if (help)
{
Console.WriteLine(helpText);
return returnCode;
}
ResgenCommand resgenCommand = new ResgenCommand();
resgenCommand.Args = inputFiles;
resgenCommand.OutputFileName = outputFile;
resgenCommand.AssemblyCulture = culture;
resgenCommand.AssemblyVersion = version;
resgenCommand.CompilationReferences = compilationReferences;
try
{

View file

@ -14,8 +14,8 @@ namespace Microsoft.DotNet.Tools.Resgen
public string OutputFileName = null;
public string AssemblyCulture = null;
public string AssemblyVersion = null;
public IReadOnlyList<string> CompilationReferences = null;
public IReadOnlyList<string> Args = null;
public IEnumerable<string> CompilationReferences = null;
public IEnumerable<string> Args = null;
public int Execute()
{

View file

@ -2,15 +2,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Graph;
using NuGet.Frameworks;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.DotNet.Tools.Restore

View file

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.DotNet.Cli.Utils;
using System;
using System.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Run
{
@ -13,56 +13,41 @@ namespace Microsoft.DotNet.Tools.Run
{
DebugHelper.HandleDebugSwitch(ref args);
var help = false;
string helpText = null;
var returnCode = 0;
CommandLineApplication app = new CommandLineApplication();
app.Name = "dotnet run";
app.FullName = ".NET Run Command";
app.Description = "Command used to run .NET apps";
app.HelpOption("-h|--help");
RunCommand runCmd = new RunCommand();
CommandOption framework = app.Option("-f|--framework", "Compile a specific framework", CommandOptionType.SingleValue);
CommandOption configuration = app.Option("-c|--configuration", "Configuration under which to build", CommandOptionType.SingleValue);
CommandOption project = app.Option("-p|--project", "The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory", CommandOptionType.SingleValue);
try
// TODO: this is not supporting args which can be switches (i.e. --test)
// TODO: we need to make a change in CommandLine utils or parse args ourselves.
CommandArgument runArgs = app.Argument("args", "Arguments to pass to the executable or script", multipleValues: true);
app.OnExecute(() =>
{
ArgumentSyntax.Parse(args, syntax =>
{
syntax.HandleHelp = false;
syntax.HandleErrors = false;
RunCommand runCmd = new RunCommand();
syntax.DefineOption("f|framework", ref runCmd.Framework, "Compile a specific framework");
syntax.DefineOption("c|configuration", ref runCmd.Configuration, "Configuration under which to build");
syntax.DefineOption("p|project", ref runCmd.Project, "The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory");
runCmd.Framework = framework.Value();
runCmd.Configuration = configuration.Value();
runCmd.Project = project.Value();
runCmd.Args = runArgs.Values;
syntax.DefineOption("h|help", ref help, "Help for compile native.");
// TODO: this is not supporting args which can be switches (i.e. --test)
// TODO: we need to make a change in System.CommandLine or parse args ourselves.
syntax.DefineParameterList("args", ref runCmd.Args, "Arguments to pass to the executable or script");
helpText = syntax.GetHelpText();
});
}
catch (ArgumentSyntaxException exception)
{
Console.Error.WriteLine(exception.Message);
help = true;
returnCode = 1;
}
if (help)
{
Console.WriteLine(helpText);
return returnCode;
}
try
{
return runCmd.Start();
});
try
{
return app.Execute(args);
}
catch (Exception ex)
{
#if DEBUG
Console.Error.WriteLine(ex);
Reporter.Error.WriteLine(ex.ToString());
#else
Console.Error.WriteLine(ex.Message);
Reporter.Error.WriteLine(ex.Message);
#endif
return 1;
}

View file

@ -3,10 +3,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using NuGet.Frameworks;
using static System.Int32;

View file

@ -11,7 +11,6 @@
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>

View file

@ -24,18 +24,12 @@
"Newtonsoft.Json": "7.0.1",
"System.Text.Encoding.CodePages": "4.0.1-rc2-24018",
"System.Diagnostics.FileVersionInfo": "4.0.0-rc2-24018",
"System.CommandLine": "0.1.0-e160323-1",
"Microsoft.ApplicationInsights": "2.0.0",
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
"Microsoft.DotNet.Compiler.Common": "1.0.0-*",
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",
"Microsoft.DotNet.ILCompiler.SDK": "1.0.6-prerelease-00003",
"Microsoft.Extensions.Logging": "1.0.0-rc2-20581",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-20581",
"Microsoft.Extensions.CommandLineUtils.Sources": {
"type": "build",
"version": "1.0.0-rc2-20221"
},
"Microsoft.Extensions.Testing.Abstractions": "1.0.0-*",
"Microsoft.NETCore.ConsoleHost": "1.0.0-rc2-24018",
"Microsoft.NETCore.TestHost": "1.0.0-rc2-24018",

View file

@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.CommandLine;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
@ -11,19 +9,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
{
public class Tests : TestBase
{
private static void EqualAfterDeserialize(IEnumerable<string> args, CommonCompilerOptions original)
{
CommonCompilerOptions newOptions = null;
ArgumentSyntax.Parse(args, syntax =>
{
newOptions = CommonCompilerOptionsExtensions.Parse(syntax);
});
Assert.Equal(original, newOptions);
}
[Fact]
public void SimpleSerialize()
{
@ -32,8 +17,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
var args = options.SerializeToArgs();
Assert.Equal(new [] { "--additional-argument:-highentropyva+" }, args);
EqualAfterDeserialize(args, options);
}
[Fact]
@ -47,8 +30,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
"--additional-argument:-highentropyva+",
"--additional-argument:-addmodule:\"path with spaces\";\"after semicolon\""
}, args);
EqualAfterDeserialize(args, options);
}
}
}