From: Johan Lorensson Date: Wed, 4 Oct 2017 06:22:29 +0000 (+0200) Subject: Merge pull request #5664 from lateralusX/lateralusX/mkbundle-windows-toolchains X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=f86145e5589879e84a0982598d37ad0b8d6953ee;hp=d7c22488d7db4276029267fa19cd03a7051af634 Merge pull request #5664 from lateralusX/lateralusX/mkbundle-windows-toolchains [Windows] Major improvement of Visual Studio toolchain and Windows SDK support in mkbundle. --- diff --git a/mcs/tools/mkbundle/mkbundle.cs b/mcs/tools/mkbundle/mkbundle.cs index d4ef1cbb552..e0309f5bb7a 100755 --- a/mcs/tools/mkbundle/mkbundle.cs +++ b/mcs/tools/mkbundle/mkbundle.cs @@ -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,25 @@ void mono_register_config_for_assembly (const char* assembly_name, cons if (!quiet) Console.WriteLine("Compiling:"); - if (style == "windows") - { - - Func 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 - } - - var compilerArgs = new List(); - compilerArgs.Add("/MT"); - - foreach (string include in includes) - compilerArgs.Add(String.Format ("/I {0}", quote (include))); - + if (style == "windows") { + ToolchainProgram compiler = GetCCompiler (); + 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 (); - 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 +1067,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 +1155,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 +1391,1193 @@ 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 { + 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.AdditionalSDKs = new List (); + } + + 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 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 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 { + static 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 installedWindowsSDKs; + List installedCRuntimeSDKs; + InstalledSDKInfo installedWindowsSDK; + InstalledSDKInfo installedCRuntimeSDK; + + static WindowsSDKHelper singletonInstance = new WindowsSDKHelper (); + static public WindowsSDKHelper GetInstance () + { + return singletonInstance; + } + + Dictionary GetInstalledWindowsKitRootFolders () + { + var rootFolders = new Dictionary (); + + 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 windowsSDKs = new List (); + List cRuntimeSDKs = new List (); + 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 GetInstalledWindowsSDKs () + { + if (installedWindowsSDKs == null) + InitializeInstalledWindowsKits (); + + return installedWindowsSDKs; + } + + List GetInstalledCRuntimeSDKs () + { + if (installedCRuntimeSDKs == null) + InitializeInstalledWindowsKits (); + + return installedCRuntimeSDKs; + } + + InstalledSDKInfo GetInstalledWindowsSDK () + { + if (installedWindowsSDK == null) { + string winSDKDir = ""; + InstalledSDKInfo windowsSDK = null; + List 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 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 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 available version for now. + var winSDKLibDirInfo = new DirectoryInfo (winSDKLibDir); + var version = winSDKLibDirInfo.GetDirectories ("*.*", SearchOption.TopDirectoryOnly) + .OrderByDescending (p => p.Name, new StringVersionComparer ()).FirstOrDefault (); + if (version != null) + winSDKLibDir = version.FullName; + } + + //Enumerat lib sub folders. + if (Directory.Exists (winSDKLibDir)) + libPaths.Add (Path.Combine (winSDKLibDir, "um", Target64BitApplication () ? "x64" : "x86")); + } + + return; + } + + public void AddCRuntimeSDKIncludePaths (List includePaths) + { + InstalledSDKInfo cRuntimeSDK = GetInstalledCRuntimeSDK (); + if (cRuntimeSDK != null) { + string cRuntimeSDKIncludeDir = FindCRuntimeSDKIncludePath (cRuntimeSDK); + + if (cRuntimeSDKIncludeDir.Length != 0) + includePaths.Add (cRuntimeSDKIncludeDir); + } + + return; + } + + public void AddCRuntimeSDKLibPaths (List libPaths) + { + InstalledSDKInfo cRuntimeSDK = GetInstalledCRuntimeSDK (); + if (cRuntimeSDK != null) { + string cRuntimeSDKLibDir = FindCRuntimeSDKLibPath (cRuntimeSDK); + + if (cRuntimeSDKLibDir.Length != 0) + libPaths.Add (cRuntimeSDKLibDir); + } + + return; + } + } + + class VisualStudioSDKHelper : SDKHelper { + List installedVisualStudioSDKs; + InstalledSDKInfo installedVisualStudioSDK; + + static VisualStudioSDKHelper singletonInstance = new VisualStudioSDKHelper (); + static public VisualStudioSDKHelper GetInstance () + { + return singletonInstance; + } + + List InitializeInstalledVisualStudioSDKs () + { + if (installedVisualStudioSDKs == null) { + List sdks = new List (); + + 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 (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 (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 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 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 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 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 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 VC14ToolchainProgram : VCToolchainProgram { + public override bool IsVersion (InstalledSDKInfo vcSDK) + { + return VisualStudioSDKHelper.GetInstance ().IsVisualStudio14 (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 VC14Compiler : VC14ToolchainProgram { + public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK) + { + return FindVCToolchainProgram ("cl.exe", vcSDK); + } + } + + class VC15Compiler : VC15ToolchainProgram { + public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK) + { + return FindVCToolchainProgram ("cl.exe", vcSDK); + } + } + + class VC14Librarian : VC14ToolchainProgram { + public override ToolchainProgram FindVCToolchainProgram (InstalledSDKInfo vcSDK) + { + return FindVCToolchainProgram ("lib.exe", 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 vcCompilers = new List (); + List vcLibrarians = new List (); + List vcClangCompilers = new List (); + + public VisualStudioSDKToolchainHelper () + { + vcCompilers.Add (new VC14Compiler ()); + vcCompilers.Add (new VC15Compiler ()); + + 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 programs) + { + var vcSDK = VisualStudioSDKHelper.GetInstance ().GetInstalledVisualStudioVCSDK (); + if (vcSDK?.ParentSDK != null) { + foreach (var item in programs) { + if (item.IsVersion (vcSDK.ParentSDK)) { + return item.FindVCToolchainProgram (vcSDK); + } + } + } + + return null; + } + + 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 includePaths) + { + includePaths.Add (Path.Combine (GetMonoDir (), @"include\mono-2.0")); + return; + } + + static void AddMonoLibPaths (List libPaths) + { + libPaths.Add (Path.Combine (GetMonoDir (), "lib")); + return; + } + + static void AddIncludePaths (List 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 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 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 (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 linkerArgs) + { + if (MakeBundle.compress) + linkerArgs.Add ("-lz"); + + return; + } + + static void AddSystemLibraries (ToolchainProgram program, bool staticLinkMono, bool staticLinkCRuntime, List 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 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 compilerArgs) + { + List includePaths = new List (); + 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 compilerArgs) + { + List includePaths = new List (); + 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 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 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 libPaths = new List (); + 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 linkerArgs) + { + // Add library search paths. + List libPaths = new List (); + 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 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 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 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 librarianArgs) + { + foreach (var objectFile in objectFiles) + librarianArgs.Add (librarian.QuoteArg (objectFile)); + + // Add library search paths. + List libPaths = new List (); + 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 librarianArgs) + { + foreach (var objectFile in objectFiles) + librarianArgs.Add (librarian.QuoteArg (objectFile)); + + // Add library search paths. + List libPaths = new List (); + 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. + Console.WriteLine (@"Warning: Couldn't find installed Visual Studio SDK, fallback to as.exe and default environment."); + 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. + Console.WriteLine (@"Warning: Couldn't find installed Visual Studio SDK, fallback to cl.exe and default environment."); + 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. + Console.WriteLine (@"Warning: Couldn't find installed Visual Studio SDK, fallback to lib.exe and default environment."); + 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 (); + + 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)); + } + + static string GetLibrarianCompilerCommand (ToolchainProgram compiler, string sourceFile, bool staticLinkMono, bool staticLinkCRuntime, out string objectFile) + { + var compilerArgs = new List (); + + 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)); + } + + static string GetLibrarianLinkerCommand (ToolchainProgram librarian, string [] objectFiles, bool staticLinkMono, bool staticLinkCRuntime, string outputFile) + { + var librarianArgs = new List (); + + 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)); + } +#endregion }