[runtime] Fix mkbundle compilation on OSX
[mono.git] / mcs / tools / mkbundle / mkbundle.cs
index 1ea1d7402455704a22e4b237c25c8fe15f3d3f9b..6e3a3e0de4bdda47067e661ff5053594aa27e4fb 100755 (executable)
@@ -40,6 +40,8 @@ class MakeBundle {
        static string output = "a.out";
        static string object_out = null;
        static List<string> link_paths = new List<string> ();
+       static List<string> aot_paths = new List<string> ();
+       static List<string> aot_names = new List<string> ();
        static Dictionary<string,string> libraries = new Dictionary<string,string> ();
        static bool autodeps = false;
        static bool keeptemp = false;
@@ -49,6 +51,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;
@@ -62,6 +65,10 @@ class MakeBundle {
        static bool custom_mode = true;
        static string embedded_options = null;
        static string runtime = null;
+       static bool aot_compile = false;
+       static string aot_args = "static";
+       static string aot_mode = "";
+       static string aot_runtime = null;
        static string sdk_path = null;
        static string lib_path = null;
        static Dictionary<string,string> environment = new Dictionary<string,string>();
@@ -134,7 +141,7 @@ class MakeBundle {
                                        return 1;
                                }
                                if (sdk_path != null || runtime != null)
-                                       Error ("You can not specify one of --runtime, --sdk or --cross");
+                                       Error ("You can only specify one of --runtime, --sdk or --cross");
                                custom_mode = false;
                                autodeps = true;
                                cross_target = args [++i];
@@ -212,7 +219,7 @@ class MakeBundle {
                                autodeps = true;
                                sdk_path = args [++i];
                                if (cross_target != null || runtime != null)
-                                       Error ("You can not specify one of --runtime, --sdk or --cross");
+                                       Error ("You can only specify one of --runtime, --sdk or --cross");
                                break;
                        case "--runtime":
                                if (i+1 == top){
@@ -347,11 +354,36 @@ class MakeBundle {
                                else
                                        environment.Add (env.Substring (0, p), env.Substring (p+1));
                                break;
+                       case "--bundled-header":
+                               bundled_header = true;
+                               break;
+                       case "--aot-runtime":
+                               aot_runtime = args [++i];
+                               break;
+                       case "--aot-mode":
+                               if (i+1 == top) {
+                                       Console.WriteLine ("Need string of aot mode");
+                                       return 1;
+                               }
+                               aot_mode = args [++i];
+                               aot_compile = true;
+                               break;
+                       case "--aot-args":
+                               if (i+1 == top) {
+                                       Console.WriteLine ("AOT arguments are passed as a comma-delimited list");
+                                       return 1;
+                               }
+                               if (args [i + 1].Contains ("outfile")) {
+                                       Console.WriteLine ("Per-aot-output arguments (ex: outfile, llvm-outfile) cannot be given");
+                                       return 1;
+                               }
+                               aot_args = String.Format("static,{0}", args [++i]);
+                               aot_compile = true;
+                               break;
                        default:
                                sources.Add (args [i]);
                                break;
                        }
-
                }
                // Modern bundling starts here
                if (!custom_mode){
@@ -372,7 +404,7 @@ class MakeBundle {
                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));
+                       Directory.CreateDirectory (directory);
                        var wc = new WebClient ();
                        var uri = new Uri ($"{target_server}{fetch_target}");
                        try {
@@ -407,6 +439,10 @@ class MakeBundle {
                foreach (string file in assemblies)
                        if (!QueueAssembly (files, file))
                                return 1;
+
+               if (aot_compile)
+                       AotCompile (files);
+
                if (custom_mode)
                        GenerateBundles (files);
                else 
@@ -533,7 +569,6 @@ class MakeBundle {
                                        Console.WriteLine ("At {0:x} with input {1}", package.Position, fileStream.Length);
                                fileStream.CopyTo (package);
                                package.Position = package.Position + (align - (package.Position % align));
-
                                return (int) ret;
                        }
                }
@@ -542,7 +577,6 @@ class MakeBundle {
                {
                        var p = package.Position;
                        var size = AddFile (fname);
-                       
                        locations [entry] = Tuple.Create(p, size);
                }
 
@@ -700,10 +734,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;
@@ -712,10 +746,11 @@ 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");
+                               tc.WriteLine ("#include <mono/jit/jit.h>\n");
+                       }
 
                        if (compress) {
                                tc.WriteLine ("typedef struct _compressed_data {");
@@ -855,6 +890,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        }
                        ts.Close ();
 
+                       // Managed assemblies baked in
                        if (compress)
                                tc.WriteLine ("\nstatic const CompressedAssembly *compressed [] = {");
                        else
@@ -864,6 +900,37 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                tc.WriteLine ("\t&{0},", c);
                        }
                        tc.WriteLine ("\tNULL\n};\n");
+
+
+                       // AOT baked in plus loader
+                       foreach (string asm in aot_names){
+                               tc.WriteLine ("\textern const void *mono_aot_module_{0}_info;", asm);
+                       }
+
+                       tc.WriteLine ("\nstatic void install_aot_modules (void) {\n");
+                       foreach (string asm in aot_names){
+                               tc.WriteLine ("\tmono_aot_register_module (mono_aot_module_{0}_info);\n", asm);
+                       }
+
+                       string enum_aot_mode;
+                       switch (aot_mode) {
+                       case "full": 
+                               enum_aot_mode = "MONO_AOT_MODE_FULL";
+                               break;
+                       case "llvmonly": 
+                               enum_aot_mode = "MONO_AOT_MODE_LLVMONLY";
+                               break;
+                       case "": 
+                               enum_aot_mode = "MONO_AOT_MODE_NORMAL";
+                               break;
+                       default:
+                               throw new Exception ("Unsupported AOT mode");
+                       }
+                       tc.WriteLine ("\tmono_jit_set_aot_mode ({0});", enum_aot_mode);
+
+                       tc.WriteLine ("\n}\n");
+
+
                        tc.WriteLine ("static char *image_name = \"{0}\";", prog);
 
                        if (ctor_func != null) {
@@ -1009,15 +1076,20 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                                        debugging = "-ggdb";
                                if (static_link)
                                {
+                                       string platform_libs;
                                        string smonolib;
-                                       if (style == "osx")
+                                       if (style == "osx") {
                                                smonolib = "`pkg-config --variable=libdir mono-2`/libmono-2.0.a ";
-                                       else
+                                               platform_libs = "-liconv -framework Foundation ";
+                                       } else {
                                                smonolib = "-Wl,-Bstatic -lmono-2.0 -Wl,-Bdynamic ";
+                                               platform_libs = "";
+                                       }
+
                                        cmd = String.Format("{4} -o '{2}' -Wall `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);
+                                               "`pkg-config --libs-only-L mono-2` {5} {6} " + platform_libs +
+                                               "`pkg-config --libs-only-l mono-2 | sed -e \"s/\\-lmono-2.0 //\"` {1} -g ",
+                                               temp_c, temp_o, output, zlib, cc, smonolib, String.Join (" ", aot_paths));
                                }
                                else
                                {
@@ -1071,23 +1143,25 @@ 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");
-               bool error = false;
+               string error = null;
 
                foreach (string name in other) {
                        try {
                                Assembly a = LoadAssembly (name);
 
                                if (a == null) {
-                                       error = true;
+                                       error = "Failed to load " + name;
                                        continue;
                                }
 
@@ -1103,8 +1177,18 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                        }
                }
 
-               if (error)
+               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);
+               }
        }
 
        
@@ -1113,6 +1197,7 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
 
        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
@@ -1122,7 +1207,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");
@@ -1152,9 +1237,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 ()) {
-                               LoadAssembly (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;
                        }
@@ -1174,7 +1268,12 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                Assembly a = null;
                
                try {
+                       if (!quiet)
+                               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) {
@@ -1197,6 +1296,8 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                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";
                        
@@ -1216,7 +1317,6 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
        static void Error (string msg, params object [] args)
        {
                Console.Error.WriteLine ("ERROR: {0}", string.Format (msg, args));
-               throw new Exception ();
                Environment.Exit (1);
        }
 
@@ -1234,6 +1334,7 @@ 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"+
@@ -1298,6 +1399,42 @@ void          mono_register_config_for_assembly (const char* assembly_name, cons
                }
        }
 
+
+       static string EncodeAotSymbol (string symbol)
+       {
+               var sb = new StringBuilder ();
+               /* This mimics what the aot-compiler does */
+               foreach (var b in System.Text.Encoding.UTF8.GetBytes (symbol)) {
+                       char c = (char) b;
+                       if ((c >= '0' && c <= '9') ||
+                               (c >= 'a' && c <= 'z') ||
+                               (c >= 'A' && c <= 'Z')) {
+                               sb.Append (c);
+                               continue;
+                       }
+                       sb.Append ('_');
+               }
+               return sb.ToString ();
+       }
+
+       static void AotCompile (List<string> files)
+       {
+               if (aot_runtime == null)
+                       aot_runtime = runtime;
+
+               foreach (var fileName in files) {
+                       string path = LocateFile (new Uri (fileName).LocalPath);
+                       string outPath = String.Format ("{0}.aot_out", path);
+                       aot_paths.Add (outPath);
+                       var name = System.Reflection.Assembly.LoadFrom(path).GetName().Name;
+                       aot_names.Add (EncodeAotSymbol (name));
+                       var aot_mode_string = "";
+                       if (aot_mode != null)
+                               aot_mode_string = "," + aot_mode;
+                       Execute (String.Format ("{0} --aot={1},outfile={2}{3} {4}", aot_runtime, aot_args, outPath, aot_mode_string, path));
+               }
+       }
+
        static void Execute (string cmdLine)
        {
                if (IsUnix) {