Bump emscripten to 1.39.20. (#20143)
[mono-project.git] / sdks / wasm / packager.cs
blobede46f44f6a87ff0c172abf708e0bcf11b8265d2
1 using System;
2 using System.Linq;
3 using System.IO;
4 using System.Collections.Generic;
5 using Mono.Cecil;
6 using Mono.Options;
7 using Mono.Cecil.Cil;
9 //
10 // Google V8 style options:
11 // - bool: --foo/--no-foo
14 enum FlagType {
15 BoolFlag,
18 // 'Option' is already used by Mono.Options
19 class Flag {
20 public Flag (string name, string desc, FlagType type) {
21 Name = name;
22 FlagType = type;
23 Description = desc;
26 public string Name {
27 get; set;
30 public FlagType FlagType {
31 get; set;
34 public string Description {
35 get; set;
39 class BoolFlag : Flag {
40 public BoolFlag (string name, string description, bool def_value, Action<bool> action) : base (name, description, FlagType.BoolFlag) {
41 Setter = action;
42 DefaultValue = def_value;
45 public Action<bool> Setter {
46 get; set;
49 public bool DefaultValue {
50 get; set;
54 class Driver {
55 static bool enable_debug, enable_linker;
56 static string app_prefix, framework_prefix, bcl_tools_prefix, bcl_facades_prefix, out_prefix;
57 static List<string> bcl_prefixes;
58 static HashSet<string> asm_map = new HashSet<string> ();
59 static List<string> file_list = new List<string> ();
60 static HashSet<string> assemblies_with_dbg_info = new HashSet<string> ();
61 static List<string> root_search_paths = new List<string>();
63 const string BINDINGS_ASM_NAME = "WebAssembly.Bindings";
64 const string BINDINGS_RUNTIME_CLASS_NAME = "WebAssembly.Runtime";
65 const string HTTP_ASM_NAME = "System.Net.Http.WebAssemblyHttpHandler";
66 const string WEBSOCKETS_ASM_NAME = "WebAssembly.Net.WebSockets";
67 const string BINDINGS_MODULE = "corebindings.o";
68 const string BINDINGS_MODULE_SUPPORT = "$tool_prefix/src/binding_support.js";
70 class AssemblyData {
71 // Assembly name
72 public string name;
73 // Base filename
74 public string filename;
75 // Path outside build tree
76 public string src_path;
77 // Path of .bc file
78 public string bc_path;
79 // Path of the wasm object file
80 public string o_path;
81 // Path in appdir
82 public string app_path;
83 // Path of the AOT depfile
84 public string aot_depfile_path;
85 // Linker input path
86 public string linkin_path;
87 // Linker output path
88 public string linkout_path;
89 // Linker pdb input path
90 public string linkin_pdb_path;
91 // Linker pdb output path
92 public string linkout_pdb_path;
93 // AOT input path
94 public string aotin_path;
95 // Final output path after IL strip
96 public string final_path;
97 // Whenever to AOT this assembly
98 public bool aot;
101 static List<AssemblyData> assemblies = new List<AssemblyData> ();
103 enum AssemblyKind {
104 User,
105 Framework,
106 Bcl,
107 None,
110 void AddFlag (OptionSet options, Flag flag) {
111 if (flag is BoolFlag) {
112 options.Add (flag.Name, s => (flag as BoolFlag).Setter (true));
113 options.Add ("no-" + flag.Name, s => (flag as BoolFlag).Setter (false));
115 option_list.Add (flag);
118 static List<Flag> option_list = new List<Flag> ();
120 static void Usage () {
121 Console.WriteLine ("Usage: packager.exe <options> <assemblies>");
122 Console.WriteLine ("Valid options:");
123 Console.WriteLine ("\t--help Show this help message");
124 Console.WriteLine ("\t--debugrt Use the debug runtime (default release) - this has nothing to do with C# debugging");
125 Console.WriteLine ("\t--aot Enable AOT mode");
126 Console.WriteLine ("\t--aot-interp Enable AOT+INTERP mode");
127 Console.WriteLine ("\t--prefix=x Set the input assembly prefix to 'x' (default to the current directory)");
128 Console.WriteLine ("\t--out=x Set the output directory to 'x' (default to the current directory)");
129 Console.WriteLine ("\t--mono-sdkdir=x Set the mono sdk directory to 'x'");
130 Console.WriteLine ("\t--deploy=x Set the deploy prefix to 'x' (default to 'managed')");
131 Console.WriteLine ("\t--vfs=x Set the VFS prefix to 'x' (default to 'managed')");
132 Console.WriteLine ("\t--template=x Set the template name to 'x' (default to 'runtime.js')");
133 Console.WriteLine ("\t--asset=x Add specified asset 'x' to list of assets to be copied");
134 Console.WriteLine ("\t--search-path=x Add specified path 'x' to list of paths used to resolve assemblies");
135 Console.WriteLine ("\t--copy=always|ifnewer Set the type of copy to perform.");
136 Console.WriteLine ("\t\t 'always' overwrites the file if it exists.");
137 Console.WriteLine ("\t\t 'ifnewer' copies or overwrites the file if modified or size is different.");
138 Console.WriteLine ("\t--profile=x Enable the 'x' mono profiler.");
139 Console.WriteLine ("\t--aot-assemblies=x List of assemblies to AOT in AOT+INTERP mode.");
140 Console.WriteLine ("\t--aot-profile=x Use 'x' as the AOT profile.");
141 Console.WriteLine ("\t--link-mode=sdkonly|all Set the link type used for AOT. (EXPERIMENTAL)");
142 Console.WriteLine ("\t\t 'sdkonly' only link the Core libraries.");
143 Console.WriteLine ("\t\t 'all' link Core and User assemblies. (default)");
144 Console.WriteLine ("\t--pinvoke-libs=x DllImport libraries used.");
145 Console.WriteLine ("\t--native-lib=x Link the native library 'x' into the final executable.");
146 Console.WriteLine ("\t--preload-file=x Preloads the file or directory 'x' into the virtual filesystem.");
147 Console.WriteLine ("\t--embed-file=x Embeds the file or directory 'x' into the virtual filesystem.");
149 Console.WriteLine ("foo.dll Include foo.dll as one of the root assemblies");
150 Console.WriteLine ();
152 Console.WriteLine ("Additional options (--option/--no-option):");
153 foreach (var flag in option_list) {
154 if (flag is BoolFlag) {
155 Console.WriteLine (" --" + flag.Name + " (" + flag.Description + ")");
156 Console.WriteLine (" type: bool default: " + ((flag as BoolFlag).DefaultValue ? "true" : "false"));
161 static void Debug (string s) {
162 Console.WriteLine (s);
165 static string FindFrameworkAssembly (string asm) {
166 return asm;
169 static bool Try (string prefix, string name, out string out_res) {
170 out_res = null;
172 string res = (Path.Combine (prefix, name));
173 if (File.Exists (res)) {
174 out_res = Path.GetFullPath (res);
175 return true;
177 return false;
180 static string ResolveWithExtension (string prefix, string name) {
181 string res = null;
183 if (Try (prefix, name, out res))
184 return res;
185 if (Try (prefix, name + ".dll", out res))
186 return res;
187 if (Try (prefix, name + ".exe", out res))
188 return res;
189 return null;
192 static string ResolveUser (string asm_name) {
193 return ResolveWithExtension (app_prefix, asm_name);
196 static string ResolveFramework (string asm_name) {
197 return ResolveWithExtension (framework_prefix, asm_name);
200 static string ResolveBcl (string asm_name) {
201 foreach (var prefix in bcl_prefixes) {
202 string res = ResolveWithExtension (prefix, asm_name);
203 if (res != null)
204 return res;
206 return null;
209 static string ResolveBclFacade (string asm_name) {
210 return ResolveWithExtension (bcl_facades_prefix, asm_name);
213 static string Resolve (string asm_name, out AssemblyKind kind) {
214 kind = AssemblyKind.User;
215 var asm = ResolveUser (asm_name);
216 if (asm != null)
217 return asm;
219 kind = AssemblyKind.Framework;
220 asm = ResolveFramework (asm_name);
221 if (asm != null)
222 return asm;
224 kind = AssemblyKind.Bcl;
225 asm = ResolveBcl (asm_name);
226 if (asm == null)
227 asm = ResolveBclFacade (asm_name);
228 if (asm != null)
229 return asm;
231 kind = AssemblyKind.None;
232 throw new Exception ($"Could not resolve {asm_name}");
235 static bool is_sdk_assembly (string filename) {
236 foreach (var prefix in bcl_prefixes)
237 if (filename.StartsWith (prefix))
238 return true;
239 return false;
242 static void Import (string ra, AssemblyKind kind) {
243 if (!asm_map.Add (Path.GetFullPath (ra)))
244 return;
245 ReaderParameters rp = new ReaderParameters();
246 bool add_pdb = enable_debug && File.Exists (Path.ChangeExtension (ra, "pdb"));
247 if (add_pdb) {
248 rp.ReadSymbols = true;
249 // Facades do not have symbols
250 rp.ThrowIfSymbolsAreNotMatching = false;
251 rp.SymbolReaderProvider = new DefaultSymbolReaderProvider(false);
254 var resolver = new DefaultAssemblyResolver();
255 root_search_paths.ForEach(resolver.AddSearchDirectory);
256 foreach (var prefix in bcl_prefixes)
257 resolver.AddSearchDirectory (prefix);
258 resolver.AddSearchDirectory(bcl_facades_prefix);
259 resolver.AddSearchDirectory(framework_prefix);
260 rp.AssemblyResolver = resolver;
262 rp.InMemory = true;
263 var image = ModuleDefinition.ReadModule (ra, rp);
264 file_list.Add (ra);
265 //Debug ($"Processing {ra} debug {add_pdb}");
267 var data = new AssemblyData () { name = image.Assembly.Name.Name, src_path = ra };
268 assemblies.Add (data);
270 if (add_pdb && (kind == AssemblyKind.User || kind == AssemblyKind.Framework)) {
271 var pdb_path = Path.ChangeExtension (Path.GetFullPath (ra), "pdb");
272 file_list.Add (pdb_path);
273 assemblies_with_dbg_info.Add (pdb_path);
276 var parent_kind = kind;
278 foreach (var ar in image.AssemblyReferences) {
279 // Resolve using root search paths first
280 AssemblyDefinition resolved = null;
281 try {
282 resolved = image.AssemblyResolver.Resolve(ar, rp);
283 } catch {
286 if (resolved == null && is_sdk_assembly (ra))
287 // FIXME: netcore assemblies have missing references
288 continue;
290 if (resolved != null) {
291 Import (resolved.MainModule.FileName, parent_kind);
292 } else {
293 var resolve = Resolve (ar.Name, out kind);
294 Import(resolve, kind);
299 void GenDriver (string builddir, List<string> profilers, ExecMode ee_mode, bool link_icalls) {
300 var symbols = new List<string> ();
301 foreach (var adata in assemblies) {
302 if (adata.aot)
303 symbols.Add (String.Format ("mono_aot_module_{0}_info", adata.name.Replace ('.', '_').Replace ('-', '_')));
306 var w = File.CreateText (Path.Combine (builddir, "driver-gen.c.in"));
308 foreach (var symbol in symbols) {
309 w.WriteLine ($"extern void *{symbol};");
312 w.WriteLine ("static void register_aot_modules ()");
313 w.WriteLine ("{");
314 foreach (var symbol in symbols)
315 w.WriteLine ($"\tmono_aot_register_module ({symbol});");
316 w.WriteLine ("}");
318 foreach (var profiler in profilers) {
319 w.WriteLine ($"void mono_profiler_init_{profiler} (const char *desc);");
320 w.WriteLine ("EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_" + profiler + " (const char *desc) { mono_profiler_init_" + profiler + " (desc); }");
323 switch (ee_mode) {
324 case ExecMode.AotInterp:
325 w.WriteLine ("#define EE_MODE_LLVMONLY_INTERP 1");
326 break;
327 case ExecMode.Aot:
328 w.WriteLine ("#define EE_MODE_LLVMONLY 1");
329 break;
330 default:
331 break;
334 if (link_icalls)
335 w.WriteLine ("#define LINK_ICALLS 1");
337 w.Close ();
340 public static int Main (string[] args) {
341 return new Driver ().Run (args);
344 enum CopyType
346 Default,
347 Always,
348 IfNewer
351 enum ExecMode {
352 Interp = 1,
353 Aot = 2,
354 AotInterp = 3
357 enum LinkMode
359 SdkOnly,
363 class WasmOptions {
364 public bool Debug;
365 public bool DebugRuntime;
366 public bool AddBinding;
367 public bool Linker;
368 public bool LinkIcalls;
369 public bool ILStrip;
370 public bool LinkerVerbose;
371 public bool EnableZLib;
372 public bool EnableFS;
373 public bool EnableThreads;
374 public bool NativeStrip;
375 public bool Simd;
376 public bool EnableDynamicRuntime;
377 public bool LinkerExcludeDeserialization;
378 public bool EnableCollation;
381 int Run (string[] args) {
382 var add_binding = true;
383 var root_assemblies = new List<string> ();
384 enable_debug = false;
385 string builddir = null;
386 string sdkdir = null;
387 string emscripten_sdkdir = null;
388 var aot_assemblies = "";
389 app_prefix = Environment.CurrentDirectory;
390 var deploy_prefix = "managed";
391 var vfs_prefix = "managed";
392 var use_release_runtime = true;
393 var enable_aot = false;
394 var enable_dedup = true;
395 var print_usage = false;
396 var emit_ninja = false;
397 bool build_wasm = false;
398 bool enable_lto = false;
399 bool link_icalls = false;
400 bool gen_pinvoke = false;
401 bool enable_zlib = false;
402 bool enable_fs = false;
403 bool enable_threads = false;
404 bool enable_dynamic_runtime = false;
405 bool is_netcore = false;
406 bool enable_simd = false;
407 var il_strip = false;
408 var linker_verbose = false;
409 var runtimeTemplate = "runtime.js";
410 var assets = new List<string> ();
411 var profilers = new List<string> ();
412 var native_libs = new List<string> ();
413 var preload_files = new List<string> ();
414 var embed_files = new List<string> ();
415 var pinvoke_libs = "";
416 var copyTypeParm = "default";
417 var copyType = CopyType.Default;
418 var ee_mode = ExecMode.Interp;
419 var linkModeParm = "all";
420 var linkMode = LinkMode.All;
421 var linkDescriptor = "";
422 var framework = "";
423 var runtimepack_dir = "";
424 string coremode, usermode;
425 string aot_profile = null;
426 string wasm_runtime_path = null;
428 var opts = new WasmOptions () {
429 AddBinding = true,
430 Debug = false,
431 DebugRuntime = false,
432 Linker = false,
433 ILStrip = true,
434 LinkerVerbose = false,
435 EnableZLib = false,
436 EnableFS = false,
437 NativeStrip = true,
438 Simd = false,
439 EnableDynamicRuntime = false,
440 LinkerExcludeDeserialization = true,
441 EnableCollation = false
444 var p = new OptionSet () {
445 { "nobinding", s => opts.AddBinding = false },
446 { "out=", s => out_prefix = s },
447 { "appdir=", s => out_prefix = s },
448 { "builddir=", s => builddir = s },
449 { "mono-sdkdir=", s => sdkdir = s },
450 { "emscripten-sdkdir=", s => emscripten_sdkdir = s },
451 { "runtimepack-dir=", s => runtimepack_dir = s },
452 { "prefix=", s => app_prefix = s },
453 { "wasm-runtime-path=", s => wasm_runtime_path = s },
454 { "deploy=", s => deploy_prefix = s },
455 { "vfs=", s => vfs_prefix = s },
456 { "aot", s => ee_mode = ExecMode.Aot },
457 { "aot-interp", s => ee_mode = ExecMode.AotInterp },
458 { "template=", s => runtimeTemplate = s },
459 { "asset=", s => assets.Add(s) },
460 { "search-path=", s => root_search_paths.Add(s) },
461 { "profile=", s => profilers.Add (s) },
462 { "copy=", s => copyTypeParm = s },
463 { "aot-assemblies=", s => aot_assemblies = s },
464 { "aot-profile=", s => aot_profile = s },
465 { "link-mode=", s => linkModeParm = s },
466 { "link-descriptor=", s => linkDescriptor = s },
467 { "pinvoke-libs=", s => pinvoke_libs = s },
468 { "native-lib=", s => native_libs.Add (s) },
469 { "preload-file=", s => preload_files.Add (s) },
470 { "embed-file=", s => embed_files.Add (s) },
471 { "framework=", s => framework = s },
472 { "help", s => print_usage = true },
475 AddFlag (p, new BoolFlag ("debug", "enable c# debugging", opts.Debug, b => opts.Debug = b));
476 AddFlag (p, new BoolFlag ("debugrt", "enable debug runtime", opts.DebugRuntime, b => opts.DebugRuntime = b));
477 AddFlag (p, new BoolFlag ("linker", "enable the linker", opts.Linker, b => opts.Linker = b));
478 AddFlag (p, new BoolFlag ("binding", "enable the binding engine", opts.AddBinding, b => opts.AddBinding = b));
479 AddFlag (p, new BoolFlag ("link-icalls", "link away unused icalls", opts.LinkIcalls, b => opts.LinkIcalls = b));
480 AddFlag (p, new BoolFlag ("il-strip", "strip IL code from assemblies in AOT mode", opts.ILStrip, b => opts.ILStrip = b));
481 AddFlag (p, new BoolFlag ("linker-verbose", "set verbose option on linker", opts.LinkerVerbose, b => opts.LinkerVerbose = b));
482 AddFlag (p, new BoolFlag ("zlib", "enable the use of zlib for System.IO.Compression support", opts.EnableZLib, b => opts.EnableZLib = b));
483 AddFlag (p, new BoolFlag ("enable-fs", "enable filesystem support (through Emscripten's file_packager.py in a later phase)", opts.EnableFS, b => opts.EnableFS = b));
484 AddFlag (p, new BoolFlag ("threads", "enable threads", opts.EnableThreads, b => opts.EnableThreads = b));
485 AddFlag (p, new BoolFlag ("dynamic-runtime", "enable dynamic runtime (support for Emscripten's dlopen)", opts.EnableDynamicRuntime, b => opts.EnableDynamicRuntime = b));
486 AddFlag (p, new BoolFlag ("native-strip", "strip final executable", opts.NativeStrip, b => opts.NativeStrip = b));
487 AddFlag (p, new BoolFlag ("simd", "enable SIMD support", opts.Simd, b => opts.Simd = b));
488 AddFlag (p, new BoolFlag ("linker-exclude-deserialization", "Link out .NET deserialization support", opts.LinkerExcludeDeserialization, b => opts.LinkerExcludeDeserialization = b));
489 AddFlag (p, new BoolFlag ("collation", "enable unicode collation support", opts.EnableCollation, b => opts.EnableCollation = b));
491 var new_args = p.Parse (args).ToArray ();
492 foreach (var a in new_args) {
493 root_assemblies.Add (a);
496 if (print_usage) {
497 Usage ();
498 return 0;
501 if (!Enum.TryParse(copyTypeParm, true, out copyType)) {
502 Console.WriteLine("Invalid copy value");
503 Usage ();
504 return 1;
507 if (!Enum.TryParse(linkModeParm, true, out linkMode)) {
508 Console.WriteLine("Invalid link-mode value");
509 Usage ();
510 return 1;
513 if (out_prefix == null) {
514 Console.Error.WriteLine ("The --appdir= argument is required.");
515 return 1;
518 enable_debug = opts.Debug;
519 enable_linker = opts.Linker;
520 add_binding = opts.AddBinding;
521 use_release_runtime = !opts.DebugRuntime;
522 il_strip = opts.ILStrip;
523 linker_verbose = opts.LinkerVerbose;
524 gen_pinvoke = pinvoke_libs != "";
525 enable_zlib = opts.EnableZLib;
526 enable_fs = opts.EnableFS;
527 enable_threads = opts.EnableThreads;
528 enable_dynamic_runtime = opts.EnableDynamicRuntime;
529 enable_simd = opts.Simd;
531 if (ee_mode == ExecMode.Aot || ee_mode == ExecMode.AotInterp)
532 enable_aot = true;
534 if (enable_aot || opts.Linker)
535 enable_linker = true;
536 if (opts.LinkIcalls)
537 link_icalls = true;
538 if (!enable_linker || !enable_aot)
539 enable_dedup = false;
540 if (enable_aot || link_icalls || gen_pinvoke || profilers.Count > 0 || native_libs.Count > 0 || preload_files.Count > 0 || embed_files.Count > 0) {
541 build_wasm = true;
542 emit_ninja = true;
544 if (!enable_aot && link_icalls)
545 enable_lto = true;
546 if (ee_mode != ExecMode.Aot)
547 // Can't strip out IL code in mixed mode, since the interpreter might execute some methods even if they have AOTed code available
548 il_strip = false;
550 if (aot_assemblies != "") {
551 if (ee_mode != ExecMode.AotInterp) {
552 Console.Error.WriteLine ("The --aot-assemblies= argument requires --aot-interp.");
553 return 1;
556 if (link_icalls && !enable_linker) {
557 Console.Error.WriteLine ("The --link-icalls option requires the --linker option.");
558 return 1;
560 if (framework != "") {
561 if (framework.StartsWith ("net5")) {
562 is_netcore = true;
563 if (runtimepack_dir == "") {
564 Console.Error.WriteLine ("The --runtimepack-dir= argument is required.");
565 return 1;
567 if (!Directory.Exists (runtimepack_dir)) {
568 Console.Error.WriteLine ($"The directory '{runtimepack_dir}' doesn't exist.");
569 return 1;
571 if (!Directory.Exists (Path.Combine (runtimepack_dir, "runtimes", "browser-wasm"))) {
572 Console.Error.WriteLine ($"The directory '{runtimepack_dir}' doesn't contain a 'runtimes/browser-wasm' subdirectory.");
573 return 1;
575 runtimepack_dir = Path.Combine (runtimepack_dir, "runtimes", "browser-wasm");
576 } else {
577 Console.Error.WriteLine ("The only valid value for --framework is 'net5...'");
578 return 1;
582 if (aot_profile != null && !File.Exists (aot_profile)) {
583 Console.Error.WriteLine ($"AOT profile file '{aot_profile}' not found.");
584 return 1;
587 if (enable_simd && !is_netcore) {
588 Console.Error.WriteLine ("--simd is only supported with netcore.");
589 return 1;
592 var tool_prefix = Path.GetDirectoryName (typeof (Driver).Assembly.Location);
594 //are we working from the tree?
595 if (sdkdir != null) {
596 framework_prefix = Path.Combine (tool_prefix, "framework"); //all framework assemblies are currently side built to packager.exe
597 } else if (Directory.Exists (Path.Combine (tool_prefix, "../out/wasm-bcl/wasm"))) {
598 framework_prefix = Path.Combine (tool_prefix, "framework"); //all framework assemblies are currently side built to packager.exe
599 sdkdir = Path.Combine (tool_prefix, "../out");
600 } else {
601 framework_prefix = Path.Combine (tool_prefix, "framework");
602 sdkdir = tool_prefix;
604 string bcl_root = Path.Combine (sdkdir, "wasm-bcl");
605 var bcl_prefix = Path.Combine (bcl_root, "wasm");
606 bcl_tools_prefix = Path.Combine (bcl_root, "wasm_tools");
607 bcl_facades_prefix = Path.Combine (bcl_prefix, "Facades");
608 bcl_prefixes = new List<string> ();
609 if (is_netcore) {
610 /* corelib */
611 bcl_prefixes.Add (Path.Combine (runtimepack_dir, "native"));
612 /* .net runtime */
613 bcl_prefixes.Add (Path.Combine (runtimepack_dir, "lib", "net5.0"));
614 } else {
615 bcl_prefixes.Add (bcl_prefix);
618 foreach (var ra in root_assemblies) {
619 AssemblyKind kind;
620 var resolved = Resolve (ra, out kind);
621 Import (resolved, kind);
623 if (add_binding) {
624 var bindings = ResolveFramework (BINDINGS_ASM_NAME + ".dll");
625 Import (bindings, AssemblyKind.Framework);
626 var http = ResolveFramework (HTTP_ASM_NAME + ".dll");
627 Import (http, AssemblyKind.Framework);
628 var websockets = ResolveFramework (WEBSOCKETS_ASM_NAME + ".dll");
629 Import (websockets, AssemblyKind.Framework);
632 if (enable_aot) {
633 var to_aot = new Dictionary<string, bool> ();
634 if (is_netcore)
635 to_aot ["System.Private.CoreLib"] = true;
636 else
637 to_aot ["mscorlib"] = true;
638 if (aot_assemblies != "") {
639 foreach (var s in aot_assemblies.Split (','))
640 to_aot [s] = true;
642 foreach (var ass in assemblies) {
643 if (aot_assemblies == "" || to_aot.ContainsKey (ass.name)) {
644 ass.aot = true;
645 to_aot.Remove (ass.name);
648 if (to_aot.Count > 0) {
649 Console.Error.WriteLine ("Unknown assembly name '" + to_aot.Keys.ToArray ()[0] + "' in --aot-assemblies option.");
650 return 1;
654 if (builddir != null) {
655 emit_ninja = true;
656 if (!Directory.Exists (builddir))
657 Directory.CreateDirectory (builddir);
660 if (!emit_ninja) {
661 if (!Directory.Exists (out_prefix))
662 Directory.CreateDirectory (out_prefix);
663 var bcl_dir = Path.Combine (out_prefix, deploy_prefix);
664 if (Directory.Exists (bcl_dir))
665 Directory.Delete (bcl_dir, true);
666 Directory.CreateDirectory (bcl_dir);
667 foreach (var f in file_list) {
668 CopyFile(f, Path.Combine (bcl_dir, Path.GetFileName (f)), copyType);
672 if (deploy_prefix.EndsWith ("/"))
673 deploy_prefix = deploy_prefix.Substring (0, deploy_prefix.Length - 1);
674 if (vfs_prefix.EndsWith ("/"))
675 vfs_prefix = vfs_prefix.Substring (0, vfs_prefix.Length - 1);
677 // wasm core bindings module
678 var wasm_core_bindings = string.Empty;
679 if (add_binding) {
680 wasm_core_bindings = BINDINGS_MODULE;
682 // wasm core bindings support file
683 var wasm_core_support = string.Empty;
684 var wasm_core_support_library = string.Empty;
685 if (add_binding) {
686 wasm_core_support = BINDINGS_MODULE_SUPPORT;
687 wasm_core_support_library = $"--js-library {BINDINGS_MODULE_SUPPORT}";
689 var runtime_js = Path.Combine (emit_ninja ? builddir : out_prefix, "runtime.js");
690 if (emit_ninja) {
691 File.Delete (runtime_js);
692 File.Copy (runtimeTemplate, runtime_js);
693 } else {
694 if (File.Exists(runtime_js) && (File.Exists(runtimeTemplate))) {
695 CopyFile (runtimeTemplate, runtime_js, CopyType.IfNewer, $"runtime template <{runtimeTemplate}> ");
696 } else {
697 if (File.Exists(runtimeTemplate))
698 CopyFile (runtimeTemplate, runtime_js, CopyType.IfNewer, $"runtime template <{runtimeTemplate}> ");
699 else {
700 var runtime_gen = "\nvar Module = {\n\tonRuntimeInitialized: function () {\n\t\tMONO.mono_load_runtime_and_bcl (\n\t\tconfig.vfs_prefix,\n\t\tconfig.deploy_prefix,\n\t\tconfig.enable_debugging,\n\t\tconfig.file_list,\n\t\tfunction () {\n\t\t\tApp.init ();\n\t\t}\n\t)\n\t},\n};";
701 File.Delete (runtime_js);
702 File.WriteAllText (runtime_js, runtime_gen);
707 AssemblyData dedup_asm = null;
709 if (enable_dedup) {
710 dedup_asm = new AssemblyData () { name = "aot-instances",
711 filename = "aot-instances.dll",
712 bc_path = "$builddir/aot-instances.dll.bc",
713 o_path = "$builddir/aot-instances.dll.o",
714 app_path = "$appdir/$deploy_prefix/aot-instances.dll",
715 linkout_path = "$builddir/linker-out/aot-instances.dll",
716 aot = true
718 assemblies.Add (dedup_asm);
719 file_list.Add ("aot-instances.dll");
722 var file_list_str = string.Join (",", file_list.Select (f => $"\"{Path.GetFileName (f)}\"").Distinct());
723 var config = String.Format ("config = {{\n \tvfs_prefix: \"{0}\",\n \tdeploy_prefix: \"{1}\",\n \tenable_debugging: {2},\n \tfile_list: [ {3} ],\n", vfs_prefix, deploy_prefix, enable_debug ? "1" : "0", file_list_str);
724 config += "}\n";
725 var config_js = Path.Combine (emit_ninja ? builddir : out_prefix, "mono-config.js");
726 File.Delete (config_js);
727 File.WriteAllText (config_js, config);
729 string wasm_runtime_dir;
730 if (is_netcore) {
731 wasm_runtime_dir = Path.Combine (runtimepack_dir, "native", "wasm", "runtimes", use_release_runtime ? "release" : "debug");
732 } else {
733 if (wasm_runtime_path == null)
734 wasm_runtime_path = Path.Combine (tool_prefix, "builds");
736 if (enable_threads)
737 wasm_runtime_dir = Path.Combine (wasm_runtime_path, use_release_runtime ? "threads-release" : "threads-debug");
738 else if (enable_dynamic_runtime)
739 wasm_runtime_dir = Path.Combine (wasm_runtime_path, use_release_runtime ? "dynamic-release" : "dynamic-debug");
740 else
741 wasm_runtime_dir = Path.Combine (wasm_runtime_path, use_release_runtime ? "release" : "debug");
743 if (!emit_ninja) {
744 var interp_files = new List<string> { "dotnet.js", "dotnet.wasm" };
745 if (enable_threads) {
746 interp_files.Add ("dotnet.worker.js");
748 foreach (var fname in interp_files) {
749 File.Delete (Path.Combine (out_prefix, fname));
750 File.Copy (
751 Path.Combine (wasm_runtime_dir, fname),
752 Path.Combine (out_prefix, fname));
755 foreach(var asset in assets) {
756 CopyFile (asset,
757 Path.Combine (out_prefix, Path.GetFileName (asset)), copyType, "Asset: ");
761 if (!emit_ninja)
762 return 0;
764 if (builddir == null) {
765 Console.Error.WriteLine ("The --builddir argument is required.");
766 return 1;
769 var filenames = new Dictionary<string, string> ();
770 foreach (var a in assemblies) {
771 var assembly = a.src_path;
772 if (assembly == null)
773 continue;
774 string filename = Path.GetFileName (assembly);
775 if (filenames.ContainsKey (filename)) {
776 Console.WriteLine ("Duplicate input assembly: " + assembly + " " + filenames [filename]);
777 return 1;
779 filenames [filename] = assembly;
782 if (build_wasm) {
783 if (sdkdir == null) {
784 Console.WriteLine ("The --mono-sdkdir argument is required.");
785 return 1;
787 if (emscripten_sdkdir == null) {
788 Console.WriteLine ("The --emscripten-sdkdir argument is required.");
789 return 1;
791 GenDriver (builddir, profilers, ee_mode, link_icalls);
794 string runtime_dir;
795 string runtime_libdir;
796 if (is_netcore) {
797 runtime_dir = "$runtimepack_dir/native";
798 runtime_libdir = "$runtimepack_dir/native";
799 } else {
800 runtime_dir = "$mono_sdkdir/wasm-runtime-release";
801 runtime_libdir = $"{runtime_dir}/lib";
803 string runtime_libs = "";
804 if (ee_mode == ExecMode.Interp || ee_mode == ExecMode.AotInterp || link_icalls) {
805 runtime_libs += $"$runtime_libdir/libmono-ee-interp.a $runtime_libdir/libmono-ilgen.a ";
806 // We need to link the icall table because the interpreter uses it to lookup icalls even if the aot-ed icall wrappers are available
807 if (!link_icalls)
808 runtime_libs += $"$runtime_libdir/libmono-icall-table.a ";
810 runtime_libs += $"$runtime_libdir/libmonosgen-2.0.a ";
811 if (is_netcore)
812 runtime_libs += $"$runtime_libdir/libSystem.Native.a";
813 else
814 runtime_libs += $"$runtime_libdir/libmono-native.a";
816 string aot_args = "llvm-path=$emscripten_sdkdir/upstream/bin,";
817 string profiler_libs = "";
818 string profiler_aot_args = "";
819 foreach (var profiler in profilers) {
820 profiler_libs += $"$runtime_libdir/libmono-profiler-{profiler}-static.a ";
821 if (profiler_aot_args != "")
822 profiler_aot_args += " ";
823 profiler_aot_args += $"--profile={profiler}";
825 string extra_link_libs = "";
826 foreach (var lib in native_libs)
827 extra_link_libs += lib + " ";
828 if (aot_profile != null) {
829 CopyFile (aot_profile, Path.Combine (builddir, Path.GetFileName (aot_profile)), CopyType.IfNewer, "");
830 aot_args += $"profile={aot_profile},profile-only,";
832 if (ee_mode == ExecMode.AotInterp)
833 aot_args += "interp,";
834 if (build_wasm)
835 enable_zlib = true;
836 if (is_netcore)
837 enable_zlib = false;
839 wasm_runtime_dir = Path.GetFullPath (wasm_runtime_dir);
840 sdkdir = Path.GetFullPath (sdkdir);
841 out_prefix = Path.GetFullPath (out_prefix);
843 string driver_deps = "";
844 if (link_icalls)
845 driver_deps += " $builddir/icall-table.h";
846 if (gen_pinvoke)
847 driver_deps += " $builddir/pinvoke-table.h";
848 string emcc_flags = "";
849 if (enable_lto)
850 emcc_flags += "--llvm-lto 1 ";
851 if (enable_zlib || is_netcore)
852 emcc_flags += "-s USE_ZLIB=1 ";
853 if (enable_fs)
854 emcc_flags += "-s FORCE_FILESYSTEM=1 ";
855 foreach (var pf in preload_files)
856 emcc_flags += "--preload-file " + pf + " ";
857 foreach (var f in embed_files)
858 emcc_flags += "--embed-file " + f + " ";
859 string emcc_link_flags = "";
860 if (enable_debug)
861 emcc_link_flags += "-O0 ";
862 string strip_cmd = "";
863 if (opts.NativeStrip)
864 strip_cmd = " && $wasm_opt --strip-dwarf $out_wasm -o $out_wasm";
865 if (enable_simd) {
866 aot_args += "mattr=simd,";
867 emcc_flags += "-s SIMD=1 ";
869 if (!use_release_runtime)
870 // -s ASSERTIONS=2 is very slow
871 emcc_flags += "-s ASSERTIONS=1 ";
873 var ninja = File.CreateText (Path.Combine (builddir, "build.ninja"));
875 // Defines
876 ninja.WriteLine ($"mono_sdkdir = {sdkdir}");
877 ninja.WriteLine ($"emscripten_sdkdir = {emscripten_sdkdir}");
878 ninja.WriteLine ($"tool_prefix = {tool_prefix}");
879 ninja.WriteLine ($"appdir = {out_prefix}");
880 ninja.WriteLine ($"builddir = .");
881 if (is_netcore)
882 ninja.WriteLine ($"runtimepack_dir = {runtimepack_dir}");
883 ninja.WriteLine ($"wasm_runtime_dir = {wasm_runtime_dir}");
884 ninja.WriteLine ($"runtime_libdir = {runtime_libdir}");
885 ninja.WriteLine ($"deploy_prefix = {deploy_prefix}");
886 ninja.WriteLine ($"bcl_dir = {bcl_prefix}");
887 ninja.WriteLine ($"bcl_facades_dir = {bcl_facades_prefix}");
888 ninja.WriteLine ($"framework_dir = {framework_prefix}");
889 ninja.WriteLine ($"tools_dir = {bcl_tools_prefix}");
890 ninja.WriteLine ($"emsdk_env = $builddir/emsdk_env.sh");
891 if (add_binding) {
892 ninja.WriteLine ($"wasm_core_bindings = $builddir/{BINDINGS_MODULE}");
893 ninja.WriteLine ($"wasm_core_support = {wasm_core_support}");
894 ninja.WriteLine ($"wasm_core_support_library = {wasm_core_support_library}");
895 } else {
896 ninja.WriteLine ("wasm_core_bindings =");
897 ninja.WriteLine ("wasm_core_support =");
898 ninja.WriteLine ("wasm_core_support_library =");
900 if (is_netcore)
901 ninja.WriteLine ("cross = $runtimepack_dir/native/cross/mono-aot-cross");
902 else
903 ninja.WriteLine ("cross = $mono_sdkdir/wasm-cross-release/bin/wasm32-unknown-none-mono-sgen");
904 ninja.WriteLine ("emcc = source $emsdk_env && emcc");
905 ninja.WriteLine ("wasm_opt = $emscripten_sdkdir/upstream/bin/wasm-opt");
906 ninja.WriteLine ($"emcc_flags = -Oz -g {emcc_flags}-s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=134217728 -s NO_EXIT_RUNTIME=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s \"EXTRA_EXPORTED_RUNTIME_METHODS=[\'ccall\', \'cwrap\', \'setValue\', \'getValue\', \'UTF8ToString\']\" -s \"EXPORTED_FUNCTIONS=[\'___cxa_is_pointer_type\', \'___cxa_can_catch\']\" -s \"DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[\'setThrew\', \'memset\']\"");
907 ninja.WriteLine ($"aot_base_args = llvmonly,asmonly,no-opt,static,direct-icalls,deterministic,{aot_args}");
909 // Rules
910 ninja.WriteLine ("rule aot");
911 ninja.WriteLine ($" command = MONO_PATH=$mono_path $cross --debug {profiler_aot_args} --aot=$aot_args,$aot_base_args,depfile=$depfile,llvm-outfile=$outfile $src_file");
912 ninja.WriteLine (" description = [AOT] $src_file -> $outfile");
913 ninja.WriteLine ("rule aot-instances");
914 ninja.WriteLine ($" command = MONO_PATH=$mono_path $cross --debug {profiler_aot_args} --aot=$aot_base_args,llvm-outfile=$outfile,dedup-include=$dedup_image $src_files");
915 ninja.WriteLine (" description = [AOT-INSTANCES] $outfile");
916 ninja.WriteLine ("rule mkdir");
917 ninja.WriteLine (" command = mkdir -p $out");
918 ninja.WriteLine ("rule cp");
919 ninja.WriteLine (" command = cp $in $out");
920 // Copy $in to $out only if it changed
921 ninja.WriteLine ("rule cpifdiff");
922 ninja.WriteLine (" command = if cmp -s $in $out ; then : ; else cp $in $out ; fi");
923 ninja.WriteLine (" restat = true");
924 ninja.WriteLine (" description = [CPIFDIFF] $in -> $out");
925 ninja.WriteLine ("rule create-emsdk-env");
926 ninja.WriteLine (" command = $emscripten_sdkdir/emsdk construct_env > $out");
927 ninja.WriteLine ("rule emcc");
928 ninja.WriteLine (" command = bash -c '$emcc $emcc_flags $flags -c -o $out $in'");
929 ninja.WriteLine (" description = [EMCC] $in -> $out");
930 ninja.WriteLine ("rule emcc-link");
931 ninja.WriteLine ($" command = bash -c '$emcc $emcc_flags {emcc_link_flags} -o $out_js --js-library $tool_prefix/src/library_mono.js --js-library $tool_prefix/src/dotnet_support.js {wasm_core_support_library} $in' {strip_cmd}");
932 ninja.WriteLine (" description = [EMCC-LINK] $in -> $out_js");
933 ninja.WriteLine ("rule linker");
934 ninja.WriteLine (" command = mono $tools_dir/monolinker.exe -out $builddir/linker-out -l none --deterministic --disable-opt unreachablebodies --exclude-feature com,remoting,etw $linker_args || exit 1; mono $tools_dir/wasm-tuner.exe --gen-empty-assemblies $out");
935 ninja.WriteLine (" description = [IL-LINK]");
936 ninja.WriteLine ("rule aot-instances-dll");
937 ninja.WriteLine (" command = echo > aot-instances.cs; csc /deterministic /out:$out /target:library aot-instances.cs");
938 ninja.WriteLine ("rule gen-runtime-icall-table");
939 ninja.WriteLine (" command = $cross --print-icall-table > $out");
940 ninja.WriteLine ("rule gen-icall-table");
941 ninja.WriteLine (" command = mono $tools_dir/wasm-tuner.exe --gen-icall-table $runtime_table $in > $out");
942 ninja.WriteLine ("rule gen-pinvoke-table");
943 ninja.WriteLine (" command = mono $tools_dir/wasm-tuner.exe --gen-pinvoke-table $pinvoke_libs $in > $out");
944 ninja.WriteLine ("rule ilstrip");
945 ninja.WriteLine (" command = cp $in $out; mono $tools_dir/mono-cil-strip.exe -q $out");
946 ninja.WriteLine (" description = [IL-STRIP]");
948 // Targets
949 ninja.WriteLine ("build $appdir: mkdir");
950 ninja.WriteLine ("build $appdir/$deploy_prefix: mkdir");
951 ninja.WriteLine ("build $appdir/runtime.js: cpifdiff $builddir/runtime.js");
952 ninja.WriteLine ("build $appdir/mono-config.js: cpifdiff $builddir/mono-config.js");
953 if (build_wasm) {
954 string src_prefix;
956 if (is_netcore)
957 src_prefix = Path.Combine (runtimepack_dir, "native", "wasm", "src");
958 else
959 src_prefix = Path.Combine (tool_prefix, "src");
960 var source_file = Path.GetFullPath (Path.Combine (src_prefix, "driver.c"));
961 ninja.WriteLine ($"build $builddir/driver.c: cpifdiff {source_file}");
962 ninja.WriteLine ($"build $builddir/driver-gen.c: cpifdiff $builddir/driver-gen.c.in");
963 source_file = Path.GetFullPath (Path.Combine (src_prefix, "pinvoke.c"));
964 ninja.WriteLine ($"build $builddir/pinvoke.c: cpifdiff {source_file}");
965 source_file = Path.GetFullPath (Path.Combine (src_prefix, "pinvoke.h"));
966 ninja.WriteLine ($"build $builddir/pinvoke.h: cpifdiff {source_file}");
968 var pinvoke_file_name = is_netcore ? "pinvoke-table.h" : "pinvoke-tables-default.h";
969 var pinvoke_file = Path.GetFullPath (Path.Combine (src_prefix, pinvoke_file_name));
970 ninja.WriteLine ($"build $builddir/pinvoke-tables-default.h: cpifdiff {pinvoke_file}");
971 driver_deps += $" $builddir/pinvoke-tables-default.h";
973 var driver_cflags = enable_aot ? "-DENABLE_AOT=1" : "";
975 if (add_binding) {
976 var bindings_source_file = Path.GetFullPath (Path.Combine (src_prefix, "corebindings.c"));
977 ninja.WriteLine ($"build $builddir/corebindings.c: cpifdiff {bindings_source_file}");
979 ninja.WriteLine ($"build $builddir/corebindings.o: emcc $builddir/corebindings.c | $emsdk_env");
980 ninja.WriteLine ($" flags = -I{runtime_dir}/include/mono-2.0");
981 driver_cflags += " -DCORE_BINDINGS ";
983 if (gen_pinvoke)
984 driver_cflags += " -DGEN_PINVOKE ";
985 if (is_netcore)
986 driver_cflags += " -DENABLE_NETCORE ";
988 ninja.WriteLine ("build $emsdk_env: create-emsdk-env");
989 ninja.WriteLine ($"build $builddir/driver.o: emcc $builddir/driver.c | $emsdk_env $builddir/driver-gen.c {driver_deps}");
990 ninja.WriteLine ($" flags = {driver_cflags} -DDRIVER_GEN=1 -I{runtime_dir}/include/mono-2.0");
991 ninja.WriteLine ($"build $builddir/pinvoke.o: emcc $builddir/pinvoke.c | $emsdk_env {driver_deps}");
992 ninja.WriteLine ($" flags = {driver_cflags} -DDRIVER_GEN=1 -I{runtime_dir}/include/mono-2.0");
994 if (enable_zlib) {
995 var zlib_source_file = Path.GetFullPath (Path.Combine (src_prefix, "zlib-helper.c"));
996 ninja.WriteLine ($"build $builddir/zlib-helper.c: cpifdiff {zlib_source_file}");
998 ninja.WriteLine ($"build $builddir/zlib-helper.o: emcc $builddir/zlib-helper.c | $emsdk_env");
999 ninja.WriteLine ($" flags = -s USE_ZLIB=1 -I{runtime_dir}/include/mono-2.0");
1001 } else {
1002 ninja.WriteLine ("build $appdir/dotnet.js: cpifdiff $wasm_runtime_dir/dotnet.js");
1003 ninja.WriteLine ("build $appdir/dotnet.wasm: cpifdiff $wasm_runtime_dir/dotnet.wasm");
1004 if (enable_threads) {
1005 ninja.WriteLine ("build $appdir/dotnet.worker.js: cpifdiff $wasm_runtime_dir/dotnet.worker.js");
1008 if (enable_aot)
1009 ninja.WriteLine ("build $builddir/aot-in: mkdir");
1011 foreach (var file in new string[] { "linker-subs.xml", "linker-disable-collation.xml", "linker-preserves.xml" }) {
1012 var source_file = Path.GetFullPath (Path.Combine (tool_prefix, "src", file));
1013 ninja.WriteLine ($"build $builddir/{file}: cpifdiff {source_file}");
1016 var ofiles = "";
1017 var bc_files = "";
1018 string linker_infiles = "";
1019 string linker_ofiles = "";
1020 string dedup_infiles = "";
1021 if (enable_linker) {
1022 string path = Path.Combine (builddir, "linker-in");
1023 if (!Directory.Exists (path))
1024 Directory.CreateDirectory (path);
1026 string aot_in_path = enable_linker ? "$builddir/linker-out" : "$builddir";
1027 foreach (var a in assemblies) {
1028 var assembly = a.src_path;
1029 if (assembly == null)
1030 continue;
1031 string filename = Path.GetFileName (assembly);
1032 var filename_noext = Path.GetFileNameWithoutExtension (filename);
1033 string filename_pdb = Path.ChangeExtension (filename, "pdb");
1034 var source_file_path = Path.GetFullPath (assembly);
1035 var source_file_path_pdb = Path.ChangeExtension (source_file_path, "pdb");
1036 string infile = "";
1037 string infile_pdb = "";
1038 bool emit_pdb = assemblies_with_dbg_info.Contains (source_file_path_pdb);
1039 if (enable_linker) {
1040 a.linkin_path = $"$builddir/linker-in/{filename}";
1041 a.linkin_pdb_path = $"$builddir/linker-in/{filename_pdb}";
1042 a.linkout_path = $"$builddir/linker-out/{filename}";
1043 a.linkout_pdb_path = $"$builddir/linker-out/{filename_pdb}";
1044 linker_infiles += $"{a.linkin_path} ";
1045 linker_ofiles += $" {a.linkout_path}";
1046 ninja.WriteLine ($"build {a.linkin_path}: cp {source_file_path}");
1047 if (File.Exists(source_file_path_pdb)) {
1048 ninja.WriteLine($"build {a.linkin_pdb_path}: cp {source_file_path_pdb}");
1049 linker_ofiles += $" {a.linkout_pdb_path}";
1050 infile_pdb = a.linkout_pdb_path;
1052 a.aotin_path = a.linkout_path;
1053 infile = $"{a.aotin_path}";
1054 } else {
1055 infile = $"$builddir/{filename}";
1056 ninja.WriteLine ($"build $builddir/{filename}: cpifdiff {source_file_path}");
1057 a.linkout_path = infile;
1058 if (emit_pdb) {
1059 ninja.WriteLine ($"build $builddir/{filename_pdb}: cpifdiff {source_file_path_pdb}");
1060 infile_pdb = $"$builddir/{filename_pdb}";
1064 a.final_path = infile;
1065 if (il_strip) {
1066 ninja.WriteLine ($"build $builddir/ilstrip-out/{filename} : ilstrip {infile}");
1067 a.final_path = $"$builddir/ilstrip-out/{filename}";
1070 ninja.WriteLine ($"build $appdir/$deploy_prefix/{filename}: cpifdiff {a.final_path}");
1071 if (emit_pdb && infile_pdb != "")
1072 ninja.WriteLine ($"build $appdir/$deploy_prefix/{filename_pdb}: cpifdiff {infile_pdb}");
1073 if (a.aot) {
1074 a.bc_path = $"$builddir/{filename}.bc";
1075 a.o_path = $"$builddir/{filename}.o";
1076 a.aot_depfile_path = $"$builddir/linker-out/{filename}.depfile";
1078 if (filename == "mscorlib.dll") {
1079 // mscorlib has no dependencies so we can skip the aot step if the input didn't change
1080 // The other assemblies depend on their references
1081 infile = "$builddir/aot-in/mscorlib.dll";
1082 a.aotin_path = infile;
1083 ninja.WriteLine ($"build {a.aotin_path}: cpifdiff {a.linkout_path}");
1085 ninja.WriteLine ($"build {a.bc_path}.tmp: aot {infile}");
1086 ninja.WriteLine ($" src_file={infile}");
1087 ninja.WriteLine ($" outfile={a.bc_path}.tmp");
1088 ninja.WriteLine ($" mono_path=$builddir/aot-in:{aot_in_path}");
1089 ninja.WriteLine ($" depfile={a.aot_depfile_path}");
1090 if (enable_dedup)
1091 ninja.WriteLine ($" aot_args=dedup-skip");
1093 ninja.WriteLine ($"build {a.bc_path}: cpifdiff {a.bc_path}.tmp");
1094 ninja.WriteLine ($"build {a.o_path}: emcc {a.bc_path} | $emsdk_env");
1096 ofiles += " " + $"{a.o_path}";
1097 bc_files += " " + $"{a.bc_path}";
1098 dedup_infiles += $" {a.aotin_path}";
1101 if (enable_dedup) {
1103 * Run the aot compiler in dedup mode:
1104 * mono --aot=<args>,dedup-include=aot-instances.dll <assemblies> aot-instances.dll
1105 * This will process all assemblies and emit all instances into the aot image of aot-instances.dll
1107 var a = dedup_asm;
1109 * The dedup process will read in the .dedup files created when running with dedup-skip, so add all the
1110 * .bc files as dependencies.
1112 ninja.WriteLine ($"build {a.bc_path}.tmp: aot-instances | {bc_files} {a.linkout_path}");
1113 ninja.WriteLine ($" dedup_image={a.filename}");
1114 ninja.WriteLine ($" src_files={dedup_infiles} {a.linkout_path}");
1115 ninja.WriteLine ($" outfile={a.bc_path}.tmp");
1116 ninja.WriteLine ($" mono_path=$builddir/aot-in:{aot_in_path}");
1117 ninja.WriteLine ($"build {a.app_path}: cpifdiff {a.linkout_path}");
1118 ninja.WriteLine ($"build {a.linkout_path}: aot-instances-dll");
1119 // The dedup image might not have changed
1120 ninja.WriteLine ($"build {a.bc_path}: cpifdiff {a.bc_path}.tmp");
1121 ninja.WriteLine ($"build {a.o_path}: emcc {a.bc_path} | $emsdk_env");
1122 ofiles += $" {a.o_path}";
1124 if (link_icalls) {
1125 string icall_assemblies = "";
1126 foreach (var a in assemblies) {
1127 if (a.name == "mscorlib" || a.name == "System")
1128 icall_assemblies += $"{a.linkout_path} ";
1130 ninja.WriteLine ("build $builddir/icall-table.json: gen-runtime-icall-table");
1131 ninja.WriteLine ($"build $builddir/icall-table.h: gen-icall-table {icall_assemblies}");
1132 ninja.WriteLine ($" runtime_table=$builddir/icall-table.json");
1134 if (gen_pinvoke) {
1135 string pinvoke_assemblies = "";
1136 foreach (var a in assemblies)
1137 pinvoke_assemblies += $"{a.linkout_path} ";
1138 ninja.WriteLine ($"build $builddir/pinvoke-table.h: cpifdiff $builddir/pinvoke-table.h.tmp");
1139 ninja.WriteLine ($"build $builddir/pinvoke-table.h.tmp: gen-pinvoke-table {pinvoke_assemblies}");
1140 ninja.WriteLine ($" pinvoke_libs=System.Native,{pinvoke_libs}");
1142 if (build_wasm) {
1143 string zlibhelper = enable_zlib ? "$builddir/zlib-helper.o" : "";
1144 ninja.WriteLine ($"build $appdir/dotnet.js $appdir/dotnet.wasm: emcc-link $builddir/driver.o $builddir/pinvoke.o {zlibhelper} {wasm_core_bindings} {ofiles} {profiler_libs} {extra_link_libs} {runtime_libs} | $tool_prefix/src/library_mono.js $tool_prefix/src/dotnet_support.js {wasm_core_support} $emsdk_env");
1145 ninja.WriteLine (" out_js=$appdir/dotnet.js");
1146 ninja.WriteLine (" out_wasm=$appdir/dotnet.wasm");
1148 if (enable_linker) {
1149 switch (linkMode) {
1150 case LinkMode.SdkOnly:
1151 coremode = "link";
1152 usermode = "copy";
1153 break;
1154 case LinkMode.All:
1155 coremode = "link";
1156 usermode = "link";
1157 break;
1158 default:
1159 coremode = "link";
1160 usermode = "link";
1161 break;
1164 string linker_args = "";
1165 if (enable_aot)
1166 // Only used by the AOT compiler
1167 linker_args += "--explicit-reflection ";
1168 linker_args += "--used-attrs-only true ";
1169 linker_args += "--substitutions linker-subs.xml ";
1170 linker_infiles += "| linker-subs.xml ";
1171 linker_args += "-x linker-preserves.xml ";
1172 linker_infiles += "linker-preserves.xml ";
1173 if (opts.LinkerExcludeDeserialization)
1174 linker_args += "--exclude-feature deserialization ";
1175 if (!opts.EnableCollation) {
1176 linker_args += "--substitutions linker-disable-collation.xml ";
1177 linker_infiles += "linker-disable-collation.xml";
1179 if (opts.Debug) {
1180 linker_args += "-b true ";
1182 if (!string.IsNullOrEmpty (linkDescriptor)) {
1183 linker_args += $"-x {linkDescriptor} ";
1184 foreach (var assembly in root_assemblies) {
1185 string filename = Path.GetFileName (assembly);
1186 linker_args += $"-p {usermode} {filename} -r linker-in/{filename} ";
1188 } else {
1189 foreach (var assembly in root_assemblies) {
1190 string filename = Path.GetFileName (assembly);
1191 linker_args += $"-a linker-in/{filename} ";
1195 if (linker_verbose) {
1196 linker_args += "--verbose ";
1198 linker_args += $"-d linker-in -d $bcl_dir -d $bcl_facades_dir -d $framework_dir -c {coremode} -u {usermode} ";
1200 ninja.WriteLine ("build $builddir/linker-out: mkdir");
1201 ninja.WriteLine ($"build {linker_ofiles}: linker {linker_infiles}");
1202 ninja.WriteLine ($" linker_args={linker_args}");
1204 if (il_strip)
1205 ninja.WriteLine ("build $builddir/ilstrip-out: mkdir");
1207 foreach(var asset in assets) {
1208 var filename = Path.GetFileName (asset);
1209 var abs_path = Path.GetFullPath (asset);
1210 ninja.WriteLine ($"build $appdir/{filename}: cpifdiff {abs_path}");
1213 ninja.Close ();
1215 return 0;
1218 static void CopyFile(string sourceFileName, string destFileName, CopyType copyType, string typeFile = "")
1220 Console.WriteLine($"{typeFile}cp: {copyType} - {sourceFileName} -> {destFileName}");
1221 switch (copyType)
1223 case CopyType.Always:
1224 File.Copy(sourceFileName, destFileName, true);
1225 break;
1226 case CopyType.IfNewer:
1227 if (!File.Exists(destFileName))
1229 File.Copy(sourceFileName, destFileName);
1231 else
1233 var srcInfo = new FileInfo (sourceFileName);
1234 var dstInfo = new FileInfo (destFileName);
1236 if (srcInfo.LastWriteTime.Ticks > dstInfo.LastWriteTime.Ticks || srcInfo.Length > dstInfo.Length)
1237 File.Copy(sourceFileName, destFileName, true);
1238 else
1239 Console.WriteLine($" skipping: {sourceFileName}");
1241 break;
1242 default:
1243 File.Copy(sourceFileName, destFileName);
1244 break;