using System; using HybridCLR.Editor.Installer; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using UnityEditor; using System.Reflection; using HybridCLR.Editor.Settings; #if (UNITY_2020 || UNITY_2021) && UNITY_IOS using UnityEditor.Build; using UnityEditor.Callbacks; using UnityEditor.iOS.Xcode; using UnityEngine; namespace HybridCLR.Editor.BuildProcessors { public static class AddLil2cppSourceCodeToXcodeproj2021OrOlder { //[MenuItem("Test/GenProj")] //public static void Modify() //{ // OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS"); //} //[MenuItem("Test/CreateLumps")] //public static void CreateLumpsCmd() //{ // CreateLumps($"{SettingsUtil.LocalIl2CppDir}/libil2cpp", $"{SettingsUtil.HybridCLRDataDir}/lumps"); //} [PostProcessBuild] public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) { if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable) return; /* * 1. 生成lump,并且添加到工程 3. 将libil2cpp目录复制到 Library/. 删除旧的. search paths里修改 libil2cpp/include为libil2cpp 3. Libraries/bdwgc/include -> Libraries/external/bdwgc/include 4. 将external目录复制到 Library/external。删除旧目录 5. 将Library/external/baselib/Platforms/OSX改名为 IOS 全大写 6. 将 external/zlib下c 文件添加到工程 7. 移除libil2cpp.a 8. Include path add libil2cpp/os/ClassLibraryPAL/brotli/include 9. add external/xxHash */ string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj"; string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp"; string lumpDir = $"{pathToBuiltProject}/Libraries/lumps"; string srcExternalDir = $"{SettingsUtil.LocalIl2CppDir}/external"; string dstExternalDir = $"{pathToBuiltProject}/Libraries/external"; //RemoveExternalLibil2cppOption(srcExternalDir, dstExternalDir); CopyLibil2cppToXcodeProj(srcLibil2cppDir, dstLibil2cppDir); CopyExternalToXcodeProj(srcExternalDir, dstExternalDir); var lumpFiles = CreateLumps(dstLibil2cppDir, lumpDir); var extraSources = GetExtraSourceFiles(dstExternalDir, dstLibil2cppDir); var cflags = new List() { "-DIL2CPP_MONO_DEBUGGER_DISABLED", }; ModifyPBXProject(pathToBuiltProject, pbxprojFile, lumpFiles, extraSources, cflags); } private static string GetRelativePathFromProj(string path) { return path.Substring(path.IndexOf("Libraries", StringComparison.Ordinal)).Replace('\\', '/'); } private static void ModifyPBXProject(string pathToBuiltProject, string pbxprojFile, List lumpFiles, List extraFiles, List cflags) { var proj = new PBXProject(); proj.ReadFromFile(pbxprojFile); string targetGUID = proj.GetUnityFrameworkTargetGuid(); // 移除旧的libil2cpp.a var libil2cppGUID = proj.FindFileGuidByProjectPath("Libraries/libil2cpp.a"); if (!string.IsNullOrEmpty(libil2cppGUID)) { proj.RemoveFileFromBuild(targetGUID, libil2cppGUID); proj.RemoveFile(libil2cppGUID); File.Delete(Path.Combine(pathToBuiltProject, "Libraries", "libil2cpp.a")); } //var lumpGroupGuid = proj.AddFile("Lumps", $"Classes/Lumps", PBXSourceTree.Group); foreach (var lumpFile in lumpFiles) { string lumpFileName = Path.GetFileName(lumpFile.lumpFile); string projPathOfFile = $"Classes/Lumps/{lumpFileName}"; string relativePathOfFile = GetRelativePathFromProj(lumpFile.lumpFile); string lumpGuid = proj.FindFileGuidByProjectPath(projPathOfFile); if (!string.IsNullOrEmpty(lumpGuid)) { proj.RemoveFileFromBuild(targetGUID, lumpGuid); proj.RemoveFile(lumpGuid); } lumpGuid = proj.AddFile(relativePathOfFile, projPathOfFile, PBXSourceTree.Source); proj.AddFileToBuild(targetGUID, lumpGuid); } foreach (var extraFile in extraFiles) { string projPathOfFile = $"Classes/Extrals/{Path.GetFileName(extraFile)}"; string extraFileGuid = proj.FindFileGuidByProjectPath(projPathOfFile); if (!string.IsNullOrEmpty(extraFileGuid)) { proj.RemoveFileFromBuild(targetGUID, extraFileGuid); proj.RemoveFile(extraFileGuid); //Debug.LogWarning($"remove exist extra file:{projPathOfFile} guid:{extraFileGuid}"); } var lumpGuid = proj.AddFile(GetRelativePathFromProj(extraFile), projPathOfFile, PBXSourceTree.Source); proj.AddFileToBuild(targetGUID, lumpGuid); } foreach(var configName in proj.BuildConfigNames()) { //Debug.Log($"build config:{bcn}"); string configGuid = proj.BuildConfigByName(targetGUID, configName); string headerSearchPaths = "HEADER_SEARCH_PATHS"; string hspProp = proj.GetBuildPropertyForConfig(configGuid, headerSearchPaths); //Debug.Log($"config guid:{configGuid} prop:{hspProp}"); string newPro = hspProp.Replace("libil2cpp/include", "libil2cpp") .Replace("Libraries/bdwgc", "Libraries/external/bdwgc"); if (!newPro.Contains("Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include")) { newPro += " $(SRCROOT)/Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include"; } if (!newPro.Contains("Libraries/external/xxHash")) { newPro += " $(SRCROOT)/Libraries/external/xxHash"; } //Debug.Log($"config:{bcn} new prop:{newPro}"); proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro); string cflagKey = "OTHER_CFLAGS"; string cfProp = proj.GetBuildPropertyForConfig(configGuid, cflagKey); foreach (var flag in cflags) { if (!cfProp.Contains(flag)) { cfProp += " " + flag; } } if (configName.Contains("Debug") && !cfProp.Contains("-DIL2CPP_DEBUG=")) { cfProp += " -DIL2CPP_DEBUG=1 -DDEBUG=1"; } proj.SetBuildPropertyForConfig(configGuid, cflagKey, cfProp); } proj.WriteToFile(pbxprojFile); } private static void CopyLibil2cppToXcodeProj(string srcLibil2cppDir, string dstLibil2cppDir) { BashUtil.RemoveDir(dstLibil2cppDir); BashUtil.CopyDir(srcLibil2cppDir, dstLibil2cppDir, true); } private static void CopyExternalToXcodeProj(string srcExternalDir, string dstExternalDir) { BashUtil.RemoveDir(dstExternalDir); BashUtil.CopyDir(srcExternalDir, dstExternalDir, true); string baselibPlatfromsDir = $"{dstExternalDir}/baselib/Platforms"; BashUtil.RemoveDir($"{baselibPlatfromsDir}/IOS"); BashUtil.CopyDir($"{baselibPlatfromsDir}/OSX", $"{baselibPlatfromsDir}/IOS", true); } class LumpFile { public List cppFiles = new List(); public readonly string lumpFile; public readonly string il2cppConfigFile; public LumpFile(string lumpFile, string il2cppConfigFile) { this.lumpFile = lumpFile; this.il2cppConfigFile = il2cppConfigFile; this.cppFiles.Add(il2cppConfigFile); } public void SaveFile() { var lumpFileContent = new List(); foreach (var file in cppFiles) { lumpFileContent.Add($"#include \"{GetRelativePathFromProj(file)}\""); } File.WriteAllLines(lumpFile, lumpFileContent, Encoding.UTF8); Debug.Log($"create lump file:{lumpFile}"); } } private static List CreateLumps(string libil2cppDir, string outputDir) { BashUtil.RecreateDir(outputDir); string il2cppConfigFile = $"{libil2cppDir}/il2cpp-config.h"; var lumpFiles = new List(); int lumpFileIndex = 0; foreach (var cppDir in Directory.GetDirectories(libil2cppDir, "*", SearchOption.AllDirectories).Concat(new string[] {libil2cppDir})) { var lumpFile = new LumpFile($"{outputDir}/lump_{Path.GetFileName(cppDir)}_{lumpFileIndex}.cpp", il2cppConfigFile); foreach (var file in Directory.GetFiles(cppDir, "*.cpp", SearchOption.TopDirectoryOnly)) { lumpFile.cppFiles.Add(file); } lumpFile.SaveFile(); lumpFiles.Add(lumpFile); ++lumpFileIndex; } var mmFiles = Directory.GetFiles(libil2cppDir, "*.mm", SearchOption.AllDirectories); if (mmFiles.Length > 0) { var lumpFile = new LumpFile($"{outputDir}/lump_mm.mm", il2cppConfigFile); foreach (var file in mmFiles) { lumpFile.cppFiles.Add(file); } lumpFile.SaveFile(); lumpFiles.Add(lumpFile); } return lumpFiles; } private static List GetExtraSourceFiles(string externalDir, string libil2cppDir) { var files = new List(); foreach (string extraDir in new string[] { $"{externalDir}/zlib", $"{externalDir}/xxHash", $"{libil2cppDir}/os/ClassLibraryPAL/brotli", }) { if (!Directory.Exists(extraDir)) { continue; } files.AddRange(Directory.GetFiles(extraDir, "*.c", SearchOption.AllDirectories)); } return files; } } } #endif