Merge pull request #284 from livarcocc/refactor_native_args

Refactor native args
This commit is contained in:
Krzysztof Wicher 2015-11-24 13:30:38 -08:00
commit 3ed32a71e1
5 changed files with 350 additions and 323 deletions

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;
using System.Collections.Generic;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
@ -18,14 +8,73 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
public string InputManagedAssemblyPath { get; set; }
public string OutputDirectory { get; set; }
public string IntermediateDirectory { get; set; }
public string BuildConfiguration { get; set; }
public string Architecture { get; set; }
public string NativeMode { get; set; }
public List<string> ReferencePaths { get; set; }
public BuildConfiguration? BuildConfiguration { get; set; }
public ArchitectureMode Architecture { get; set; }
public NativeIntermediateMode? NativeMode { get; set; }
public IEnumerable<string> ReferencePaths { get; set; }
public string IlcArgs { get; set; }
public List<string> LinkLibPaths { get; set; }
public IEnumerable<string> LinkLibPaths { get; set; }
public string AppDepSDKPath { get; set; }
public string IlcPath { get; set; }
}
public NativeCompileSettings GetNativeCompileSettings()
{
var config = NativeCompileSettings.Default;
config.InputManagedAssemblyPath = InputManagedAssemblyPath;
config.Architecture = Architecture;
if (BuildConfiguration.HasValue)
{
config.BuildType = BuildConfiguration.Value;
}
if (!string.IsNullOrEmpty(OutputDirectory))
{
config.OutputDirectory = OutputDirectory;
}
if (!string.IsNullOrEmpty(IntermediateDirectory))
{
config.IntermediateDirectory = IntermediateDirectory;
}
if (NativeMode.HasValue)
{
config.NativeMode = NativeMode.Value;
}
if (!string.IsNullOrEmpty(AppDepSDKPath))
{
config.AppDepSDKPath = AppDepSDKPath;
}
if (!string.IsNullOrEmpty(IlcPath))
{
config.IlcPath = IlcPath;
}
if (!string.IsNullOrEmpty(LogPath))
{
config.LogPath = LogPath;
}
if (!string.IsNullOrEmpty(IlcArgs))
{
config.IlcArgs = IlcArgs;
}
foreach (var reference in ReferencePaths)
{
config.AddReference(reference);
}
foreach (var lib in LinkLibPaths)
{
config.AddLinkLibPath(lib);
}
return config;
}
}
}

