2015-11-16 11:21:57 -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.
using System ;
2015-10-20 13:27:56 -07:00
using System.CommandLine ;
using System.Collections.Generic ;
using System.Diagnostics ;
2015-10-18 01:17:13 -07:00
using System.IO ;
2015-10-20 13:27:56 -07:00
using System.Linq ;
using System.Runtime.InteropServices ;
using System.Text ;
using Microsoft.DotNet.Cli.Compiler.Common ;
2015-10-18 01:17:13 -07:00
using Microsoft.DotNet.Cli.Utils ;
2015-11-27 16:19:54 -08:00
using Microsoft.DotNet.ProjectModel ;
2015-10-18 01:17:13 -07:00
namespace Microsoft.DotNet.Tools.Compiler.Csc
{
public class Program
{
2015-10-20 13:27:56 -07:00
private const int ExitFailed = 1 ;
2015-10-18 19:02:09 -07:00
public static int Main ( string [ ] args )
2015-10-18 01:17:13 -07:00
{
DebugHelper . HandleDebugSwitch ( ref args ) ;
2015-10-20 13:27:56 -07:00
CommonCompilerOptions commonOptions = 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 ;
try
{
ArgumentSyntax . Parse ( args , syntax = >
{
commonOptions = CommonCompilerOptionsExtensions . Parse ( syntax ) ;
syntax . DefineOption ( "temp-output" , ref tempOutDir , "Compilation temporary directory" ) ;
syntax . DefineOption ( "out" , ref outputName , "Name of the output assembly" ) ;
2015-11-07 01:52:59 -08:00
syntax . DefineOptionList ( "reference" , ref references , "Path to a compiler metadata reference" ) ;
2015-10-20 13:27:56 -07:00
syntax . DefineOptionList ( "resource" , ref resources , "Resources to embed" ) ;
2015-10-18 01:17:13 -07:00
2015-10-20 13:27:56 -07:00
syntax . DefineParameterList ( "source-files" , ref sources , "Compilation sources" ) ;
2015-10-18 01:17:13 -07:00
2015-10-20 13:27:56 -07:00
if ( tempOutDir = = null )
{
syntax . ReportError ( "Option '--temp-output' is required" ) ;
}
} ) ;
}
catch ( ArgumentSyntaxException )
2015-10-18 01:17:13 -07:00
{
2015-10-20 13:27:56 -07:00
return ExitFailed ;
}
var translated = TranslateCommonOptions ( commonOptions ) ;
var allArgs = new List < string > ( translated ) ;
allArgs . AddRange ( GetDefaultOptions ( ) ) ;
if ( outputName ! = null )
{
2015-11-04 12:04:51 -08:00
allArgs . Add ( $"-out:\" { outputName } \ "" ) ;
2015-10-20 13:27:56 -07:00
}
2015-10-18 01:17:13 -07:00
2015-11-04 12:04:51 -08:00
allArgs . AddRange ( references . Select ( r = > $"-r:\" { r } \ "" ) ) ;
2015-10-20 13:27:56 -07:00
allArgs . AddRange ( resources . Select ( resource = > $"-resource:{resource}" ) ) ;
2015-11-04 12:04:51 -08:00
allArgs . AddRange ( sources . Select ( s = > $"\" { s } \ "" ) ) ;
2015-10-20 13:27:56 -07:00
2015-11-04 12:04:51 -08:00
var rsp = Path . Combine ( tempOutDir , "dotnet-compile-csc.rsp" ) ;
2015-10-20 13:27:56 -07:00
File . WriteAllLines ( rsp , allArgs , Encoding . UTF8 ) ;
// Execute CSC!
var result = RunCsc ( $"-noconfig @\" { rsp } \ "" )
. ForwardStdErr ( )
. ForwardStdOut ( )
. Execute ( ) ;
return result . ExitCode ;
}
// TODO: Review if this is the place for default options
private static IEnumerable < string > GetDefaultOptions ( )
{
var args = new List < string > ( )
{
"-nostdlib" ,
"-nologo"
} ;
args . Add ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows )
? "-debug:full"
: "-debug:portable" ) ;
args . Add ( "-nowarn:CS1701" ) ;
args . Add ( "-nowarn:CS1702" ) ;
args . Add ( "-nowarn:CS1705" ) ;
return args ;
}
private static IEnumerable < string > TranslateCommonOptions ( CommonCompilerOptions options )
{
List < string > commonArgs = new List < string > ( ) ;
if ( options . Defines ! = null )
{
commonArgs . AddRange ( options . Defines . Select ( def = > $"-d:{def}" ) ) ;
}
if ( options . LanguageVersion ! = null )
{
2015-11-06 05:53:16 -08:00
commonArgs . Add ( $"-langversion:{GetLanguageVersion(options.LanguageVersion)}" ) ;
2015-10-20 13:27:56 -07:00
}
if ( options . Platform ! = null )
{
commonArgs . Add ( $"-platform:{options.Platform}" ) ;
}
if ( options . AllowUnsafe = = true )
{
commonArgs . Add ( "-unsafe" ) ;
}
if ( options . WarningsAsErrors = = true )
{
commonArgs . Add ( "-warnaserror" ) ;
}
if ( options . Optimize = = true )
{
commonArgs . Add ( "-optimize" ) ;
}
if ( options . KeyFile ! = null )
{
commonArgs . Add ( $"-keyfile:\" { options . KeyFile } \ "" ) ;
2015-11-18 00:00:31 -08:00
// If we're not on Windows, full signing isn't supported, so we'll
// public sign, unless the public sign switch has explicitly been
// set to false
if ( ! RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) & &
options . PublicSign = = null )
{
commonArgs . Add ( "-publicsign" ) ;
}
2015-10-20 13:27:56 -07:00
}
if ( options . DelaySign = = true )
{
commonArgs . Add ( "-delaysign" ) ;
}
2015-11-17 23:37:39 -08:00
if ( options . PublicSign = = true )
{
commonArgs . Add ( "-publicsign" ) ;
}
2015-10-20 13:27:56 -07:00
if ( options . EmitEntryPoint ! = true )
{
commonArgs . Add ( "-t:library" ) ;
}
2015-10-18 01:17:13 -07:00
2015-10-20 13:27:56 -07:00
return commonArgs ;
2015-10-18 01:17:13 -07:00
}
2015-11-06 05:53:16 -08:00
private static string GetLanguageVersion ( string languageVersion )
{
// project.json supports the enum that the roslyn APIs expose
if ( languageVersion ? . StartsWith ( "csharp" , StringComparison . OrdinalIgnoreCase ) = = true )
{
// We'll be left with the number csharp6 = 6
return languageVersion . Substring ( "csharp" . Length ) ;
}
return languageVersion ;
}
2015-10-18 01:17:13 -07:00
private static Command RunCsc ( string cscArgs )
{
// Locate CoreRun
2015-11-10 17:30:01 -08:00
return Command . Create ( "csc" , cscArgs ) ;
2015-10-18 01:17:13 -07:00
}
}
}