public void GenerateBundledAssembly(string assemblyFile, string outputFile, out string configFile) { var assemblyName = Symbols.GetBundledAssemblyName(assemblyFile, Log); var assemblyConfigFileCopy = Path.Combine(Path.GetDirectoryName(outputFile), assemblyName) + ".config"; var configName = (assemblyName + ".config").ToLower(); try { configFile = ConfigFiles.First(t => Path.GetFileName(t.ItemSpec ?? "").ToLower() == configName).ItemSpec; } catch { configFile = null; } if (SkipUnchanged && File.Exists(outputFile) && File.Exists(assemblyFile) && File.GetLastWriteTime(outputFile) >= File.GetLastWriteTime(assemblyFile)) { if (configFile == null && !File.Exists(assemblyConfigFileCopy) || configFile != null && File.Exists(assemblyConfigFileCopy) && File.GetLastWriteTime(configFile) >= File.GetLastWriteTime(assemblyConfigFileCopy)) { Log.LogDebugMessage(" Not regenerating bundle file for unchanged assembly: {0}", assemblyFile); return; } } Log.LogDebugMessage($" Generating output '{outputFile}' from assembly '{assemblyFile}'"); var bundledAssemblyGetter = Symbols.GetBundledAssemblyGetter(assemblyName); var bundledAssemblyConfigGetter = Symbols.GetBundledAssemblyConfigGetter(assemblyName); var bundledAssemblyCleanup = Symbols.GetBundledAssemblyCleanup(assemblyName); using (var ins = File.OpenRead(assemblyFile)) { using (var outs = new StreamWriter(File.Create(outputFile))) { outs.WriteLine("static const unsigned char bundle_data [] = {"); WriteFileAsCArray(ins, outs); outs.WriteLine("};"); outs.WriteLine("typedef struct { const char* name; const unsigned char* data; const unsigned int size; } MonoBundledAssembly;"); outs.WriteLine($"static const MonoBundledAssembly bundle = {{\"{assemblyName}\", bundle_data, sizeof (bundle_data)}};"); outs.WriteLine($"const MonoBundledAssembly *{bundledAssemblyGetter} (void) {{ return &bundle; }}"); outs.WriteLine("typedef struct { const char* name; const char* data; } MonoBundledAssemblyConfig;"); if (configFile != null) { try { using (var cfgs = File.OpenRead(configFile)) { Log.LogDebugMessage($" Found assembly config file '{configFile}' for assembly '{assemblyFile}'"); outs.WriteLine("static const char config_data [] = {"); WriteFileAsCArray(cfgs, outs); outs.WriteLine("0};"); outs.WriteLine($"static const MonoBundledAssemblyConfig config = {{\"{assemblyName}\", config_data}};"); } } catch { // Return NULL if the assembly has no config file. configFile = null; } } if (configFile == null) { Log.LogDebugMessage($" No assembly config file found for assembly '{assemblyFile}'"); outs.WriteLine($"static const MonoBundledAssemblyConfig config = {{\"{assemblyName}\", 0L}};"); } if (File.Exists(assemblyConfigFileCopy)) { File.Delete(assemblyConfigFileCopy); } if (configFile != null) { File.Copy(configFile, assemblyConfigFileCopy); } outs.WriteLine($"const MonoBundledAssemblyConfig *{bundledAssemblyConfigGetter} (void) {{ return &config; }}"); // Cleanup function does nothing for now. Will be needed for compressed bundled. outs.WriteLine($"void {bundledAssemblyCleanup} (void) {{ return; }}"); } } }
private bool DoExecute() { if (string.IsNullOrEmpty(LauncherFileName)) { LauncherFileName = "launcher.c"; } AotAssemblies = AotAssemblies ?? new ITaskItem[0]; BundledAssemblies = BundledAssemblies ?? new ITaskItem[0]; Log.LogDebugMessage("GenerateLauncher Task"); Log.LogDebugMessage(" OutputDirectory: {0}", OutputDirectory); Log.LogDebugMessage(" MainAssemblyName: {0}", MainAssemblyName); Log.LogDebugMessage(" LauncherTemplatePath: {0}", LauncherTemplatePath); Log.LogDebugMessage(" LauncherFileName: {0}", LauncherFileName); Log.LogDebugMessage(" UseCustomPlatformImpl: {0}", UseCustomPlatformImpl); Log.LogDebugTaskItems(" AotAssemblies:", AotAssemblies); Log.LogDebugTaskItems(" BundledAssemblies:", BundledAssemblies); var mainAssemblyName = MainAssemblyName; if (!SkipMain && string.IsNullOrEmpty(mainAssemblyName)) { var found = AotAssemblies.FirstOrDefault(a => Path.GetExtension(a.ItemSpec).ToLower() == ".exe"); if (found == null) { throw new InvalidOperationException("Could not determine main assembly. No .exe assembly found."); } mainAssemblyName = Path.GetFileName(found.ItemSpec); Log.LogDebugMessage(" Found main assembly: {0}", mainAssemblyName); } var aoted = AotAssemblies.Select(a => Symbols.GetAotModuleSymbolName(a.ItemSpec, UserSymbolPrefix)).ToList(); var bundled = BundledAssemblies.Select(a => { var assemblyName = Symbols.GetBundledAssemblyName(a.ItemSpec, Log); return(new { getterSymbol = Symbols.GetBundledAssemblyGetter(assemblyName), configGetterSymbol = Symbols.GetBundledAssemblyConfigGetter(assemblyName), cleanupSymbol = Symbols.GetBundledAssemblyCleanup(assemblyName) }); }).ToList(); var nl = "\n"; var launcher = string.IsNullOrEmpty(LauncherTemplatePath) ? Resources.LauncherTemplate : File.ReadAllText(LauncherTemplatePath); var aotModules = new StringBuilder() .AppendLine("BEGIN_DECLARE_AOT_MODULES") .AppendLine(string.Join(nl, aoted.Select(a => $"\tDECLARE_AOT_MODULE ({a})"))) .AppendLine("END_DECLARE_AOT_MODULES") .AppendLine("BEGIN_DEFINE_AOT_MODULES") .AppendLine(string.Join(nl, aoted.Select(a => $"\tDEFINE_AOT_MODULE ({a})"))) .AppendLine("END_DEFINE_AOT_MODULES"); launcher = Regex.Replace(launcher, @"(//\s*)\$\{AOTModules\}", aotModules.ToString()); var bundledAssemblies = new StringBuilder() .AppendLine("BEGIN_DECLARE_BUNDLED_ASSEMBLIES") .AppendLine(string.Join(nl, bundled.Select(a => $"\tDECLARE_BUNDLED_ASSEMBLY ({a.getterSymbol})"))) .AppendLine("END_DECLARE_BUNDLED_ASSEMBLIES") .AppendLine("BEGIN_DEFINE_BUNDLED_ASSEMBLIES") .AppendLine(string.Join(nl, bundled.Select(a => $"\tDEFINE_BUNDLED_ASSEMBLY ({a.getterSymbol})"))) .AppendLine("END_DEFINE_BUNDLED_ASSEMBLIES"); launcher = Regex.Replace(launcher, @"(//\s*)\$\{BundledAssemblies\}", bundledAssemblies.ToString()); var bundledAssemblyConfigs = new StringBuilder() .AppendLine("BEGIN_DECLARE_BUNDLED_ASSEMBLY_CONFIGS") .AppendLine(string.Join(nl, bundled.Select(a => $"\tDECLARE_BUNDLED_ASSEMBLY_CONFIG ({a.configGetterSymbol})"))) .AppendLine("END_DECLARE_BUNDLED_ASSEMBLY_CONFIGS") .AppendLine("BEGIN_DEFINE_BUNDLED_ASSEMBLY_CONFIGS") .AppendLine(string.Join(nl, bundled.Select(a => $"\tDEFINE_BUNDLED_ASSEMBLY_CONFIG ({a.configGetterSymbol})"))) .AppendLine("END_DEFINE_BUNDLED_ASSEMBLY_CONFIGS"); launcher = Regex.Replace(launcher, @"(//\s*)\$\{BundledAssemblyConfigs\}", bundledAssemblyConfigs.ToString()); var bundledAssemblyCleanups = new StringBuilder() .AppendLine("BEGIN_DECLARE_BUNDLED_ASSEMBLY_CLEANUPS") .AppendLine(string.Join(nl, bundled.Select(a => $"\tDECLARE_BUNDLED_ASSEMBLY_CLEANUP ({a.cleanupSymbol})"))) .AppendLine("END_DECLARE_BUNDLED_ASSEMBLY_CLEANUPS") .AppendLine("BEGIN_DEFINE_BUNDLED_ASSEMBLY_CLEANUPS") .AppendLine(string.Join(nl, bundled.Select(a => $"\tDEFINE_BUNDLED_ASSEMBLY_CLEANUP ({a.cleanupSymbol})"))) .AppendLine("END_DEFINE_BUNDLED_ASSEMBLY_CLEANUPS"); launcher = Regex.Replace(launcher, @"(//\s*)\$\{BundledAssemblyCleanups\}", bundledAssemblyCleanups.ToString()); var defines = new List <string>(); if (SkipMain) { defines.Add("SKIP_MAIN=1"); } if (!string.IsNullOrEmpty(CustomDefines)) { defines.AddRange(CustomDefines.Split(';')); } defines.RemoveAll(d => String.IsNullOrWhiteSpace(d)); defines = defines .Select(d => d.Split("=".ToCharArray(), 2)) .Select(a => "#define " + string.Join(" ", a.ToArray()).Trim()).ToList(); launcher = Regex.Replace(launcher, @"(//\s*)\$\{Defines\}", string.Join(nl, defines)); launcher = Regex.Replace(launcher, @"\$\{MainAssemblyName\}", mainAssemblyName ?? ""); if (!Directory.Exists(OutputDirectory)) { Directory.CreateDirectory(OutputDirectory); } var outputFiles = new List <string>(); var outputFile = Path.Combine(OutputDirectory, LauncherFileName); var writeOutputFile = true; if (File.Exists(outputFile)) { var oldContents = File.ReadAllText(outputFile); writeOutputFile = oldContents != launcher; } if (writeOutputFile) { File.WriteAllText(outputFile, launcher); } else { Log.LogDebugMessage(" Output file {0} hasn't changed. Won't overwrite.", outputFile); } outputFiles.Add(outputFile); if (string.IsNullOrEmpty(LauncherTemplatePath)) { // Copy the bundled platform.h var platformHeaderFile = Path.Combine(OutputDirectory, "platform.h"); File.WriteAllText(platformHeaderFile, Resources.PlatformHeader); outputFiles.Add(platformHeaderFile); if (!UseCustomPlatformImpl) { // Use the bundled platform.c var platformImplFile = Path.Combine(OutputDirectory, "platform.c"); File.WriteAllText(platformImplFile, Resources.PlatformImpl); outputFiles.Add(platformImplFile); } } GeneratedFiles = outputFiles.Select(f => new TaskItem(f)).ToArray(); Log.LogDebugTaskItems(" [Output] GeneratedFiles:", GeneratedFiles); return(true); }