Review feedback + drop VS2013 support.
[mono.git] / mcs / tools / mkbundle / mkbundle.cs
index cc891536b8af26f751fb8fa1aebc08c5a5a42487..e0309f5bb7a1a33eabeaac11ca883abdcd24cbc4 100755 (executable)
@@ -3,6 +3,16 @@
 //
 // Based on the `make-bundle' Perl script written by Paolo Molaro (lupus@debian.org)
 //
+// TODO:
+//   [x] Rename the paths for the zip file that is downloaded
+//   [x] Update documentation with new flag
+//   [x] Load internationalized assemblies
+//   [x] Dependencies - if System.dll -> include Mono.Security.* (not needed, automatic)
+//   [x] --list-targets should download from a different url
+//   [x] --fetch-target should unpack zip file
+//   [x] Update --cross to use not a runtime, but an SDK
+//   [x] Update --local-targets to show the downloaded SDKs
+//
 // Author:
 //   Miguel de Icaza
 //
@@ -39,6 +49,7 @@ class MakeBundle {
        static string machine_config_file = null;
        static string config_dir = null;
        static string style = "linux";
+       static bool bundled_header = false;
        static string os_message = "";
        static bool compress;
        static bool nomain;
@@ -52,6 +63,8 @@ class MakeBundle {
        static bool custom_mode = true;
        static string embedded_options = null;
        static string runtime = null;
+       static string sdk_path = null;
+       static string lib_path = null;
        static Dictionary<string,string> environment = new Dictionary<string,string>();
        static string [] i18n = new string [] {
                "West",
@@ -74,7 +87,7 @@ class MakeBundle {
                link_paths.Add (".");
 
                DetectOS ();
-               
+
                for (int i = 0; i < top; i++){
                        switch (args [i]){
                        case "--help": case "-h": case "-?":
@@ -121,6 +134,8 @@ class MakeBundle {
                                        Help (); 
                                        return 1;
                                }
+                               if (sdk_path != null || runtime != null)
+                                       Error ("You can only specify one of --runtime, --sdk or --cross");
                                custom_mode = false;
                                autodeps = true;
                                cross_target = args [++i];
@@ -146,10 +161,8 @@ class MakeBundle {
                                        alias = lspec.Substring (0, p);
                                        path = lspec.Substring (p+1);
                                }
-                               if (!File.Exists (path)){
-                                       Console.Error.WriteLine ($"The specified library file {path} does not exist");
-                                       return 1;
-                               }
+                               if (!File.Exists (path))
+                                       Error ($"The specified library file {path} does not exist");
                                libraries [alias] = path;
                                break;
 
@@ -162,10 +175,10 @@ class MakeBundle {
                                break;
 
                        case "--list-targets":
+                               CommandLocalTargets ();
                                var wc = new WebClient ();
-                               var s = wc.DownloadString (new Uri (target_server + "target-list.txt"));
-                               Console.WriteLine ("Cross-compilation targets available:\n" + s);
-                               
+                               var s = wc.DownloadString (new Uri (target_server + "target-sdks.txt"));
+                               Console.WriteLine ("Targets available for download with --fetch-target:\n" + s);
                                return 0;
                                
                        case "--target-server":
@@ -191,11 +204,24 @@ class MakeBundle {
                                }
                                embedded_options = args [++i];
                                break;
+                       case "--sdk":
+                               if (i + 1 == top) {
+                                       Help ();
+                                       return 1;
+                               }
+                               custom_mode = false;
+                               autodeps = true;
+                               sdk_path = args [++i];
+                               if (cross_target != null || runtime != null)
+                                       Error ("You can only specify one of --runtime, --sdk or --cross");
+                               break;
                        case "--runtime":
                                if (i+1 == top){
                                        Help (); 
                                        return 1;
                                }
+                               if (sdk_path != null || cross_target != null)
+                                       Error ("You can only specify one of --runtime, --sdk or --cross");
                                custom_mode = false;
                                autodeps = true;
                                runtime = args [++i];
@@ -283,7 +309,7 @@ class MakeBundle {
                                case "linux":
                                        break;
                                default:
-                                       Console.Error.WriteLine ("Invalid style '{0}' - only 'windows', 'mac' and 'linux' are supported for --style argument", style);
+                                       Error ("Invalid style '{0}' - only 'windows', 'mac' and 'linux' are supported for --style argument", style);
                                        return 1;
                                }
                                        
@@ -322,27 +348,48 @@ class MakeBundle {
                                else
                                        environment.Add (env.Substring (0, p), env.Substring (p+1));
                                break;
+                       case "--bundled-header":
+                               bundled_header = true;
+                               break;
                        default:
                                sources.Add (args [i]);
                                break;
                        }
 
                }
+               // Modern bundling starts here
+               if (!custom_mode){
+                       if (runtime != null){
+                               // Nothing to do here, the user has chosen to manually specify --runtime nad libraries
+                       } else if (sdk_path != null) {
+                               VerifySdk (sdk_path);
+                       } else if (cross_target == "default" || cross_target == null){
+                               sdk_path = Path.GetFullPath (Path.Combine (Process.GetCurrentProcess().MainModule.FileName, "..", ".."));
+                               VerifySdk (sdk_path);
+                       } else {
+                               sdk_path = Path.Combine (targets_dir, cross_target);
+                               Console.WriteLine ("From: " + sdk_path);
+                               VerifySdk (sdk_path);
+                       }
+               }
 
                if (fetch_target != null){
-                       var truntime = Path.Combine (targets_dir, fetch_target, "mono");
-                       Directory.CreateDirectory (Path.GetDirectoryName (truntime));
+                       var directory = Path.Combine (targets_dir, fetch_target);
+                       var zip_download = Path.Combine (directory, "sdk.zip");
+                       Directory.CreateDirectory (directory);
                        var wc = new WebClient ();
                        var uri = new Uri ($"{target_server}{fetch_target}");
                        try {
                                if (!quiet){
-                                       Console.WriteLine ($"Downloading runtime {uri} to {truntime}");
+                                       Console.WriteLine ($"Downloading runtime {uri} to {zip_download}");
                                }
                                
-                               wc.DownloadFile (uri, truntime);
+                               wc.DownloadFile (uri, zip_download);
+                               ZipFile.ExtractToDirectory(zip_download, directory);
+                               File.Delete (zip_download);
                        } catch {
                                Console.Error.WriteLine ($"Failure to download the specified runtime from {uri}");
-                               File.Delete (truntime);
+                               File.Delete (zip_download);
                                return 1;
                        }
                        return 0;
@@ -359,48 +406,41 @@ class MakeBundle {
                }
 
                List<string> assemblies = LoadAssemblies (sources);
+               LoadLocalizedAssemblies (assemblies);
                List<string> files = new List<string> ();
                foreach (string file in assemblies)
                        if (!QueueAssembly (files, file))
                                return 1;
                if (custom_mode)
                        GenerateBundles (files);
-               else {
-                       if (cross_target == "default")
-                               runtime = null;
-                       else {
-                               if (runtime == null){
-                                       if (cross_target == null){
-                                               Console.Error.WriteLine ("you should specify either a --runtime or a --cross compilation target");
-                                               Environment.Exit (1);
-                                       }
-                                       runtime = Path.Combine (targets_dir, cross_target, "mono");
-                                       if (!File.Exists (runtime)){
-                                               Console.Error.WriteLine ($"The runtime for the {cross_target} does not exist, use --fetch-target {cross_target} to download first");
-                                               return 1;
-                                       }
-                               } else {
-                                       if (!File.Exists (runtime)){
-                                               Console.Error.WriteLine ($"The Mono runtime specified with --runtime does not exist");
-                                               return 1;
-                                       }
-                               }
-                               
-                               Console.WriteLine ("Using runtime {0} for {1}", runtime, output);
-                       }
+               else 
                        GeneratePackage (files);
-               }
-               
+
+               Console.WriteLine ("Generated {0}", output);
+
                return 0;
        }
 
+       static void VerifySdk (string path)
+       {
+               if (!Directory.Exists (path))
+                       Error ($"The specified SDK path does not exist: {path}");
+               runtime = Path.Combine (sdk_path, "bin", "mono");
+               if (!File.Exists (runtime))
+                       Error ($"The SDK location does not contain a {path}/bin/mono runtime");
+               lib_path = Path.Combine (path, "lib", "mono", "4.5");
+               if (!Directory.Exists (lib_path))
+                       Error ($"The SDK location does not contain a {path}/lib/mono/4.5 directory");
+               link_paths.Add (lib_path);
+       }
+
        static string targets_dir = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".mono", "targets");
        
        static void CommandLocalTargets ()
        {
                string [] targets;
 
-               Console.WriteLine ("Available targets:");
+               Console.WriteLine ("Available targets locally:");
                Console.WriteLine ("\tdefault\t- Current System Mono");
                try {
                        targets = Directory.GetDirectories (targets_dir);
@@ -408,7 +448,7 @@ class MakeBundle {
                        return;
                }
                foreach (var target in targets){
-                       var p = Path.Combine (target, "mono");
+                       var p = Path.Combine (target, "bin", "mono");
                        if (File.Exists (p))
                                Console.WriteLine ("\t{0}", Path.GetFileName (target));
                }
@@ -437,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;
                }
        }
@@ -580,10 +626,12 @@ class MakeBundle {
                        return true;
                
                if (!File.Exists (file)){
-                       Console.Error.WriteLine ("The file {0} does not exist", file);
+                       Error ("The file {0} does not exist", file);
                        return false;
                }
                maker.Add (code, file);
+               // add a space after code (="systemconfig:" or "machineconfig:")
+               Console.WriteLine (code + " " + file);
                return true;
        }
        
@@ -593,21 +641,22 @@ class MakeBundle {
                        if (IsUnix)
                                runtime = Process.GetCurrentProcess().MainModule.FileName;
                        else {
-                               Console.Error.WriteLine ("You must specify at least one runtime with --runtime or --cross");
+                               Error ("You must specify at least one runtime with --runtime or --cross");
                                Environment.Exit (1);
                        }
                }
                if (!File.Exists (runtime)){
-                       Console.Error.WriteLine ($"The specified runtime at {runtime} does not exist");
+                       Error ($"The specified runtime at {runtime} does not exist");
                        Environment.Exit (1);
                }
                
                if (ctor_func != null){
-                       Console.Error.WriteLine ("--static-ctor not supported with package bundling, you must use native compilation for this");
+                       Error ("--static-ctor not supported with package bundling, you must use native compilation for this");
                        return false;
                }
                
                var maker = new PackageMaker (output);
+               Console.WriteLine ("Using runtime: " + runtime);
                maker.AddFile (runtime);
                
                foreach (var url in files){
@@ -615,14 +664,20 @@ class MakeBundle {
                        string aname = MakeBundle.GetAssemblyName (fname);
 
                        maker.Add ("assembly:" + aname, fname);
-                       if (File.Exists (fname + ".config"))
+                       Console.WriteLine ("     Assembly: " + fname);
+                       if (File.Exists (fname + ".config")){
                                maker.Add ("config:" + aname, fname + ".config");
+                               Console.WriteLine ("       Config: " + fname + ".config");
+                       }
                }
+               
                if (!MaybeAddFile (maker, "systemconfig:", config_file) || !MaybeAddFile (maker, "machineconfig:", machine_config_file))
                        return false;
 
-               if (config_dir != null)
+               if (config_dir != null){
                        maker.Add ("config_dir:", config_dir);
+                       Console.WriteLine ("   Config_dir: " + config_dir );
+               }
                if (embedded_options != null)
                        maker.AddString ("options:", embedded_options);
                if (environment.Count > 0){
@@ -631,6 +686,7 @@ class MakeBundle {
                }
                if (libraries.Count > 0){
                        foreach (var alias_and_path in libraries){
+                               Console.WriteLine ("     Library:  " + alias_and_path.Value);
                                maker.Add ("library:" + alias_and_path.Key, alias_and_path.Value);
                        }
                }
@@ -643,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;
@@ -658,10 +714,10 @@ class MakeBundle {
                        using (StreamWriter tc = new StreamWriter (File.Create (temp_c))) {
                        string prog = null;
 
-#if XAMARIN_ANDROID
-                       tc.WriteLine ("/* This source code was produced by mkbundle, do not edit */");
-                       tc.WriteLine ("\n#ifndef NULL\n#define NULL (void *)0\n#endif");
-                       tc.WriteLine (@"
+                       if (bundled_header) {
+                               tc.WriteLine ("/* This source code was produced by mkbundle, do not edit */");
+                               tc.WriteLine ("\n#ifndef NULL\n#define NULL (void *)0\n#endif");
+                               tc.WriteLine (@"
 typedef struct {
        const char *name;
        const unsigned char *data;
@@ -670,10 +726,10 @@ typedef struct {
 void          mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies);
 void          mono_register_config_for_assembly (const char* assembly_name, const char* config_xml);
 ");
-#else
-                       tc.WriteLine ("#include <mono/metadata/mono-config.h>");
-                       tc.WriteLine ("#include <mono/metadata/assembly.h>\n");
-#endif
+                       } else {
+                               tc.WriteLine ("#include <mono/metadata/mono-config.h>");
+                               tc.WriteLine ("#include <mono/metadata/assembly.h>\n");
+                       }
 
                        if (compress) {
                                tc.WriteLine ("typedef struct _compressed_data {");
@@ -780,7 +836,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                try {
                                        conf = File.OpenRead (config_file);
                                } catch {
-                                       Error (String.Format ("Failure to open {0}", config_file));
+                                       Error ("Failure to open {0}", config_file);
                                        return;
                                }
                                if (!quiet)
@@ -799,7 +855,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                try {
                                        conf = File.OpenRead (machine_config_file);
                                } catch {
-                                       Error (String.Format ("Failure to open {0}", machine_config_file));
+                                       Error ("Failure to open {0}", machine_config_file);
                                        return;
                                }
                                if (!quiet)
@@ -865,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)
@@ -875,90 +930,31 @@ 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
-                               }
-
-                               var compilerArgs = new List<string>();
-                               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<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
                        {
                                string zlib = (compress ? "-lz" : "");
+                               string objc = (style == "osx" ? "-framework CoreFoundation -lobjc" : "");
                                string debugging = "-g";
                                string cc = GetEnv("CC", "cc");
                                string cmd = null;
@@ -972,16 +968,16 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                                smonolib = "`pkg-config --variable=libdir mono-2`/libmono-2.0.a ";
                                        else
                                                smonolib = "-Wl,-Bstatic -lmono-2.0 -Wl,-Bdynamic ";
-                                       cmd = String.Format("{4} -o '{2}' -Wall `pkg-config --cflags mono-2` {0} {3} " +
+                                       cmd = String.Format("{4} -o '{2}' -Wall {5} `pkg-config --cflags mono-2` {0} {3} " +
                                                "`pkg-config --libs-only-L mono-2` " + smonolib +
                                                "`pkg-config --libs-only-l mono-2 | sed -e \"s/\\-lmono-2.0 //\"` {1}",
-                                               temp_c, temp_o, output, zlib, cc);
+                                               temp_c, temp_o, output, zlib, cc, objc);
                                }
                                else
                                {
 
-                                       cmd = String.Format("{4} " + debugging + " -o '{2}' -Wall {0} `pkg-config --cflags --libs mono-2` {3} {1}",
-                                               temp_c, temp_o, output, zlib, cc);
+                                       cmd = String.Format("{4} " + debugging + " -o '{2}' -Wall {5} {0} `pkg-config --cflags --libs mono-2` {3} {1}",
+                                               temp_c, temp_o, output, zlib, cc, objc);
                                }
                                Execute (cmd);
                        }
@@ -1008,11 +1004,9 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                List<string> assemblies = new List<string> ();
                bool error = false;
 
-               var other = i18n.Select (x=> "I18N." + x + (x.Length > 0 ? "." : "") + "dll");
-               
-               foreach (string name in sources.Concat (other)){
+               foreach (string name in sources){
                        try {
-                               Assembly a = LoadAssembly (name);
+                               Assembly a = LoadAssemblyFile (name);
 
                                if (a == null){
                                        error = true;
@@ -1031,17 +1025,61 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        }
                }
 
-               if (error)
+               if (error) {
+                       Error ("Couldn't load one or more of the assemblies.");
                        Environment.Exit (1);
+               }
 
                return assemblies;
        }
+
+       static void LoadLocalizedAssemblies (List<string> assemblies)
+       {
+               var other = i18n.Select (x => "I18N." + x + (x.Length > 0 ? "." : "") + "dll");
+               string error = null;
+
+               foreach (string name in other) {
+                       try {
+                               Assembly a = LoadAssembly (name);
+
+                               if (a == null) {
+                                       error = "Failed to load " + name;
+                                       continue;
+                               }
+
+                               assemblies.Add (a.CodeBase);
+                       } catch (Exception) {
+                               if (skip_scan) {
+                                       if (!quiet)
+                                               Console.WriteLine ("File will not be scanned: {0}", name);
+                                       assemblies.Add (new Uri (new FileInfo (name).FullName).ToString ());
+                               } else {
+                                       throw;
+                               }
+                       }
+               }
+
+               if (error != null) {
+                       Console.Error.WriteLine ("Failure to load i18n assemblies, the following directories were searched for the assemblies:");
+                       foreach (var path in link_paths){
+                               Console.Error.WriteLine ("   Path: " + path);
+                       }
+                       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);
+               }
+       }
+
        
        static readonly Universe universe = new Universe ();
        static readonly Dictionary<string, string> loaded_assemblies = new Dictionary<string, string> ();
 
        public static string GetAssemblyName (string path)
        {
+               string resourcePathSeparator = style == "windows" ? "\\\\" : "/";
                string name = Path.GetFileName (path);
 
                // A bit of a hack to support satellite assemblies. They all share the same name but
@@ -1051,7 +1089,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        string dir = Path.GetDirectoryName (path);
                        int idx = dir.LastIndexOf (Path.DirectorySeparatorChar);
                        if (idx >= 0) {
-                               name = dir.Substring (idx + 1) + Path.DirectorySeparatorChar + name;
+                               name = dir.Substring (idx + 1) + resourcePathSeparator + name;
                                Console.WriteLine ($"Storing satellite assembly '{path}' with name '{name}'");
                        } else if (!quiet)
                                Console.WriteLine ($"Warning: satellite assembly {path} doesn't have locale path prefix, name conflicts possible");
@@ -1070,7 +1108,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                var name = GetAssemblyName (path);
                string found;
                if (loaded_assemblies.TryGetValue (name, out found)) {
-                       Error (string.Format ("Duplicate assembly name `{0}'. Both `{1}' and `{2}' use same assembly name.", name, path, found));
+                       Error ("Duplicate assembly name `{0}'. Both `{1}' and `{2}' use same assembly name.", name, path, found);
                        return false;
                }
 
@@ -1081,9 +1119,18 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        return true;
                try {
                        Assembly a = universe.LoadFile (path);
+                       if (a == null) {
+                               Error ("Unable to to load assembly `{0}'", path);
+                               return false;
+                       }
 
                        foreach (AssemblyName an in a.GetReferencedAssemblies ()) {
-                               a = universe.Load (an.FullName);
+                               a = LoadAssembly (an.Name);
+                               if (a == null) {
+                                       Error ("Unable to load assembly `{0}' referenced by `{1}'", an.Name, path);
+                                       return false;
+                               }
+
                                if (!QueueAssembly (files, a.CodeBase))
                                        return false;
                        }
@@ -1095,56 +1142,63 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                return true;
        }
 
-       static Assembly LoadAssembly (string assembly)
+       //
+       // Loads an assembly from a specific path
+       //
+       static Assembly LoadAssemblyFile (string assembly)
        {
-               Assembly a;
+               Assembly a = null;
                
                try {
-                       char[] path_chars = { '/', '\\' };
-                       
-                       if (assembly.IndexOfAny (path_chars) != -1) {
-                               a = universe.LoadFile (assembly);
-                       } else {
-                               string ass = assembly;
-                               if (ass.EndsWith (".dll"))
-                                       ass = assembly.Substring (0, assembly.Length - 4);
-                               a = universe.Load (ass);
-                       }
-                       return a;
-               } catch (FileNotFoundException){
-                       string total_log = "";
-                       
-                       foreach (string dir in link_paths){
-                               string full_path = Path.Combine (dir, assembly);
-                               if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
-                                       full_path += ".dll";
-                               
-                               try {
-                                       a = universe.LoadFile (full_path);
-                                       return a;
-                               } catch (FileNotFoundException ff) {
-                                       total_log += ff.FusionLog;
-                                       continue;
-                               }
-                       }
-                       Error ("Cannot find assembly `" + assembly + "'" );
                        if (!quiet)
-                               Console.WriteLine ("Log: \n" + total_log);
+                               Console.WriteLine ("Attempting to load assembly: {0}", assembly);
+                       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) {
                        if (skip_scan)
                                throw;
-                       Error ("Cannot load assembly (bad file format) " + f.Message);
+                       Error ($"Cannot load assembly (bad file format) " + f.Message);
                } catch (FileLoadException f){
-                       Error ("Cannot load assembly " + f.Message);
+                       Error ($"Cannot load assembly " + f.Message);
                } catch (ArgumentNullException){
-                       Error("Cannot load assembly (null argument)");
+                       Error( $"Cannot load assembly (null argument)");
                }
-               return null;
+               return a;
        }
 
-       static void Error (string msg)
+       //
+       // Loads an assembly from any of the link directories provided
+       //
+       static Assembly LoadAssembly (string assembly)
        {
-               Console.Error.WriteLine ("ERROR: " + msg);
+               string total_log = "";
+               foreach (string dir in link_paths){
+                       string full_path = Path.Combine (dir, assembly);
+                       if (!quiet)
+                               Console.WriteLine ("Attempting to load assembly from: " + full_path);
+                       if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
+                               full_path += ".dll";
+                       
+                       try {
+                               var a = universe.LoadFile (full_path);
+                               return a;
+                       } catch (FileNotFoundException ff) {
+                               total_log += ff.FusionLog;
+                               continue;
+                       }
+               }
+               if (!quiet)
+                       Console.WriteLine ("Log: \n" + total_log);
+               return null;
+       }
+       
+       static void Error (string msg, params object [] args)
+       {
+               Console.Error.WriteLine ("ERROR: {0}", string.Format (msg, args));
                Environment.Exit (1);
        }
 
@@ -1162,16 +1216,19 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                   "    --skip-scan          Skip scanning assemblies that could not be loaded (but still embed them).\n" +
                                   "    --i18n ENCODING      none, all or comma separated list of CJK, MidWest, Other, Rare, West.\n" +
                                   "    -v                   Verbose output\n" + 
+                                  "    --bundled-header     Do not attempt to include 'mono-config.h'. Define the entry points directly in the generated code\n" +
                                   "\n" + 
                                   "--simple   Simple mode does not require a C toolchain and can cross compile\n" + 
                                   "    --cross TARGET       Generates a binary for the given TARGET\n"+
                                   "    --env KEY=VALUE      Hardcodes an environment variable for the target\n" +
+                                  "    --fetch-target NAME  Downloads the target SDK from the remote server\n" + 
                                   "    --library [LIB,]PATH Bundles the specified dynamic library to be used at runtime\n" +
                                   "                         LIB is optional shortname for file located at PATH\n" + 
                                   "    --list-targets       Lists available targets on the remote server\n" +
                                   "    --local-targets      Lists locally available targets\n" +
                                   "    --options OPTIONS    Embed the specified Mono command line options on target\n" +
                                   "    --runtime RUNTIME    Manually specifies the Mono runtime to use\n" +
+                                  "    --sdk PATH           Use a Mono SDK root location instead of a target\n" + 
                                   "    --target-server URL  Specified a server to download targets from, default is " + target_server + "\n" +
                                   "\n" +
                                   "--custom   Builds a custom launcher, options for --custom\n" +
@@ -1302,7 +1359,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        p.WaitForExit ();
                        int ret = p.ExitCode;
                        if (ret != 0){
-                               Error (String.Format("[Fail] {0}", ret));
+                               Error ("[Fail] {0}", ret);
                        }
                }
        }
@@ -1334,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<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.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 {
+               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<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 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<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 (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<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 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 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<VCToolchainProgram> vcCompilers = new List<VCToolchainProgram> ();
+               List<VCToolchainProgram> vcLibrarians = new List<VCToolchainProgram> ();
+               List<VCToolchainProgram> vcClangCompilers = new List<VCToolchainProgram> ();
+
+               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<VCToolchainProgram> 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<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 (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.
+                       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<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));
+       }
+
+       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));
+       }
+
+       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));
+       }
+#endregion
 }