View file

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
namespace Microsoft.DotNet.Tools.Compiler.Native
{
internal static class ArgumentsParser
{
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;
string ilcArgs = null;
string ilcPath = null;
string appDepSdk = null;
string logPath = null;
IReadOnlyList<string> references = Array.Empty<string>();
IReadOnlyList<string> linklib = Array.Empty<string>();
try
{
ArgumentSyntax.Parse(args, syntax =>
{
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.DefineOption("ilcargs", ref ilcArgs, "Use to specify custom arguments for the IL Compiler.");
syntax.DefineOption("ilcpath", ref ilcPath, "Use to plug in a custom built ilc.exe");
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.");
syntax.DefineParameter("INPUT_ASSEMBLY", ref inputAssembly,
"The managed input assembly to compile to native.");
if (string.IsNullOrWhiteSpace(inputAssembly))
{
syntax.ReportError("Input Assembly is a required parameter.");
}
if (!string.IsNullOrEmpty(configuration))
{
try
{
buildConfiguration = EnumExtensions.Parse<BuildConfiguration>(configuration);
}
catch (ArgumentException)
{
syntax.ReportError($"Invalid Configuration Option: {configuration}");
}
}
if (!string.IsNullOrEmpty(mode))
{
try
{
nativeMode = EnumExtensions.Parse<NativeIntermediateMode>(mode);
}
catch (ArgumentException)
{
syntax.ReportError($"Invalid Mode Option: {mode}");
}
}
});
}
catch (ArgumentSyntaxException)
{
//return ExitFailed;
}
Console.WriteLine($"Input Assembly: {inputAssembly}");
return new ArgValues
{
InputManagedAssemblyPath = inputAssembly,
OutputDirectory = outputDirectory,
IntermediateDirectory = temporaryOutputDirectory,
Architecture = ArchitectureMode.x64,
BuildConfiguration = buildConfiguration,
NativeMode = nativeMode,
ReferencePaths = references,
IlcArgs = ilcArgs,
IlcPath = ilcPath,
LinkLibPaths = linklib,
AppDepSDKPath = appDepSdk,
LogPath = logPath
};
}
}
}

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
{

View file

@ -1,53 +1,195 @@
using System;
using System.Collections.Generic;
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 class NativeCompileSettings
{
public string LogPath { get; set; }
public string InputManagedAssemblyPath { get; set; }
public string OutputDirectory { get; set; }
public string IntermediateDirectory { get; set; }
private const BuildConfiguration DefaultBuiltType = BuildConfiguration.debug;
private const NativeIntermediateMode DefaultNativeModel = NativeIntermediateMode.ryujit;
private const ArchitectureMode DefaultArchitectureMode = ArchitectureMode.x64;
private string _inputManagedAssemblyPath;
private string _appDepSdkPath;
private string _ilcPath;
private string _outputDirectory;
private string _intermediateDirectory;
private string _logPath;
private string _ilcArgs;
private readonly List<string> _referencePaths;
private readonly List<string> _linkLibPaths;
public string LogPath
{
get { return _logPath; }
set { _logPath = Path.GetFullPath(value); }
}
public string InputManagedAssemblyPath
{
get
{
return _inputManagedAssemblyPath;
}
set
{
if(!File.Exists(value))
{
throw new Exception($"Could not find the input managed assembly: {value}");
}
_inputManagedAssemblyPath = Path.GetFullPath(value);
}
}
public string OutputDirectory
{
get
{
return _outputDirectory ?? GetDefaultOutputDirectory();
}
set
{
_outputDirectory = value;
}
}
public string IntermediateDirectory
{
get
{
return _intermediateDirectory ?? GetDefaultIntermediateDirectory();
}
set
{
_intermediateDirectory = value;
}
}
public BuildConfiguration BuildType { get; set; }
public ArchitectureMode Architecture { get; set; }
public NativeIntermediateMode NativeMode { get; set; }
public OSMode OS { get; set; }
public List<string> ReferencePaths { get; set; }
// Optional Customization Points (Can be null)
public string IlcArgs { get; set; }
public List<string> LinkLibPaths { get; set; }
// Required Customization Points (Must have default)
public string AppDepSDKPath { get; set; }
public string IlcPath { get; set; }
public NativeCompileSettings()
public IEnumerable<string> ReferencePaths
{
LinkLibPaths = new List<string>();
ReferencePaths = new List<string>();
}
get
{
var referencePaths = new List<string>(_referencePaths)
{
Path.Combine(AppDepSDKPath, "*.dll")
};
return referencePaths;
}
}
// Optional Customization Points (Can be null)
public string IlcArgs
{
get { return _ilcArgs; }
set { _ilcArgs = Path.GetFullPath(value); }
}
public IEnumerable<string> LinkLibPaths => _linkLibPaths;
// Required Customization Points (Must have default)
public string AppDepSDKPath {
get
{
return _appDepSdkPath;
}
set
{
if (!Directory.Exists(value))
{
throw new Exception($"AppDepSDK Directory does not exist: {value}.");
}
_appDepSdkPath = value;
}
}
public string IlcPath
{
get
{
return _ilcPath;
}
set
{
if (!Directory.Exists(value))
{
throw new Exception($"ILC Directory does not exist: {value}.");
}
_ilcPath = value;
}
}
private NativeCompileSettings()
{
_linkLibPaths = new List<string>();
_referencePaths = new List<string>();
IlcPath = AppContext.BaseDirectory;
Architecture = DefaultArchitectureMode;
BuildType = DefaultBuiltType;
NativeMode = DefaultNativeModel;
AppDepSDKPath = Path.Combine(AppContext.BaseDirectory, "appdepsdk");
}
public static NativeCompileSettings Default
{
get
{
var defaultNativeCompileSettings = new NativeCompileSettings
{
OS = RuntimeInformationExtensions.GetCurrentOS()
};
return defaultNativeCompileSettings;
}
}
public string DetermineFinalOutputPath()
{
var outputDirectory = this.OutputDirectory;
var outputDirectory = OutputDirectory;
var filename = Path.GetFileNameWithoutExtension(this.InputManagedAssemblyPath);
var filename = Path.GetFileNameWithoutExtension(InputManagedAssemblyPath);
var outFile = Path.Combine(outputDirectory, filename + Constants.ExeSuffix);
return outFile;
}
public void AddReference(string reference)
{
_referencePaths.Add(Path.GetFullPath(reference));
}
public void AddLinkLibPath(string linkLibPath)
{
_linkLibPaths.Add(linkLibPath);
}
private string GetDefaultOutputDirectory()
{
return GetOutputDirectory(Constants.BinDirectoryName);
}
private string GetDefaultIntermediateDirectory()
{
return GetOutputDirectory(Constants.ObjDirectoryName);
}
private string GetOutputDirectory(string beginsWith)
{
var dir = Path.Combine(beginsWith, Architecture.ToString(), BuildType.ToString(), "native");
return Path.GetFullPath(dir);
}
}
}

