2015-12-10 13:06:33 -08:00
// 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.
2016-02-03 10:57:25 -08:00
using System ;
2015-12-10 13:06:33 -08:00
using System.Collections.Generic ;
using System.IO ;
2016-02-03 10:57:25 -08:00
using System.Linq ;
2015-12-10 13:06:33 -08:00
using Microsoft.Dnx.Runtime.Common.CommandLine ;
using Microsoft.DotNet.Cli.Utils ;
using Microsoft.DotNet.ProjectModel ;
2016-02-03 10:57:25 -08:00
using Microsoft.Extensions.PlatformAbstractions ;
2015-12-10 13:06:33 -08:00
using NuGet.Frameworks ;
2015-12-21 10:42:41 -08:00
// This class is responsible with defining the arguments for the Compile verb.
// It knows how to interpret them and set default values
2015-12-10 13:06:33 -08:00
namespace Microsoft.DotNet.Tools.Compiler
{
public delegate bool OnExecute ( List < ProjectContext > contexts , CompilerCommandApp compilerCommand ) ;
public class CompilerCommandApp
{
private readonly CommandLineApplication _app ;
2015-12-21 10:42:41 -08:00
// options and arguments for compilation
2015-12-10 13:06:33 -08:00
private CommandOption _outputOption ;
2016-02-03 10:57:25 -08:00
private CommandOption _buildBasePath ;
2015-12-10 13:06:33 -08:00
private CommandOption _frameworkOption ;
2016-01-29 09:21:55 -08:00
private CommandOption _runtimeOption ;
2016-02-18 01:09:23 -08:00
private CommandOption _versionSuffixOption ;
2015-12-10 13:06:33 -08:00
private CommandOption _configurationOption ;
private CommandArgument _projectArgument ;
private CommandOption _nativeOption ;
private CommandOption _archOption ;
private CommandOption _ilcArgsOption ;
private CommandOption _ilcPathOption ;
private CommandOption _ilcSdkPathOption ;
private CommandOption _appDepSdkPathOption ;
private CommandOption _cppModeOption ;
private CommandOption _cppCompilerFlagsOption ;
2015-12-21 10:42:41 -08:00
// resolved values for the options and arguments
2015-12-10 13:06:33 -08:00
public string ProjectPathValue { get ; set ; }
2016-02-03 10:57:25 -08:00
public string BuildBasePathValue { get ; set ; }
2015-12-10 13:06:33 -08:00
public string OutputValue { get ; set ; }
2016-02-18 01:09:23 -08:00
public string RuntimeValue { get ; set ; }
public string VersionSuffixValue { get ; set ; }
2015-12-10 13:06:33 -08:00
public string ConfigValue { get ; set ; }
public bool IsNativeValue { get ; set ; }
public string ArchValue { get ; set ; }
2016-02-03 16:34:03 -08:00
public IEnumerable < string > IlcArgsValue { get ; set ; }
2015-12-10 13:06:33 -08:00
public string IlcPathValue { get ; set ; }
public string IlcSdkPathValue { get ; set ; }
public bool IsCppModeValue { get ; set ; }
public string AppDepSdkPathValue { get ; set ; }
public string CppCompilerFlagsValue { get ; set ; }
2015-12-21 10:42:41 -08:00
// workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params
2016-02-18 01:09:23 -08:00
private readonly Dictionary < string , CommandOption > baseClassOptions ;
2015-12-10 13:06:33 -08:00
public CompilerCommandApp ( string name , string fullName , string description )
{
_app = new CommandLineApplication
{
Name = name ,
FullName = fullName ,
Description = description
} ;
baseClassOptions = new Dictionary < string , CommandOption > ( ) ;
AddCompileParameters ( ) ;
}
private void AddCompileParameters ( )
{
_app . HelpOption ( "-h|--help" ) ;
_outputOption = _app . Option ( "-o|--output <OUTPUT_DIR>" , "Directory in which to place outputs" , CommandOptionType . SingleValue ) ;
2016-02-03 10:57:25 -08:00
_buildBasePath = _app . Option ( "-b|--build-base-path <OUTPUT_DIR>" , "Directory in which to place temporary outputs" , CommandOptionType . SingleValue ) ;
2015-12-10 13:06:33 -08:00
_frameworkOption = _app . Option ( "-f|--framework <FRAMEWORK>" , "Compile a specific framework" , CommandOptionType . MultipleValue ) ;
_configurationOption = _app . Option ( "-c|--configuration <CONFIGURATION>" , "Configuration under which to build" , CommandOptionType . SingleValue ) ;
2016-01-29 09:21:55 -08:00
_runtimeOption = _app . Option ( "-r|--runtime <RUNTIME_IDENTIFIER>" , "Target runtime to publish for" , CommandOptionType . SingleValue ) ;
2016-02-18 01:09:23 -08:00
_versionSuffixOption = _app . Option ( "--version-suffix <VERSION_SUFFIX>" , "Defines what `*` should be replaced with in version field in project.json" , CommandOptionType . SingleValue ) ;
2015-12-10 13:06:33 -08:00
_projectArgument = _app . Argument ( "<PROJECT>" , "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory" ) ;
// Native Args
_nativeOption = _app . Option ( "-n|--native" , "Compiles source to native machine code." , CommandOptionType . NoValue ) ;
_archOption = _app . Option ( "-a|--arch <ARCH>" , "The architecture for which to compile. x64 only currently supported." , CommandOptionType . SingleValue ) ;
2016-02-03 16:34:03 -08:00
_ilcArgsOption = _app . Option ( "--ilcarg <ARG>" , "Command line option to be passed directly to ILCompiler." , CommandOptionType . MultipleValue ) ;
2015-12-10 13:06:33 -08:00
_ilcPathOption = _app . Option ( "--ilcpath <PATH>" , "Path to the folder containing custom built ILCompiler." , CommandOptionType . SingleValue ) ;
_ilcSdkPathOption = _app . Option ( "--ilcsdkpath <PATH>" , "Path to the folder containing ILCompiler application dependencies." , CommandOptionType . SingleValue ) ;
_appDepSdkPathOption = _app . Option ( "--appdepsdkpath <PATH>" , "Path to the folder containing ILCompiler application dependencies." , CommandOptionType . SingleValue ) ;
_cppModeOption = _app . Option ( "--cpp" , "Flag to do native compilation with C++ code generator." , CommandOptionType . NoValue ) ;
_cppCompilerFlagsOption = _app . Option ( "--cppcompilerflags <flags>" , "Additional flags to be passed to the native compiler." , CommandOptionType . SingleValue ) ;
}
public int Execute ( OnExecute execute , string [ ] args )
{
_app . OnExecute ( ( ) = >
{
// Locate the project and get the name and full path
ProjectPathValue = _projectArgument . Value ;
if ( string . IsNullOrEmpty ( ProjectPathValue ) )
{
ProjectPathValue = Directory . GetCurrentDirectory ( ) ;
}
OutputValue = _outputOption . Value ( ) ;
2016-02-03 10:57:25 -08:00
BuildBasePathValue = _buildBasePath . Value ( ) ;
2015-12-10 13:06:33 -08:00
ConfigValue = _configurationOption . Value ( ) ? ? Constants . DefaultConfiguration ;
2016-01-29 09:21:55 -08:00
RuntimeValue = _runtimeOption . Value ( ) ;
2016-02-18 01:09:23 -08:00
VersionSuffixValue = _versionSuffixOption . Value ( ) ;
2015-12-10 13:06:33 -08:00
IsNativeValue = _nativeOption . HasValue ( ) ;
ArchValue = _archOption . Value ( ) ;
2016-02-03 16:34:03 -08:00
IlcArgsValue = _ilcArgsOption . HasValue ( ) ? _ilcArgsOption . Values : Enumerable . Empty < string > ( ) ;
2015-12-10 13:06:33 -08:00
IlcPathValue = _ilcPathOption . Value ( ) ;
IlcSdkPathValue = _ilcSdkPathOption . Value ( ) ;
AppDepSdkPathValue = _appDepSdkPathOption . Value ( ) ;
IsCppModeValue = _cppModeOption . HasValue ( ) ;
CppCompilerFlagsValue = _cppCompilerFlagsOption . Value ( ) ;
2016-02-03 10:57:25 -08:00
IEnumerable < ProjectContext > contexts ;
2016-02-18 01:09:23 -08:00
// Set defaults based on the environment
var settings = ProjectReaderSettings . ReadFromEnvironment ( ) ;
if ( ! string . IsNullOrEmpty ( VersionSuffixValue ) )
{
settings . VersionSuffix = VersionSuffixValue ;
}
2016-02-03 10:57:25 -08:00
if ( _frameworkOption . HasValue ( ) )
{
contexts = _frameworkOption . Values
2016-02-18 01:09:23 -08:00
. Select ( f = >
{
return ProjectContext . CreateBuilder ( ProjectPathValue , NuGetFramework . Parse ( f ) )
. WithReaderSettings ( settings )
. Build ( ) ;
} ) ;
2016-02-03 10:57:25 -08:00
}
else
{
if ( ! string . IsNullOrEmpty ( OutputValue ) )
{
throw new InvalidOperationException ( $"'{_frameworkOption.LongName}' is required when '{_outputOption.LongName}' is specified" ) ;
}
else
{
2016-02-18 01:09:23 -08:00
contexts = ProjectContext . CreateContextForEachFramework ( ProjectPathValue , settings ) ;
2016-02-03 10:57:25 -08:00
}
}
2015-12-10 13:06:33 -08:00
var success = execute ( contexts . ToList ( ) , this ) ;
return success ? 0 : 1 ;
} ) ;
return _app . Execute ( args ) ;
}
2015-12-21 10:42:41 -08:00
public CompilerCommandApp ShallowCopy ( )
{
2016-02-18 01:09:23 -08:00
return ( CompilerCommandApp ) MemberwiseClone ( ) ;
2015-12-21 10:42:41 -08:00
}
// CommandOptionType is internal. Cannot pass it as argument. Therefore the method name encodes the option type.
2016-02-18 01:09:23 -08:00
protected void AddNoValueOption ( string optionTemplate , string descriptino )
{
2015-12-10 13:06:33 -08:00
baseClassOptions [ optionTemplate ] = _app . Option ( optionTemplate , descriptino , CommandOptionType . NoValue ) ;
}
protected bool OptionHasValue ( string optionTemplate )
{
CommandOption option ;
return baseClassOptions . TryGetValue ( optionTemplate , out option ) & & option . HasValue ( ) ;
}
2016-02-16 08:42:00 -08:00
public IEnumerable < string > GetRuntimes ( )
{
var rids = new List < string > ( ) ;
if ( string . IsNullOrEmpty ( RuntimeValue ) )
{
return PlatformServices . Default . Runtime . GetAllCandidateRuntimeIdentifiers ( ) ;
}
else
{
2016-02-18 01:09:23 -08:00
return new [ ] { RuntimeValue } ;
2016-02-16 08:42:00 -08:00
}
}
2015-12-10 13:06:33 -08:00
}
2016-02-03 16:34:03 -08:00
}