2015-10-23 15:21:49 -07:00
using System ;
2015-10-13 14:31:29 -07:00
using System.Collections.Generic ;
2015-10-06 10:46:43 -07:00
using System.IO ;
using System.Linq ;
2015-10-18 07:10:22 -07:00
using System.Runtime.InteropServices ;
2015-10-06 10:46:43 -07:00
using Microsoft.Dnx.Runtime.Common.CommandLine ;
using Microsoft.DotNet.Cli.Utils ;
2015-10-18 19:02:09 -07:00
using Microsoft.DotNet.Tools.Common ;
2015-10-13 14:31:29 -07:00
using Microsoft.Extensions.ProjectModel ;
using Microsoft.Extensions.ProjectModel.Compilation ;
2015-11-01 16:21:10 -08:00
using Microsoft.Extensions.ProjectModel.Graph ;
2015-10-13 14:31:29 -07:00
using NuGet.Frameworks ;
2015-10-06 10:46:43 -07:00
namespace Microsoft.DotNet.Tools.Compiler
{
public class Program
{
public static int Main ( string [ ] args )
{
2015-10-13 14:31:29 -07:00
DebugHelper . HandleDebugSwitch ( ref args ) ;
2015-10-06 10:46:43 -07:00
var app = new CommandLineApplication ( ) ;
app . Name = "dotnet compile" ;
app . FullName = ".NET Compiler" ;
app . Description = "Compiler for the .NET Platform" ;
app . HelpOption ( "-h|--help" ) ;
var output = app . Option ( "-o|--output <OUTPUT_DIR>" , "Directory in which to place outputs" , CommandOptionType . SingleValue ) ;
2015-11-01 05:50:39 -08:00
var intermediateOutput = app . Option ( "-t|--temp-output <OUTPUT_DIR>" , "Directory in which to place temporary outputs" , CommandOptionType . SingleValue ) ;
2015-10-13 14:31:29 -07:00
var framework = app . Option ( "-f|--framework <FRAMEWORK>" , "Compile a specific framework" , CommandOptionType . MultipleValue ) ;
var configuration = app . Option ( "-c|--configuration <CONFIGURATION>" , "Configuration under which to build" , CommandOptionType . SingleValue ) ;
2015-10-17 23:43:28 -07:00
var noProjectDependencies = app . Option ( "--no-project-dependencies" , "Skips building project references." , CommandOptionType . NoValue ) ;
2015-10-06 10:46:43 -07:00
var project = app . Argument ( "<PROJECT>" , "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory" ) ;
2015-10-30 15:13:53 -07:00
var native = app . Option ( "-n|--native" , "Compiles source to native machine code." , CommandOptionType . NoValue ) ;
2015-10-06 10:46:43 -07:00
app . OnExecute ( ( ) = >
{
// Locate the project and get the name and full path
var path = project . Value ;
if ( string . IsNullOrEmpty ( path ) )
{
path = Directory . GetCurrentDirectory ( ) ;
}
2015-10-13 14:31:29 -07:00
2015-10-18 07:41:59 -07:00
var buildProjectReferences = ! noProjectDependencies . HasValue ( ) ;
2015-10-29 12:03:01 -07:00
var isNative = native . HasValue ( ) ;
2015-10-13 14:31:29 -07:00
// Load project contexts for each framework and compile them
bool success = true ;
if ( framework . HasValue ( ) )
2015-10-06 10:46:43 -07:00
{
2015-10-13 14:31:29 -07:00
foreach ( var context in framework . Values . Select ( f = > ProjectContext . Create ( path , NuGetFramework . Parse ( f ) ) ) )
{
2015-11-01 05:50:39 -08:00
success & = Compile ( context , configuration . Value ( ) ? ? Constants . DefaultConfiguration , output . Value ( ) , intermediateOutput . Value ( ) , buildProjectReferences ) ;
2015-11-01 16:21:10 -08:00
2015-10-29 12:03:01 -07:00
if ( isNative )
{
2015-10-30 15:20:14 -07:00
success & = CompileNative ( context , configuration . Value ( ) ? ? Constants . DefaultConfiguration , output . Value ( ) , buildProjectReferences ) ;
2015-10-29 12:03:01 -07:00
}
2015-10-13 14:31:29 -07:00
}
2015-10-06 10:46:43 -07:00
}
2015-10-13 14:31:29 -07:00
else
2015-10-06 10:46:43 -07:00
{
2015-10-13 14:31:29 -07:00
foreach ( var context in ProjectContext . CreateContextForEachFramework ( path ) )
{
2015-11-01 05:50:39 -08:00
success & = Compile ( context , configuration . Value ( ) ? ? Constants . DefaultConfiguration , output . Value ( ) , intermediateOutput . Value ( ) , buildProjectReferences ) ;
2015-11-01 16:21:10 -08:00
2015-10-29 12:03:01 -07:00
if ( isNative )
{
2015-10-30 15:34:50 -07:00
success & = CompileNative ( context , configuration . Value ( ) ? ? Constants . DefaultConfiguration , output . Value ( ) , buildProjectReferences ) ;
2015-10-29 12:03:01 -07:00
}
2015-10-13 14:31:29 -07:00
}
2015-10-06 10:46:43 -07:00
}
2015-10-13 14:31:29 -07:00
return success ? 0 : 1 ;
2015-10-06 10:46:43 -07:00
} ) ;
try
{
return app . Execute ( args ) ;
}
2015-10-18 02:06:15 -07:00
catch ( Exception ex )
2015-10-06 10:46:43 -07:00
{
2015-10-20 01:43:37 -07:00
#if DEBUG
Console . Error . WriteLine ( ex ) ;
#else
2015-10-06 10:46:43 -07:00
Console . Error . WriteLine ( ex . Message ) ;
2015-10-20 01:43:37 -07:00
#endif
2015-10-06 10:46:43 -07:00
return 1 ;
}
}
2015-10-30 15:13:53 -07:00
private static bool CompileNative ( ProjectContext context , string configuration , string outputOptionValue , bool buildProjectReferences )
2015-10-30 14:48:09 -07:00
{
string outputPath = Path . Combine ( GetOutputPath ( context , configuration , outputOptionValue ) , "native" ) ;
2015-11-01 16:21:10 -08:00
2015-10-29 13:29:38 -07:00
var compilationOptions = context . ProjectFile . GetCompilerOptions ( context . TargetFramework , configuration ) ;
2015-10-29 12:03:01 -07:00
var managedBinaryPath = Path . Combine ( outputPath , context . ProjectFile . Name + ( compilationOptions . EmitEntryPoint . GetValueOrDefault ( ) ? ".exe" : ".dll" ) ) ;
2015-11-01 16:21:10 -08:00
2015-10-29 12:03:01 -07:00
// Do Native Compilation
2015-10-29 13:29:38 -07:00
var result = Command . Create ( $"dotnet-compile-native" , $"\" { managedBinaryPath } \ " \"{outputPath}\"" )
2015-10-29 12:03:01 -07:00
. ForwardStdErr ( )
. ForwardStdOut ( )
. Execute ( ) ;
2015-11-01 16:21:10 -08:00
2015-10-29 13:29:38 -07:00
return result . ExitCode = = 0 ;
2015-10-29 12:03:01 -07:00
}
2015-11-01 05:50:39 -08:00
private static bool Compile ( ProjectContext context , string configuration , string outputOptionValue , string intermediateOutputValue , bool buildProjectReferences )
2015-10-06 10:46:43 -07:00
{
2015-11-01 05:40:19 -08:00
// Set up Output Paths
2015-10-29 12:03:01 -07:00
string outputPath = GetOutputPath ( context , configuration , outputOptionValue ) ;
2015-11-01 05:50:39 -08:00
string intermediateOutputPath = GetIntermediateOutputPath ( context , configuration , intermediateOutputValue , outputOptionValue ) ;
2015-10-29 12:03:01 -07:00
2015-11-01 05:40:19 -08:00
Directory . CreateDirectory ( outputPath ) ;
Directory . CreateDirectory ( intermediateOutputPath ) ;
2015-10-29 12:03:01 -07:00
2015-10-13 14:31:29 -07:00
// Create the library exporter
var exporter = context . CreateExporter ( configuration ) ;
2015-10-21 00:26:57 -07:00
var diagnostics = new List < DiagnosticMessage > ( ) ;
2015-10-17 03:49:49 -07:00
2015-10-21 00:26:57 -07:00
// Collect dependency diagnostics
diagnostics . AddRange ( context . LibraryManager . GetAllDiagnostics ( ) ) ;
2015-10-17 03:49:49 -07:00
2015-10-13 14:31:29 -07:00
// Gather exports for the project
2015-11-01 16:21:10 -08:00
var dependencies = exporter . GetDependencies ( ) . ToList ( ) ;
2015-10-13 14:31:29 -07:00
2015-10-18 07:41:59 -07:00
if ( buildProjectReferences )
2015-10-06 10:46:43 -07:00
{
2015-10-17 23:43:28 -07:00
var projects = new Dictionary < string , ProjectDescription > ( ) ;
// Build project references
2015-11-01 05:40:19 -08:00
foreach ( var dependency in dependencies )
2015-10-13 14:31:29 -07:00
{
2015-10-17 23:43:28 -07:00
var projectDependency = dependency . Library as ProjectDescription ;
2015-11-01 05:40:19 -08:00
if ( projectDependency ! = null & & projectDependency . Project . Files . SourceFiles . Any ( ) )
2015-10-17 23:43:28 -07:00
{
projects [ projectDependency . Identity . Name ] = projectDependency ;
}
}
foreach ( var projectDependency in Sort ( projects ) )
{
// Skip compiling project dependencies since we've already figured out the build order
2015-11-01 05:50:39 -08:00
var compileResult = Command . Create ( "dotnet-compile" , $"--framework {projectDependency.Framework} --configuration {configuration} --output \" { outputPath } \ " --temp-output \"{intermediateOutputPath}\" --no-project-dependencies \"{projectDependency.Project.ProjectDirectory}\"" )
2015-10-17 23:43:28 -07:00
. ForwardStdOut ( )
. ForwardStdErr ( )
2015-10-21 03:11:27 -07:00
. Execute ( ) ;
2015-10-17 23:43:28 -07:00
2015-10-13 14:31:29 -07:00
if ( compileResult . ExitCode ! = 0 )
{
return false ;
}
}
2015-10-18 07:41:59 -07:00
projects . Clear ( ) ;
2015-10-06 10:46:43 -07:00
}
2015-11-01 16:21:10 -08:00
Reporter . Output . WriteLine ( $"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}" ) ;
2015-10-13 14:31:29 -07:00
// Dump dependency data
2015-10-17 03:49:49 -07:00
// TODO: Turn on only if verbose, we can look at the response
// file anyways
// ShowDependencyInfo(dependencies);
2015-10-13 14:31:29 -07:00
// Get compilation options
2015-11-01 05:40:19 -08:00
var outputName = GetProjectOutput ( context . ProjectFile , context . TargetFramework , configuration , outputPath ) ;
2015-10-21 15:21:14 -07:00
2015-10-18 01:17:13 -07:00
// Assemble args
var compilerArgs = new List < string > ( )
2015-10-06 10:46:43 -07:00
{
2015-10-13 14:31:29 -07:00
"-nostdlib" ,
"-nologo" ,
2015-10-15 12:56:07 -07:00
$"-out:\" { outputName } \ ""
2015-10-13 14:31:29 -07:00
} ;
2015-10-18 19:02:09 -07:00
2015-10-21 01:18:14 -07:00
// Default suppressions, some versions of mono don't support these
compilerArgs . Add ( "-nowarn:CS1701" ) ;
compilerArgs . Add ( "-nowarn:CS1702" ) ;
compilerArgs . Add ( "-nowarn:CS1705" ) ;
2015-10-21 15:21:14 -07:00
2015-11-01 05:40:19 -08:00
var compilationOptions = context . ProjectFile . GetCompilerOptions ( context . TargetFramework , configuration ) ;
2015-10-13 14:31:29 -07:00
// Add compilation options to the args
2015-10-21 01:18:14 -07:00
ApplyCompilationOptions ( compilationOptions , compilerArgs ) ;
2015-10-13 14:31:29 -07:00
foreach ( var dependency in dependencies )
{
2015-11-01 05:40:19 -08:00
var projectDependency = dependency . Library as ProjectDescription ;
if ( projectDependency ! = null )
{
if ( projectDependency . Project . Files . SourceFiles . Any ( ) )
{
var projectOutputPath = GetProjectOutput ( projectDependency . Project , projectDependency . Framework , configuration , outputPath ) ;
compilerArgs . Add ( $"-r:\" { projectOutputPath } \ "" ) ;
}
}
else
{
compilerArgs . AddRange ( dependency . CompilationAssemblies . Select ( r = > $"-r:\" { r . ResolvedPath } \ "" ) ) ;
}
2015-10-22 03:32:32 -07:00
compilerArgs . AddRange ( dependency . SourceReferences . Select ( s = > $"\" { s } \ "" ) ) ;
2015-10-06 10:46:43 -07:00
}
2015-10-13 14:31:29 -07:00
// Add project source files
2015-10-23 15:21:49 -07:00
var sourceFiles = context . ProjectFile . Files . SourceFiles ;
compilerArgs . AddRange ( sourceFiles . Select ( s = > $"\" { s } \ "" ) ) ;
2015-10-18 01:17:13 -07:00
2015-10-18 21:07:48 -07:00
if ( ! AddResources ( context . ProjectFile , compilerArgs , intermediateOutputPath ) )
{
return false ;
}
2015-10-18 19:02:09 -07:00
2015-10-23 15:21:49 -07:00
var compilerName = context . ProjectFile . CompilerName ;
2015-10-26 09:23:58 -07:00
compilerName = compilerName ? ? "csc" ;
2015-10-13 14:31:29 -07:00
// Write RSP file
2015-11-01 05:40:19 -08:00
var rsp = Path . Combine ( intermediateOutputPath , $"dotnet-compile.{compilerName}.{context.ProjectFile.Name}.rsp" ) ;
2015-10-18 01:17:13 -07:00
File . WriteAllLines ( rsp , compilerArgs ) ;
2015-10-23 15:21:49 -07:00
var result = Command . Create ( $"dotnet-compile-{compilerName}" , $"\" { rsp } \ "" )
2015-10-21 03:11:27 -07:00
. OnErrorLine ( line = >
2015-10-21 00:26:57 -07:00
{
var diagnostic = ParseDiagnostic ( context . ProjectDirectory , line ) ;
if ( diagnostic ! = null )
{
diagnostics . Add ( diagnostic ) ;
}
else
{
2015-11-01 16:21:10 -08:00
Reporter . Error . WriteLine ( line ) ;
2015-10-21 00:26:57 -07:00
}
} )
. OnOutputLine ( line = >
{
var diagnostic = ParseDiagnostic ( context . ProjectDirectory , line ) ;
if ( diagnostic ! = null )
{
diagnostics . Add ( diagnostic ) ;
}
else
{
2015-11-01 16:21:10 -08:00
Reporter . Output . WriteLine ( line ) ;
2015-10-21 00:26:57 -07:00
}
} )
2015-10-21 03:11:27 -07:00
. Execute ( ) ;
2015-10-18 01:17:13 -07:00
2015-10-21 00:26:57 -07:00
foreach ( var diag in diagnostics )
{
PrintDiagnostic ( diag ) ;
}
2015-10-21 15:21:14 -07:00
var success = result . ExitCode = = 0 ;
2015-11-01 02:04:26 -08:00
if ( success & & compilationOptions . EmitEntryPoint . GetValueOrDefault ( ) )
2015-10-21 15:21:14 -07:00
{
2015-11-01 02:04:26 -08:00
var runtimeContext = ProjectContext . Create ( context . ProjectDirectory , context . TargetFramework , new [ ] { RuntimeIdentifier . Current } ) ;
2015-11-01 16:21:10 -08:00
MakeRunnable ( runtimeContext ,
outputPath ,
2015-11-01 02:04:26 -08:00
runtimeContext . CreateExporter ( configuration ) ) ;
2015-10-21 15:21:14 -07:00
}
2015-10-21 15:21:14 -07:00
PrintSummary ( success , diagnostics ) ;
2015-10-21 00:26:57 -07:00
return success ;
}
2015-11-01 05:40:19 -08:00
private static string GetProjectOutput ( Project project , NuGetFramework framework , string configuration , string outputPath )
{
var compilationOptions = project . GetCompilerOptions ( framework , configuration ) ;
var outputExtension = ".dll" ;
if ( framework . IsDesktop ( ) & & compilationOptions . EmitEntryPoint . GetValueOrDefault ( ) )
{
outputExtension = ".exe" ;
}
return Path . Combine ( outputPath , project . Name + outputExtension ) ;
}
2015-10-29 12:03:01 -07:00
private static string GetOutputPath ( ProjectContext context , string configuration , string outputOptionValue )
{
2015-10-30 14:48:09 -07:00
var outputPath = string . Empty ;
2015-10-21 00:26:57 -07:00
2015-10-29 12:03:01 -07:00
if ( string . IsNullOrEmpty ( outputOptionValue ) )
{
outputPath = Path . Combine (
GetDefaultRootOutputPath ( context , outputOptionValue ) ,
Constants . BinDirectoryName ,
configuration ,
context . TargetFramework . GetTwoDigitShortFolderName ( ) ) ;
}
else
{
outputPath = outputOptionValue ;
}
return outputPath ;
}
2015-11-01 05:50:39 -08:00
private static string GetIntermediateOutputPath ( ProjectContext context , string configuration , string intermediateOutputValue , string outputOptionValue )
2015-10-29 12:03:01 -07:00
{
2015-11-01 05:40:19 -08:00
var intermediateOutputPath = string . Empty ;
2015-10-29 12:03:01 -07:00
2015-11-01 05:50:39 -08:00
if ( string . IsNullOrEmpty ( intermediateOutputValue ) )
2015-10-29 12:03:01 -07:00
{
intermediateOutputPath = Path . Combine (
GetDefaultRootOutputPath ( context , outputOptionValue ) ,
Constants . ObjDirectoryName ,
configuration ,
context . TargetFramework . GetTwoDigitShortFolderName ( ) ) ;
}
else
{
2015-11-01 05:50:39 -08:00
intermediateOutputPath = intermediateOutputValue ;
2015-10-29 12:03:01 -07:00
}
return intermediateOutputPath ;
}
2015-10-29 13:29:38 -07:00
private static string GetDefaultRootOutputPath ( ProjectContext context , string outputOptionValue )
2015-10-29 12:03:01 -07:00
{
2015-11-01 05:40:19 -08:00
string rootOutputPath = string . Empty ;
2015-10-29 12:03:01 -07:00
if ( string . IsNullOrEmpty ( outputOptionValue ) )
{
2015-11-01 16:21:10 -08:00
rootOutputPath = context . ProjectFile . ProjectDirectory ;
2015-10-29 12:03:01 -07:00
}
return rootOutputPath ;
}
private static void CleanOrCreateDirectory ( string path )
{
if ( Directory . Exists ( path ) )
2015-11-01 16:21:10 -08:00
{
2015-10-30 14:56:10 -07:00
try
{
Directory . Delete ( path , recursive : true ) ;
}
2015-11-01 16:21:10 -08:00
catch ( Exception e )
2015-10-30 14:56:10 -07:00
{
Console . WriteLine ( "Unable to remove directory: " + path ) ;
Console . WriteLine ( e . Message ) ;
}
2015-10-29 12:03:01 -07:00
}
2015-11-01 16:21:10 -08:00
2015-10-29 13:29:38 -07:00
Directory . CreateDirectory ( path ) ;
2015-10-29 12:03:01 -07:00
}
2015-11-01 02:04:26 -08:00
2015-11-01 04:06:12 -08:00
private static void MakeRunnable ( ProjectContext runtimeContext , string outputPath , LibraryExporter exporter )
2015-11-01 02:04:26 -08:00
{
if ( runtimeContext . TargetFramework . IsDesktop ( ) )
{
// On desktop we need to copy dependencies since we don't own the host
2015-11-01 16:21:10 -08:00
foreach ( var export in exporter . GetDependencies ( ) )
2015-11-01 02:04:26 -08:00
{
2015-11-01 16:21:10 -08:00
CopyExport ( outputPath , export ) ;
2015-11-01 02:04:26 -08:00
}
}
else
{
2015-11-01 04:06:12 -08:00
EmitHost ( runtimeContext , outputPath , exporter ) ;
2015-11-01 02:04:26 -08:00
}
}
2015-11-01 16:21:10 -08:00
private static void CopyExport ( string outputPath , LibraryExport export )
{
CopyFiles ( export . RuntimeAssemblies , outputPath ) ;
CopyFiles ( export . NativeLibraries , outputPath ) ;
}
2015-11-01 04:06:12 -08:00
private static void EmitHost ( ProjectContext runtimeContext , string outputPath , LibraryExporter exporter )
2015-10-21 15:21:14 -07:00
{
// Write the Host information file (basically a simplified form of the lock file)
2015-11-01 02:04:26 -08:00
var lines = new List < string > ( ) ;
2015-11-01 16:21:10 -08:00
foreach ( var export in exporter . GetAllExports ( ) )
2015-10-21 15:21:14 -07:00
{
2015-11-01 16:21:10 -08:00
if ( export . Library = = runtimeContext . RootProject )
2015-11-01 04:06:12 -08:00
{
2015-11-01 05:40:19 -08:00
continue ;
2015-11-01 04:06:12 -08:00
}
2015-11-01 16:21:10 -08:00
if ( export . Library is ProjectDescription )
{
// Copy project dependencies to the output folder
CopyFiles ( export . RuntimeAssemblies , outputPath ) ;
CopyFiles ( export . NativeLibraries , outputPath ) ;
}
2015-11-01 04:06:12 -08:00
else
{
lines . AddRange ( GenerateLines ( export , export . RuntimeAssemblies , "runtime" ) ) ;
lines . AddRange ( GenerateLines ( export , export . NativeLibraries , "native" ) ) ;
}
2015-10-21 15:21:14 -07:00
}
2015-11-01 04:06:12 -08:00
File . WriteAllLines ( Path . Combine ( outputPath , runtimeContext . ProjectFile . Name + ".deps" ) , lines ) ;
2015-10-21 15:21:14 -07:00
// Copy the host in
2015-11-01 04:06:12 -08:00
CopyHost ( Path . Combine ( outputPath , runtimeContext . ProjectFile . Name + Constants . ExeSuffix ) ) ;
2015-10-21 15:21:14 -07:00
}
private static void CopyHost ( string target )
{
var hostPath = Path . Combine ( AppContext . BaseDirectory , Constants . HostExecutableName ) ;
2015-11-01 05:40:19 -08:00
File . Copy ( hostPath , target , overwrite : true ) ;
2015-10-21 15:21:14 -07:00
}
private static IEnumerable < string > GenerateLines ( LibraryExport export , IEnumerable < LibraryAsset > items , string type )
{
return items . Select ( item = >
EscapeCsv ( export . Library . Identity . Type . Value ) + "," +
EscapeCsv ( export . Library . Identity . Name ) + "," +
EscapeCsv ( export . Library . Identity . Version . ToNormalizedString ( ) ) + "," +
EscapeCsv ( export . Library . Hash ) + "," +
EscapeCsv ( type ) + "," +
EscapeCsv ( item . Name ) + "," +
EscapeCsv ( item . RelativePath ) + "," ) ;
}
private static string EscapeCsv ( string input )
{
return "\"" + input . Replace ( "\\" , "\\\\" ) . Replace ( "\"" , "\\\"" ) + "\"" ;
}
2015-10-21 15:21:14 -07:00
private static void PrintSummary ( bool success , List < DiagnosticMessage > diagnostics )
2015-10-21 00:26:57 -07:00
{
2015-11-01 16:21:10 -08:00
Reporter . Output . WriteLine ( ) ;
2015-10-21 00:26:57 -07:00
var errorCount = diagnostics . Count ( d = > d . Severity = = DiagnosticMessageSeverity . Error ) ;
var warningCount = diagnostics . Count ( d = > d . Severity = = DiagnosticMessageSeverity . Warning ) ;
if ( errorCount > 0 )
{
Reporter . Output . WriteLine ( "Compilation failed." . Red ( ) ) ;
}
else
2015-10-18 07:32:42 -07:00
{
2015-10-21 00:26:57 -07:00
Reporter . Output . WriteLine ( "Compilation succeeded." . Green ( ) ) ;
2015-10-18 07:32:42 -07:00
}
2015-10-21 00:26:57 -07:00
Reporter . Output . WriteLine ( $" {warningCount} Warning(s)" ) ;
Reporter . Output . WriteLine ( $" {errorCount} Error(s)" ) ;
2015-11-01 16:21:10 -08:00
Reporter . Output . WriteLine ( ) ;
2015-10-13 14:31:29 -07:00
}
2015-10-18 21:07:48 -07:00
private static bool AddResources ( Project project , List < string > compilerArgs , string intermediateOutputPath )
2015-10-18 19:02:09 -07:00
{
string root = PathUtility . EnsureTrailingSlash ( project . ProjectDirectory ) ;
foreach ( var resourceFile in project . Files . ResourceFiles )
{
string resourceName = null ;
string rootNamespace = null ;
var resourcePath = resourceFile . Key ;
if ( string . IsNullOrEmpty ( resourceFile . Value ) )
{
// No logical name, so use the file name
resourceName = ResourcePathUtility . GetResourceName ( root , resourcePath ) ;
rootNamespace = project . Name ;
}
else
{
resourceName = CreateCSharpManifestResourceName . EnsureResourceExtension ( resourceFile . Value , resourcePath ) ;
rootNamespace = null ;
}
var name = CreateCSharpManifestResourceName . CreateManifestName ( resourceName , rootNamespace ) ;
var fileName = resourcePath ;
2015-10-18 21:07:48 -07:00
if ( ResourcePathUtility . IsResxResourceFile ( fileName ) )
{
var ext = Path . GetExtension ( fileName ) ;
if ( string . Equals ( ext , ".resx" , StringComparison . OrdinalIgnoreCase ) )
{
// {file}.resx -> {file}.resources
var resourcesFile = Path . Combine ( intermediateOutputPath , name ) ;
2015-10-22 03:32:32 -07:00
var result = Command . Create ( "resgen" , $"\" { fileName } \ " \"{resourcesFile}\"" )
2015-10-18 21:07:48 -07:00
. ForwardStdErr ( )
. ForwardStdOut ( )
2015-10-21 03:11:27 -07:00
. Execute ( ) ;
2015-10-18 21:07:48 -07:00
if ( result . ExitCode ! = 0 )
{
return false ;
}
// Use this as the resource name instead
fileName = resourcesFile ;
}
}
2015-10-18 19:02:09 -07:00
compilerArgs . Add ( $"-resource:\" { fileName } \ ",{name}" ) ;
}
2015-10-18 21:07:48 -07:00
return true ;
2015-10-18 19:02:09 -07:00
}
2015-10-17 23:43:28 -07:00
private static ISet < ProjectDescription > Sort ( Dictionary < string , ProjectDescription > projects )
{
var outputs = new HashSet < ProjectDescription > ( ) ;
foreach ( var pair in projects )
{
Sort ( pair . Value , projects , outputs ) ;
}
return outputs ;
}
private static void Sort ( ProjectDescription project , Dictionary < string , ProjectDescription > projects , ISet < ProjectDescription > outputs )
{
// Sorts projects in dependency order so that we only build them once per chain
foreach ( var dependency in project . Dependencies )
{
ProjectDescription projectDependency ;
if ( projects . TryGetValue ( dependency . Name , out projectDependency ) )
{
Sort ( projectDependency , projects , outputs ) ;
}
}
outputs . Add ( project ) ;
}
2015-10-21 00:26:57 -07:00
private static DiagnosticMessage ParseDiagnostic ( string projectRootPath , string line )
{
var error = CanonicalError . Parse ( line ) ;
if ( error ! = null )
{
var severity = error . category = = CanonicalError . Parts . Category . Error ?
DiagnosticMessageSeverity . Error : DiagnosticMessageSeverity . Warning ;
2015-10-21 15:21:14 -07:00
2015-10-21 00:26:57 -07:00
return new DiagnosticMessage (
error . code ,
error . text ,
Path . IsPathRooted ( error . origin ) ? line : projectRootPath + Path . DirectorySeparatorChar + line ,
Path . Combine ( projectRootPath , error . origin ) ,
severity ,
error . line ,
error . column ,
error . endColumn ,
error . endLine ,
source : null ) ;
}
return null ;
}
2015-10-21 15:21:14 -07:00
2015-10-21 00:26:57 -07:00
private static void PrintDiagnostic ( DiagnosticMessage diag )
{
switch ( diag . Severity )
{
case DiagnosticMessageSeverity . Info :
Reporter . Error . WriteLine ( diag . FormattedMessage ) ;
break ;
case DiagnosticMessageSeverity . Warning :
Reporter . Error . WriteLine ( diag . FormattedMessage . Yellow ( ) . Bold ( ) ) ;
break ;
case DiagnosticMessageSeverity . Error :
Reporter . Error . WriteLine ( diag . FormattedMessage . Red ( ) . Bold ( ) ) ;
break ;
}
}
2015-10-21 01:18:14 -07:00
private static void ApplyCompilationOptions ( CompilerOptions compilationOptions , List < string > compilerArgs )
2015-10-13 14:31:29 -07:00
{
2015-10-15 12:56:07 -07:00
var targetType = compilationOptions . EmitEntryPoint . GetValueOrDefault ( ) ? "exe" : "library" ;
2015-10-17 03:32:58 -07:00
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( $"-target:{targetType}" ) ;
2015-10-17 03:32:58 -07:00
2015-10-15 12:56:07 -07:00
if ( compilationOptions . AllowUnsafe . GetValueOrDefault ( ) )
2015-10-13 14:31:29 -07:00
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( "-unsafe+" ) ;
2015-10-13 14:31:29 -07:00
}
2015-10-17 03:32:58 -07:00
2015-10-21 01:18:14 -07:00
compilerArgs . AddRange ( compilationOptions . Defines . Select ( d = > $"-d:{d}" ) ) ;
2015-10-17 03:32:58 -07:00
2015-10-15 12:56:07 -07:00
if ( compilationOptions . Optimize . GetValueOrDefault ( ) )
2015-10-06 10:46:43 -07:00
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( "-optimize" ) ;
2015-10-06 10:46:43 -07:00
}
2015-10-17 03:32:58 -07:00
2015-10-13 14:31:29 -07:00
if ( ! string . IsNullOrEmpty ( compilationOptions . Platform ) )
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( $"-platform:{compilationOptions.Platform}" ) ;
2015-10-13 14:31:29 -07:00
}
2015-10-17 03:32:58 -07:00
2015-10-15 12:56:07 -07:00
if ( compilationOptions . WarningsAsErrors . GetValueOrDefault ( ) )
2015-10-13 14:31:29 -07:00
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( "-warnaserror" ) ;
2015-10-13 14:31:29 -07:00
}
2015-10-17 03:32:58 -07:00
if ( compilationOptions . DelaySign . GetValueOrDefault ( ) )
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( "-delaysign+" ) ;
2015-10-17 03:32:58 -07:00
}
if ( ! string . IsNullOrEmpty ( compilationOptions . KeyFile ) )
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( $"-keyFile:\" { compilationOptions . KeyFile } \ "" ) ;
2015-10-17 03:32:58 -07:00
}
2015-10-21 01:18:14 -07:00
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
2015-10-18 07:10:22 -07:00
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( "-debug:full" ) ;
2015-10-18 07:10:22 -07:00
}
else
{
2015-10-21 01:18:14 -07:00
compilerArgs . Add ( "-debug:portable" ) ;
2015-10-18 07:10:22 -07:00
}
2015-10-18 19:02:09 -07:00
2015-10-17 03:32:58 -07:00
// TODO: OSS signing
2015-10-13 14:31:29 -07:00
}
2015-10-06 10:46:43 -07:00
2015-10-13 14:31:29 -07:00
private static void ShowDependencyInfo ( IEnumerable < LibraryExport > dependencies )
{
foreach ( var dependency in dependencies )
{
if ( ! dependency . Library . Resolved )
2015-10-06 10:46:43 -07:00
{
2015-10-13 14:31:29 -07:00
Reporter . Error . WriteLine ( $" Unable to resolve dependency {dependency.Library.Identity.ToString().Red().Bold()}" ) ;
Reporter . Error . WriteLine ( "" ) ;
2015-10-06 10:46:43 -07:00
}
2015-10-13 14:31:29 -07:00
else
{
Reporter . Output . WriteLine ( $" Using {dependency.Library.Identity.Type.Value.Cyan().Bold()} dependency {dependency.Library.Identity.ToString().Cyan().Bold()}" ) ;
Reporter . Output . WriteLine ( $" Path: {dependency.Library.Path}" ) ;
2015-10-06 10:46:43 -07:00
2015-10-13 14:31:29 -07:00
foreach ( var metadataReference in dependency . CompilationAssemblies )
{
Reporter . Output . WriteLine ( $" Assembly: {metadataReference}" ) ;
}
foreach ( var sourceReference in dependency . SourceReferences )
{
Reporter . Output . WriteLine ( $" Source: {sourceReference}" ) ;
}
Reporter . Output . WriteLine ( "" ) ;
}
}
2015-10-06 10:46:43 -07:00
}
2015-11-01 02:04:26 -08:00
private static void CopyFiles ( IEnumerable < LibraryAsset > files , string outputPath )
{
foreach ( var file in files )
{
File . Copy ( file . ResolvedPath , Path . Combine ( outputPath , Path . GetFileName ( file . ResolvedPath ) ) , overwrite : true ) ;
}
}
2015-10-06 10:46:43 -07:00
}
}