View file

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Compiler.Native
@ -14,72 +11,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
DebugHelper.HandleDebugSwitch(ref args);
return ExecuteApp(args);
}
private static ArgValues GetArgs(string[] args)
{
string inputAssembly = null;
string outputDirectory = null;
string temporaryOutputDirectory = null;
string configuration = null;
string mode = null;
string ilcArgs = null;
string ilcPath = null;
string appDepSdk = null;
string logPath = null;
IReadOnlyList<string> references = Array.Empty<string>();
IReadOnlyList<string> linklib = Array.Empty<string>();
try
{
ArgumentSyntax.Parse(args, syntax =>
{
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.DefineOption("ilcargs", ref ilcArgs, "Use to specify custom arguments for the IL Compiler.");
syntax.DefineOption("ilcpath", ref ilcPath, "Use to plug in a custom built ilc.exe");
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.");
syntax.DefineParameter("INPUT_ASSEMBLY", ref inputAssembly, "The managed input assembly to compile to native.");
});
}
catch (ArgumentSyntaxException)
{
//return ExitFailed;
}
Console.WriteLine($"Input Assembly: {inputAssembly}");
return new ArgValues()
{
InputManagedAssemblyPath = inputAssembly,
OutputDirectory = outputDirectory,
IntermediateDirectory = temporaryOutputDirectory,
Architecture = "x64",
BuildConfiguration = configuration,
NativeMode = mode,
ReferencePaths = references.ToList(),
IlcArgs = ilcArgs,
IlcPath = ilcPath,
LinkLibPaths = linklib.ToList(),
AppDepSDKPath = appDepSdk,
LogPath = logPath
};
}
}
private static int ExecuteApp(string[] args)
{
@ -99,8 +31,8 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
try
{
var cmdLineArgs = GetArgs(args);
var config = ParseAndValidateArgs(cmdLineArgs);
var cmdLineArgs = ArgumentsParser.Parse(args);
var config = cmdLineArgs.GetNativeCompileSettings();
DirectoryExtensions.CleanOrCreateDirectory(config.OutputDirectory);
DirectoryExtensions.CleanOrCreateDirectory(config.IntermediateDirectory);
@ -114,7 +46,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
catch (Exception ex)
{
#if DEBUG
System.Console.WriteLine(ex);
Console.WriteLine(ex);
#else
Reporter.Error.WriteLine(ex.Message);
#endif
@ -130,213 +62,19 @@ namespace Microsoft.DotNet.Tools.Compiler.Native
return null;
}
string content = null;
string content;
try
{
content = File.ReadAllText(rspPath);
}
catch (Exception e)
catch (Exception)
{
Reporter.Error.WriteLine("Unable to Read Response File");
return null;
}
string[] nArgs = content.Split(new [] {"\r\n", "\n"}, StringSplitOptions.RemoveEmptyEntries);
var nArgs = content.Split(new [] {"\r\n", "\n"}, StringSplitOptions.RemoveEmptyEntries);
return nArgs;
}
private static NativeCompileSettings ParseAndValidateArgs(ArgValues args)
{
var config = new NativeCompileSettings();
// Managed Input
if (string.IsNullOrEmpty(args.InputManagedAssemblyPath) || !File.Exists(args.InputManagedAssemblyPath))
{
//TODO make this message good
throw new Exception("Invalid Managed Assembly Argument.");
}
config.InputManagedAssemblyPath = Path.GetFullPath(args.InputManagedAssemblyPath);
// Architecture
if(string.IsNullOrEmpty(args.Architecture))
{
config.Architecture = RuntimeExtensions.GetCurrentArchitecture();
// CoreRT does not support x86 yet
if (config.Architecture != ArchitectureMode.x64)
{
throw new Exception("Native Compilation currently only supported for x64.");
}
}
else
{
try
{
config.Architecture = EnumExtensions.Parse<ArchitectureMode>(args.Architecture.ToLower());
}
catch (Exception e)
{
throw new Exception("Invalid Architecture Option.");
}
}
// BuildConfiguration
if(string.IsNullOrEmpty(args.BuildConfiguration))
{
config.BuildType = GetDefaultBuildType();
}
else
{
try
{
config.BuildType = EnumExtensions.Parse<BuildConfiguration>(args.BuildConfiguration.ToLower());
}
catch (Exception e)
{
throw new Exception("Invalid Configuration Option.");
}
}
// Output
if(string.IsNullOrEmpty(args.OutputDirectory))
{
config.OutputDirectory = GetDefaultOutputDir(config);
}
else
{
config.OutputDirectory = args.OutputDirectory;
}
// Intermediate
if(string.IsNullOrEmpty(args.IntermediateDirectory))
{
config.IntermediateDirectory = GetDefaultIntermediateDir(config);
}
else
{
config.IntermediateDirectory = args.IntermediateDirectory;
}
// Mode
if (string.IsNullOrEmpty(args.NativeMode))
{
config.NativeMode = GetDefaultNativeMode();
}
else
{
try
{
config.NativeMode = EnumExtensions.Parse<NativeIntermediateMode>(args.NativeMode.ToLower());
}
catch (Exception e)
{
throw new Exception("Invalid Mode Option.");
}
}
// AppDeps (TEMP)
if(!string.IsNullOrEmpty(args.AppDepSDKPath))
{
if (!Directory.Exists(args.AppDepSDKPath))
{
throw new Exception("AppDepSDK Directory does not exist.");
}
config.AppDepSDKPath = args.AppDepSDKPath;
var reference = Path.Combine(config.AppDepSDKPath, "*.dll");
config.ReferencePaths.Add(reference);
}
else
{
config.AppDepSDKPath = GetDefaultAppDepSDKPath();
var reference = Path.Combine(config.AppDepSDKPath, "*.dll");
config.ReferencePaths.Add(reference);
}
// IlcPath
if (!string.IsNullOrEmpty(args.IlcPath))
{
if (!Directory.Exists(args.IlcPath))
{
throw new Exception("ILC Directory does not exist.");
}
config.IlcPath = args.IlcPath;
}
else
{
config.IlcPath = GetDefaultIlcPath();
}
// logpath
if (!string.IsNullOrEmpty(args.LogPath))
{
config.LogPath = Path.GetFullPath(args.LogPath);
}
// CodeGenPath
if (!string.IsNullOrEmpty(args.IlcArgs))
{
config.IlcArgs = Path.GetFullPath(args.IlcArgs);
}
// Reference Paths
foreach (var reference in args.ReferencePaths)
{
config.ReferencePaths.Add(Path.GetFullPath(reference));
}
// Link Libs
foreach (var lib in args.LinkLibPaths)
{
config.LinkLibPaths.Add(lib);
}
// OS
config.OS = RuntimeInformationExtensions.GetCurrentOS();
return config;
}
private static string GetDefaultOutputDir(NativeCompileSettings config)
{
var dir = Path.Combine(Constants.BinDirectoryName, config.Architecture.ToString(), config.BuildType.ToString(), "native");
return Path.GetFullPath(dir);
}
private static string GetDefaultIntermediateDir(NativeCompileSettings config)
{
var dir = Path.Combine(Constants.ObjDirectoryName, config.Architecture.ToString(), config.BuildType.ToString(), "native");
return Path.GetFullPath(dir);
}
private static BuildConfiguration GetDefaultBuildType()
{
return BuildConfiguration.debug;
}
private static NativeIntermediateMode GetDefaultNativeMode()
{
return NativeIntermediateMode.ryujit;
}
private static string GetDefaultAppDepSDKPath()
{
var appRoot = AppContext.BaseDirectory;
var dir = Path.Combine(appRoot, "appdepsdk");
return dir;
}
private static string GetDefaultIlcPath()
{
return AppContext.BaseDirectory;
}
}
}