Major improvement of Visual Studio toolchain and Windows SDK support in mkbundle.
authorlateralusX <lateralusx.github@gmail.com>
Thu, 24 Aug 2017 11:54:34 +0000 (13:54 +0200)
committerlateralusX <lateralusx.github@gmail.com>
Mon, 2 Oct 2017 10:50:02 +0000 (12:50 +0200)
Current implementation of Windows builds in mkbundle is not supporting
Visual Studio toolchains and Windows SDK's in a working way. Windows version
of mkbundle also lacked support for 64-bit builds together with a dependency on
GCC assembler etc.

This commit improves things in many different areas. The following toolchains
are intended to work together with this commit:

VS2013, VS2015, VS2017.

NOTE, default Mono SDK distribution is build targeting VS2015/VS2017 and static
version of libmono-static.lib won’t work with VS2013. If static use case is needed
with VS2013, a custom build mono under VS2013 must be used.  Dynamic use case is
working as expected for all three versions.

The commit also improves the support for Cygwin GCC compatible toolchains on Windows.

The commit adds support to use installed versions of both Windows 8.1 as well
as Windows 10 SDK's together with all above VS toolchains.

The commit extends support to include 64-bit mkbundle builds (using all supported
Windows toolchains). The target is decided based on mkbundle process type, 32-bit
mono builds 32-bit bundle and 64-bit mono builds 64-bit bundle.

mkbundle might still need to have a working GCC as.exe when running, but this commit
also adds support for Clang for VS CodeGen as assembler available in VS2015 Update3
and VS2017 (separate option in VS setup). When using this option there is no needed
for available GCC toolchains when running mkbundle on Windows.

A recommended way of running mkbundle on Windows is by using one of the targeted toolchains
development consoles. This way mkbundle will get all needed paths and installation folders
directly from the development consoles environment, matching a predefined setup.

Old mkbundle environment variables on Windows will continue to work. There are also a number
of new variables that can be set (or are set by the VS development consoles). The important ones
are:

VisualStudioVersion: set to pick a specific VS version, like 12.0, 14.0 or 15.0. If a none existing
version is specified, mkbundle will fallback to latest installed version.

WindowsSdkVersion: set to pick a specific Windows SDK version, like 8.1, 10.0.10240.0, 10.0.15063.0 etc.
If a none existing version is specified, mkbundle will fallback to latest installed version.

AS: If Clang for VS CodeGen is not installed this must point to a working as.exe assembler.

MONOPREFIX: set to pick a custom Mono SDK install root directory (need to match the architecture of mkbundle
process running). If not set, mkbundle will look for installed Mono SDK’s matching targeted architecture.

MONOLIB: if a different library name is used, it can be specified here. It is also possible to add an absolute
path to the mono library used in linking. NOTE, correct library needs to be supplied for static/dynamic use cases.

INCLUDE: override all custom include path handling, normally set by VS developer consoles.

LIB: override all custom lib path handling, normally set by VS developer consoles.

VCCRT: Gives possibility to use static or dynamic C-Runtime linking. By default mkbundle will use dynamic C-Runtime
linking on Windows to be compatible with default Mono SDK distribution. If a custom build Mono
using static C-Runtime linkage is used, setting this variable to MT (default MD), will link using static
C-Runtime.

VCSUBSYSTEM: mkbundle will by default use windows subsystem. If console subsystem is preferred this variable
can be set to console.

Should resolve:

https://bugzilla.xamarin.com/show_bug.cgi?id=57893

and partial resolves (needs https://github.com/mono/mono/pull/5656 as well):

https://bugzilla.xamarin.com/show_bug.cgi?id=57892

mcs/tools/mkbundle/mkbundle.cs

index d4ef1cbb5520e4f8c493fdcce14d61e2b21730f1..8603736b26bb75cbbb90176beb7240c386a5df01 100755 (executable)
@@ -477,12 +477,18 @@ class MakeBundle {
                                name, size);
                        break;
                case "windows":
+                       string mangled_symbol_name = "";
+                       if (Target64BitApplication())
+                               mangled_symbol_name = name;
+                       else
+                               mangled_symbol_name = "_" + name;
+
                        sw.WriteLine (
-                               ".globl _{0}\n" +
+                               ".globl {0}\n" +
                                "\t.section .rdata,\"dr\"\n" +
                                "\t.align 32\n" +
-                               "_{0}:\n",
-                               name, size);
+                               "{0}:\n",
+                               mangled_symbol_name);
                        break;
                }
        }
