// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Win32;
using System.Text;
namespace UnrealBuildTool
{
///
/// Stores information about a Visual C++ installation and compile environment
///
class VCEnvironment
{
///
/// The platform the envvars have been initialized for
///
public readonly CppPlatform Platform;
///
/// The compiler version we're using
///
public readonly WindowsCompiler Compiler;
///
/// The path to the base Visual Studio install directory (may be null for standalone toolchain)
///
public readonly DirectoryReference VSInstallDir;
///
/// The path to the base Visual C++ install directory
///
public readonly DirectoryReference VCInstallDir;
///
/// The path to the 32bit platform tool binaries.
///
public readonly DirectoryReference VCToolPath32;
///
/// The path to the 64bit platform tool binaries.
///
public readonly DirectoryReference VCToolPath64;
///
/// Installation folder of the Windows SDK, e.g. C:\Program Files\Microsoft SDKs\Windows\v6.0A\
///
public readonly string WindowsSDKDir;
///
///
///
public readonly string WindowsSDKExtensionDir;
///
/// Installation folder of the Windows SDK Extensions, e.g. C:\Program Files (x86)\Windows SDKs\10
///
public readonly string WindowsSDKLibVersion;
///
/// Installation folder of the NetFx SDK, since that is split out from platform SDKs >= v10
///
public readonly string NetFxSDKExtensionDir;
///
/// // 10.0.9910.0 for instance...
///
public readonly Version WindowsSDKExtensionHeaderLibVersion;
///
/// The path to the linker for linking executables
///
public readonly FileReference CompilerPath;
///
/// The version of cl.exe we're running
///
public readonly Version CLExeVersion;
///
/// The path to the linker for linking executables
///
public readonly FileReference LinkerPath;
///
/// The path to the linker for linking libraries
///
public readonly FileReference LibraryManagerPath;
///
/// The path to the resource compiler
///
public readonly FileReference ResourceCompilerPath;
///
/// For Visual Studio 2015; the path to the universal CRT.
///
public readonly string UniversalCRTDir;
///
/// For Visual Studio 2015; the universal CRT version to use.
///
public readonly string UniversalCRTVersion;
static readonly string InitialIncludePaths = Environment.GetEnvironmentVariable("INCLUDE");
static readonly string InitialLibraryPaths = Environment.GetEnvironmentVariable("LIB");
private string _MSBuildPath = null;
///
///
///
public string MSBuildPath // The path to MSBuild
{
get
{
if (_MSBuildPath == null)
{
_MSBuildPath = GetMSBuildToolPath();
}
return _MSBuildPath;
}
}
///
/// Initializes environment variables required by toolchain. Different for 32 and 64 bit.
///
public static VCEnvironment SetEnvironment(CppPlatform Platform, WindowsCompiler Compiler)
{
if (EnvVars != null && EnvVars.Platform == Platform)
{
return EnvVars;
}
EnvVars = new VCEnvironment(Platform, Compiler);
return EnvVars;
}
private VCEnvironment(CppPlatform InPlatform, WindowsCompiler InCompiler)
{
Platform = InPlatform;
Compiler = InCompiler;
// Get the Visual Studio install directory
WindowsPlatform.TryGetVSInstallDir(Compiler, out VSInstallDir);
// Get the Visual C++ compiler install directory.
if(!WindowsPlatform.TryGetVCInstallDir(Compiler, out VCInstallDir))
{
throw new BuildException(WindowsPlatform.GetCompilerName(Compiler) + " must be installed in order to build this target.");
}
// Figure out the default toolchain directory. VS15 separates this out into separate directories, with platforms as subdirectories under that.
DirectoryReference VCToolChainDir = null;
if(Compiler == WindowsCompiler.VisualStudio2017)
{
string Version = File.ReadAllText(FileReference.Combine(VCInstallDir, "Auxiliary", "Build", "Microsoft.VCToolsVersion.default.txt").FullName).Trim();
VCToolChainDir = DirectoryReference.Combine(VCInstallDir, "Tools", "MSVC", Version);
}
WindowsSDKDir = FindWindowsSDKInstallationFolder(Platform, Compiler);
WindowsSDKLibVersion = FindWindowsSDKLibVersion(WindowsSDKDir);
WindowsSDKExtensionDir = FindWindowsSDKExtensionInstallationFolder(Compiler);
NetFxSDKExtensionDir = FindNetFxSDKExtensionInstallationFolder(Compiler);
WindowsSDKExtensionHeaderLibVersion = FindWindowsSDKExtensionLatestVersion(WindowsSDKExtensionDir);
FindUniversalCRT(Compiler, out UniversalCRTDir, out UniversalCRTVersion);
VCToolPath32 = GetVCToolPath32(Compiler, VCInstallDir, VCToolChainDir);
VCToolPath64 = GetVCToolPath64(Compiler, VCInstallDir, VCToolChainDir);
// Compile using 64 bit tools for 64 bit targets, and 32 for 32.
DirectoryReference CompilerDir = (Platform == CppPlatform.Win64) ? VCToolPath64 : VCToolPath32;
// Regardless of the target, if we're linking on a 64 bit machine, we want to use the 64 bit linker (it's faster than the 32 bit linker and can handle large linking jobs)
DirectoryReference LinkerDir = VCToolPath64;
CompilerPath = GetCompilerToolPath(InPlatform, CompilerDir);
CLExeVersion = FindCLExeVersion(CompilerPath.FullName);
LinkerPath = GetLinkerToolPath(InPlatform, LinkerDir);
LibraryManagerPath = GetLibraryLinkerToolPath(InPlatform, LinkerDir);
ResourceCompilerPath = new FileReference(GetResourceCompilerToolPath(Platform));
// Make sure the base 32-bit VS tool path is in the PATH, regardless of which configuration we're using. The toolchain may need to reference support DLLs from this directory (eg. mspdb120.dll).
string PathEnvironmentVariable = Environment.GetEnvironmentVariable("PATH") ?? "";
if (!PathEnvironmentVariable.Split(';').Any(x => String.Compare(x, VCToolPath32.FullName, true) == 0))
{
PathEnvironmentVariable = VCToolPath32.FullName + ";" + PathEnvironmentVariable;
Environment.SetEnvironmentVariable("PATH", PathEnvironmentVariable);
}
// Setup the INCLUDE environment variable
List IncludePaths = GetVisualCppIncludePaths(Compiler, VCInstallDir, VCToolChainDir, UniversalCRTDir, UniversalCRTVersion, NetFxSDKExtensionDir, WindowsSDKDir, WindowsSDKLibVersion);
if(InitialIncludePaths != null)
{
IncludePaths.Add(InitialIncludePaths);
}
Environment.SetEnvironmentVariable("INCLUDE", String.Join(";", IncludePaths));
// Setup the LIB environment variable
List LibraryPaths = GetVisualCppLibraryPaths(Compiler, VCInstallDir, VCToolChainDir, UniversalCRTDir, UniversalCRTVersion, NetFxSDKExtensionDir, WindowsSDKDir, WindowsSDKLibVersion, Platform);
if(InitialLibraryPaths != null)
{
LibraryPaths.Add(InitialLibraryPaths);
}
Environment.SetEnvironmentVariable("LIB", String.Join(";", LibraryPaths));
}
/// The path to Windows SDK directory for the specified version.
private static string FindWindowsSDKInstallationFolder(CppPlatform InPlatform, WindowsCompiler InCompiler)
{
// When targeting Windows XP on Visual Studio 2012+, we need to point at the older Windows SDK 7.1A that comes
// installed with Visual Studio 2012 Update 1. (http://blogs.msdn.com/b/vcblog/archive/2012/10/08/10357555.aspx)
string Version;
switch (InCompiler)
{
case WindowsCompiler.VisualStudio2017:
case WindowsCompiler.VisualStudio2015:
if (WindowsPlatform.bUseWindowsSDK10)
{
Version = "v10.0";
}
else
{
Version = "v8.1";
}
break;
default:
throw new BuildException("Unexpected compiler setting when trying to determine Windows SDK folder");
}
// Based on VCVarsQueryRegistry
string FinalResult = null;
foreach (string IndividualVersion in Version.Split('|'))
{
object Result = Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\" + IndividualVersion, "InstallationFolder", null)
?? Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\" + IndividualVersion, "InstallationFolder", null)
?? Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\" + IndividualVersion, "InstallationFolder", null);
if (Result != null)
{
FinalResult = (string)Result;
break;
}
}
if (FinalResult == null)
{
throw new BuildException("Windows SDK {0} must be installed in order to build this target.", Version);
}
return FinalResult;
}
///
/// Gets the version of the Windows SDK libraries to use. As per VCVarsQueryRegistry.bat, this is the directory name that sorts last.
///
static string FindWindowsSDKLibVersion(string WindowsSDKDir)
{
string WindowsSDKLibVersion;
if (WindowsPlatform.bUseWindowsSDK10)
{
DirectoryInfo IncludeDir = new DirectoryInfo(Path.Combine(WindowsSDKDir, "include"));
if (!IncludeDir.Exists)
{
throw new BuildException("Couldn't find Windows 10 SDK include directory ({0})", IncludeDir.FullName);
}
DirectoryInfo LatestIncludeDir = IncludeDir.EnumerateDirectories().OrderBy(x => x.Name).LastOrDefault();
if (LatestIncludeDir == null)
{
throw new BuildException("No Windows 10 SDK versions found under ({0})", IncludeDir.FullName);
}
WindowsSDKLibVersion = LatestIncludeDir.Name;
}
else
{
WindowsSDKLibVersion = "winv6.3";
}
return WindowsSDKLibVersion;
}
private static string FindNetFxSDKExtensionInstallationFolder(WindowsCompiler Compiler)
{
string[] Versions;
switch (Compiler)
{
case WindowsCompiler.VisualStudio2017:
case WindowsCompiler.VisualStudio2015:
Versions = new string[] { "4.6", "4.6.1", "4.6.2" };
break;
default:
return string.Empty;
}
foreach (string Version in Versions)
{
string Result = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\NETFXSDK\" + Version, "KitsInstallationFolder", null) as string
?? Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\NETFXSDK\" + Version, "KitsInstallationFolder", null) as string;
if (Result != null)
{
return Result.TrimEnd('\\');
}
}
return string.Empty;
}
private static string FindWindowsSDKExtensionInstallationFolder(WindowsCompiler Compiler)
{
string Version;
switch (Compiler)
{
case WindowsCompiler.VisualStudio2017:
case WindowsCompiler.VisualStudio2015:
if (WindowsPlatform.bUseWindowsSDK10)
{
Version = "v10.0";
}
else
{
return string.Empty;
}
break;
default:
return string.Empty;
}
// Based on VCVarsQueryRegistry
string FinalResult = null;
{
object Result = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows SDKs\" + Version, "InstallationFolder", null)
?? Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows SDKs\" + Version, "InstallationFolder", null);
if (Result == null)
{
Result = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\" + Version, "InstallationFolder", null)
?? Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\" + Version, "InstallationFolder", null);
}
if (Result != null)
{
FinalResult = ((string)Result).TrimEnd('\\');
}
}
if (FinalResult == null)
{
FinalResult = string.Empty;
}
return FinalResult;
}
static Version FindWindowsSDKExtensionLatestVersion(string WindowsSDKExtensionDir)
{
Version LatestVersion = new Version(0, 0, 0, 0);
if (WindowsPlatform.bUseWindowsSDK10 &&
!string.IsNullOrEmpty(WindowsSDKExtensionDir) &&
Directory.Exists(WindowsSDKExtensionDir))
{
string IncludesBaseDirectory = Path.Combine(WindowsSDKExtensionDir, "include");
if (Directory.Exists(IncludesBaseDirectory))
{
string[] IncludeVersions = Directory.GetDirectories(IncludesBaseDirectory);
foreach (string IncludeVersion in IncludeVersions)
{
string VersionString = Path.GetFileName(IncludeVersion);
Version FoundVersion;
if (Version.TryParse(VersionString, out FoundVersion) && FoundVersion > LatestVersion)
{
LatestVersion = FoundVersion;
}
}
}
}
return LatestVersion;
}
///
/// Gets the path to the 32bit tool binaries.
///
/// The compiler version
/// Base install directory for the VC toolchain
/// Base directory for the VC toolchain
/// Directory containing the 32-bit toolchain binaries
static DirectoryReference GetVCToolPath32(WindowsCompiler Compiler, DirectoryReference VCInstallDir, DirectoryReference VCToolChainDir)
{
if (Compiler == WindowsCompiler.VisualStudio2017)
{
FileReference NativeCompilerPath = FileReference.Combine(VCToolChainDir, "bin", "HostX64", "x86", "cl.exe");
if (FileReference.Exists(NativeCompilerPath))
{
return NativeCompilerPath.Directory;
}
FileReference CrossCompilerPath = FileReference.Combine(VCToolChainDir, "bin", "HostX86", "x86", "cl.exe");
if (FileReference.Exists(CrossCompilerPath))
{
return CrossCompilerPath.Directory;
}
throw new BuildException("No 32-bit compiler toolchain found in {0} or {1}", NativeCompilerPath, CrossCompilerPath);
}
else
{
FileReference CompilerPath = FileReference.Combine(VCInstallDir, "bin", "cl.exe");
if (FileReference.Exists(CompilerPath))
{
return CompilerPath.Directory;
}
throw new BuildException("No 32-bit compiler toolchain found in {0}", CompilerPath);
}
}
///
/// Gets the path to the 64bit tool binaries.
///
/// The version of the compiler being used
/// Base install directory for the VC toolchain
/// Base directory for the VC toolchain
/// Directory containing the 64-bit toolchain binaries
static DirectoryReference GetVCToolPath64(WindowsCompiler Compiler, DirectoryReference VCInstallDir, DirectoryReference VCToolChainDir)
{
if (Compiler == WindowsCompiler.VisualStudio2017)
{
// Use the native 64-bit compiler if present
FileReference NativeCompilerPath = FileReference.Combine(VCToolChainDir, "bin", "HostX64", "x64", "cl.exe");
if (FileReference.Exists(NativeCompilerPath))
{
return NativeCompilerPath.Directory;
}
// Otherwise try the x64-on-x86 compiler. VS Express only includes the latter.
FileReference CrossCompilerPath = FileReference.Combine(VCToolChainDir, "bin", "HostX86", "x64", "cl.exe");
if (FileReference.Exists(CrossCompilerPath))
{
return CrossCompilerPath.Directory;
}
throw new BuildException("No 64-bit compiler toolchain found in {0} or {1}", NativeCompilerPath, CrossCompilerPath);
}
else
{
// Use the native 64-bit compiler if present
FileReference NativeCompilerPath = FileReference.Combine(VCInstallDir, "bin", "amd64", "cl.exe");
if (FileReference.Exists(NativeCompilerPath))
{
return NativeCompilerPath.Directory;
}
// Otherwise use the amd64-on-x86 compiler. VS2012 Express only includes the latter.
FileReference CrossCompilerPath = FileReference.Combine(VCInstallDir, "bin", "x86_amd64", "cl.exe");
if (FileReference.Exists(CrossCompilerPath))
{
return CrossCompilerPath.Directory;
}
throw new BuildException("No 64-bit compiler toolchain found in {0} or {1}", NativeCompilerPath, CrossCompilerPath);
}
}
///
/// Gets the path to the compiler.
///
static FileReference GetCompilerToolPath(CppPlatform Platform, DirectoryReference PlatformVSToolPath)
{
// If we were asked to use Clang, then we'll redirect the path to the compiler to the LLVM installation directory
if (WindowsPlatform.bCompileWithClang)
{
string CompilerDriverName;
string Result;
if (WindowsPlatform.bUseVCCompilerArgs)
{
// Use 'clang-cl', a wrapper around Clang that supports Visual C++ compiler command-line arguments
CompilerDriverName = "clang-cl.exe";
}
else
{
// Use regular Clang compiler on Windows
CompilerDriverName = "clang.exe";
}
Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "LLVM", "bin", CompilerDriverName);
if (!File.Exists(Result))
{
Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "LLVM", "bin", CompilerDriverName);
}
if (!File.Exists(Result))
{
throw new BuildException("Clang was selected as the Windows compiler, but LLVM/Clang does not appear to be installed. Could not find: " + Result);
}
return new FileReference(Result);
}
if (WindowsPlatform.bCompileWithICL)
{
var Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "IntelSWTools", "compilers_and_libraries", "windows", "bin", Platform == CppPlatform.Win32 ? "ia32" : "intel64", "icl.exe");
if (!File.Exists(Result))
{
throw new BuildException("ICL was selected as the Windows compiler, but does not appear to be installed. Could not find: " + Result);
}
return new FileReference(Result);
}
return FileReference.Combine(PlatformVSToolPath, "cl.exe");
}
/// The version of the compiler.
private static Version FindCLExeVersion(string CompilerExe)
{
// Check that the cl.exe exists (GetVersionInfo doesn't handle this well).
if (!File.Exists(CompilerExe))
{
// By default VS2015 doesn't install the C++ toolchain. Help developers out with a special message.
throw new BuildException("Failed to find cl.exe in the default toolchain directory " + CompilerExe + ". Please verify that \"Common Tools for Visual C++ 2015\" was selected when installing Visual Studio 2015.");
}
FileVersionInfo ExeVersionInfo = FileVersionInfo.GetVersionInfo(CompilerExe);
if (ExeVersionInfo == null)
{
throw new BuildException("Failed to read the version number of: " + CompilerExe);
}
return new Version(ExeVersionInfo.FileMajorPart, ExeVersionInfo.FileMinorPart, ExeVersionInfo.FileBuildPart, ExeVersionInfo.FilePrivatePart);
}
///
/// Gets the path to the linker.
///
static FileReference GetLinkerToolPath(CppPlatform Platform, DirectoryReference PlatformVSToolPath)
{
// If we were asked to use Clang, then we'll redirect the path to the compiler to the LLVM installation directory
if (WindowsPlatform.bCompileWithClang && WindowsPlatform.bAllowClangLinker)
{
string Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "LLVM", "bin", "lld.exe");
if (!File.Exists(Result))
{
Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "LLVM", "bin", "lld.exe");
}
if (!File.Exists(Result))
{
throw new BuildException("Clang was selected as the Windows compiler, but LLVM/Clang does not appear to be installed. Could not find: " + Result);
}
return new FileReference(Result);
}
if (WindowsPlatform.bCompileWithICL && WindowsPlatform.bAllowICLLinker)
{
var Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "IntelSWTools", "compilers_and_libraries", "windows", "bin", Platform == CppPlatform.Win32 ? "ia32" : "intel64", "xilink.exe");
if (!File.Exists(Result))
{
throw new BuildException("ICL was selected as the Windows compiler, but does not appear to be installed. Could not find: " + Result);
}
return new FileReference(Result);
}
return FileReference.Combine(PlatformVSToolPath, "link.exe");
}
///
/// Gets the path to the library linker.
///
static FileReference GetLibraryLinkerToolPath(CppPlatform Platform, DirectoryReference PlatformVSToolPath)
{
// Regardless of the target, if we're linking on a 64 bit machine, we want to use the 64 bit linker (it's faster than the 32 bit linker)
//@todo.WIN32: Using the 64-bit linker appears to be broken at the moment.
if (WindowsPlatform.bCompileWithICL && WindowsPlatform.bAllowICLLinker)
{
var Result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "IntelSWTools", "compilers_and_libraries", "windows", "bin", Platform == CppPlatform.Win32 ? "ia32" : "intel64", "xilib.exe");
if (!File.Exists(Result))
{
throw new BuildException("ICL was selected as the Windows compiler, but does not appear to be installed. Could not find: " + Result);
}
return new FileReference(Result);
}
return FileReference.Combine(PlatformVSToolPath, "lib.exe");
}
///
/// Gets the path to the resource compiler's rc.exe for the specified platform.
///
string GetResourceCompilerToolPath(CppPlatform Platform)
{
// 64 bit -- we can use the 32 bit version to target 64 bit on 32 bit OS.
if (Platform == CppPlatform.Win64)
{
if (WindowsPlatform.bUseWindowsSDK10)
{
return Path.Combine(WindowsSDKExtensionDir, "bin/x64/rc.exe");
}
else
{
return Path.Combine(WindowsSDKDir, "bin/x64/rc.exe");
}
}
else
{
if (WindowsPlatform.bUseWindowsSDK10)
{
return Path.Combine(WindowsSDKExtensionDir, "bin/x86/rc.exe");
}
else
{
return Path.Combine(WindowsSDKDir, "bin/x86/rc.exe");
}
}
}
///
/// Gets the path to MSBuild.
/// This mirrors the logic in GetMSBuildPath.bat.
///
public static string GetMSBuildToolPath()
{
// Try to get the MSBuild 14.0 path directly (see https://msdn.microsoft.com/en-us/library/hh162058(v=vs.120).aspx)
string ToolPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "MSBuild", "14.0", "bin", "MSBuild.exe");
if(File.Exists(ToolPath))
{
return ToolPath;
}
// Try to get the MSBuild 14.0 path from the registry
if (TryReadMsBuildInstallPath("Microsoft\\MSBuild\\ToolsVersions\\14.0", "MSBuildToolsPath", "MSBuild.exe", out ToolPath))
{
return ToolPath;
}
// Check for MSBuild 15. This is installed alongside Visual Studio 2017, so we get the path relative to that.
if (TryReadMsBuildInstallPath("Microsoft\\VisualStudio\\SxS\\VS7", "15.0", "MSBuild\\15.0\\bin\\MSBuild.exe", out ToolPath))
{
return ToolPath;
}
// Check for older versions of MSBuild. These are registered as separate versions in the registry.
if (TryReadMsBuildInstallPath("Microsoft\\MSBuild\\ToolsVersions\\12.0", "MSBuildToolsPath", "MSBuild.exe", out ToolPath))
{
return ToolPath;
}
if (TryReadMsBuildInstallPath("Microsoft\\MSBuild\\ToolsVersions\\4.0", "MSBuildToolsPath", "MSBuild.exe", out ToolPath))
{
return ToolPath;
}
throw new BuildException("NOTE: Please ensure that 64bit Tools are installed with DevStudio - there is usually an option to install these during install");
}
///
/// Function to query the registry under HKCU/HKLM Win32/Wow64 software registry keys for a certain install directory.
/// This mirrors the logic in GetMSBuildPath.bat.
///
///
static bool TryReadMsBuildInstallPath(string KeyRelativePath, string KeyName, string MsBuildRelativePath, out string OutMsBuildPath)
{
string[] KeyBasePaths =
{
@"HKEY_CURRENT_USER\SOFTWARE\",
@"HKEY_LOCAL_MACHINE\SOFTWARE\",
@"HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\"
};
foreach (string KeyBasePath in KeyBasePaths)
{
string Value = Registry.GetValue(KeyBasePath + KeyRelativePath, KeyName, null) as string;
if (Value != null)
{
string MsBuildPath = Path.Combine(Value, MsBuildRelativePath);
if (File.Exists(MsBuildPath))
{
OutMsBuildPath = MsBuildPath;
return true;
}
}
}
OutMsBuildPath = null;
return false;
}
///
/// Gets the version of the Universal CRT to use. As per VCVarsQueryRegistry.bat, this is the directory name that sorts last.
///
static void FindUniversalCRT(WindowsCompiler Compiler, out string UniversalCRTDir, out string UniversalCRTVersion)
{
if (Compiler < WindowsCompiler.VisualStudio2015)
{
UniversalCRTDir = null;
UniversalCRTVersion = null;
return;
}
string[] RootKeys =
{
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots",
"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots",
"HKEY_CURRENT_USER\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots",
};
List IncludeDirs = new List();
foreach(string RootKey in RootKeys)
{
string IncludeDirString = Registry.GetValue(RootKey, "KitsRoot10", null) as string;
if(IncludeDirString != null)
{
DirectoryInfo IncludeDir = new DirectoryInfo(Path.Combine(IncludeDirString, "include"));
if (IncludeDir.Exists)
{
IncludeDirs.AddRange(IncludeDir.EnumerateDirectories());
}
}
}
DirectoryInfo LatestIncludeDir = IncludeDirs.OrderBy(x => x.Name).LastOrDefault(n => n.Name.All(s => (s >= '0' && s <= '9') || s == '.') && Directory.Exists(n.FullName + "\\ucrt"));
if(LatestIncludeDir == null)
{
UniversalCRTDir = null;
UniversalCRTVersion = null;
}
else
{
UniversalCRTDir = LatestIncludeDir.Parent.Parent.FullName;
UniversalCRTVersion = LatestIncludeDir.Name;
}
}
///
/// Sets the Visual C++ INCLUDE environment variable
///
static List GetVisualCppIncludePaths(WindowsCompiler Compiler, DirectoryReference VisualCppDir, DirectoryReference VisualCppToolchainDir, string UniversalCRTDir, string UniversalCRTVersion, string NetFXSDKDir, string WindowsSDKDir, string WindowsSDKLibVersion)
{
List IncludePaths = new List();
// Add the standard Visual C++ include paths
if (Compiler == WindowsCompiler.VisualStudio2017)
{
DirectoryReference StdIncludeDir = DirectoryReference.Combine(VisualCppToolchainDir, "INCLUDE");
if (DirectoryReference.Exists(StdIncludeDir))
{
IncludePaths.Add(StdIncludeDir.FullName);
}
DirectoryReference AtlMfcIncludeDir = DirectoryReference.Combine(VisualCppToolchainDir, "ATLMFC", "INCLUDE");
if (DirectoryReference.Exists(AtlMfcIncludeDir))
{
IncludePaths.Add(AtlMfcIncludeDir.FullName);
}
}
else
{
DirectoryReference StdIncludeDir = DirectoryReference.Combine(VisualCppDir, "INCLUDE");
if (DirectoryReference.Exists(StdIncludeDir))
{
IncludePaths.Add(StdIncludeDir.FullName);
}
DirectoryReference AtlMfcIncludeDir = DirectoryReference.Combine(VisualCppDir, "ATLMFC", "INCLUDE");
if (DirectoryReference.Exists(AtlMfcIncludeDir))
{
IncludePaths.Add(AtlMfcIncludeDir.FullName);
}
}
// Add the universal CRT paths
if (!String.IsNullOrEmpty(UniversalCRTDir) && !String.IsNullOrEmpty(UniversalCRTVersion))
{
IncludePaths.Add(Path.Combine(UniversalCRTDir, "include", UniversalCRTVersion, "ucrt"));
}
// Add the NETFXSDK include path
if (!String.IsNullOrEmpty(NetFXSDKDir))
{
IncludePaths.Add(Path.Combine(NetFXSDKDir, "include", "um")); // 2015
}
// Add the Windows SDK paths
if (Compiler >= WindowsCompiler.VisualStudio2015 && WindowsPlatform.bUseWindowsSDK10)
{
IncludePaths.Add(Path.Combine(WindowsSDKDir, "include", WindowsSDKLibVersion, "shared"));
IncludePaths.Add(Path.Combine(WindowsSDKDir, "include", WindowsSDKLibVersion, "um"));
IncludePaths.Add(Path.Combine(WindowsSDKDir, "include", WindowsSDKLibVersion, "winrt"));
}
else
{
IncludePaths.Add(Path.Combine(WindowsSDKDir, "include", "shared"));
IncludePaths.Add(Path.Combine(WindowsSDKDir, "include", "um"));
IncludePaths.Add(Path.Combine(WindowsSDKDir, "include", "winrt"));
}
// Add the existing include paths
string ExistingIncludePaths = Environment.GetEnvironmentVariable("INCLUDE");
if (ExistingIncludePaths != null)
{
IncludePaths.AddRange(ExistingIncludePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
}
// Set the environment variable
return IncludePaths;
}
///
/// Sets the Visual C++ LIB environment variable
///
static List GetVisualCppLibraryPaths(WindowsCompiler Compiler, DirectoryReference VisualCppDir, DirectoryReference VisualCppToolchainDir, string UniversalCRTDir, string UniversalCRTVersion, string NetFXSDKDir, string WindowsSDKDir, string WindowsSDKLibVersion, CppPlatform Platform)
{
List LibraryPaths = new List();
// Add the standard Visual C++ library paths
if (Compiler == WindowsCompiler.VisualStudio2017)
{
if (Platform == CppPlatform.Win32)
{
DirectoryReference StdLibraryDir = DirectoryReference.Combine(VisualCppToolchainDir, "lib", "x86");
if (DirectoryReference.Exists(StdLibraryDir))
{
LibraryPaths.Add(StdLibraryDir.FullName);
}
}
else
{
DirectoryReference StdLibraryDir = DirectoryReference.Combine(VisualCppToolchainDir, "lib", "x64");
if (DirectoryReference.Exists(StdLibraryDir))
{
LibraryPaths.Add(StdLibraryDir.FullName);
}
}
}
else
{
if (Platform == CppPlatform.Win32)
{
DirectoryReference StdLibraryDir = DirectoryReference.Combine(VisualCppDir, "LIB");
if (DirectoryReference.Exists(StdLibraryDir))
{
LibraryPaths.Add(StdLibraryDir.FullName);
}
DirectoryReference AtlMfcLibraryDir = DirectoryReference.Combine(VisualCppDir, "ATLMFC", "LIB");
if (DirectoryReference.Exists(AtlMfcLibraryDir))
{
LibraryPaths.Add(AtlMfcLibraryDir.FullName);
}
}
else
{
DirectoryReference StdLibraryDir = DirectoryReference.Combine(VisualCppDir, "LIB", "amd64");
if (DirectoryReference.Exists(StdLibraryDir))
{
LibraryPaths.Add(StdLibraryDir.FullName);
}
DirectoryReference AtlMfcLibraryDir = DirectoryReference.Combine(VisualCppDir, "ATLMFC", "LIB", "amd64");
if (DirectoryReference.Exists(AtlMfcLibraryDir))
{
LibraryPaths.Add(AtlMfcLibraryDir.FullName);
}
}
}
// Add the Universal CRT
if (!String.IsNullOrEmpty(UniversalCRTDir) && !String.IsNullOrEmpty(UniversalCRTVersion))
{
if (Platform == CppPlatform.Win32)
{
LibraryPaths.Add(Path.Combine(UniversalCRTDir, "lib", UniversalCRTVersion, "ucrt", "x86"));
}
else
{
LibraryPaths.Add(Path.Combine(UniversalCRTDir, "lib", UniversalCRTVersion, "ucrt", "x64"));
}
}
// Add the NETFXSDK include path
if (!String.IsNullOrEmpty(NetFXSDKDir))
{
if (Platform == CppPlatform.Win32)
{
LibraryPaths.Add(Path.Combine(NetFXSDKDir, "lib", "um", "x86"));
}
else
{
LibraryPaths.Add(Path.Combine(NetFXSDKDir, "lib", "um", "x64"));
}
}
// Add the standard Windows SDK paths
if (Platform == CppPlatform.Win32)
{
LibraryPaths.Add(Path.Combine(WindowsSDKDir, "lib", WindowsSDKLibVersion, "um", "x86"));
}
else
{
LibraryPaths.Add(Path.Combine(WindowsSDKDir, "lib", WindowsSDKLibVersion, "um", "x64"));
}
// Add the existing library paths
string ExistingLibraryPaths = Environment.GetEnvironmentVariable("LIB");
if (ExistingLibraryPaths != null)
{
LibraryPaths.AddRange(ExistingLibraryPaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
}
return LibraryPaths;
}
static VCEnvironment EnvVars = null;
}
}