X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Ftools%2Fmkbundle%2Fmkbundle.cs;h=3351fd24d0b8933a92c8c5c77e6c620158ed7512;hb=5d2f0cfa018a77d32a2fb569ec8103a743c6f5fe;hp=9f75c85749a37752bcad3cd58875435b4db876a1;hpb=883a0ae745bf33b35d44bb730d5714936a2141f7;p=mono.git diff --git a/mcs/tools/mkbundle/mkbundle.cs b/mcs/tools/mkbundle/mkbundle.cs index 9f75c85749a..3351fd24d0b 100755 --- a/mcs/tools/mkbundle/mkbundle.cs +++ b/mcs/tools/mkbundle/mkbundle.cs @@ -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 // @@ -23,7 +33,6 @@ using System.Runtime.InteropServices; using System.Text; using IKVM.Reflection; using System.Linq; -using System.Diagnostics; using System.Net; using System.Threading.Tasks; @@ -31,6 +40,7 @@ class MakeBundle { static string output = "a.out"; static string object_out = null; static List link_paths = new List (); + static Dictionary libraries = new Dictionary (); static bool autodeps = false; static bool keeptemp = false; static bool compile_only = false; @@ -46,12 +56,27 @@ class MakeBundle { static bool? use_dos2unix = null; static bool skip_scan; static string ctor_func; - static bool quiet; + static bool quiet = true; static string cross_target = null; static string fetch_target = null; 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 environment = new Dictionary(); + static string [] i18n = new string [] { + "West", + "" + }; + static string [] i18n_all = new string [] { + "CJK", + "MidEast", + "Other", + "Rare", + "West", + "" + }; static string target_server = "https://download.mono-project.com/runtimes/raw/"; static int Main (string [] args) @@ -61,7 +86,7 @@ class MakeBundle { link_paths.Add ("."); DetectOS (); - + for (int i = 0; i < top; i++){ switch (args [i]){ case "--help": case "-h": case "-?": @@ -72,6 +97,24 @@ class MakeBundle { custom_mode = false; autodeps = true; break; + + case "-v": + quiet = false; + break; + + case "--i18n": + if (i+1 == top){ + Help (); + return 1; + } + var iarg = args [++i]; + if (iarg == "all") + i18n = i18n_all; + else if (iarg == "none") + i18n = new string [0]; + else + i18n = iarg.Split (','); + break; case "--custom": custom_mode = true; @@ -90,11 +133,38 @@ class MakeBundle { Help (); return 1; } + if (sdk_path != null || runtime != null) + Error ("You can not specify one of --runtime, --sdk or --cross"); custom_mode = false; autodeps = true; cross_target = args [++i]; break; + case "--library": + if (i+1 == top){ + Help (); + return 1; + } + if (custom_mode){ + Console.Error.WriteLine ("--library can only be used with --simple/--runtime/--cross mode"); + Help (); + return 1; + } + var lspec = args [++i]; + var p = lspec.IndexOf (","); + string alias, path; + if (p == -1){ + alias = Path.GetFileName (lspec); + path = lspec; + } else { + alias = lspec.Substring (0, p); + path = lspec.Substring (p+1); + } + if (!File.Exists (path)) + Error ($"The specified library file {path} does not exist"); + libraries [alias] = path; + break; + case "--fetch-target": if (i+1 == top){ Help (); @@ -104,10 +174,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": @@ -133,11 +203,26 @@ 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 not 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]; break; case "-oo": @@ -223,7 +308,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; } @@ -249,68 +334,109 @@ class MakeBundle { case "--quiet": quiet = true; break; + case "-e": + case "--env": + if (i+1 == top) { + Help (); + return 1; + } + var env = args [++i]; + p = env.IndexOf ('='); + if (p == -1) + environment.Add (env, ""); + else + environment.Add (env.Substring (0, p), env.Substring (p+1)); + 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 directory = Path.Combine (targets_dir, fetch_target); + var zip_download = Path.Combine (directory, "sdk.zip"); + Directory.CreateDirectory (Path.GetDirectoryName (directory)); + var wc = new WebClient (); + var uri = new Uri ($"{target_server}{fetch_target}"); + try { + if (!quiet){ + Console.WriteLine ($"Downloading runtime {uri} to {zip_download}"); + } + + 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 (zip_download); + return 1; + } + return 0; + } + if (!quiet) { Console.WriteLine (os_message); Console.WriteLine ("Sources: {0} Auto-dependencies: {1}", sources.Count, autodeps); } + if (sources.Count == 0 || output == null) { Help (); Environment.Exit (1); } List assemblies = LoadAssemblies (sources); + LoadLocalizedAssemblies (assemblies); List files = new List (); foreach (string file in assemblies) if (!QueueAssembly (files, file)) return 1; - - if (fetch_target != null){ - var truntime = Path.Combine (targets_dir, fetch_target, "mono"); - Directory.CreateDirectory (Path.GetDirectoryName (truntime)); - var wc = new WebClient (); - var uri = new Uri ($"{target_server}{fetch_target}"); - try { - wc.DownloadFile (uri, truntime); - } catch { - Console.Error.WriteLine ($"Failure to download the specified runtime from {uri}"); - File.Delete (truntime); - return 1; - } - return 0; - } - if (custom_mode) GenerateBundles (files); - else { - if (cross_target == "default") - runtime = null; - else { - var truntime = Path.Combine (targets_dir, cross_target, "mono"); - if (!File.Exists (truntime)){ - Console.Error.WriteLine ($"The runtime for the {cross_target} does not exist, use --fetch-target {cross_target} to download first"); - return 1; - } - } + 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); @@ -318,7 +444,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)); } @@ -402,8 +528,9 @@ class MakeBundle { { using (Stream fileStream = File.OpenRead (fname)){ var ret = fileStream.Length; - - Console.WriteLine ("At {0:x} with input {1}", package.Position, fileStream.Length); + + if (!quiet) + Console.WriteLine ("At {0:x} with input {1}", package.Position, fileStream.Length); fileStream.CopyTo (package); package.Position = package.Position + (align - (package.Position % align)); @@ -427,8 +554,30 @@ class MakeBundle { package.Position = package.Position + (align - (package.Position % align)); } + public void AddStringPair (string entry, string key, string value) + { + var kbytes = Encoding.UTF8.GetBytes (key); + var vbytes = Encoding.UTF8.GetBytes (value); + + Console.WriteLine ("ADDING {0} to {1}", key, value); + if (kbytes.Length > 255){ + Console.WriteLine ("The key value can not exceed 255 characters: " + key); + Environment.Exit (1); + } + + locations [entry] = Tuple.Create (package.Position, kbytes.Length+vbytes.Length+3); + package.WriteByte ((byte)kbytes.Length); + package.Write (kbytes, 0, kbytes.Length); + package.WriteByte (0); + package.Write (vbytes, 0, vbytes.Length); + package.WriteByte (0); + package.Position = package.Position + (align - (package.Position % align)); + } + public void Dump () { + if (quiet) + return; foreach (var floc in locations.Keys){ Console.WriteLine ($"{floc} at {locations[floc]:x}"); } @@ -467,7 +616,7 @@ 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); @@ -480,31 +629,36 @@ 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){ string fname = LocateFile (new Uri (url).LocalPath); - string aname = Path.GetFileName (fname); + 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: " + runtime); + } } + if (!MaybeAddFile (maker, "systemconfig:", config_file) || !MaybeAddFile (maker, "machineconfig:", machine_config_file)) return false; @@ -512,6 +666,16 @@ class MakeBundle { maker.Add ("config_dir:", config_dir); if (embedded_options != null) maker.AddString ("options:", embedded_options); + if (environment.Count > 0){ + foreach (var key in environment.Keys) + maker.AddStringPair ("env:" + key, key, environment [key]); + } + 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); + } + } maker.Dump (); maker.Close (); return true; @@ -605,7 +769,7 @@ void mono_register_config_for_assembly (const char* assembly_name, cons var symbolEscapeRE = new System.Text.RegularExpressions.Regex ("[^\\w_]"); foreach (var url in files) { string fname = LocateFile (new Uri (url).LocalPath); - string aname = Path.GetFileName (fname); + string aname = MakeBundle.GetAssemblyName (fname); string encoded = symbolEscapeRE.Replace (aname, "_"); if (prog == null) @@ -658,7 +822,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) @@ -677,7 +841,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) @@ -764,7 +928,7 @@ void mono_register_config_for_assembly (const char* assembly_name, cons 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" }; + // string[] libs = new string[] { winsdkPath + @"\Lib\winv6.3\um\x86" , vsPath + @"\lib" }; var linkLibraries = new string[] { "kernel32.lib", "version.lib", "Ws2_32.lib", @@ -885,10 +1049,10 @@ void mono_register_config_for_assembly (const char* assembly_name, cons { List assemblies = new List (); bool error = false; - + foreach (string name in sources){ try { - Assembly a = LoadAssembly (name); + Assembly a = LoadAssemblyFile (name); if (a == null){ error = true; @@ -907,26 +1071,81 @@ 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 assemblies) + { + var other = i18n.Select (x => "I18N." + x + (x.Length > 0 ? "." : "") + "dll"); + bool error = false; + + foreach (string name in other) { + try { + Assembly a = LoadAssembly (name); + + if (a == null) { + error = true; + 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) { + Error ("Couldn't load one or more of the i18n assemblies."); + Environment.Exit (1); + } + } + static readonly Universe universe = new Universe (); static readonly Dictionary loaded_assemblies = new Dictionary (); - + + public static string GetAssemblyName (string path) + { + string name = Path.GetFileName (path); + + // A bit of a hack to support satellite assemblies. They all share the same name but + // are placed in subdirectories named after the locale they implement. Also, all of + // them end in .resources.dll, therefore we can use that to detect the circumstances. + if (name.EndsWith (".resources.dll", StringComparison.OrdinalIgnoreCase)) { + string dir = Path.GetDirectoryName (path); + int idx = dir.LastIndexOf (Path.DirectorySeparatorChar); + if (idx >= 0) { + name = dir.Substring (idx + 1) + Path.DirectorySeparatorChar + 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"); + } + + return name; + } + static bool QueueAssembly (List files, string codebase) { - // Console.WriteLine ("CODE BASE IS {0}", codebase); + //Console.WriteLine ("CODE BASE IS {0}", codebase); if (files.Contains (codebase)) return true; var path = new Uri(codebase).LocalPath; - var name = Path.GetFileName (path); + 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; } @@ -939,7 +1158,7 @@ void mono_register_config_for_assembly (const char* assembly_name, cons Assembly a = universe.LoadFile (path); foreach (AssemblyName an in a.GetReferencedAssemblies ()) { - a = universe.Load (an.FullName); + LoadAssembly (an.FullName); if (!QueueAssembly (files, a.CodeBase)) return false; } @@ -951,56 +1170,57 @@ 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; + a = universe.LoadFile (assembly); } 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); + 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) + { + 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 { + 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: " + msg); + Console.Error.WriteLine ("ERROR: {0}", string.Format (msg, args)); + throw new Exception (); Environment.Exit (1); } @@ -1008,37 +1228,44 @@ void mono_register_config_for_assembly (const char* assembly_name, cons { Console.WriteLine ("Usage is: mkbundle [options] assembly1 [assembly2...]\n\n" + "Options:\n" + - " --config F Bundle system config file `F'\n" + - " --config-dir D Set MONO_CFG_DIR to `D'\n" + - " --deps Turns on automatic dependency embedding (default on simple)\n" + - " -L path Adds `path' to the search path for assemblies\n" + - " --machine-config F Use the given file as the machine.config for the application.\n" + - " -o out Specifies output filename\n" + - " --nodeps Turns off automatic dependency embedding (default on custom)\n" + - " --skip-scan Skip scanning assemblies that could not be loaded (but still embed them).\n" + + " --config F Bundle system config file `F'\n" + + " --config-dir D Set MONO_CFG_DIR to `D'\n" + + " --deps Turns on automatic dependency embedding (default on simple)\n" + + " -L path Adds `path' to the search path for assemblies\n" + + " --machine-config F Use the given file as the machine.config for the application.\n" + + " -o out Specifies output filename\n" + + " --nodeps Turns off automatic dependency embedding (default on custom)\n" + + " --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" + "\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"+ - " --local-targets Lists locally available targets\n" + - " --list-targets Lists available targets on the remote server\n" + - " --options OPTIONS Embed the specified Mono command line options on target\n" + - " --runtime RUNTIME Manually specifies the Mono runtime to use\n" + - " --target-server URL Specified a server to download targets from, default is " + target_server + "\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" + - " -c Produce stub only, do not compile\n" + - " -oo obj Specifies output filename for helper object file\n" + + " -c Produce stub only, do not compile\n" + + " -oo obj Specifies output filename for helper object file\n" + " --dos2unix[=true|false]\n" + - " When no value provided, or when `true` specified\n" + - " `dos2unix` will be invoked to convert paths on Windows.\n" + - " When `--dos2unix=false` used, dos2unix is NEVER used.\n" + - " --keeptemp Keeps the temporary files\n" + - " --static Statically link to mono libs\n" + - " --nomain Don't include a main() function, for libraries\n" + - " --custom-main C Link the specified compilation unit (.c or .obj) with entry point/init code\n" + - " -z Compress the assemblies before embedding.\n" + - " --static-ctor ctor Add a constructor call to the supplied function.\n" + - " You need zlib development headers and libraries.\n"); + " When no value provided, or when `true` specified\n" + + " `dos2unix` will be invoked to convert paths on Windows.\n" + + " When `--dos2unix=false` used, dos2unix is NEVER used.\n" + + " --keeptemp Keeps the temporary files\n" + + " --static Statically link to mono libs\n" + + " --nomain Don't include a main() function, for libraries\n" + + " --custom-main C Link the specified compilation unit (.c or .obj) with entry point/init code\n" + + " -z Compress the assemblies before embedding.\n" + + " --static-ctor ctor Add a constructor call to the supplied function.\n" + + " You need zlib development headers and libraries.\n"); } [DllImport ("libc")] @@ -1153,7 +1380,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); } } }