提交 cabc2c74 编写于 作者: J Jared Parsons

Explicitly pass down compiler exe location

The common parts of the compiler were attempting to deduce the directory
of the compiler exe by using various reflection / assembly APIs.  This
is a fragile method that is easy to break in unrelated code.
Additionally this API is not available on CoreFx.

The fix is to simply thread the compiler exe path through from the Main
methods on the EXE.

closes #1705
上级 f4a6ccd2
......@@ -16,11 +16,11 @@ internal Csc(string responseFile, string baseDirectory, string[] args)
{
}
internal static int Run(string[] args)
internal static int Run(string clientDir, string[] args)
{
FatalError.Handler = FailFast.OnFatalException;
var responseFile = CommonCompiler.GetResponseFileFullPath(CSharpCompiler.ResponseFileName);
var responseFile = Path.Combine(clientDir, CSharpCompiler.ResponseFileName);
Csc compiler = new Csc(responseFile, Directory.GetCurrentDirectory(), args);
// We store original encoding and restore it later to revert
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.BuildTasks;
using static Microsoft.CodeAnalysis.CompilerServer.BuildProtocolConstants;
......@@ -8,6 +9,11 @@ namespace Microsoft.CodeAnalysis.CSharp.CommandLine
public class Program
{
public static int Main(string[] args)
=> BuildClient.RunWithConsoleOutput(args, RequestLanguage.CSharpCompile, Csc.Run);
=> BuildClient.RunWithConsoleOutput(
args,
clientDir: AppDomain.CurrentDomain.BaseDirectory,
workingDir: Environment.CurrentDirectory,
language: RequestLanguage.CSharpCompile,
fallbackCompiler: Csc.Run);
}
}
......@@ -26,31 +26,6 @@ internal abstract partial class CommonCompiler
internal const int Failed = 1;
internal const int Succeeded = 0;
/// <summary>
/// Return the path in which to look for response files. This should only be called
/// on EXE entry points as the implementation relies on managed entry points.
/// </summary>
/// <returns></returns>
internal static string GetResponseFileDirectory()
{
var exePath = Assembly.GetEntryAssembly().Location;
// This assert will fire when this method is called from places like xUnit and certain
// types of AppDomains. It should only be called on EXE entry points to help guarantee
// this is being called from an executed assembly.
Debug.Assert(exePath != null);
return Path.GetDirectoryName(exePath);
}
/// <summary>
/// Called from a compiler exe entry point to get the full path to the response file for
/// the given name. Will return a fully qualified path.
/// </summary>
internal static string GetResponseFileFullPath(string responseFileName)
{
return Path.Combine(GetResponseFileDirectory(), responseFileName);
}
public CommonMessageProvider MessageProvider { get; private set; }
public CommandLineArguments Arguments { get; private set; }
public abstract DiagnosticFormatter DiagnosticFormatter { get; }
......
......@@ -30,24 +30,6 @@ internal static class BuildClient
// Spend up to 20s connecting to a new process, to allow time for it to start.
private const int TimeOutMsNewProcess = 20000;
/// <summary>
/// Try to get the directory this assembly is in. Returns null if assembly
/// was in the GAC.
/// </summary>
private static string TryGetClientDir()
{
var assembly = typeof(BuildClient).Assembly;
if (assembly.GlobalAssemblyCache)
return null;
var uri = new Uri(assembly.CodeBase);
string assemblyPath = uri.IsFile
? uri.LocalPath
: Assembly.GetCallingAssembly().Location;
return Path.GetDirectoryName(assemblyPath);
}
/// <summary>
/// Run a compilation through the compiler server and print the output
/// to the console. If the compiler server fails, run the fallback
......@@ -55,8 +37,10 @@ private static string TryGetClientDir()
/// </summary>
public static int RunWithConsoleOutput(
string[] args,
string clientDir,
string workingDir,
RequestLanguage language,
Func<string[], int> fallbackCompiler)
Func<string, string[], int> fallbackCompiler)
{
args = args.Select(arg => arg.Trim()).ToArray();
......@@ -79,7 +63,8 @@ private static string TryGetClientDir()
{
var responseTask = TryRunServerCompilation(
language,
Environment.CurrentDirectory,
clientDir,
workingDir,
parsedArgs,
default(CancellationToken),
keepAlive: keepAlive,
......@@ -92,7 +77,7 @@ private static string TryGetClientDir()
}
}
return fallbackCompiler(parsedArgs.ToArray());
return fallbackCompiler(clientDir, parsedArgs.ToArray());
}
private static int HandleResponse(BuildResponse response)
......@@ -135,19 +120,17 @@ private static int HandleResponse(BuildResponse response)
/// </summary>
public static Task<BuildResponse> TryRunServerCompilation(
RequestLanguage language,
string clientDir,
string workingDir,
IList<string> arguments,
CancellationToken cancellationToken,
string keepAlive = null,
string libEnvVariable = null,
string fallbackCompilerExeDir = null)
string libEnvVariable = null)
{
try
{
NamedPipeClientStream pipe;
var clientDir = TryGetClientDir() ?? fallbackCompilerExeDir;
if (clientDir == null)
return Task.FromResult<BuildResponse>(null);
......
......@@ -6,6 +6,7 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using Microsoft.Build.Framework;
......@@ -310,11 +311,11 @@ protected override int ExecuteTool(string pathToTool, string responseFileCommand
{
var responseTask = BuildClient.TryRunServerCompilation(
Language,
TryGetClientDir() ?? Path.GetDirectoryName(pathToTool),
CurrentDirectoryToUse(),
GetArguments(commandLineCommands, responseFileCommands),
_sharedCompileCts.Token,
libEnvVariable: LibDirectoryToUse(),
fallbackCompilerExeDir: Path.GetDirectoryName(pathToTool));
libEnvVariable: LibDirectoryToUse());
responseTask.Wait(_sharedCompileCts.Token);
......@@ -336,6 +337,24 @@ protected override int ExecuteTool(string pathToTool, string responseFileCommand
return ExitCode;
}
/// <summary>
/// Try to get the directory this assembly is in. Returns null if assembly
/// was in the GAC.
/// </summary>
private static string TryGetClientDir()
{
var assembly = typeof(ManagedCompiler).Assembly;
if (assembly.GlobalAssemblyCache)
return null;
var uri = new Uri(assembly.CodeBase);
string assemblyPath = uri.IsFile
? uri.LocalPath
: Assembly.GetCallingAssembly().Location;
return Path.GetDirectoryName(assemblyPath);
}
/// <summary>
/// Cancel the in-process build task.
/// </summary>
......@@ -870,4 +889,4 @@ string win32Manifest
return win32Manifest;
}
}
}
\ No newline at end of file
}
......@@ -68,6 +68,10 @@ public static int Main(string[] args)
TimeSpan? keepAliveTimeout = null;
// VBCSCompiler is installed in the same directory as csc.exe and vbc.exe which is also the
// location of the response files.
var compilerExeDirectory = AppDomain.CurrentDomain.BaseDirectory;
try
{
int keepAliveValue;
......@@ -99,9 +103,6 @@ public static int Main(string[] args)
CompilerServerLogger.Log("Keep alive timeout is: {0} milliseconds.", keepAliveTimeout?.TotalMilliseconds ?? 0);
FatalError.Handler = FailFast.OnFatalException;
// VBCSCompiler is installed in the same directory as csc.exe and vbc.exe which is also the
// location of the response files.
var compilerExeDirectory = CommonCompiler.GetResponseFileDirectory();
var dispatcher = new ServerDispatcher(new CompilerRequestHandler(compilerExeDirectory), new EmptyDiagnosticListener());
dispatcher.ListenAndDispatchConnections(
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.BuildTasks;
using static Microsoft.CodeAnalysis.CompilerServer.BuildProtocolConstants;
......@@ -8,6 +9,11 @@ namespace Microsoft.CodeAnalysis.VisualBasic.CommandLine
public class Program
{
public static int Main(string[] args)
=> BuildClient.RunWithConsoleOutput(args, RequestLanguage.VisualBasicCompile, Vbc.Run);
=> BuildClient.RunWithConsoleOutput(
args,
clientDir: AppDomain.CurrentDomain.BaseDirectory,
workingDir: Environment.CurrentDirectory,
language: RequestLanguage.VisualBasicCompile,
fallbackCompiler: Vbc.Run);
}
}
......@@ -17,11 +17,11 @@ internal Vbc(string responseFile, string baseDirectory, string[] args)
{
}
internal static int Run(string[] args)
internal static int Run(string clientDir, string[] args)
{
FatalError.Handler = FailFast.OnFatalException;
var responseFile = CommonCompiler.GetResponseFileFullPath(VisualBasicCompiler.ResponseFileName);
var responseFile = Path.Combine(clientDir, VisualBasicCompiler.ResponseFileName);
Vbc compiler = new Vbc(responseFile, Directory.GetCurrentDirectory(), args);
// We store original encoding and restore it later to revert
......
......@@ -27,7 +27,7 @@ internal static int Main(string[] args)
{
try
{
var responseFile = CommonCompiler.GetResponseFileFullPath(InteractiveResponseFileName);
var responseFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, InteractiveResponseFileName);
return ScriptCompilerUtil.RunInteractive(new Csi(responseFile, Directory.GetCurrentDirectory(), args), Console.Out);
}
catch (Exception ex)
......
......@@ -22,7 +22,7 @@ Friend NotInheritable Class Vbi
Public Shared Function Main(args As String()) As Integer
Try
Dim responseFile = CommonCompiler.GetResponseFileFullPath(InteractiveResponseFileName)
Dim responseFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, InteractiveResponseFileName)
Return ScriptCompilerUtil.RunInteractive(New Vbi(responseFile, Directory.GetCurrentDirectory(), args), Console.Out)
Catch ex As Exception
Console.WriteLine(ex.ToString())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册