Major improvement of Visual Studio toolchain and Windows SDK support in mkbundle.
[mono.git] / 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
 }