@@ -693,7 +699,7 @@ class MakeBundle {
        {
                string temp_s = "temp.s"; // Path.GetTempFileName ();
                string temp_c = "temp.c";
-               string temp_o = "temp.o";
+               string temp_o = (style != "windows") ? "temp.o" : "temp.s.obj";
 
                if (compile_only)
                        temp_c = output;
@@ -915,8 +921,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
 
                        tc.Close ();
 
-                       string assembler = GetEnv("AS", "as");
-                       string as_cmd = String.Format("{0} -o {1} {2} ", assembler, temp_o, temp_s);
+                       string as_cmd = GetAssemblerCommand (temp_s, temp_o);
                        Execute(as_cmd);
 
                        if (compile_only)
@@ -925,85 +930,34 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        if (!quiet)
                                Console.WriteLine("Compiling:");
 
-                       if (style == "windows")
-                       {
-
-                               Func<string, string> quote = (pp) => { return "\"" + pp + "\""; };
-
-                               string compiler = GetEnv("CC", "cl.exe");
-                               string winsdkPath = GetEnv("WINSDK", @"C:\Program Files (x86)\Windows Kits\8.1");
-                               string vsPath = GetEnv("VSINCLUDE", @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC");
-                               string monoPath = GetEnv("MONOPREFIX", @"C:\Program Files (x86)\Mono");
-
-                               string[] includes = new string[] {winsdkPath + @"\Include\um", winsdkPath + @"\Include\shared", vsPath + @"\include", monoPath + @"\include\mono-2.0", "." };
-                               // string[] libs = new string[] { winsdkPath + @"\Lib\winv6.3\um\x86" , vsPath + @"\lib" };
-                               var linkLibraries = new string[] {  "kernel32.lib",
-                                                                                               "version.lib",
-                                                                                               "Ws2_32.lib",
-                                                                                               "Mswsock.lib",
-                                                                                               "Psapi.lib",
-                                                                                               "shell32.lib",
-                                                                                               "OleAut32.lib",
-                                                                                               "ole32.lib",
-                                                                                               "winmm.lib",
-                                                                                               "user32.lib",
-                                                                                               "libvcruntime.lib",
-                                                                                               "advapi32.lib",
-                                                                                               "OLDNAMES.lib",
-                                                                                               "libucrt.lib" };
-
-                               string glue_obj = "mkbundle_glue.obj";
-                               string monoLib;
-
-                               if (static_link)
-                                       monoLib = LocateFile (monoPath + @"\lib\monosgen-2.0-static.lib");
-
-                               else {
-                                       Console.WriteLine ("WARNING: Dynamically linking the Mono runtime on Windows is not a tested option.");
-                                       monoLib = LocateFile (monoPath + @"\lib\monosgen-2.0.lib");
-                                       LocateFile (monoPath + @"\lib\monosgen-2.0.dll"); // in this case, the .lib is just the import library, and the .dll is also needed
+                       if (style == "windows") {
+                               ToolchainProgram compiler = GetCCompiler ();
+                               if (compiler != null && compiler.ParentSDK != null) {
+                                       if (compiler.IsVSToolChain && VisualStudioSDKHelper.GetInstance ().IsVisualStudio12 (compiler.ParentSDK) && static_link)
+                                               Console.WriteLine (     @"Warning: Static linking the Mono runtime on Windows using VC " +
+                                                                       @"12.0, won't support static Mono runtime library distributed in Mono SDK since it has " +
+                                                                       @"been build using different C-runtime version. If build results in " +
+                                                                       @"link errors related to C-runtime functions, please rebuild mono runtime distribution " +
+                                                                       @"using targeted VC compiler and linker and rerun using MONOPREFIX.");
                                }
 
-                               var compilerArgs = new List<string>();
-                               compilerArgs.Add("/MT");
-
-                               foreach (string include in includes)
-                                       compilerArgs.Add(String.Format ("/I {0}", quote (include)));
-
+                               bool staticLinkCRuntime = GetEnv ("VCCRT", "MD") != "MD";
                                if (!nomain || custom_main != null) {
-                                       compilerArgs.Add(quote(temp_c));
-                                       compilerArgs.Add(quote(temp_o));
-                                       if (custom_main != null)
-                                               compilerArgs.Add(quote(custom_main));
-                                       compilerArgs.Add(quote(monoLib));
-                                       compilerArgs.Add("/link");
-                                       compilerArgs.Add("/NODEFAULTLIB");
-                                       compilerArgs.Add("/SUBSYSTEM:windows");
-                                       compilerArgs.Add("/ENTRY:mainCRTStartup");
-                                       compilerArgs.AddRange(linkLibraries);
-                                       compilerArgs.Add("/out:"+ output);
-
-                                       string cl_cmd = String.Format("{0} {1}", compiler, String.Join(" ", compilerArgs.ToArray()));
-                                       Execute (cl_cmd);
-                               }
-                               else
-                               {
-                                       // we are just creating a .lib
-                                       compilerArgs.Add("/c"); // compile only
-                                       compilerArgs.Add(temp_c);
-                                       compilerArgs.Add(String.Format("/Fo" + glue_obj)); // .obj output name
-
-                                       string cl_cmd = String.Format("{0} {1}", compiler, String.Join(" ", compilerArgs.ToArray()));
+                                       string cl_cmd = GetCompileAndLinkCommand (compiler, temp_c, temp_o, custom_main, static_link, staticLinkCRuntime, output);
                                        Execute (cl_cmd);
+                               } else {
+                                       string temp_c_o = "";
+                                       try {
+                                               string cl_cmd = GetLibrarianCompilerCommand (compiler, temp_c, static_link, staticLinkCRuntime, out temp_c_o);
+                                               Execute(cl_cmd);
+
+                                               ToolchainProgram librarian = GetLibrarian ();
+                                               string lib_cmd = GetLibrarianLinkerCommand (librarian, new string[] { temp_o, temp_c_o }, static_link, staticLinkCRuntime, output);
+                                               Execute (lib_cmd);
+                                       } finally {
+                                               File.Delete (temp_c_o);
+                                       }
 
-                                       string librarian = GetEnv ("LIB", "lib.exe");
-                                       var librarianArgs = new List<string> ();
-                                       librarianArgs.Add (String.Format ("/out:{0}.lib" + output));
-                                       librarianArgs.Add (temp_o);
-                                       librarianArgs.Add (glue_obj);
-                                       librarianArgs.Add (monoLib);
-                                       string lib_cmd = String.Format("{0} {1}", librarian, String.Join(" ", librarianArgs.ToArray()));
-                                       Execute (lib_cmd);
                                }
                        }
                        else
@@ -1122,7 +1076,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        if (custom_mode){
                                Console.WriteLine ("In Custom mode, you need to provide the directory to lookup assemblies from using -L");
                        }
-                       
+
                        Error ("Couldn't load one or more of the i18n assemblies: " + error);
                        Environment.Exit (1);
                }
@@ -1210,7 +1164,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        a = universe.LoadFile (assembly);
                        if (!quiet)
                                Console.WriteLine ("Assembly {0} loaded successfully.", assembly);
-                       
+
                } catch (FileNotFoundException){
                        Error ($"Cannot find assembly `{assembly}'");
                } catch (IKVM.Reflection.BadImageFormatException f) {
@@ -1446,4 +1400,1226 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                else
                        throw new FileNotFoundException(default_path);
        }
+
+       static string GetAssemblerCommand (string sourceFile, string objectFile)
+       {
+               if (style == "windows") {
+                       string additionalArguments = "";
+                       var assembler = GetAssemblerCompiler ();
+                       if (assembler.Name.Contains ("clang.exe"))
+                               //Clang uses additional arguments.
+                               additionalArguments = "-c -x assembler";
+
+                       return String.Format ("\"{0}\" {1} -o {2} {3} ", assembler.Path, additionalArguments, objectFile, sourceFile);
+               } else {
+                       return String.Format ("{0} -o {1} {2} ", GetEnv ("AS", "as"), objectFile, sourceFile);
+               }
+       }
+
+#region WindowsToolchainSupport
+
+       class StringVersionComparer : IComparer<string> {
+               public int Compare (string stringA, string stringB)
+               {
+                       Version versionA;
+                       Version versionB;
+
+                       var versionAMatch = System.Text.RegularExpressions.Regex.Match (stringA, @"\d+(\.\d +) + ");
+                       if (versionAMatch.Success)
+                               stringA = versionAMatch.ToString ();
+
+                       var versionBMatch = System.Text.RegularExpressions.Regex.Match (stringB, @"\d+(\.\d+)+");
+                       if (versionBMatch.Success)
+                               stringB = versionBMatch.ToString ();
+
+                       if (Version.TryParse (stringA, out versionA) && Version.TryParse (stringB, out versionB))
+                               return versionA.CompareTo (versionB);
+
+                       return string.Compare (stringA, stringB, StringComparison.OrdinalIgnoreCase);
+               }
+       }
+
+       class InstalledSDKInfo {
+               public InstalledSDKInfo (string name, string version, string installationFolder)
+               {
+                       this.Name = name;
+                       this.Version = Version.Parse (version);
+                       this.InstallationFolder = installationFolder;
+                       this.IsSubVersion = false;
+                       this.AdditionalSDKs = new List<InstalledSDKInfo> ();
+               }
+
+               public InstalledSDKInfo (string name, string version, string installationFolder, bool isSubVersion)
+                       : this (name, version, installationFolder)
+               {
+                       this.IsSubVersion = isSubVersion;
+               }
+
+               public InstalledSDKInfo (string name, string version, string installationFolder, bool isSubVersion, InstalledSDKInfo parentSDK)
+                       : this (name, version, installationFolder, isSubVersion)
+               {
+                       this.ParentSDK = parentSDK;
+               }
+
+               public string Name { get; set; }
+               public Version Version { get; set; }
+               public string InstallationFolder { get; set; }
+               public bool IsSubVersion { get; set; }
+               public List<InstalledSDKInfo> AdditionalSDKs { get; }
+               public InstalledSDKInfo ParentSDK { get; set; }
+       }
+
+       class ToolchainProgram {
+               public ToolchainProgram (string name, string path)
+               {
+                       this.Name = name;
+                       this.Path = path;
+               }
+
+               public ToolchainProgram (string name, string path, InstalledSDKInfo parentSDK)
+                       : this (name, path)
+               {
+                       this.ParentSDK = parentSDK;
+               }
+
+               public Func<string, string> QuoteArg = arg => "\"" + arg + "\"";
+               public string Name { get; set; }
+               public string Path { get; set; }
+               public InstalledSDKInfo ParentSDK { get; set; }
+               public bool IsVSToolChain { get { return (Name.Contains ("cl.exe") || Name.Contains ("lib.exe")); } }
+               public bool IsGCCToolChain { get { return !IsVSToolChain;  } }
+       }
+
+       class SDKHelper {
+
+               protected Microsoft.Win32.RegistryKey GetToolchainRegistrySubKey (string subKey)
+               {
+                       Microsoft.Win32.RegistryKey key = null;
+
+                       if (Environment.Is64BitProcess) {
+                               key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SOFTWARE\Wow6432Node" + subKey) ??
+                                       Microsoft.Win32.Registry.CurrentUser.OpenSubKey (@"SOFTWARE\Wow6432Node" + subKey);
+                       }
+
+                       if (key == null) {
+                               key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SOFTWARE" + subKey) ??
+                                       Microsoft.Win32.Registry.CurrentUser.OpenSubKey (@"SOFTWARE" + subKey);
+                       }
+
+                       return key;
+               }
+       }
+
+       class WindowsSDKHelper : SDKHelper {
+
+               List<InstalledSDKInfo> installedWindowsSDKs;
+               List<InstalledSDKInfo> installedCRuntimeSDKs;
+               InstalledSDKInfo installedWindowsSDK;
+               InstalledSDKInfo installedCRuntimeSDK;
+
+               static WindowsSDKHelper singletonInstance = new WindowsSDKHelper ();
+               static public WindowsSDKHelper GetInstance ()
+               {
+                       return singletonInstance;
+               }
+
+               Dictionary<string, string> GetInstalledWindowsKitRootFolders ()
+               {
+                       var rootFolders = new Dictionary<string, string> ();
+
+                       using (var subKey = GetToolchainRegistrySubKey (@"\Microsoft\Microsoft SDKs\Windows\")) {
+                               if (subKey != null) {
+                                       foreach (var keyName in subKey.GetSubKeyNames ()) {
+                                               var keyNameIsVersion = System.Text.RegularExpressions.Regex.Match (keyName, @"\d+(\.\d+)+");
+                                               if (keyNameIsVersion.Success) {
+                                                       var installFolder = (string)Microsoft.Win32.Registry.GetValue (subKey.ToString () + @"\" + keyName, "InstallationFolder", "");
+                                                       if (!rootFolders.ContainsKey (installFolder))
+                                                               rootFolders.Add (installFolder, keyNameIsVersion.ToString ());
+                                               }
+                                       }
+                               }
+                       }
+
+                       using (var subKey = GetToolchainRegistrySubKey (@"\Microsoft\Windows Kits\Installed Roots")) {
+                               if (subKey != null) {
+                                       foreach (var valueName in subKey.GetValueNames ()) {
+                                               var valueNameIsKitsRoot = System.Text.RegularExpressions.Regex.Match (valueName, @"KitsRoot\d*");
+                                               if (valueNameIsKitsRoot.Success) {
+                                                       var installFolder = (string)Microsoft.Win32.Registry.GetValue (subKey.ToString (), valueName, "");
+                                                       if (!rootFolders.ContainsKey (installFolder)) {
+                                                               var valueNameIsVersion = System.Text.RegularExpressions.Regex.Match (valueName, @"\d+(\.*\d+)+");
+                                                               if (valueNameIsVersion.Success)
+                                                                       rootFolders.Add (installFolder, valueNameIsVersion.ToString ());
+                                                               else
+                                                                       rootFolders.Add (installFolder, "");
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       return rootFolders;
+               }
+
+               void InitializeInstalledWindowsKits ()
+               {
+                       if (installedWindowsSDKs == null && installedCRuntimeSDKs == null) {
+                               List<InstalledSDKInfo> windowsSDKs = new List<InstalledSDKInfo> ();
+                               List<InstalledSDKInfo> cRuntimeSDKs = new List<InstalledSDKInfo> ();
+                               var rootFolders = GetInstalledWindowsKitRootFolders ();
+                               foreach (var winKitRoot in rootFolders) {
+                                       // Try to locate Windows and CRuntime SDKs.
+                                       string winKitRootDir = winKitRoot.Key;
+                                       string winKitRootVersion = winKitRoot.Value;
+                                       string winKitIncludeDir = Path.Combine (winKitRootDir, "include");
+
+                                       //Search for installed SDK versions.
+                                       if (Directory.Exists (winKitIncludeDir)) {
+                                               var winKitIncludeDirInfo = new DirectoryInfo (winKitIncludeDir);
+                                               var versions = winKitIncludeDirInfo.GetDirectories (
+                                                       "*.*", SearchOption.TopDirectoryOnly).OrderByDescending (p => p.Name, new StringVersionComparer ());
+
+                                               foreach (var version in versions) {
+                                                       string versionedWindowsSDKHeaderPath = Path.Combine (version.FullName, "um", "windows.h");
+                                                       string versionedCRuntimeSDKHeaderPath = Path.Combine (version.FullName, "ucrt", "stdlib.h");
+                                                       var hasSubVersion = System.Text.RegularExpressions.Regex.Match (version.Name, @"\d+(\.\d+)+");
+                                                       if (hasSubVersion.Success) {
+                                                               if (File.Exists (versionedWindowsSDKHeaderPath))
+                                                                       //Found a specific Windows SDK sub version.
+                                                                       windowsSDKs.Add (new InstalledSDKInfo ("WindowsSDK", hasSubVersion.ToString (), winKitRootDir, true));
+                                                               if (File.Exists (versionedCRuntimeSDKHeaderPath))
+                                                                       //Found a specific CRuntime SDK sub version.
+                                                                       cRuntimeSDKs.Add (new InstalledSDKInfo ("CRuntimeSDK", hasSubVersion.ToString (), winKitRootDir, true));
+                                                       }
+                                               }
+                                       }
+
+                                       // Try to find SDK without specific sub version.
+                                       string windowsSDKHeaderPath = Path.Combine (winKitIncludeDir, "um", "windows.h");
+                                       if (File.Exists (windowsSDKHeaderPath))
+                                               //Found a Windows SDK version.
+                                               windowsSDKs.Add (new InstalledSDKInfo ("WindowsSDK", winKitRootVersion, winKitRootDir, false));
+
+                                       string cRuntimeSDKHeaderPath = Path.Combine (winKitIncludeDir, "ucrt", "stdlib.h");
+                                       if (File.Exists (cRuntimeSDKHeaderPath))
+                                               //Found a CRuntime SDK version.
+                                               cRuntimeSDKs.Add (new InstalledSDKInfo ("CRuntimeSDK", winKitRootVersion, winKitRootDir, false));
+                               }
+
+                               // Sort based on version.
+                               windowsSDKs = windowsSDKs.OrderByDescending (p => p.Version.ToString (), new StringVersionComparer ()).ToList ();
+                               cRuntimeSDKs = cRuntimeSDKs.OrderByDescending (p => p.Version.ToString (), new StringVersionComparer ()).ToList ();
+
+                               installedWindowsSDKs = windowsSDKs;
+                               installedCRuntimeSDKs = cRuntimeSDKs;
+
+                               if (!quiet && installedWindowsSDKs != null) {
+                                       Console.WriteLine ("--- Windows SDK's ---");
+                                       foreach (var windowsSDK in installedWindowsSDKs) {
+                                               Console.WriteLine ("Path: " + windowsSDK.InstallationFolder);
+                                               Console.WriteLine ("Version: " + windowsSDK.Version);
+                                       }
+                                       Console.WriteLine ("---------------");
+                               }
+
+                               if (!quiet && installedCRuntimeSDKs != null) {
+                                       Console.WriteLine ("--- C-Runtime SDK's ---");
+                                       foreach (var cRuntimeSDK in installedCRuntimeSDKs) {
+                                               Console.WriteLine ("Path: " + cRuntimeSDK.InstallationFolder);
+                                               Console.WriteLine ("Version: " + cRuntimeSDK.Version);
+                                               if (cRuntimeSDK.ParentSDK != null) {
+                                                       Console.WriteLine ("Parent SDK Path: " + cRuntimeSDK.ParentSDK.InstallationFolder);
+                                                       Console.WriteLine ("Parent SDK Version: " + cRuntimeSDK.ParentSDK.Version);
+                                               }
+                                       }
+                                       Console.WriteLine ("---------------");
+                               }
+                       }
+
+                       return;
+               }
+
+               List<InstalledSDKInfo> GetInstalledWindowsSDKs ()
+               {
+                       if (installedWindowsSDKs == null)
+                               InitializeInstalledWindowsKits ();
+
+                       return installedWindowsSDKs;
+               }
+
+               List<InstalledSDKInfo> GetInstalledCRuntimeSDKs ()
+               {
+                       if (installedCRuntimeSDKs == null)
+                               InitializeInstalledWindowsKits ();
+
+                       return installedCRuntimeSDKs;
+               }
+
+               InstalledSDKInfo GetInstalledWindowsSDK ()
+               {
+                       if (installedWindowsSDK == null) {
+                               string winSDKDir = "";
+                               InstalledSDKInfo windowsSDK = null;
+                               List<InstalledSDKInfo> windowsSDKs = GetInstalledWindowsSDKs ();
+
+                               // Check that env doesn't already include needed values.
+                               winSDKDir = GetEnv ("WINSDK", "");
+                               if (winSDKDir.Length == 0)
+                                       // If executed from a VS developer command prompt, SDK dir set in env.
+                                       winSDKDir = GetEnv ("WindowsSdkDir", "");
+
+                               // Check that env doesn't already include needed values.
+                               // If executed from a VS developer command prompt, SDK version set in env.
+                               var winSDKVersion = System.Text.RegularExpressions.Regex.Match (GetEnv ("WindowsSdkVersion", ""), @"\d+(\.\d+)+");
+
+                               if (winSDKDir.Length != 0 && windowsSDKs != null) {
+                                       // Find installed SDK based on requested info.
+                                       if (winSDKVersion.Success)
+                                               windowsSDK = windowsSDKs.Find (x => (x.InstallationFolder == winSDKDir && x.Version.ToString () == winSDKVersion.ToString ()));
+                                       else
+                                               windowsSDK = windowsSDKs.Find (x => x.InstallationFolder == winSDKDir);
+                               }
+
+                               if (windowsSDK == null && winSDKVersion.Success && windowsSDKs != null)
+                                       // Find installed SDK based on requested info.
+                                       windowsSDK = windowsSDKs.Find (x => x.Version.ToString () == winSDKVersion.ToString ());
+
+                               if (windowsSDK == null && windowsSDKs != null)
+                                       // Get latest installed verison.
+                                       windowsSDK = windowsSDKs.First ();
+
+                               installedWindowsSDK = windowsSDK;
+                       }
+
+                       return installedWindowsSDK;
+               }
+
+               string FindCRuntimeSDKIncludePath (InstalledSDKInfo sdk)
+               {
+                       string cRuntimeIncludePath = Path.Combine (sdk.InstallationFolder, "include");
+                       if (sdk.IsSubVersion)
+                               cRuntimeIncludePath = Path.Combine (cRuntimeIncludePath, sdk.Version.ToString ());
+
+                       cRuntimeIncludePath = Path.Combine (cRuntimeIncludePath, "ucrt");
+                       if (!Directory.Exists (cRuntimeIncludePath))
+                               cRuntimeIncludePath = "";
+
+                       return cRuntimeIncludePath;
+               }
+
+               string FindCRuntimeSDKLibPath (InstalledSDKInfo sdk)
+               {
+                       string cRuntimeLibPath = Path.Combine (sdk.InstallationFolder, "lib");
+                       if (sdk.IsSubVersion)
+                               cRuntimeLibPath = Path.Combine (cRuntimeLibPath, sdk.Version.ToString ());
+
+                       cRuntimeLibPath = Path.Combine (cRuntimeLibPath, "ucrt", Target64BitApplication () ? "x64" : "x86");
+                       if (!Directory.Exists (cRuntimeLibPath))
+                               cRuntimeLibPath = "";
+
+                       return cRuntimeLibPath;
+               }
+
+               InstalledSDKInfo GetInstalledCRuntimeSDK ()
+               {
+                       if (installedCRuntimeSDK == null) {
+                               InstalledSDKInfo cRuntimeSDK = null;
+                               var windowsSDK = GetInstalledWindowsSDK ();
+                               var cRuntimeSDKs = GetInstalledCRuntimeSDKs ();
+
+                               if (windowsSDK != null && cRuntimeSDKs != null) {
+                                       cRuntimeSDK = cRuntimeSDKs.Find (x => x.Version.ToString () == windowsSDK.Version.ToString ());
+                                       if (cRuntimeSDK == null && cRuntimeSDKs.Count != 0)
+                                               cRuntimeSDK = cRuntimeSDKs.First ();
+
+                                       installedCRuntimeSDK = cRuntimeSDK;
+                               }
+                       }
+
+                       return installedCRuntimeSDK;
+               }
+
+               public void AddWindowsSDKIncludePaths (List<string> includePaths)
+               {
+                       InstalledSDKInfo winSDK = GetInstalledWindowsSDK ();
+                       if (winSDK != null) {
+                               string winSDKIncludeDir = Path.Combine (winSDK.InstallationFolder, "include");
+
+                               if (winSDK.IsSubVersion)
+                                       winSDKIncludeDir = Path.Combine (winSDKIncludeDir, winSDK.Version.ToString ());
+
+                               // Include sub folders.
+                               if (Directory.Exists (winSDKIncludeDir)) {
+                                       includePaths.Add (Path.Combine (winSDKIncludeDir, "um"));
+                                       includePaths.Add (Path.Combine (winSDKIncludeDir, "shared"));
+                                       includePaths.Add (Path.Combine (winSDKIncludeDir, "winrt"));
+                               }
+                       }
+
+                       return;
+               }
+
+               public void AddWindowsSDKLibPaths (List<string> libPaths)
+               {
+                       InstalledSDKInfo winSDK = GetInstalledWindowsSDK ();
+                       if (winSDK != null) {
+                               string winSDKLibDir = Path.Combine (winSDK.InstallationFolder, "lib");
+
+                               if (winSDK.IsSubVersion) {
+                                       winSDKLibDir = Path.Combine (winSDKLibDir, winSDK.Version.ToString ());
+                               } else {
+                                       // Older WinSDK's header folders are not versioned, but installed libraries are, use latest availalble version for now.
+                                       var winSDKLibDirInfo = new DirectoryInfo (winSDKLibDir);
+                                       var versions = winSDKLibDirInfo.GetDirectories ("*.*", SearchOption.TopDirectoryOnly).OrderByDescending (p => p.Name, new StringVersionComparer ());
+                                       if (versions != null && versions.First () != null)
+                                               winSDKLibDir = versions.First ().FullName;
+                               }
+
+                               //Enumerat lib sub folders.
+                               if (Directory.Exists (winSDKLibDir))
+                                       libPaths.Add (Path.Combine (winSDKLibDir, "um", Target64BitApplication () ? "x64" : "x86"));
+                       }
+
+                       return;
+               }
+
+               public void AddCRuntimeSDKIncludePaths (List<string> includePaths)
+               {
+                       InstalledSDKInfo cRuntimeSDK = GetInstalledCRuntimeSDK ();
+                       if (cRuntimeSDK != null) {
+                               string cRuntimeSDKIncludeDir = FindCRuntimeSDKIncludePath (cRuntimeSDK);
+
+                               if (cRuntimeSDKIncludeDir.Length != 0)
+                                       includePaths.Add (cRuntimeSDKIncludeDir);
+                       }
+
+                       return;
+               }
+
+               public void AddCRuntimeSDKLibPaths (List<string> libPaths)
+               {
+                       InstalledSDKInfo cRuntimeSDK = GetInstalledCRuntimeSDK ();
+                       if (cRuntimeSDK != null) {
+                               string cRuntimeSDKLibDir = FindCRuntimeSDKLibPath (cRuntimeSDK);
+
+                               if (cRuntimeSDKLibDir.Length != 0)
+                                       libPaths.Add (cRuntimeSDKLibDir);
+                       }
+
+                       return;
+               }
+       }
+
+       class VisualStudioSDKHelper : SDKHelper {
+
+               List<InstalledSDKInfo> installedVisualStudioSDKs;
+               InstalledSDKInfo installedVisualStudioSDK;
+
+               static VisualStudioSDKHelper singletonInstance = new VisualStudioSDKHelper ();
+               static public VisualStudioSDKHelper GetInstance ()
+               {
+                       return singletonInstance;
+               }
+
+               List<InstalledSDKInfo> InitializeInstalledVisualStudioSDKs ()
+               {
+                       if (installedVisualStudioSDKs == null) {
+                               List<InstalledSDKInfo> sdks = new List<InstalledSDKInfo> ();
+
+                               using (var subKey = GetToolchainRegistrySubKey (@"\Microsoft\VisualStudio\SxS\VS7")) {
+                                       if (subKey != null) {
+                                               foreach (var keyName in subKey.GetValueNames ()) {
+                                                       var vsInstalltionFolder = (string)Microsoft.Win32.Registry.GetValue (subKey.ToString (), keyName, "");
+                                                       if (Directory.Exists (vsInstalltionFolder)) {
+                                                               var vsSDK = new InstalledSDKInfo ("VisualStudio", keyName, vsInstalltionFolder, false);
+                                                               var vcInstallationFolder = Path.Combine (vsInstalltionFolder, "VC");
+
+                                                               if (Directory.Exists (vcInstallationFolder))
+                                                                       vsSDK.AdditionalSDKs.Add (new InstalledSDKInfo ("VisualStudioVC", keyName, vcInstallationFolder, false, vsSDK));
+
+                                                               sdks.Add (vsSDK);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // TODO: Add VS15 SetupConfiguration support.
+                               // To reduce dependecies use vswhere.exe, if available.
+
+                               // Sort based on version.
+                               sdks = sdks.OrderByDescending (p => p.Version.ToString (), new StringVersionComparer ()).ToList ();
+                               installedVisualStudioSDKs = sdks;
+                       }
+
+                       return installedVisualStudioSDKs;
+               }
+
+               string FindVisualStudioVCFolderPath (InstalledSDKInfo vcSDK, string subPath)
+               {
+                       string folderPath = "";
+                       if (vcSDK != null && vcSDK.ParentSDK != null) {
+                               if (IsVisualStudio12 (vcSDK.ParentSDK) || IsVisualStudio14 (vcSDK.ParentSDK)) {
+                                       folderPath = Path.Combine (vcSDK.InstallationFolder, subPath);
+                               } else if (IsVisualStudio15 (vcSDK.ParentSDK)) {
+                                       string msvcVersionPath = Path.Combine (vcSDK.InstallationFolder, "Tools", "MSVC");
+
+                                       // Add latest found version of MSVC toolchain.
+                                       if (Directory.Exists (msvcVersionPath)) {
+                                               var msvcVersionDirInfo = new DirectoryInfo (msvcVersionPath);
+                                               var versions = msvcVersionDirInfo.GetDirectories ("*.*", SearchOption.TopDirectoryOnly).OrderByDescending (p => p.Name, new StringVersionComparer ());
+
+                                               foreach (var version in versions) {
+                                                       msvcVersionPath = Path.Combine (version.FullName, subPath);
+                                                       if (Directory.Exists (msvcVersionPath)) {
+                                                               folderPath = msvcVersionPath;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       return folderPath;
+               }
+
+               string FindVisualStudioVCLibSubPath (InstalledSDKInfo vcSDK)
+               {
+                       string subPath = "";
+
+                       if (vcSDK != null && vcSDK.ParentSDK != null) {
+                               if (IsVisualStudio12 (vcSDK.ParentSDK) || IsVisualStudio14 (vcSDK.ParentSDK))
+                                       subPath = Target64BitApplication () ? @"lib\amd64" : "lib";
+                               else if (IsVisualStudio15 (vcSDK.ParentSDK))
+                                       subPath = Target64BitApplication () ? @"lib\x64" : @"lib\x86";
+                       }
+
+                       return subPath;
+               }
+
+               public InstalledSDKInfo GetInstalledVisualStudioSDK ()
+               {
+                       if (installedVisualStudioSDK == null) {
+                               List<InstalledSDKInfo> visualStudioSDKs = InitializeInstalledVisualStudioSDKs ();
+                               InstalledSDKInfo visualStudioSDK = null;
+
+                               // Check that env doesn't already include needed values.
+                               // If executed from a VS developer command prompt, Visual Studio install dir set in env.
+                               string vsVersion = GetEnv ("VisualStudioVersion", "");
+
+                               if (vsVersion.Length != 0 && visualStudioSDKs != null)
+                                       // Find installed SDK based on requested info.
+                                       visualStudioSDK = visualStudioSDKs.Find (x => x.Version.ToString () == vsVersion);
+
+                               if (visualStudioSDK == null && visualStudioSDKs != null)
+                                       // Get latest installed verison.
+                                       visualStudioSDK = visualStudioSDKs.First ();
+
+                               installedVisualStudioSDK = visualStudioSDK;
+                       }
+
+                       return installedVisualStudioSDK;
+               }
+
+               public InstalledSDKInfo GetInstalledVisualStudioVCSDK ()
+               {
+                       InstalledSDKInfo visualStudioVCSDK = null;
+
+                       // Check that env doesn't already include needed values.
+                       // If executed from a VS developer command prompt, Visual Studio install dir set in env.
+                       string vcInstallDir = GetEnv ("VCINSTALLDIR", "");
+                       if (vcInstallDir.Length != 0) {
+                               List<InstalledSDKInfo> installedVisualStudioSDKs = InitializeInstalledVisualStudioSDKs ();
+                               if (installedVisualStudioSDKs != null) {
+                                       foreach (var currentInstalledSDK in installedVisualStudioSDKs) {
+                                               // Find installed SDK based on requested info.
+                                               visualStudioVCSDK = currentInstalledSDK.AdditionalSDKs.Find (x => x.InstallationFolder == vcInstallDir);
+                                               if (visualStudioVCSDK != null)
+                                                       break;
+                                       }
+                               }
+                       }
+
+                       // Get latest installed VS VC SDK version.
+                       if (visualStudioVCSDK == null) {
+                               var visualStudioSDK = GetInstalledVisualStudioSDK ();
+                               if (visualStudioSDK != null)
+                                       visualStudioVCSDK = visualStudioSDK.AdditionalSDKs.Find (x => x.Name == "VisualStudioVC");
+                       }
+
+                       return visualStudioVCSDK;
+               }
+
+               public bool IsVisualStudio12 (InstalledSDKInfo vsSDK)
+               {
+                       return vsSDK.Version.Major == 12 || vsSDK.Version.Major == 2013;
+               }
+
+               public bool IsVisualStudio14 (InstalledSDKInfo vsSDK)
+               {
+                       return vsSDK.Version.Major == 14 || vsSDK.Version.Major == 2015;
+               }
+
+               public bool IsVisualStudio15 (InstalledSDKInfo vsSDK)
+               {
+                       return vsSDK.Version.Major == 15 || vsSDK.Version.Major == 2017;
+               }
+
+               public void AddVisualStudioVCIncludePaths (List<string> includePaths)
+               {
+                       // Check that env doesn't already include needed values.
+                       string vcIncludeDir = GetEnv ("VSINCLUDE", "");
+                       if (vcIncludeDir.Length == 0) {
+                               var visualStudioVCSDK = GetInstalledVisualStudioVCSDK ();
+                               vcIncludeDir = FindVisualStudioVCFolderPath (visualStudioVCSDK, "include");
+                       }
+
+                       if (vcIncludeDir.Length != 0)
+                               includePaths.Add (vcIncludeDir);
+
+                       return;
+               }
+
+               public void AddVisualStudioVCLibPaths (List<string> libPaths)
+               {
+                       // Check that env doesn't already include needed values.
+                       string vcLibDir = GetEnv ("VSLIB", "");
+                       if (vcLibDir.Length == 0) {
+                               var vcSDK = GetInstalledVisualStudioVCSDK ();
+                               vcLibDir = FindVisualStudioVCFolderPath (vcSDK, FindVisualStudioVCLibSubPath (vcSDK));
+                       }
+
+                       if (vcLibDir.Length != 0)
+                               libPaths.Add (vcLibDir);
+
+                       return;
+               }
+       }
+
+       class VCToolchainProgram {
+
+               protected ToolchainProgram toolchain;
+               public virtual bool IsVersion (InstalledSDKInfo vcSDK) { return false; }
+               public virtual ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK) { return null; }
+       }
+
+       class VC12ToolchainProgram : VCToolchainProgram {
+
+               public override bool IsVersion (InstalledSDKInfo vcSDK)
+               {
+                       return VisualStudioSDKHelper.GetInstance ().IsVisualStudio12 (vcSDK);
+               }
+
+               protected ToolchainProgram FindVCToolchainProgram (string tool, InstalledSDKInfo vcSDK)
+               {
+                       if (toolchain == null) {
+                               string toolPath = "";
+                               if (!string.IsNullOrEmpty (vcSDK?.InstallationFolder)) {
+                                       if (Target64BitApplication ())
+                                               toolPath = Path.Combine (new string [] { vcSDK.InstallationFolder, "bin", "amd64", tool });
+                                       else
+                                               toolPath = Path.Combine (new string [] { vcSDK.InstallationFolder, "bin", tool });
+
+                                       if (!File.Exists (toolPath))
+                                               toolPath = "";
+                               }
+
+                               toolchain = new ToolchainProgram (tool, toolPath, vcSDK);
+                       }
+
+                       return toolchain;
+               }
+       }
+
+       class VC15ToolchainProgram : VCToolchainProgram {
+               public override bool IsVersion (InstalledSDKInfo vcSDK)
+               {
+                       return VisualStudioSDKHelper.GetInstance ().IsVisualStudio15 (vcSDK);
+               }
+
+               protected ToolchainProgram FindVCToolchainProgram (string tool, InstalledSDKInfo vcSDK)
+               {
+                       if (toolchain == null) {
+                               string toolPath = "";
+                               if (!string.IsNullOrEmpty (vcSDK?.InstallationFolder)) {
+                                       string toolsVersionFilePath = Path.Combine (vcSDK.InstallationFolder, "Auxiliary", "Build", "Microsoft.VCToolsVersion.default.txt");
+                                       string toolsVersion = File.ReadAllLines (toolsVersionFilePath).ElementAt (0).Trim ();
+                                       string toolsVersionPath = Path.Combine (vcSDK.InstallationFolder, "Tools", "MSVC", toolsVersion);
+
+                                       if (Target64BitApplication ())
+                                               toolPath = Path.Combine (toolsVersionPath, "bin", "HostX64", "x64", tool);
+                                       else
+                                               toolPath = Path.Combine (toolsVersionPath, "bin", "HostX86", "x86", tool);
+                               }
+
+                               toolchain = new ToolchainProgram (tool, toolPath, vcSDK);
+                       }
+
+                       return toolchain;
+               }
+       }
+
+       class VC12Compiler : VC12ToolchainProgram {
+               public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK)
+               {
+                       return FindVCToolchainProgram ("cl.exe", vcSDK);
+               }
+       }
+
+       class VC14Compiler : VC12Compiler {
+               public override bool IsVersion (InstalledSDKInfo vcSDK)
+               {
+                       return VisualStudioSDKHelper.GetInstance ().IsVisualStudio14 (vcSDK);
+               }
+       }
+
+       class VC15Compiler : VC15ToolchainProgram {
+               public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK)
+               {
+                       return FindVCToolchainProgram ("cl.exe", vcSDK);
+               }
+       }
+
+       class VC12Librarian : VC12ToolchainProgram {
+               public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK)
+               {
+                       return FindVCToolchainProgram ("lib.exe", vcSDK);
+               }
+       }
+
+       class VC14Librarian : VC12Compiler {
+               public override bool IsVersion (InstalledSDKInfo vcSDK)
+               {
+                       return VisualStudioSDKHelper.GetInstance ().IsVisualStudio14 (vcSDK);
+               }
+       }
+
+       class VC15Librarian : VC15ToolchainProgram {
+               public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK)
+               {
+                       return FindVCToolchainProgram ("lib.exe", vcSDK);
+               }
+       }
+
+       class VC14Clang : VCToolchainProgram {
+               public override bool IsVersion (InstalledSDKInfo vcSDK)
+               {
+                       return VisualStudioSDKHelper.GetInstance ().IsVisualStudio14 (vcSDK);
+               }
+
+               public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK)
+               {
+                       if (toolchain == null) {
+                               string clangPath = "";
+                               if (!string.IsNullOrEmpty (vcSDK?.InstallationFolder)) {
+                                       clangPath = Path.Combine (new string [] { vcSDK.InstallationFolder, "ClangC2", "bin", Target64BitApplication () ? "amd64" : "x86", "clang.exe" });
+
+                                       if (!File.Exists (clangPath))
+                                               clangPath = "";
+                               }
+
+                               toolchain = new ToolchainProgram ("clang.exe", clangPath, vcSDK);
+                       }
+
+                       return toolchain;
+               }
+       }
+
+       class VC15Clang : VCToolchainProgram {
+               public override bool IsVersion (InstalledSDKInfo vcSDK)
+               {
+                       return VisualStudioSDKHelper.GetInstance ().IsVisualStudio15 (vcSDK);
+               }
+
+               public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK)
+               {
+                       if (toolchain == null) {
+                               string clangPath = "";
+                               if (!string.IsNullOrEmpty (vcSDK?.InstallationFolder)) {
+                                       string clangVersionFilePath = Path.Combine (vcSDK.InstallationFolder, "Auxiliary", "Build", "Microsoft.ClangC2Version.default.txt");
+                                       string clangVersion = File.ReadAllLines (clangVersionFilePath).ElementAt (0).Trim ();
+                                       string clangVersionPath = Path.Combine (vcSDK.InstallationFolder, "Tools", "ClangC2", clangVersion);
+
+                                       clangPath = Path.Combine (clangVersionPath, "bin", Target64BitApplication () ? "HostX64" : "HostX86", "clang.exe");
+                               }
+
+                               toolchain = new ToolchainProgram ("clang.exe", clangPath, vcSDK);
+                       }
+
+                       return toolchain;
+               }
+       }
+
+       class VisualStudioSDKToolchainHelper {
+               List<VCToolchainProgram> vcCompilers = new List<VCToolchainProgram> ();
+               List<VCToolchainProgram> vcLibrarians = new List<VCToolchainProgram> ();
+               List<VCToolchainProgram> vcClangCompilers = new List<VCToolchainProgram> ();
+
+               public VisualStudioSDKToolchainHelper ()
+               {
+                       vcCompilers.Add (new VC12Compiler ());
+                       vcCompilers.Add (new VC14Compiler ());
+                       vcCompilers.Add (new VC15Compiler ());
+
+                       vcLibrarians.Add (new VC12Librarian ());
+                       vcLibrarians.Add (new VC14Librarian ());
+                       vcLibrarians.Add (new VC15Librarian ());
+
+                       vcClangCompilers.Add (new VC14Clang ());
+                       vcClangCompilers.Add (new VC15Clang ());
+               }
+
+               static VisualStudioSDKToolchainHelper singletonInstance = new VisualStudioSDKToolchainHelper ();
+               static public VisualStudioSDKToolchainHelper GetInstance ()
+               {
+                       return singletonInstance;
+               }
+
+               ToolchainProgram GetVCToolChainProgram (List<VCToolchainProgram> programs)
+               {
+                       ToolchainProgram program = null;
+                       var vcSDK = VisualStudioSDKHelper.GetInstance ().GetInstalledVisualStudioVCSDK ();
+                       if (vcSDK?.ParentSDK != null) {
+                               foreach (var item in programs) {
+                                       if (item.IsVersion (vcSDK.ParentSDK)) {
+                                               program = item.FindVCToolchainProgram (vcSDK);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       return program;
+               }
+
+               public ToolchainProgram GetVCCompiler ()
+               {
+                       return GetVCToolChainProgram (vcCompilers);
+               }
+
+               public ToolchainProgram GetVCLibrarian ()
+               {
+                       return GetVCToolChainProgram (vcLibrarians);
+               }
+
+               public ToolchainProgram GetVCClangCompiler ()
+               {
+                       return GetVCToolChainProgram (vcClangCompilers);
+               }
+       }
+
+       static bool Target64BitApplication ()
+       {
+               // Should probably handled the --cross and sdk parameters.
+               return Environment.Is64BitProcess;
+       }
+
+       static string GetMonoDir ()
+       {
+               // Check that env doesn't already include needed values.
+               string monoInstallDir = GetEnv ("MONOPREFIX", "");
+               if (monoInstallDir.Length == 0) {
+                       using (var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey (Microsoft.Win32.RegistryHive.LocalMachine,
+                               Target64BitApplication () ? Microsoft.Win32.RegistryView.Registry64 : Microsoft.Win32.RegistryView.Registry32)) {
+
+                               if (baseKey != null) {
+                                       using (var subKey = baseKey.OpenSubKey (@"SOFTWARE\Mono")) {
+                                               if (subKey != null)
+                                                       monoInstallDir = (string)subKey.GetValue ("SdkInstallRoot", "");
+                                       }
+                               }
+                       }
+               }
+
+               return monoInstallDir;
+       }
+
+       static void AddMonoIncludePaths (List<string> includePaths)
+       {
+               includePaths.Add (Path.Combine (GetMonoDir (), @"include\mono-2.0"));
+               return;
+       }
+
+       static void AddMonoLibPaths (List<string> libPaths)
+       {
+               libPaths.Add (Path.Combine (GetMonoDir (), "lib"));
+               return;
+       }
+
+       static void AddIncludePaths (List<string> includePaths)
+       {
+               // Check that env doesn't already include needed values.
+               // If executed from a VS developer command prompt, all includes are already setup in env.
+               string includeEnv = GetEnv ("INCLUDE", "");
+               if (includeEnv.Length == 0) {
+                       VisualStudioSDKHelper.GetInstance ().AddVisualStudioVCIncludePaths (includePaths);
+                       WindowsSDKHelper.GetInstance ().AddCRuntimeSDKIncludePaths (includePaths);
+                       WindowsSDKHelper.GetInstance ().AddWindowsSDKIncludePaths (includePaths);
+               }
+
+               AddMonoIncludePaths (includePaths);
+               includePaths.Add (".");
+
+               return;
+       }
+
+       static void AddLibPaths (List<string> libPaths)
+       {
+               // Check that env doesn't already include needed values.
+               // If executed from a VS developer command prompt, all libs are already setup in env.
+               string libEnv = GetEnv ("LIB", "");
+               if (libEnv.Length == 0) {
+                       VisualStudioSDKHelper.GetInstance ().AddVisualStudioVCLibPaths (libPaths);
+                       WindowsSDKHelper.GetInstance ().AddCRuntimeSDKLibPaths (libPaths);
+                       WindowsSDKHelper.GetInstance ().AddWindowsSDKLibPaths (libPaths);
+               }
+
+               AddMonoLibPaths (libPaths);
+               libPaths.Add (".");
+
+               return;
+       }
+
+       static void AddVCSystemLibraries (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> linkerArgs)
+       {
+               linkerArgs.Add ("kernel32.lib");
+               linkerArgs.Add ("version.lib");
+               linkerArgs.Add ("ws2_32.lib");
+               linkerArgs.Add ("mswsock.lib");
+               linkerArgs.Add ("psapi.lib");
+               linkerArgs.Add ("shell32.lib");
+               linkerArgs.Add ("oleaut32.lib");
+               linkerArgs.Add ("ole32.lib");
+               linkerArgs.Add ("winmm.lib");
+               linkerArgs.Add ("user32.lib");
+               linkerArgs.Add ("advapi32.lib");
+
+               if (program != null && program.ParentSDK != null && VisualStudioSDKHelper.GetInstance ().IsVisualStudio12 (program.ParentSDK)) {
+                       if (staticLinkCRuntime) {
+                               // Static release c-runtime support.
+                               linkerArgs.Add ("libcmt.lib");
+                               linkerArgs.Add ("oldnames.lib");
+                       } else {
+                               // Dynamic release c-runtime support.
+                               linkerArgs.Add ("msvcrt.lib");
+                               linkerArgs.Add ("oldnames.lib");
+                       }
+               } else {
+                       if (staticLinkCRuntime) {
+                               // Static release c-runtime support.
+                               linkerArgs.Add ("libucrt.lib");
+                               linkerArgs.Add ("libvcruntime.lib");
+                               linkerArgs.Add ("libcmt.lib");
+                               linkerArgs.Add ("oldnames.lib");
+                       } else {
+                               // Dynamic release c-runtime support.
+                               linkerArgs.Add ("ucrt.lib");
+                               linkerArgs.Add ("vcruntime.lib");
+                               linkerArgs.Add ("msvcrt.lib");
+                               linkerArgs.Add ("oldnames.lib");
+                       }
+               }
+
+               return;
+       }
+
+       static void AddGCCSystemLibraries (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> linkerArgs)
+       {
+               if (MakeBundle.compress)
+                       linkerArgs.Add ("-lz");
+
+               return;
+       }
+
+       static void AddSystemLibraries (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> linkerArgs)
+       {
+               if (program.IsVSToolChain)
+                       AddVCSystemLibraries (program, staticLinkMono, staticLinkCRuntime, linkerArgs);
+               else
+                       AddGCCSystemLibraries (program, staticLinkMono, staticLinkCRuntime, linkerArgs);
+
+               return;
+       }
+
+       static void AddMonoLibraries (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> linkerArguments)
+       {
+               bool vsToolChain = program.IsVSToolChain;
+               string libPrefix = !vsToolChain ? "-l" : "";
+               string libExtension = vsToolChain ? ".lib" : "";
+               string monoLibrary = GetEnv ("LIBMONO", "");
+
+               if (monoLibrary.Length == 0) {
+                       if (staticLinkMono) {
+                               if (program.IsGCCToolChain) {
+                                       Console.WriteLine (     @"Warning: Static linking using default Visual Studio build libmono-static-sgen" +
+                                                               @"might cause link errors when using GCC toolchain.");
+                               }
+                               monoLibrary = "libmono-static-sgen";
+                       } else {
+                               monoLibrary = "mono-2.0-sgen";
+                       }
+               }
+
+               if (!Path.IsPathRooted (monoLibrary)) {
+                       if (!monoLibrary.EndsWith (libExtension))
+                               monoLibrary = monoLibrary + libExtension;
+
+                       linkerArguments.Add (libPrefix + monoLibrary);
+               } else {
+                       linkerArguments.Add (monoLibrary);
+               }
+
+               return;
+       }
+
+       static void AddVCCompilerArguments (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> compilerArgs)
+       {
+               List<string> includePaths = new List<string> ();
+               AddIncludePaths (includePaths);
+
+               if (staticLinkCRuntime)
+                       // Add targeted c-runtime (MT = static release).
+                       compilerArgs.Add ("/MT");
+               else
+                       // Add targeted c-runtime (MD = dynamic release).
+                       compilerArgs.Add ("/MD");
+
+               // Add include search paths.
+               foreach (string include in includePaths)
+                       compilerArgs.Add (String.Format("/I {0}", program.QuoteArg (include)));
+
+               return;
+       }
+
+       static void AddGCCCompilerArguments (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> compilerArgs)
+       {
+               List<string> includePaths = new List<string> ();
+               AddMonoIncludePaths (includePaths);
+
+               // Add include search paths.
+               foreach (string include in includePaths)
+                       compilerArgs.Add (String.Format ("-I {0}", program.QuoteArg (include)));
+
+               return;
+       }
+
+       static void AddCompilerArguments (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List<string> compilerArgs)
+       {
+               if (program.IsVSToolChain)
+                       AddVCCompilerArguments (program, staticLinkMono, staticLinkCRuntime, compilerArgs);
+               else
+                       AddGCCCompilerArguments (program, staticLinkMono, staticLinkCRuntime, compilerArgs);
+
+               return;
+       }
+
+       static void AddVCLinkerArguments (ToolchainProgram linker, bool staticLinkMono, bool staticLinkCRuntime, string customMain, string outputFile, List<string> linkerArgs)
+       {
+               linkerArgs.Add ("/link");
+
+               var subsystem = GetEnv ("VCSUBSYSTEM", "windows");
+               linkerArgs.Add ("/SUBSYSTEM:" + subsystem);
+
+               if (customMain != null && customMain.Length != 0)
+                       linkerArgs.Add (linker.QuoteArg (customMain));
+               else
+                       linkerArgs.Add ("/ENTRY:mainCRTStartup");
+
+               // Ignore other c-runtime directives from linked libraries.
+               linkerArgs.Add ("/NODEFAULTLIB");
+
+               AddMonoLibraries (linker, staticLinkMono, staticLinkCRuntime, linkerArgs);
+               AddSystemLibraries (linker, staticLinkMono, staticLinkCRuntime, linkerArgs);
+
+               // Add library search paths.
+               List<string> libPaths = new List<string> ();
+               AddLibPaths (libPaths);
+
+               foreach (string lib in libPaths)
+                       linkerArgs.Add (String.Format ("/LIBPATH:{0}", linker.QuoteArg (lib)));
+
+               // Linker output target.
+               linkerArgs.Add ("/OUT:" + linker.QuoteArg (outputFile));
+
+               return;
+       }
+
+       static void AddGCCLinkerArguments (ToolchainProgram linker, bool staticLinkMono, bool staticLinkCRuntime, string customMain, string outputFile, List<string> linkerArgs)
+       {
+               // Add library search paths.
+               List<string> libPaths = new List<string> ();
+               AddMonoLibPaths (libPaths);
+
+               foreach (string lib in libPaths)
+                       linkerArgs.Add (String.Format ("-L {0}", linker.QuoteArg (lib)));
+
+               // Add libraries.
+               if (staticLinkMono)
+                       linkerArgs.Add ("-Wl,-Bstatic");
+
+               AddMonoLibraries (linker, staticLinkMono, staticLinkCRuntime, linkerArgs);
+
+               if (staticLinkMono)
+                       linkerArgs.Add ("-Wl,-Bdynamic");
+
+               AddSystemLibraries (linker, staticLinkMono, staticLinkCRuntime, linkerArgs);
+
+               // Linker output target.
+               linkerArgs.Add ("-o " + linker.QuoteArg (outputFile));
+       }
+
+       static void AddLinkerArguments (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, string customMain, string outputFile, List<string> linkerArgs)
+       {
+               if (program.IsVSToolChain)
+                       AddVCLinkerArguments (program, staticLinkMono, staticLinkCRuntime, customMain, outputFile, linkerArgs);
+               else
+                       AddGCCLinkerArguments (program, staticLinkMono, staticLinkCRuntime, customMain, outputFile, linkerArgs);
+
+               return;
+       }
+
+       static void AddVCLibrarianCompilerArguments (ToolchainProgram compiler, string sourceFile, bool staticLinkMono, bool staticLinkCRuntime, List<string> compilerArgs, out string objectFile)
+       {
+               compilerArgs.Add ("/c");
+               compilerArgs.Add (compiler.QuoteArg (sourceFile));
+
+               objectFile = sourceFile + ".obj";
+               compilerArgs.Add (String.Format ("/Fo" + compiler.QuoteArg (objectFile)));
+
+               return;
+       }
+
+       static void AddGCCLibrarianCompilerArguments (ToolchainProgram compiler, string sourceFile, bool staticLinkMono, bool staticLinkCRuntime, List<string> compilerArgs, out string objectFile)
+       {
+               compilerArgs.Add ("-c");
+               compilerArgs.Add (compiler.QuoteArg (sourceFile));
+
+               objectFile = sourceFile + ".o";
+               compilerArgs.Add (String.Format ("-o " + compiler.QuoteArg (objectFile)));
+
+               return;
+       }
+
+       static void AddVCLibrarianLinkerArguments (ToolchainProgram librarian, string [] objectFiles, bool staticLinkMono, bool staticLinkCRuntime, string outputFile, List<string> librarianArgs)
+       {
+               foreach (var objectFile in objectFiles)
+                       librarianArgs.Add (librarian.QuoteArg (objectFile));
+
+               // Add library search paths.
+               List<string> libPaths = new List<string> ();
+               AddLibPaths (libPaths);
+
+               foreach (string lib in libPaths) {
+                       librarianArgs.Add (String.Format ("/LIBPATH:{0}", librarian.QuoteArg (lib)));
+               }
+
+               AddMonoLibraries (librarian, staticLinkMono, staticLinkCRuntime, librarianArgs);
+
+               librarianArgs.Add ("/OUT:" + librarian.QuoteArg (output));
+
+               return;
+       }
+
+       static void AddGCCLibrarianLinkerArguments (ToolchainProgram librarian, string [] objectFiles, bool staticLinkMono, bool staticLinkCRuntime, string outputFile, List<string> librarianArgs)
+       {
+               foreach (var objectFile in objectFiles)
+                       librarianArgs.Add (librarian.QuoteArg (objectFile));
+
+               // Add library search paths.
+               List<string> libPaths = new List<string> ();
+               AddMonoLibPaths (libPaths);
+
+               foreach (string lib in libPaths)
+                       librarianArgs.Add (String.Format ("-L {0}", librarian.QuoteArg (lib)));
+
+               AddMonoLibraries (librarian, staticLinkMono, staticLinkCRuntime, librarianArgs);
+
+               librarianArgs.Add ("-o " + librarian.QuoteArg (output));
+
+               return;
+       }
+
+       static ToolchainProgram GetAssemblerCompiler ()
+       {
+               // First check if env is set (old behavior) and use that.
+               string assembler = GetEnv ("AS", "");
+               if (assembler.Length != 0)
+                       return new ToolchainProgram ("AS", assembler);
+
+               var vcClangAssembler = VisualStudioSDKToolchainHelper.GetInstance ().GetVCClangCompiler ();
+               if (vcClangAssembler == null)
+                       // Fallback to GNU assembler if clang for VS was not installed.
+                       // Why? because mkbundle generates GNU assembler not compilable by VS tools like ml.
+                       return new ToolchainProgram ("AS", "as.exe");
+
+               return vcClangAssembler;
+       }
+
+       static ToolchainProgram GetCCompiler ()
+       {
+               // First check if env is set (old behavior) and use that.
+               string compiler = GetEnv ("CC", "");
+               if (compiler.Length != 0)
+                       return new ToolchainProgram ("CC", compiler);
+
+               var vcCompiler = VisualStudioSDKToolchainHelper.GetInstance ().GetVCCompiler ();
+               if (vcCompiler == null)
+                       // Fallback to cl.exe if VC compiler was not installed.
+                       return new ToolchainProgram ("cl.exe", "cl.exe");
+
+               return vcCompiler;
+       }
+
+       static ToolchainProgram GetLibrarian ()
+       {
+               ToolchainProgram vcLibrarian = VisualStudioSDKToolchainHelper.GetInstance ().GetVCLibrarian ();
+               if (vcLibrarian == null)
+                       // Fallback to lib.exe if VS was not installed.
+                       return new ToolchainProgram ("lib.exe", "lib.exe");
+
+               return vcLibrarian;
+       }
+
+       static string GetCompileAndLinkCommand (ToolchainProgram compiler, string sourceFile, string objectFile, string customMain, bool staticLinkMono, bool staticLinkCRuntime, string outputFile)
+       {
+               var compilerArgs = new List<string> ();
+
+               AddCompilerArguments (compiler, staticLinkMono, staticLinkCRuntime, compilerArgs);
+
+               // Add source file to compile.
+               compilerArgs.Add (compiler.QuoteArg (sourceFile));
+
+               // Add assembled object file.
+               compilerArgs.Add (compiler.QuoteArg (objectFile));
+
+               // Add linker arguments.
+               AddLinkerArguments (compiler, staticLinkMono, staticLinkCRuntime, customMain, outputFile, compilerArgs);
+
+               return String.Format ("{0} {1}", compiler.QuoteArg (compiler.Path), String.Join (" ", compilerArgs.ToArray ()));
+       }
+
+       static string GetLibrarianCompilerCommand (ToolchainProgram compiler, string sourceFile, bool staticLinkMono, bool staticLinkCRuntime, out string objectFile)
+       {
+               var compilerArgs = new List<string> ();
+
+               AddCompilerArguments (compiler, staticLinkMono, staticLinkCRuntime, compilerArgs);
+
+               if (compiler.IsVSToolChain)
+                       AddVCLibrarianCompilerArguments (compiler, sourceFile, staticLinkMono, staticLinkCRuntime, compilerArgs, out objectFile);
+               else
+                       AddGCCLibrarianCompilerArguments (compiler, sourceFile, staticLinkMono, staticLinkCRuntime, compilerArgs, out objectFile);
+
+               return String.Format ("{0} {1}", compiler.QuoteArg (compiler.Path), String.Join (" ", compilerArgs.ToArray ()));
+       }
+
+       static string GetLibrarianLinkerCommand (ToolchainProgram librarian, string [] objectFiles, bool staticLinkMono, bool staticLinkCRuntime, string outputFile)
+       {
+               var librarianArgs = new List<string> ();
+
+               if (librarian.IsVSToolChain)
+                       AddVCLibrarianLinkerArguments (librarian, objectFiles, staticLinkMono, staticLinkCRuntime, outputFile, librarianArgs);
+               else
+                       AddGCCLibrarianLinkerArguments (librarian, objectFiles, staticLinkMono, staticLinkCRuntime, outputFile, librarianArgs);
+
+               return String.Format ("{0} {1}", librarian.QuoteArg (librarian.Path), String.Join (" ", librarianArgs.ToArray ()));
+       }
+#endregion
 }