Skip to content

Commit

Permalink
Merge pull request #6683 from rainersigwald/64-bit-environment
Browse files Browse the repository at this point in the history
Fixes #6681.

### Context

The change to make Visual Studio 64-bit means that projects loaded in Visual Studio get the 64-bit MSBuild, and other tools are more likely to be loading our API in a 64-bit process as well. That found this difference between the way projects are evaluated in `devenv.exe` and in `vcxprojReader.exe`.

### Changes Made

Find the VS root from the current assembly and then reconstruct the path to the appropriate MSBuild.exe based on that + the current process's bitness, ensuring that API consumers and MSBuild.exe/devenv.exe see the same MSBuildToolsPath.

### Testing

Manual overlay with a trivial API consumer.
  • Loading branch information
ladipro committed Jul 28, 2021
2 parents 9f91131 + 255b4d0 commit d592862
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 51 deletions.
43 changes: 3 additions & 40 deletions src/Build.UnitTests/BuildEnvironmentHelper_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,51 +57,14 @@ public void FindBuildEnvironmentByEnvironmentVariable()
/// If MSBUILD_EXE_PATH is explicitly set, we should detect it as a VisualStudio instance even in older scenarios
/// (for example when the install path is under 15.0).
/// </summary>
/// <param name="is64BitMSbuild">When true, run the test pointing to amd64 msbuild.exe.</param>
[Theory]
[InlineData(true)]
[InlineData(false)]
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp, "No Visual Studio install for netcore")]
[PlatformSpecific(TestPlatforms.Windows)]
public void FindVisualStudioEnvironmentByEnvironmentVariable(bool is64BitMSbuild)
public void FindVisualStudioEnvironmentByEnvironmentVariable()
{
using (var env = new EmptyVSEnviroment())
{
var msbuildBinDirectory = is64BitMSbuild
? Path.Combine(env.BuildDirectory, "amd64")
: env.BuildDirectory;

var msBuildPath = Path.Combine(msbuildBinDirectory, MSBuildExeName);
var msBuildConfig = Path.Combine(msbuildBinDirectory, $"{MSBuildExeName}.config");
var vsMSBuildDirectory = Path.Combine(env.TempFolderRoot, "MSBuild");

env.WithEnvironment("MSBUILD_EXE_PATH", msBuildPath);
BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly(ReturnNull, ReturnNull, ReturnNull, env.VsInstanceMock, env.EnvironmentMock, () => false);

BuildEnvironmentHelper.Instance.Mode.ShouldBe(BuildEnvironmentMode.VisualStudio);
BuildEnvironmentHelper.Instance.MSBuildExtensionsPath.ShouldBe(vsMSBuildDirectory);
BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory.ShouldBe(msbuildBinDirectory);
BuildEnvironmentHelper.Instance.CurrentMSBuildExePath.ShouldBe(msBuildPath);
BuildEnvironmentHelper.Instance.CurrentMSBuildConfigurationFile.ShouldBe(msBuildConfig);
// This code is not running inside the Visual Studio devenv.exe process
BuildEnvironmentHelper.Instance.RunningInVisualStudio.ShouldBeFalse();
BuildEnvironmentHelper.Instance.VisualStudioInstallRootDirectory.ShouldBe(env.TempFolderRoot);
BuildEnvironmentHelper.Instance.RunningTests.ShouldBeFalse();
}
}

[Theory]
[InlineData(true)]
[InlineData(false)]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp, "No Visual Studio install for netcore")]
[PlatformSpecific(TestPlatforms.Windows)]
public void FindOlderVisualStudioEnvironmentByEnvironmentVariable(bool is64BitMSbuild)
{
using (var env = new EmptyVSEnviroment("15.0"))
{
var msbuildBinDirectory = is64BitMSbuild
? Path.Combine(env.BuildDirectory, "amd64")
: env.BuildDirectory;
var msbuildBinDirectory = env.BuildDirectory;

var msBuildPath = Path.Combine(msbuildBinDirectory, MSBuildExeName);
var msBuildConfig = Path.Combine(msbuildBinDirectory, $"{MSBuildExeName}.config");
Expand Down
20 changes: 9 additions & 11 deletions src/Shared/BuildEnvironmentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private static BuildEnvironment TryFromEnvironmentVariable()

return msBuildExePath == null
? null
: TryFromMSBuildAssemblyUnderVisualStudio(msBuildExePath, msBuildExePath, true) ?? TryFromStandaloneMSBuildExe(msBuildExePath);
: TryFromMSBuildExeUnderVisualStudio(msBuildExePath, allowLegacyToolsVersion: true) ?? TryFromStandaloneMSBuildExe(msBuildExePath);
}

private static BuildEnvironment TryFromVisualStudioProcess()
Expand Down Expand Up @@ -183,7 +183,7 @@ private static BuildEnvironment TryFromMSBuildAssembly()
var msBuildDll = Path.Combine(FileUtilities.GetFolderAbove(buildAssembly), "MSBuild.dll");

// First check if we're in a VS installation
var environment = TryFromMSBuildAssemblyUnderVisualStudio(buildAssembly, msBuildExe);
var environment = TryFromMSBuildExeUnderVisualStudio(msBuildExe);
if (environment != null)
{
return environment;
Expand All @@ -208,25 +208,22 @@ private static BuildEnvironment TryFromMSBuildAssembly()
return null;
}

private static BuildEnvironment TryFromMSBuildAssemblyUnderVisualStudio(string msbuildAssembly, string msbuildExe, bool allowLegacyToolsVersion = false)
private static BuildEnvironment TryFromMSBuildExeUnderVisualStudio(string msbuildExe, bool allowLegacyToolsVersion = false)
{
string msBuildPathPattern = allowLegacyToolsVersion
? $@".*\\MSBuild\\({CurrentToolsVersion}|\d+\.0)\\Bin\\.*"
: $@".*\\MSBuild\\{CurrentToolsVersion}\\Bin\\.*";

if (NativeMethodsShared.IsWindows &&
Regex.IsMatch(msbuildAssembly, msBuildPathPattern, RegexOptions.IgnoreCase))
Regex.IsMatch(msbuildExe, msBuildPathPattern, RegexOptions.IgnoreCase))
{
// In a Visual Studio path we must have MSBuild.exe
if (FileSystems.Default.FileExists(msbuildExe))
{
return new BuildEnvironment(
string visualStudioRoot = GetVsRootFromMSBuildAssembly(msbuildExe);
return new BuildEnvironment(
BuildEnvironmentMode.VisualStudio,
msbuildExe,
runningTests: s_runningTests(),
runningInVisualStudio: false,
visualStudioPath: GetVsRootFromMSBuildAssembly(msbuildExe));
}
visualStudioPath: visualStudioRoot);
}

return null;
Expand Down Expand Up @@ -320,7 +317,8 @@ private static BuildEnvironment TryFromStandaloneMSBuildExe(string msBuildExePat
private static string GetVsRootFromMSBuildAssembly(string msBuildAssembly)
{
return FileUtilities.GetFolderAbove(msBuildAssembly,
Regex.IsMatch(msBuildAssembly, $@"\\Bin\\Amd64\\MSBuild\.exe", RegexOptions.IgnoreCase)
Path.GetDirectoryName(msBuildAssembly)
.EndsWith(@"\amd64", StringComparison.OrdinalIgnoreCase)
? 5
: 4);
}
Expand Down

0 comments on commit d592862

Please sign in to comment.