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; }}");
                }
            }
        }
Esempio n. 2
0
        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);
        }