private void ReplaceAssembly(string assemblyDefinitionFilePath) { Debug.LogFormat("Replacing scripts for assembly definition file {0}", assemblyDefinitionFilePath); string asmdefDirectory = Path.GetDirectoryName(assemblyDefinitionFilePath); string assemblyName = Path.GetFileNameWithoutExtension(assemblyDefinitionFilePath); Assembly assemblyToReplace = CompilationPipeline.GetAssemblies().ToList().Find(assembly => assembly.name.ToLower().Equals(assemblyName.ToLower())); string assemblyPath = assemblyToReplace.outputPath; string assemblyFileName = Path.GetFileName(assemblyPath); string[] assemblyFilePathInAssets = Directory.GetFiles("./Assets", assemblyFileName, SearchOption.AllDirectories); // save the guid/classname correspondance of the scripts that we will remove Dictionary <string, string> oldGUIDToClassNameMap = new Dictionary <string, string>(); if (assemblyFilePathInAssets.Length <= 0) { // Move all script files outside the asset folder foreach (string sourceFile in assemblyToReplace.sourceFiles) { string tempScriptPath = Path.Combine(TempSourceFilePath, sourceFile); Directory.CreateDirectory(Path.GetDirectoryName(tempScriptPath)); if (!File.Exists(sourceFile)) { Debug.LogErrorFormat("File {0} does not exist while the assembly {1} references it.", sourceFile, assemblyToReplace.name); } Debug.Log("will move " + sourceFile + " to " + tempScriptPath); // save the guid of the file because we may need to replace it later MonoScript monoScript = AssetDatabase.LoadAssetAtPath <MonoScript>(sourceFile); if (monoScript != null && monoScript.GetClass() != null) { oldGUIDToClassNameMap.Add(AssetDatabase.AssetPathToGUID(sourceFile), monoScript.GetClass().FullName); } FileUtil.MoveFileOrDirectory(sourceFile, tempScriptPath); } Debug.Log("Map of GUID/Class : \n" + String.Join("\n", oldGUIDToClassNameMap.Select(pair => pair.Key + " : " + pair.Value).ToArray())); string finalAssemblyPath = Path.Combine(asmdefDirectory, assemblyFileName); Debug.Log("will move " + assemblyPath + " to " + finalAssemblyPath); FileUtil.MoveFileOrDirectory(assemblyPath, finalAssemblyPath); string tempAsmdefPath = Path.Combine(TempSourceFilePath, Path.GetFileName(assemblyDefinitionFilePath)); Debug.Log("will move " + assemblyDefinitionFilePath + " to " + tempAsmdefPath); FileUtil.MoveFileOrDirectory(assemblyDefinitionFilePath, tempAsmdefPath); // Rename the asmdef meta file to the dll meta file so that the dll guid stays the same FileUtil.MoveFileOrDirectory(assemblyDefinitionFilePath + ".meta", finalAssemblyPath + ".meta"); pathsOfAssemblyFilesInAssetFolder.Add(finalAssemblyPath); pathsOfAssemblyFilesCreatedByUnity.Add(assemblyPath); // We need to refresh before accessing the assets in the new assembly AssetDatabase.Refresh(); // We need to remove .\ when using LoadAsslAssetsAtPath string cleanFinalAssemblyPath = finalAssemblyPath.Replace(".\\", ""); var assetsInAssembly = AssetDatabase.LoadAllAssetsAtPath(cleanFinalAssemblyPath); // list all components in the assembly file. var assemblyObjects = assetsInAssembly.OfType <MonoScript>().ToArray(); // save the new GUID and file ID for the MonoScript in the new assembly Dictionary <string, KeyValuePair <string, long> > newMonoScriptToIDsMap = new Dictionary <string, KeyValuePair <string, long> >(); // for each component, replace the guid and fileID file for (var i = 0; i < assemblyObjects.Length; i++) { long dllFileId; string dllGuid = null; if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(assemblyObjects[i], out dllGuid, out dllFileId)) { string fullClassName = assemblyObjects[i].GetClass().FullName; newMonoScriptToIDsMap.Add(fullClassName, new KeyValuePair <string, long>(dllGuid, dllFileId)); } } Debug.Log("Map of Class/GUID:FILEID : \n" + String.Join("\n", newMonoScriptToIDsMap.Select(pair => pair.Key + " : " + pair.Value.Key + " - " + pair.Value.Value).ToArray())); ReplaceIdsInAssets(oldGUIDToClassNameMap, newMonoScriptToIDsMap); } else { Debug.Log("Already found an assembly file named " + assemblyFileName + " in asset folder"); } }
public IEnumerable <Assembly> GetAssemblies(Func <string, bool> shouldFileBePartOfSolution) { // CompilationPipeline.GetAssemblies(AssembliesType.Player).Where(i => 0 < i.sourceFiles.Length && i.sourceFiles.Any(shouldFileBePartOfSolution)); return(CompilationPipeline.GetAssemblies().Where(i => 0 < i.sourceFiles.Length && i.sourceFiles.Any(shouldFileBePartOfSolution))); }
private Dictionary <string, CSProjectInfo> CreateUnityProjects(string projectOutputPath) { // Not all of these will be converted to C# objects, only the ones found to be referenced Dictionary <string, AssemblyDefinitionInfo> asmDefInfoMap = new Dictionary <string, AssemblyDefinitionInfo>(); HashSet <string> builtInPackagesWithoutSource = new HashSet <string>(); // Parse the builtInPackagesFirst DirectoryInfo builtInPackagesDirectory = new DirectoryInfo(Utilities.BuiltInPackagesPath); foreach (DirectoryInfo packageDirectory in builtInPackagesDirectory.GetDirectories()) { FileInfo[] asmDefFiles = packageDirectory.GetFiles("*.asmdef", SearchOption.AllDirectories); if (asmDefFiles.Length == 0) { builtInPackagesWithoutSource.Add(packageDirectory.Name.ToLower()); continue; } foreach (FileInfo fileInfo in asmDefFiles) { AssemblyDefinitionInfo assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(fileInfo, this, null, true); asmDefInfoMap.Add(Path.GetFileNameWithoutExtension(fileInfo.Name), assemblyDefinitionInfo); } } Dictionary <string, Assembly> unityAssemblies = CompilationPipeline.GetAssemblies().ToDictionary(t => t.name); Dictionary <string, CSProjectInfo> projectsMap = new Dictionary <string, CSProjectInfo>(); Queue <string> projectsToProcess = new Queue <string>(); // Parse the unity assemblies foreach (KeyValuePair <string, Assembly> pair in unityAssemblies) { if (!asmDefInfoMap.TryGetValue(pair.Key, out AssemblyDefinitionInfo assemblyDefinitionInfo)) { string asmDefPath = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(pair.Key); if (string.IsNullOrEmpty(asmDefPath)) { if (!pair.Key.StartsWith("Assembly-CSharp")) { throw new InvalidOperationException($"Failed to retrieve AsmDef for script assembly: {pair.Key}"); } assemblyDefinitionInfo = AssemblyDefinitionInfo.GetDefaultAssemblyCSharpInfo(pair.Value); projectsToProcess.Enqueue(pair.Key); } else { assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(new FileInfo(Utilities.GetFullPathFromKnownRelative(asmDefPath)), this, pair.Value); if (asmDefPath.StartsWith("Assets/")) { // Add as mandatory projectsToProcess.Enqueue(pair.Key); } } asmDefInfoMap.Add(pair.Key, assemblyDefinitionInfo); } } while (projectsToProcess.Count > 0) { string projectKey = projectsToProcess.Dequeue(); if (!projectsMap.ContainsKey(projectKey)) { GetProjectInfo(projectsMap, asmDefInfoMap, builtInPackagesWithoutSource, projectKey, projectOutputPath); } } // Ignore test projects when generating docs with Unity 2019 #if UNITY_2019_3_OR_NEWER projectsMap.Remove("Microsoft.MixedReality.Toolkit.Tests.EditModeTests"); projectsMap.Remove("Microsoft.MixedReality.Toolkit.Tests.PlayModeTests"); #endif return(projectsMap); }
private void OnPostBuildPlayerScriptDLLsImpl(BuildReport report) { BurstPlatformAotSettings aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(report.summary.platform); // Early exit if burst is not activated or the platform is not supported if (aotSettingsForTarget.DisableBurstCompilation || !IsSupportedPlatform(report.summary.platform)) { return; } // Collect all method signatures var methodsToCompile = BurstReflection.FindExecuteMethods(AssembliesType.Player); if (methodsToCompile.Count == 0) { return; // Nothing to do } // Prepare options // We are grouping methods per their compiler options (float precision...etc) var methodGroups = new Dictionary <string, List <string> >(); for (var i = 0; i < methodsToCompile.Count; i++) { var burstCompileTarget = methodsToCompile[i]; if (!burstCompileTarget.IsSupported) { continue; } var methodStr = BurstCompilerService.GetMethodSignature(burstCompileTarget.Method); var methodFullSignature = methodStr + "--" + Hash128.Compute(methodStr); if (aotSettingsForTarget.DisableOptimisations) { burstCompileTarget.Options.DisableOptimizations = true; } burstCompileTarget.Options.EnableBurstSafetyChecks = !aotSettingsForTarget.DisableSafetyChecks; string optionsAsStr; if (burstCompileTarget.TryGetOptionsAsString(false, out optionsAsStr)) { List <string> methodOptions; if (!methodGroups.TryGetValue(optionsAsStr, out methodOptions)) { methodOptions = new List <string>(); methodGroups.Add(optionsAsStr, methodOptions); } methodOptions.Add(GetOption(OptionAotMethod, methodFullSignature)); } } var methodGroupOptions = new List <string>(); // We should have something like this in the end: // // --group 1st group of method with the following shared options // --float-mode=xxx // --method=... // --method=... // // --group 2nd group of methods with the different shared options // --float-mode=yyy // --method=... // --method=... if (methodGroups.Count == 1) { var methodGroup = methodGroups.FirstOrDefault(); // No need to create a group if we don't have multiple methodGroupOptions.Add(methodGroup.Key); foreach (var methodOption in methodGroup.Value) { methodGroupOptions.Add(methodOption); } } else { foreach (var methodGroup in methodGroups) { methodGroupOptions.Add(GetOption(OptionGroup)); methodGroupOptions.Add(methodGroup.Key); foreach (var methodOption in methodGroup.Value) { methodGroupOptions.Add(methodOption); } } } var commonOptions = new List <string>(); var targetCpu = TargetCpu.Auto; var targetPlatform = GetTargetPlatformAndDefaultCpu(report.summary.platform, out targetCpu); commonOptions.Add(GetOption(OptionPlatform, targetPlatform)); // TODO: Add support for configuring the optimizations/CPU // TODO: Add support for per method options var stagingFolder = Path.GetFullPath(TempStagingManaged); //Debug.Log($"Burst CompileAot - To Folder {stagingFolder}"); // Prepare assembly folder list var assemblyFolders = new List <string>(); assemblyFolders.Add(stagingFolder); var playerAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Player); foreach (var assembly in playerAssemblies) { foreach (var assemblyRef in assembly.compiledAssemblyReferences) { // Exclude folders with assemblies already compiled in the `folder` var assemblyName = Path.GetFileName(assemblyRef); if (assemblyName != null && File.Exists(Path.Combine(stagingFolder, assemblyName))) { continue; } var directory = Path.GetDirectoryName(assemblyRef); if (directory != null) { var fullPath = Path.GetFullPath(directory); if (IsMonoReferenceAssemblyDirectory(fullPath) || IsDotNetStandardAssemblyDirectory(fullPath)) { // Don't pass reference assemblies to burst because they contain methods without implementation // If burst accidentally resolves them, it will emit calls to burst_abort. fullPath = Path.Combine(EditorApplication.applicationContentsPath, "MonoBleedingEdge/lib/mono/unityaot"); fullPath = Path.GetFullPath(fullPath); // GetFullPath will normalize path separators to OS native format if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } fullPath = Path.Combine(fullPath, "Facades"); if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } } else if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } } } } commonOptions.AddRange(assemblyFolders.Select(folder => GetOption(OptionAotAssemblyFolder, folder))); var combinations = new List <BurstOutputCombination>(); if (targetPlatform == TargetPlatform.macOS) { // NOTE: OSX has a special folder for the plugin // Declared in GetStagingAreaPluginsFolder // PlatformDependent\OSXPlayer\Extensions\Managed\OSXDesktopStandalonePostProcessor.cs combinations.Add(new BurstOutputCombination("UnityPlayer.app/Contents/Plugins", targetCpu)); } else if (targetPlatform == TargetPlatform.iOS) { if (Application.platform != RuntimePlatform.OSXEditor) { Debug.LogWarning("Burst Cross Compilation to iOS for standalone player, is only supported on OSX Editor at this time, burst is disabled for this build."); } else { var targetArchitecture = (IOSArchitecture)UnityEditor.PlayerSettings.GetArchitecture(report.summary.platformGroup); if (targetArchitecture == IOSArchitecture.ARMv7 || targetArchitecture == IOSArchitecture.Universal) { // PlatformDependent\iPhonePlayer\Extensions\Common\BuildPostProcessor.cs combinations.Add(new BurstOutputCombination("StaticLibraries", TargetCpu.ARMV7A_NEON32, DefaultLibraryName + "32")); } if (targetArchitecture == IOSArchitecture.ARM64 || targetArchitecture == IOSArchitecture.Universal) { // PlatformDependent\iPhonePlayer\Extensions\Common\BuildPostProcessor.cs combinations.Add(new BurstOutputCombination("StaticLibraries", TargetCpu.ARMV8A_AARCH64, DefaultLibraryName + "64")); } } } else if (targetPlatform == TargetPlatform.Android) { //TODO: would be better to query AndroidNdkRoot (but thats not exposed from unity) string ndkRoot = null; // 2019.1 now has an embedded ndk #if UNITY_2019_1_OR_NEWER if (EditorPrefs.HasKey("NdkUseEmbedded")) { if (EditorPrefs.GetBool("NdkUseEmbedded")) { ndkRoot = Path.Combine(BuildPipeline.GetPlaybackEngineDirectory(BuildTarget.Android, BuildOptions.None), "NDK"); } else { ndkRoot = EditorPrefs.GetString("AndroidNdkRootR16b"); } } #endif // If we still don't have a valid root, try the old key if (string.IsNullOrEmpty(ndkRoot)) { ndkRoot = EditorPrefs.GetString("AndroidNdkRoot"); } // Verify the directory at least exists, if not we fall back to ANDROID_NDK_ROOT current setting if (!string.IsNullOrEmpty(ndkRoot) && !Directory.Exists(ndkRoot)) { ndkRoot = null; } // Always set the ANDROID_NDK_ROOT (if we got a valid result from above), so BCL knows where to find the Android toolchain and its the one the user expects if (!string.IsNullOrEmpty(ndkRoot)) { Environment.SetEnvironmentVariable("ANDROID_NDK_ROOT", ndkRoot); } var androidTargetArch = UnityEditor.PlayerSettings.Android.targetArchitectures; if ((androidTargetArch & AndroidArchitecture.ARMv7) != 0) { combinations.Add(new BurstOutputCombination("libs/armeabi-v7a", TargetCpu.ARMV7A_NEON32)); } if ((androidTargetArch & AndroidArchitecture.ARM64) != 0) { combinations.Add(new BurstOutputCombination("libs/arm64-v8a", TargetCpu.ARMV8A_AARCH64)); } #if !UNITY_2019_2_OR_NEWER if ((androidTargetArch & AndroidArchitecture.X86) != 0) { combinations.Add(new BurstOutputCombination("libs/x86", TargetCpu.X86_SSE2)); } #endif } else if (targetPlatform == TargetPlatform.UWP) { // TODO: Make it configurable for x86 (sse2, sse4) combinations.Add(new BurstOutputCombination("Plugins/x64", TargetCpu.X64_SSE4)); combinations.Add(new BurstOutputCombination("Plugins/x86", TargetCpu.X86_SSE2)); combinations.Add(new BurstOutputCombination("Plugins/ARM", TargetCpu.THUMB2_NEON32)); combinations.Add(new BurstOutputCombination("Plugins/ARM64", TargetCpu.ARMV8A_AARCH64)); } else { combinations.Add(new BurstOutputCombination("Data/Plugins/", targetCpu)); } foreach (var combination in combinations) { // Gets the output folder var stagingOutputFolder = Path.GetFullPath(Path.Combine(TempStaging, combination.OutputPath)); var outputFilePrefix = Path.Combine(stagingOutputFolder, combination.LibraryName); var options = new List <string>(commonOptions); options.Add(GetOption(OptionAotOutputPath, outputFilePrefix)); options.Add(GetOption(OptionTarget, combination.TargetCpu)); if (targetPlatform == TargetPlatform.iOS) { options.Add(GetOption(OptionStaticLinkage)); } // finally add method group options options.AddRange(methodGroupOptions); var responseFile = Path.GetTempFileName(); File.WriteAllLines(responseFile, options); //Debug.Log("Burst compile with response file: " + responseFile); try { string generatedDebugInformationInOutput = ""; if ((report.summary.options & BuildOptions.Development) != 0) { // Workaround for clang >6 development issue (due to latest being 7.0.0) - IOS & newer PS4 SDKS are affected because its a source level IR compatability issue if ((targetPlatform != TargetPlatform.iOS) && (targetPlatform != TargetPlatform.PS4)) { generatedDebugInformationInOutput = GetOption(OptionDebug); } } BclRunner.RunManagedProgram(Path.Combine(BurstLoader.RuntimePath, BurstAotCompilerExecutable), $"{generatedDebugInformationInOutput} @{responseFile}", new BclOutputErrorParser(), report); } catch (Exception e) { // We don't expect any error, but in case we have one, we identify that it is burst and we print the details here Debug.LogError("Unexpected error while running the burst compiler: " + e); } } }
public IEnumerable <AssemblyInfo> Compile(IProgressBar progressBar = null) { #if UNITY_2018_1_OR_NEWER var assemblies = CompilationPipeline.GetAssemblies(AssembliesType.Player); #else var assemblies = CompilationPipeline.GetAssemblies(); #endif #if UNITY_2018_2_OR_NEWER if (progressBar != null) { var numAssemblies = assemblies.Length; progressBar.Initialize("Assembly Compilation", "Compiling project scripts", numAssemblies); m_OnAssemblyCompilationStarted = (s) => { progressBar.AdvanceProgressBar(Path.GetFileName(s)); }; CompilationPipeline.assemblyCompilationStarted += m_OnAssemblyCompilationStarted; } CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; m_OutputFolder = FileUtil.GetUniqueTempPathInProject(); var input = new ScriptCompilationSettings { target = EditorUserBuildSettings.activeBuildTarget, group = EditorUserBuildSettings.selectedBuildTargetGroup }; var compilationResult = PlayerBuildInterface.CompilePlayerScripts(input, m_OutputFolder); if (progressBar != null) { progressBar.ClearProgressBar(); } if (!m_Success) { Dispose(); throw new AssemblyCompilationException(); } var compiledAssemblyPaths = compilationResult.assemblies.Select(assembly => Path.Combine(m_OutputFolder, assembly)); #else // fallback to CompilationPipeline assemblies var compiledAssemblyPaths = CompilationPipeline.GetAssemblies() .Where(a => a.flags != AssemblyFlags.EditorAssembly).Select(assembly => assembly.outputPath); #endif var assemblyInfos = new List <AssemblyInfo>(); foreach (var compiledAssemblyPath in compiledAssemblyPaths) { var assemblyInfo = AssemblyHelper.GetAssemblyInfoFromAssemblyPath(compiledAssemblyPath); var assembly = assemblies.First(a => a.name.Equals(assemblyInfo.name)); var sourcePaths = assembly.sourceFiles.Select(file => file.Remove(0, assemblyInfo.relativePath.Length + 1)); assemblyInfo.sourcePaths = sourcePaths.ToArray(); assemblyInfos.Add(assemblyInfo); } return(assemblyInfos); }
private static HashSet <string> GetReferencedAssemblyNameSet() { if (s_referencedAssemblyNameSet != null) { return(s_referencedAssemblyNameSet); } s_referencedAssemblyNameSet = new HashSet <string>(); Assembly playerAssembly = typeof(VRModule).Assembly; Assembly editorAssembly = typeof(VRModuleManagerEditor).Assembly; // C# player referenced assemblies foreach (AssemblyName asmName in playerAssembly.GetReferencedAssemblies()) { s_referencedAssemblyNameSet.Add(asmName.Name); } // C# editor referenced assemblies foreach (AssemblyName asmName in editorAssembly.GetReferencedAssemblies()) { s_referencedAssemblyNameSet.Add(asmName.Name); } #if UNITY_2018_1_OR_NEWER // Unity player referenced assemblies UnityEditor.Compilation.Assembly playerUnityAsm = FindUnityAssembly(playerAssembly.GetName().Name, AssembliesType.Player); if (playerUnityAsm != null) { foreach (UnityEditor.Compilation.Assembly asm in playerUnityAsm.assemblyReferences) { s_referencedAssemblyNameSet.Add(asm.name); } } else { Debug.LogWarning("Player assembly not found."); } // Unity editor referenced assemblies UnityEditor.Compilation.Assembly editorUnityAsm = FindUnityAssembly(editorAssembly.GetName().Name, AssembliesType.Editor); if (editorUnityAsm != null) { foreach (UnityEditor.Compilation.Assembly asm in editorUnityAsm.assemblyReferences) { s_referencedAssemblyNameSet.Add(asm.name); } } else { Debug.LogWarning("Editor assembly not found."); } #elif UNITY_2017_3_OR_NEWER UnityEditor.Compilation.Assembly[] assemblies = CompilationPipeline.GetAssemblies(); foreach (UnityEditor.Compilation.Assembly asm in assemblies) { s_referencedAssemblyNameSet.Add(asm.name); } #endif return(s_referencedAssemblyNameSet); }
public void OnPostBuildPlayerScriptDLLs(BuildReport report) { BurstPlatformAotSettings aotSettingsForTarget = BurstPlatformAotSettings.GetOrCreateSettings(report.summary.platform); // Early exit if burst is not activated or the platform is not supported if (aotSettingsForTarget.DisableBurstCompilation || !IsSupportedPlatform(report.summary.platform)) { return; } // Collect all method signatures var methodsToCompile = BurstReflection.FindExecuteMethods(AssembliesType.Player); if (methodsToCompile.Count == 0) { return; // Nothing to do } // Prepare options var commonOptions = new List <string>(); for (var i = 0; i < methodsToCompile.Count; i++) { var burstCompileTarget = methodsToCompile[i]; if (!burstCompileTarget.SupportsBurst) { continue; } var methodStr = BurstCompilerService.GetMethodSignature(burstCompileTarget.Method); var methodFullSignature = methodStr + "--" + Hash128.Compute(methodStr); commonOptions.Add(GetOption(OptionAotMethod, methodFullSignature)); } var targetCpu = TargetCpu.Auto; var targetPlatform = GetTargetPlatformAndDefaultCpu(report.summary.platform, out targetCpu); commonOptions.Add(GetOption(OptionPlatform, targetPlatform)); if (!BurstEditorOptions.EnableBurstSafetyChecks) { commonOptions.Add(GetOption(OptionDisableSafetyChecks)); } // TODO: Add support for configuring the optimizations/CPU // TODO: Add support for per method options var stagingFolder = Path.GetFullPath(TempStagingManaged); //Debug.Log($"Burst CompileAot - To Folder {stagingFolder}"); // Prepare assembly folder list var assemblyFolders = new List <string>(); assemblyFolders.Add(stagingFolder); var playerAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Player); foreach (var assembly in playerAssemblies) { foreach (var assemblyRef in assembly.compiledAssemblyReferences) { // Exclude folders with assemblies already compiled in the `folder` var assemblyName = Path.GetFileName(assemblyRef); if (assemblyName != null && File.Exists(Path.Combine(stagingFolder, assemblyName))) { continue; } var directory = Path.GetDirectoryName(assemblyRef); if (directory != null) { var fullPath = Path.GetFullPath(directory); if (IsMonoReferenceAssemblyDirectory(fullPath) || IsDotNetStandardAssemblyDirectory(fullPath)) { // Don't pass reference assemblies to burst because they contain methods without implementation // If burst accidentally resolves them, it will emit calls to burst_abort. fullPath = Path.Combine(EditorApplication.applicationContentsPath, "MonoBleedingEdge/lib/mono/unityaot"); fullPath = Path.GetFullPath(fullPath); // GetFullPath will normalize path separators to OS native format if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } fullPath = Path.Combine(fullPath, "Facades"); if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } } else if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } } } } commonOptions.AddRange(assemblyFolders.Select(folder => GetOption(OptionAotAssemblyFolder, folder))); // Gets platform specific IL2CPP plugin folder // Only the following platforms are providing a dedicated Tools directory switch (report.summary.platform) { case BuildTarget.XboxOne: case BuildTarget.PS4: case BuildTarget.Android: case BuildTarget.iOS: var pluginFolder = BuildPipeline.GetBuildToolsDirectory(report.summary.platform); commonOptions.Add(GetOption(OptionAotIL2CPPPluginFolder, pluginFolder)); break; } var combinations = new List <BurstOutputCombination>(); if (targetPlatform == TargetPlatform.macOS) { // NOTE: OSX has a special folder for the plugin // Declared in GetStagingAreaPluginsFolder // PlatformDependent\OSXPlayer\Extensions\Managed\OSXDesktopStandalonePostProcessor.cs combinations.Add(new BurstOutputCombination("UnityPlayer.app/Contents/Plugins", targetCpu)); } else if (targetPlatform == TargetPlatform.iOS) { var targetArchitecture = (IOSArchitecture)UnityEditor.PlayerSettings.GetArchitecture(report.summary.platformGroup); if (targetArchitecture == IOSArchitecture.ARMv7 || targetArchitecture == IOSArchitecture.Universal) { // PlatformDependent\iPhonePlayer\Extensions\Common\BuildPostProcessor.cs combinations.Add(new BurstOutputCombination("StaticLibraries", TargetCpu.ARMV7A_NEON32, DefaultLibraryName + "32")); } if (targetArchitecture == IOSArchitecture.ARM64 || targetArchitecture == IOSArchitecture.Universal) { // PlatformDependent\iPhonePlayer\Extensions\Common\BuildPostProcessor.cs combinations.Add(new BurstOutputCombination("StaticLibraries", TargetCpu.ARMV8A_AARCH64, DefaultLibraryName + "64")); } } else if (targetPlatform == TargetPlatform.Android) { // Set the ANDROID_NDK_ROOT so IL2CPP knows where to find the Android toolchain if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ANDROID_NDK_ROOT"))) { var ndkRoot = EditorPrefs.GetString("AndroidNdkRoot"); if (!string.IsNullOrEmpty(ndkRoot)) { Environment.SetEnvironmentVariable("ANDROID_NDK_ROOT", ndkRoot); } } var androidTargetArch = UnityEditor.PlayerSettings.Android.targetArchitectures; if ((androidTargetArch & AndroidArchitecture.ARMv7) != 0) { combinations.Add(new BurstOutputCombination("libs/armeabi-v7a", TargetCpu.ARMV7A_NEON32)); } if ((androidTargetArch & AndroidArchitecture.ARM64) != 0) { combinations.Add(new BurstOutputCombination("libs/arm64-v8a", TargetCpu.ARMV8A_AARCH64)); } if ((androidTargetArch & AndroidArchitecture.X86) != 0) { combinations.Add(new BurstOutputCombination("libs/x86", TargetCpu.X86_SSE2)); } } else if (targetPlatform == TargetPlatform.UWP) { // TODO: Make it configurable for x86 (sse2, sse4) combinations.Add(new BurstOutputCombination("Plugins/x64", TargetCpu.X64_SSE4)); combinations.Add(new BurstOutputCombination("Plugins/x86", TargetCpu.X86_SSE2)); combinations.Add(new BurstOutputCombination("Plugins/ARM", TargetCpu.THUMB2_NEON32)); combinations.Add(new BurstOutputCombination("Plugins/ARM64", TargetCpu.ARMV8A_AARCH64)); } else { combinations.Add(new BurstOutputCombination("Data/Plugins/", targetCpu)); } foreach (var combination in combinations) { // Gets the output folder var stagingOutputFolder = Path.GetFullPath(Path.Combine(TempStaging, combination.OutputPath)); var outputFilePrefix = Path.Combine(stagingOutputFolder, combination.LibraryName); var options = new List <string>(commonOptions); options.Add(GetOption(OptionAotOutputPath, outputFilePrefix)); options.Add(GetOption(OptionTarget, combination.TargetCpu)); if (aotSettingsForTarget.DisableOptimisations) { options.Add(GetOption(OptionDisableOpt)); } if (aotSettingsForTarget.DisableSafetyChecks) { options.Add(GetOption(OptionDisableSafetyChecks)); } else { options.Add(GetOption(OptionSafetyChecks)); } if (targetPlatform == TargetPlatform.iOS) { options.Add(GetOption(OptionStaticLinkage)); } var responseFile = Path.GetTempFileName(); File.WriteAllLines(responseFile, options); //Debug.Log("Burst compile with response file: " + responseFile); try { Runner.RunManagedProgram(Path.Combine(BurstLoader.RuntimePath, BurstAotCompilerExecutable), "--debug=true " + "@" + responseFile, Application.dataPath + "/..", new BclParser(), null); } catch (Exception e) { Debug.LogError(e.ToString()); } } }
static void BuildTypeTreeTools() { var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = true, IndentChars = " ", }; using (var xw = XmlWriter.Create(Path.Combine(ProjectDirectory, "Generated.props"), settings)) { xw.WriteStartDocument(); xw.WriteStartElement("Project"); xw.WriteStartElement("PropertyGroup"); var version = Application.unityVersion; var split = Application.unityVersion.Split(VersionSplitChars, StringSplitOptions.RemoveEmptyEntries); xw.WriteStartElement("EditorVersion"); xw.WriteString(version); xw.WriteEndElement(); xw.WriteStartElement("EditorVersionMajor"); xw.WriteString(split[0]); xw.WriteEndElement(); xw.WriteStartElement("EditorVersionMinor"); xw.WriteString(split[1]); xw.WriteEndElement(); xw.WriteStartElement("EditorContentsDir"); xw.WriteString(EditorApplication.applicationContentsPath); xw.WriteEndElement(); foreach (var assembly in CompilationPipeline.GetAssemblies()) { if (assembly.name != "Assembly-CSharp-Editor") { continue; } var defines = string.Join(";", assembly.defines); xw.WriteStartElement("DefineConstants"); xw.WriteString(defines); xw.WriteEndElement(); xw.WriteEndElement(); xw.WriteStartElement("ItemGroup"); foreach (var reference in assembly.allReferences) { var name = Path.GetFileNameWithoutExtension(reference); var path = Path.GetFullPath(reference); if (name == ProjectName) { continue; } xw.WriteStartElement("Reference"); xw.WriteAttributeString("Private", bool.FalseString); xw.WriteAttributeString("Include", name); xw.WriteAttributeString("HintPath", path); xw.WriteEndElement(); } } xw.WriteEndElement(); xw.WriteEndElement(); xw.WriteEndDocument(); } var process = new Process { StartInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = "build", WorkingDirectory = ProjectDirectory } }; process.Start(); process.WaitForExit(); }
public AssemblySelector(Options options) { if (options == null) { throw new ArgumentException("options must not be null", "options"); } if (options.compiledAssemblies == null) { throw new ArgumentException( "options.compiledAssemblies must not be null", "options"); } if (options.assemblies == null) { throw new ArgumentException( "options.assemblies must not be null", "options"); } if (Application.dataPath == null) { throw new ArgumentException("Application.dataPath must not be null"); } foreach (string assemblyName in options.compiledAssemblies) { _compiledAssemblyPaths.Add(FindDllLocation(assemblyName)); } foreach (string assemblyName in options.assemblies) { _assemblyPaths.Add(FindDllLocation(assemblyName)); } #if UNITY_2017_3_OR_NEWER if (!options.includeCompilationPipelineAssemblies) { return; } string projectDir = Path.GetDirectoryName(Application.dataPath); #if UNITY_2018_1_OR_NEWER foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies(AssembliesType.Player)) { #else foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies()) { if ((assembly.flags & AssemblyFlags.EditorAssembly) != 0) { continue; } #endif if (assembly.name.Contains("-firstpass")) { continue; } if (assembly.sourceFiles.Length == 0) { continue; } if (assembly.sourceFiles[0].StartsWith("Packages")) { continue; } string dllLocation = Path.Combine(projectDir, assembly.outputPath).Replace('\\', '/'); // If the assembly is for a different build target platform, oddly it will still be in the compilation // pipeline, however the file won't actually exist. if (File.Exists(dllLocation)) { _assemblyPaths.Add(dllLocation); } } #endif }
protected override AdvancedDropdownItem BuildRoot() { AdvancedDropdownItem root = new AdvancedDropdownItem("Assemblies"); Dictionary <Group, AdvancedDropdownItem> groupDropdowns = new Dictionary <Group, AdvancedDropdownItem>(new Group.Comparer()); var allAssemblies = AppDomain.CurrentDomain.GetAssemblies().OrderBy(assembly => assembly.FullName); // Populate Unity-compiled assemblies. // This includes assemblies in the Assets and Packages directories that are not plugins. UAssembly[] assemblies = CompilationPipeline.GetAssemblies(); Dictionary <string, UAssembly> nameToAssembly = new Dictionary <string, UAssembly>(); foreach (UAssembly assembly in assemblies) { nameToAssembly.Add(assembly.name, assembly); } // Append root locations foreach (Location location in Enum.GetValues(typeof(Location))) { var locationRoot = new AdvancedDropdownItem(location.ToString()); root.AddChild(locationRoot); groupDropdowns.Add(new Group(location), locationRoot); } foreach (Assembly assembly in allAssemblies) { Group group = GetGroup(assembly, nameToAssembly); Type[] types = assembly.GetTypes(); List <Type> filteredTypes = new List <Type>(); foreach (Type type in types) { bool requirementsMet = true; foreach (Type constraint in constraints) { if (!type.IsSubclassOf(constraint) && type != constraint) { requirementsMet = false; } } foreach (Type requiredInterface in requiredInterfaces) { if (!type.GetInterfaces().Contains(requiredInterface)) { requirementsMet = false; } } if (requirementsMet) { filteredTypes.Add(type); } } if (filteredTypes.Count != 0) { if (!groupDropdowns.TryGetValue(group, out AdvancedDropdownItem groupRoot)) { groupDropdowns.Add(group, groupRoot = new AdvancedDropdownItem(group.Context)); groupDropdowns[new Group(group.Location)].AddChild(groupRoot); } string assemblyName = assembly.GetName().Name; var assemblyDropdownItem = new AdvancedDropdownItem(assemblyName); groupRoot.AddChild(assemblyDropdownItem); foreach (Type type in filteredTypes) { assemblyDropdownItem.AddChild(new TypeDropdownItem(type)); } } } root.AddSeparator(); AdvancedDropdownItem initializeOnLoad = new AdvancedDropdownItem("Initialize On Load"); foreach (Type type in TypeCache.GetTypesWithAttribute <InitializeOnLoadAttribute>()) { initializeOnLoad.AddChild(new TypeDropdownItem(type)); } foreach (MethodInfo method in TypeCache.GetMethodsWithAttribute <InitializeOnLoadMethodAttribute>()) { initializeOnLoad.AddChild(new TypeDropdownItem(method.DeclaringType)); } root.AddChild(initializeOnLoad); AdvancedDropdownItem runtimeInitializeOnLoad = new AdvancedDropdownItem("Runtime Initialize On Load"); foreach (MethodInfo method in TypeCache.GetMethodsWithAttribute <RuntimeInitializeOnLoadMethodAttribute>()) { runtimeInitializeOnLoad.AddChild(new TypeDropdownItem(method.DeclaringType)); } root.AddChild(runtimeInitializeOnLoad); return(root); }
static DateTime GetAssemblyBuildTime(string assemblyName) { var assembly = CompilationPipeline.GetAssemblies(AssembliesType.PlayerWithoutTestAssemblies).FirstOrDefault(a => a.name == assemblyName); return(assembly != null?File.GetLastWriteTimeUtc(assembly.outputPath) : DateTime.MinValue); }
private static void TryWeaveAssembly(string assPath) { //check if assembly is editor only for applying the InitializeOnLoadMethodAttribute method instead of RuntimeInitializeOnLoadMethodAttribute. //used mainly assemblies that run tests. bool isEditor = CompilationPipeline.GetAssemblies().Any(a => a.flags == AssemblyFlags.EditorAssembly && assPath.EndsWith(a.outputPath)); using (var assembly = AssemblyDefinition.ReadAssembly(assPath, new ReaderParameters() { ReadWrite = true, ReadingMode = ReadingMode.Immediate, AssemblyResolver = new DefaultAssemblyResolver(), SymbolReaderProvider = new PdbReaderProvider(), //need to keep it in memory so we can write it back to the file. Otherwise it throws a sharing violation. InMemory = true, ReadSymbols = true })) { var sourceModule = assembly.MainModule; var injectionModule = assembly.MainModule; var attributeType = isEditor ? typeof(InitializeOnLoadMethodAttribute) : typeof(RuntimeInitializeOnLoadMethodAttribute); var construction = injectionModule.ImportReference(attributeType.GetConstructor(Type.EmptyTypes)); var customAttribute = new CustomAttribute(injectionModule.ImportReference(construction)); var containerParameter = new ParameterDefinition("container", ParameterAttributes.None, injectionModule.ImportReference(typeof(Container))); var constructorTypes = new List <TypeDefinition>(); var injectionTypes = new List <TypeDefinition>(); foreach (var type in sourceModule.GetTypes()) { var injectRef = sourceModule.ImportReference(typeof(InjectAttribute)); if (NeedsConstructor(type, injectRef)) { constructorTypes.Add(type); Debug.Log($"Baking Factory for type: {type.FullName}"); } if (NeedsFields(type, injectRef)) { injectionTypes.Add(type); Debug.Log($"Baking Injector for type: {type.FullName}"); } } if (constructorTypes.Count > 0) { var injectAttributeRef = injectionModule.ImportReference(typeof(InjectAttribute)); var factoryMethods = new List <KeyValuePair <TypeReference, MethodDefinition> >(); var injectionMethods = new List <KeyValuePair <TypeReference, MethodDefinition> >(); //type where all static injection baking processing is done. var typeAdder = new TypeDefinition("Injection", "Baker", TypeAttributes.Class | TypeAttributes.Public, injectionModule.TypeSystem.Object); injectionModule.Types.Add(typeAdder); //method where all registration is done. var bakerMethod = new MethodDefinition("BakeInjection", MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.HideBySig, injectionModule.TypeSystem.Void); typeAdder.Methods.Add(bakerMethod); //create factories for constructor marked with the inject attribute. foreach (var type in constructorTypes) { ExposeType(type); var typeRef = injectionModule.ImportReference(type); var factoryMethod = new MethodDefinition(type.Name + "FactoryMethod", MethodAttributes.Static | MethodAttributes.Assembly, injectionModule.TypeSystem.Object); factoryMethod.Parameters.Add(containerParameter); type.Methods.Add(factoryMethod); CreateFactoryMethodBody(factoryMethod, type, injectionModule, injectAttributeRef); factoryMethods.Add(new KeyValuePair <TypeReference, MethodDefinition>(typeRef, factoryMethod)); } //create injection static methods that resolve each field marked with inject attribute. foreach (var type in injectionTypes) { ExposeType(type); var typeRef = injectionModule.ImportReference(type); var injectionMethod = new MethodDefinition(type.Name + "InjectionMethod", MethodAttributes.Static | MethodAttributes.Assembly, injectionModule.TypeSystem.Void); injectionMethod.Parameters.Add(new ParameterDefinition("instance", ParameterAttributes.None, injectionModule.TypeSystem.Object)); injectionMethod.Parameters.Add(containerParameter); type.Methods.Add(injectionMethod); CreateInjectionMethodBody(injectionMethod, type, injectionModule, injectAttributeRef); injectionMethods.Add(new KeyValuePair <TypeReference, MethodDefinition>(typeRef, injectionMethod)); } CreateBakeMethodBody(bakerMethod, factoryMethods, injectionMethods, injectionModule); bakerMethod.CustomAttributes.Add(customAttribute); var writeParams = new WriterParameters() { //write symbols for debugging to work WriteSymbols = true, SymbolWriterProvider = new PdbWriterProvider() }; assembly.Write(assPath, writeParams); } } }
private static Assembly[] GetAllProjectAssemblies() { Assembly[] assemblies = CompilationPipeline.GetAssemblies(); Array.Sort(assemblies, (x, y) => String.Compare(x.name, y.name)); return(assemblies); }
public UnityProjectInfo(IEnumerable <CompilationPlatformInfo> availablePlatforms, string projectOutputPath) { this.availablePlatforms = availablePlatforms; Dictionary <string, Assembly> unityAssemblies = CompilationPipeline.GetAssemblies().ToDictionary(t => t.name); Dictionary <string, CSProjectInfo> csProjects = new Dictionary <string, CSProjectInfo>(); CSProjects = new ReadOnlyDictionary <string, CSProjectInfo>(csProjects); foreach (KeyValuePair <string, Assembly> pair in unityAssemblies) { CSProjectInfo toAdd; string asmDefPath = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(pair.Key); if (string.IsNullOrEmpty(asmDefPath)) { if (!pair.Key.StartsWith("Assembly-CSharp")) { Debug.LogError($"Failed to retrieve AsmDef for script assembly: {pair.Key}"); } toAdd = new CSProjectInfo(availablePlatforms, Guid.NewGuid(), null, pair.Value, projectOutputPath); } else { string guid = AssetDatabase.AssetPathToGUID(asmDefPath); if (!Guid.TryParse(guid, out Guid guidResult)) { Debug.LogError($"Failed to get GUID of the AsmDef at '{asmDefPath}' for assembly: {pair.Key}"); } else { guidResult = Guid.NewGuid(); } AssemblyDefinitionAsset assemblyDefinitionAsset = AssetDatabase.LoadAssetAtPath <AssemblyDefinitionAsset>(asmDefPath); AssemblyDefinitionInfo assemblyDefinitionInfo = assemblyDefinitionAsset == null ? null : JsonUtility.FromJson <AssemblyDefinitionInfo>(assemblyDefinitionAsset.text); assemblyDefinitionInfo?.Validate(availablePlatforms); toAdd = new CSProjectInfo(availablePlatforms, guidResult, assemblyDefinitionInfo, pair.Value, projectOutputPath); } csProjects.Add(pair.Key, toAdd); } Plugins = new ReadOnlyCollection <PluginAssemblyInfo>(ScanForPluginDLLs()); foreach (PluginAssemblyInfo plugin in Plugins) { if (plugin.Type == PluginType.Native) { Debug.LogWarning($"Native plugin {plugin.ReferencePath.AbsolutePath} not yet supported for MSBuild project."); } } foreach (CSProjectInfo project in CSProjects.Values) { // Get the assembly references first from AssemblyDefinitionInfo if available (it's actually more correct), otherwise fallback to Assemby IEnumerable <string> references = project.AssemblyDefinitionInfo == null ? project.Assembly.assemblyReferences.Select(t => t.name) : (project.AssemblyDefinitionInfo.references ?? Array.Empty <string>()); foreach (string reference in references) { if (CSProjects.TryGetValue(reference, out CSProjectInfo dependency)) { project.AddDependency(dependency); } else { Debug.LogError($"Failed to get dependency '{reference}' for project '{project.Name}'."); } } foreach (PluginAssemblyInfo plugin in Plugins) { if (plugin.AutoReferenced && plugin.Type != PluginType.Native) { project.AddDependency(plugin); } } } }
public IEnumerable <UnityEditor.Compilation.Assembly> GetAssemblies() { return(CompilationPipeline. GetAssemblies(AssembliesType.Editor).Where(WillProcess)); }
public void SetupCodegeneration(BuildContext context, Mode mode) { var classicContext = context.GetValue <IncrementalClassicSharedData>(); var assemblyGraph = new List <Assembly>(CompilationPipeline.GetAssemblies(AssembliesType.PlayerWithoutTestAssemblies)); var editorAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Editor); //codegen assemblies are not part of the CompilationPipeline.GetAssemblies(Player) graph. we need to grab them from the editor one. //it would be kind of a waste to compile all the many assemblies they reference from the editorgraph, as they are all also in the player one. var codeGenAssemblies = editorAssemblies.Where(e => e.IsCodeGenAssembly()) .Select(assembly => TransplantFromEditorGraphIntoPlayerGraph(assembly, assemblyGraph)).ToList(); var assembliesToCompile = assemblyGraph.Where(a => !Path.GetFileName(a.outputPath).Contains("Test")) .OrderByDependencies().ToList(); //We should probably at some point switch back to using the roslyn that ships in the editor, however that has a bug where it crashes //with /refout on our postprocessing code. To work around that for now, we're going to compile with the latest roslyn from stevedore. var csharpCompiler = Csc.Latest; //new UnityEditorCsc CSharpProgram.DefaultConfig = new CSharpProgramConfiguration(CSharpCodeGen.Release, csharpCompiler, DebugFormat.PortablePdb); Dictionary <Assembly, (CSharpProgram program, DotNetAssembly assembly)> unityAssemblyToCSharpProgramAndBuiltAssembly = SetupCSharpProgramsFor(context, assembliesToCompile); ScriptAssembliesJsonGenerator.Setup(unityAssemblyToCSharpProgramAndBuiltAssembly, classicContext.DataDeployDirectory); var postProcessedPlayerAssemblies = SetupPostProcessPlayerAssembliesFor(assembliesToCompile, classicContext, codeGenAssemblies, unityAssemblyToCSharpProgramAndBuiltAssembly, context.UsesIL2CPP()); var playerAssemblies = postProcessedPlayerAssemblies.Where(kvp => !IsEditorAssembly(kvp.unityAssembly)).Select(w => w.dotNetAssembly).ToArray(); SetupTypeResourcesFor(playerAssemblies, classicContext.DataDeployDirectory, classicContext.TypeDBOutputDirectory); if (mode == Mode.EnoughToProduceTypeDB) { return; } postProcessedPlayerAssemblies.FilterByBool(p => IsExternal(p.unityAssembly), out var external, out var locals); var localAssemblies = locals.Select(l => l.dotNetAssembly).ToArray(); var externalAssemblies = external.Select(l => l.dotNetAssembly).ToArray(); var burstSettings = context.GetOrCreateValue <BurstSettings>(); using (new ProfilerMarker(nameof(BurstCompiler)).Auto()) { foreach (var arch in classicContext.Architectures) { var a = arch.Value; var burstCompiler = new BurstCompiler(a.BurstTarget, classicContext.PlatformName, a.DynamicLibraryDeployDirectory); switch (burstSettings.BurstGranularity) { case BurstGranularity.One: burstCompiler.Setup(arch.Key, localAssemblies.Concat(externalAssemblies).ToArray(), 0, "wholeprogram", burstSettings.EnvironmentVariables, BurstCompiler.BurstOutputMode.SingleLibrary); break; case BurstGranularity.OnePerJob: int assemblyIndex = 0; //compile all exeternal assemblies into one big burst library burstCompiler.Setup(arch.Key, externalAssemblies, assemblyIndex++, "externalassemblies", burstSettings.EnvironmentVariables, BurstCompiler.BurstOutputMode.SingleLibrary); //and the local ones, in one burst library per assembly. foreach (var localAssembly in localAssemblies) { var producedLibraries = burstCompiler.Setup(arch.Key, new[] { localAssembly }, assemblyIndex, localAssembly.Path.FileNameWithoutExtension, burstSettings.EnvironmentVariables, BurstCompiler.BurstOutputMode.LibraryPerJob); if (producedLibraries.Length > 0) { assemblyIndex++; } } break; } } } var copiedPrebuiltAssemblies = SetupCopyPrebuiltAssemblies(classicContext, GetDestinationDirectoryForManagedAssemblies(classicContext, context.UsesIL2CPP()), assemblyGraph, context.UsesIL2CPP()).ToList(); context.SetValue(new Il2CppInputAssemblies() { prebuiltAssemblies = copiedPrebuiltAssemblies, processedAssemblies = postProcessedPlayerAssemblies }); }
public void OnPostBuildPlayerScriptDLLs(BuildReport report) { // Early exit if burst is not activated or the platform is not supported if (!BurstEditorOptions.EnableBurstCompilation || !IsSupportedPlatform(report.summary.platform)) { return; } // Collect all method signatures var methodsToCompile = BurstReflection.FindExecuteMethods(AssembliesType.Player); if (methodsToCompile.Count == 0) { return; // Nothing to do } // Prepare options var commonOptions = new List <string>(); for (var i = 0; i < methodsToCompile.Count; i++) { var burstCompileTarget = methodsToCompile[i]; if (!burstCompileTarget.SupportsBurst) { continue; } var methodStr = BurstCompilerService.GetMethodSignature(burstCompileTarget.Method); var methodFullSignature = methodStr + "--" + Hash128.Compute(methodStr); commonOptions.Add(GetOption(OptionAotMethod, methodFullSignature)); } var targetCpu = TargetCpu.Auto; var targetPlatform = GetTargetPlatformAndDefaultCpu(report.summary.platform, out targetCpu); commonOptions.Add(GetOption(OptionPlatform, targetPlatform)); if (!BurstEditorOptions.EnableBurstSafetyChecks) { commonOptions.Add(GetOption(OptionDisableSafetyChecks)); } // TODO: Add support for configuring the optimizations/CPU // TODO: Add support for per method options var stagingFolder = Path.GetFullPath(TempStagingManaged); //Debug.Log($"Burst CompileAot - To Folder {stagingFolder}"); // Prepare assembly folder list var assemblyFolders = new List <string>(); assemblyFolders.Add(stagingFolder); var playerAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Player); foreach (var assembly in playerAssemblies) { foreach (var assemblyRef in assembly.compiledAssemblyReferences) { // Exclude folders with assemblies already compiled in the `folder` var assemblyName = Path.GetFileName(assemblyRef); if (assemblyName != null && File.Exists(Path.Combine(stagingFolder, assemblyName))) { continue; } var directory = Path.GetDirectoryName(assemblyRef); if (directory != null) { var fullPath = Path.GetFullPath(directory); if (!assemblyFolders.Contains(fullPath)) { assemblyFolders.Add(fullPath); } } } } commonOptions.AddRange(assemblyFolders.Select(folder => GetOption(OptionAotAssemblyFolder, folder))); // Gets platform specific IL2CPP plugin folder // Only the following platforms are providing a dedicated Tools directory switch (report.summary.platform) { case BuildTarget.XboxOne: case BuildTarget.PS4: case BuildTarget.Android: case BuildTarget.iOS: var pluginFolder = BuildPipeline.GetBuildToolsDirectory(report.summary.platform); commonOptions.Add(GetOption(OptionAotIL2CPPPluginFolder, pluginFolder)); break; } var combinations = new List <BurstOutputCombination>(); if (targetPlatform == TargetPlatform.macOS) { // NOTE: OSX has a special folder for the plugin // Declared in GetStagingAreaPluginsFolder // PlatformDependent\OSXPlayer\Extensions\Managed\OSXDesktopStandalonePostProcessor.cs combinations.Add(new BurstOutputCombination("UnityPlayer.app/Contents/Plugins", targetCpu)); } else if (targetPlatform == TargetPlatform.iOS) { // Check if we are under il2cpp as we may have to force a CPU backend for it // TODO: Should use report.summary.platformGroup instead? bool isUsingIL2CPP = PlayerSettings.GetScriptingBackend(BuildTargetGroup.Standalone) == ScriptingImplementation.IL2CPP; if (!isUsingIL2CPP) { var targetArchitecture = (IOSArchitecture)UnityEditor.PlayerSettings.GetArchitecture(report.summary.platformGroup); switch (targetArchitecture) { case IOSArchitecture.ARMv7: targetCpu = TargetCpu.ARMV7A_NEON32; break; case IOSArchitecture.ARM64: targetCpu = TargetCpu.ARMV8A_AARCH64; break; case IOSArchitecture.Universal: // TODO: How do we proceed here? targetCpu = TargetCpu.ARMV7A_NEON32; break; } } // PlatformDependent\iPhonePlayer\Extensions\Common\BuildPostProcessor.cs combinations.Add(new BurstOutputCombination("Frameworks", targetCpu)); } else if (targetPlatform == TargetPlatform.Android) { // Set the ANDROID_NDK_ROOT so IL2CPP knows where to find the Android toolchain var ndkRoot = EditorPrefs.GetString("AndroidNdkRoot"); if (!string.IsNullOrEmpty(ndkRoot)) { Environment.SetEnvironmentVariable("ANDROID_NDK_ROOT", ndkRoot); } var androidTargetArch = UnityEditor.PlayerSettings.Android.targetArchitectures; if ((androidTargetArch & AndroidArchitecture.ARMv7) != 0) { combinations.Add(new BurstOutputCombination("libs/armeabi-v7a", TargetCpu.ARMV7A_NEON32)); } if ((androidTargetArch & AndroidArchitecture.ARM64) != 0) { combinations.Add(new BurstOutputCombination("libs/arm64-v8a", TargetCpu.ARMV8A_AARCH64)); } if ((androidTargetArch & AndroidArchitecture.X86) != 0) { combinations.Add(new BurstOutputCombination("libs/x86", TargetCpu.X86_SSE2)); } } else if (targetPlatform == TargetPlatform.UWP) { // TODO: Make it configurable for x86 (sse2, sse4) combinations.Add(new BurstOutputCombination("Plugins/x64", TargetCpu.X64_SSE4)); combinations.Add(new BurstOutputCombination("Plugins/x86", TargetCpu.X86_SSE2)); combinations.Add(new BurstOutputCombination("Plugins/ARM", TargetCpu.THUMB2_NEON32)); } else { combinations.Add(new BurstOutputCombination("Data/Plugins/", targetCpu)); } foreach (var combination in combinations) { // Gets the output folder var stagingOutputFolder = Path.GetFullPath(Path.Combine(TempStaging, combination.OutputPath)); var outputFilePrefix = Path.Combine(stagingOutputFolder, DefaultLibraryName); var options = new List <string>(commonOptions); options.Add(GetOption(OptionAotOutputPath, outputFilePrefix)); options.Add(GetOption(OptionTarget, combination.TargetCpu)); var responseFile = Path.GetTempFileName(); File.WriteAllLines(responseFile, options); //Debug.Log("Burst compile with response file: " + responseFile); Runner.RunManagedProgram(Path.Combine(BurstLoader.RuntimePath, BurstAotCompilerExecutable), "@" + responseFile, Application.dataPath + "/..", new BclParser(), null); } }
private static IEnumerable <Assembly> GetAllAssemblies() => CompilationPipeline.GetAssemblies(AssembliesType.Editor) .GroupBy(assembly => assembly.outputPath) .Select(grouping => grouping.First());
private static bool IsReferenced(Assembly assembly) { // C# player referenced assemblies foreach (AssemblyName asmName in typeof(VRModule).Assembly.GetReferencedAssemblies()) { if (assembly.GetName().Name == asmName.Name) { return(true); } } // C# editor referenced assemblies foreach (AssemblyName asmName in typeof(VRModuleManagerEditor).Assembly.GetReferencedAssemblies()) { if (assembly.GetName().Name == asmName.Name) { return(true); } } #if UNITY_2018_1_OR_NEWER // Unity player referenced assemblies UnityEditor.Compilation.Assembly playerUnityAsm = FindUnityAssembly(typeof(VRModule).Assembly.GetName().Name, AssembliesType.Player); if (playerUnityAsm != null) { foreach (UnityEditor.Compilation.Assembly asm in playerUnityAsm.assemblyReferences) { if (assembly.GetName().Name == asm.name) { return(true); } } } else { Debug.LogWarning("Player assembly not found."); } // Unity editor referenced assemblies UnityEditor.Compilation.Assembly editorUnityAsm = FindUnityAssembly(typeof(VRModuleManagerEditor).Assembly.GetName().Name, AssembliesType.Editor); if (editorUnityAsm != null) { foreach (UnityEditor.Compilation.Assembly asm in editorUnityAsm.assemblyReferences) { if (assembly.GetName().Name == asm.name) { return(true); } } } else { Debug.LogWarning("Editor assembly not found."); } #elif UNITY_2017_3_OR_NEWER UnityEditor.Compilation.Assembly[] assemblies = CompilationPipeline.GetAssemblies(); foreach (UnityEditor.Compilation.Assembly asm in assemblies) { if (assembly.GetName().Name == asm.name) { return(true); } } #endif return(false); }
// This shouldn't be exposed normally, but if AsmRefPreprocessor ever breaks this is useful for debugging // [MenuItem("Debug/Fix optional dependencies")] private static void FixOptionalDependencies() { const string MAGIC = "OPT_REF_"; var assemblies = CompilationPipeline.GetAssemblies(); var optionalRefs = new List <OptionalRefMetadata>(); var foundAssemblies = new List <string>(); // go over all assemblies, scan for optional references foreach (var assembly in assemblies) { var asmRef = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(assembly.name); if (asmRef != null) { var path = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(assembly.name); var obj = JsonConvert.DeserializeObject(File.ReadAllText(path)) as dynamic; foundAssemblies.Add((obj.name as JValue).Value <string>()); if (obj.versionDefines == null) { continue; } foreach (var define in obj.versionDefines) { var d = (define.define as JValue).Value <string>(); if (d.StartsWith(MAGIC)) { // found one to resolve! optionalRefs.Add(new OptionalRefMetadata(path, assembly.name, d.Substring(MAGIC.Length, d.Length - MAGIC.Length).Replace("_", "."))); } } } } // go over the found optional references and fix asmrefs foreach (var optionalRef in optionalRefs) { var defineString = optionalRef.ReferenceTo.Replace(".", "_").ToUpper(); var obj = JsonConvert.DeserializeObject(File.ReadAllText(optionalRef.AsmRefPath)) as dynamic; // does a reference exist? var foundRefIndex = -1; for (int i = 0; i < obj.references.Count; i++) { if (obj.references[i] == optionalRef.ReferenceTo) { foundRefIndex = i; break; } } // does the conditional-compilation define exist? var foundDefineIndex = -1; for (int i = 0; i < obj.versionDefines.Count; i++) { if (obj.versionDefines[i].name == optionalRef.ReferencedBy && obj.versionDefines[i].define == defineString) { foundDefineIndex = i; break; } } // if the assembly is loaded, make sure we have the reference and the define, add them if not if (foundAssemblies.Contains(optionalRef.ReferenceTo)) { if (foundRefIndex == -1) { obj.references.Add(optionalRef.ReferenceTo); } if (foundDefineIndex == -1) { // this is ugly but using an anonymous type here breaks jsonconvert, so we do it directly instead obj.versionDefines.Add(new JObject { { "name", optionalRef.ReferencedBy }, { "expression", "" }, { "define", defineString } }); } } else { // if it's not loaded, remove any reference that exists if (foundRefIndex != -1) { obj.references.RemoveAt(foundRefIndex); } if (foundDefineIndex != -1) { obj.versionDefines.RemoveAt(foundDefineIndex); } } // done File.WriteAllText(optionalRef.AsmRefPath, JsonConvert.SerializeObject(obj)); } }
static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) { // Do nothing if there were compile errors on the target if (CompilerMessagesContainError(messages)) { Debug.Log("Weaver: stop because compile errors on target"); return; } // Should not run on the editor only assemblies if (assemblyPath.Contains("-Editor") || assemblyPath.Contains(".Editor")) { return; } // don't weave mirror files string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); if (assemblyName == MirrorRuntimeAssemblyName || assemblyName == MirrorWeaverAssemblyName) { return; } // find Mirror.dll string mirrorRuntimeDll = FindMirrorRuntime(); if (string.IsNullOrEmpty(mirrorRuntimeDll)) { Debug.LogError("Failed to find Mirror runtime assembly"); return; } if (!File.Exists(mirrorRuntimeDll)) { // this is normal, it happens with any assembly that is built before mirror // such as unity packages or your own assemblies // those don't need to be weaved // if any assembly depends on mirror, then it will be built after return; } // find UnityEngine.CoreModule.dll string unityEngineCoreModuleDLL = UnityEditorInternal.InternalEditorUtility.GetEngineCoreModuleAssemblyPath(); if (string.IsNullOrEmpty(unityEngineCoreModuleDLL)) { Debug.LogError("Failed to find UnityEngine assembly"); return; } // build directory list for later asm/symbol resolving using CompilationPipeline refs HashSet <string> dependencyPaths = new HashSet <string>(); dependencyPaths.Add(Path.GetDirectoryName(assemblyPath)); foreach (UnityAssembly unityAsm in CompilationPipeline.GetAssemblies()) { if (unityAsm.outputPath != assemblyPath) { continue; } foreach (string unityAsmRef in unityAsm.compiledAssemblyReferences) { dependencyPaths.Add(Path.GetDirectoryName(unityAsmRef)); } } // passing null in the outputDirectory param will do an in-place update of the assembly if (Program.Process(unityEngineCoreModuleDLL, mirrorRuntimeDll, null, new[] { assemblyPath }, dependencyPaths.ToArray(), HandleWarning, HandleError)) { WeaveFailed = false; //Debug.Log("Weaving succeeded for: " + assemblyPath); } else { WeaveFailed = true; if (UnityLogEnabled) { Debug.LogError("Weaving failed for: " + assemblyPath); } } }
/// <returns>Returns a dictionary of type name inside MRTK DLLs mapped to additional data.</returns> private static Dictionary <string, ClassInformation> ProcessCompiledDLLs(string temporaryDirectoryName, string outputDirectory, Dictionary <string, string> asmDefMappings) { Assembly[] dlls = CompilationPipeline.GetAssemblies(); string tmpDirPath = Path.Combine(Application.dataPath, temporaryDirectoryName); if (Directory.Exists(tmpDirPath)) { Directory.Delete(tmpDirPath); } Directory.CreateDirectory(tmpDirPath); try { foreach (Assembly dll in dlls) { if (dll.name.Contains("MixedReality")) { File.Copy(dll.outputPath, Path.Combine(tmpDirPath, $"{dll.name}.dll"), true); } } // Load these directories AssetDatabase.Refresh(); Dictionary <string, ClassInformation> toReturn = new Dictionary <string, ClassInformation>(); if (Directory.Exists(outputDirectory)) { Directory.Delete(outputDirectory, true); } Directory.CreateDirectory(outputDirectory); foreach (Assembly dll in dlls) { if (dll.name.Contains("MixedReality")) { if (!asmDefMappings.TryGetValue($"{dll.name}.dll", out string newDllGuid)) { throw new InvalidOperationException($"No guid based on .asmdef was generated for DLL '{dll.name}'."); } File.Copy(Path.Combine(tmpDirPath, $"{dll.name}.dll"), Path.Combine(outputDirectory, $"{dll.name}.dll")); File.Copy(Path.Combine(tmpDirPath, $"{dll.name}.dll.meta"), Path.Combine(outputDirectory, $"{dll.name}.dll.meta")); Object[] assets = AssetDatabase.LoadAllAssetsAtPath(Path.Combine("Assets", temporaryDirectoryName, $"{dll.name}.dll")); foreach (Object asset in assets) { MonoScript monoScript = asset as MonoScript; if (!(monoScript is null) && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(monoScript, out string guid, out long fileId)) { Type type = monoScript.GetClass(); if (type.Namespace == null || !type.Namespace.Contains("Microsoft.MixedReality.Toolkit")) { throw new InvalidDataException($"Type {type.Name} is not a member of the Microsoft.MixedReality.Toolkit namespace"); } toReturn.Add(type.FullName, new ClassInformation() { Name = type.Name, Namespace = type.Namespace, FileId = fileId, Guid = newDllGuid }); } } } } return(toReturn); } finally { Directory.Delete(tmpDirPath, true); AssetDatabase.Refresh(); } }
static Assembly FindCompilationPipelineAssembly(string assemblyName) => CompilationPipeline.GetAssemblies().First(assembly => assembly.name == assemblyName);
public override void Execute(Pipeline pipeline) { var mani = pipeline.Manifest; var allThunderstoreManifests = pipeline.Datums.OfType <ThunderstoreManifest>(); var thunderstoreManifest = mani.Data.OfType <ThunderstoreManifest>().First(); var dependencies = thunderstoreManifest.dependencies; bool IsDependency(string dependency, ThunderstoreManifest man) => $"{man.author}-{man.name}-{man.versionNumber}".Equals(dependency); var dependantManifests = pipeline.manifests .Where(man => man.Data.OfType <ThunderstoreManifest>().Any()) .Select(man => (manifest: man, tsManifest: man.Data.OfType <ThunderstoreManifest>().First())) .Where(projection => dependencies.Any(dep => IsDependency(dep, projection.tsManifest))) .Select(projection => projection.manifest); var explicitDownstreamAssets = dependantManifests .SelectMany(man => man.Data.OfType <AssetBundleDefs>()) .SelectMany(mabd => mabd.assetBundles) .SelectMany(ab => ab.assets) .Select(asset => AssetDatabase.GetAssetPath(asset)) .ToArray(); AssetDatabase.SaveAssets(); foreach (var assetBundleDef in mani.Data.OfType <AssetBundleDefs>()) { var playerAssemblies = CompilationPipeline.GetAssemblies(); var assemblyFiles = playerAssemblies.Select(pa => pa.outputPath).ToArray(); var sourceFiles = playerAssemblies.SelectMany(pa => pa.sourceFiles).ToArray(); var excludedExtensions = new[] { ".dll" }; var builds = new AssetBundleBuild[assetBundleDef.assetBundles.Length]; var fileCount = 0; var logBuilder = new StringBuilder(); logBuilder.AppendLine("Constructing AssetBundles"); for (int i = 0; i < assetBundleDef.assetBundles.Length; i++) { var def = assetBundleDef.assetBundles[i]; var explicitAssets = assetBundleDef.assetBundles.Where((ab, abi) => abi != i).SelectMany(ab => ab.assets).Select(asset => AssetDatabase.GetAssetPath(asset)).ToArray(); var build = builds[i]; var assets = new List <string>(); logBuilder.AppendLine($"Building bundle: {def.assetBundleName}"); if (def.assets.OfType <SceneAsset>().Any()) { assets.Add(AssetDatabase.GetAssetPath(def.assets.OfType <SceneAsset>().First())); } else { foreach (var asset in def.assets) { var assetPath = AssetDatabase.GetAssetPath(asset); bool isFolder = AssetDatabase.IsValidFolder(assetPath); logBuilder.AppendLine($"Asset: {asset.name} is a {(isFolder ? "Folder" : "File")}"); if (isFolder) { var bundleAssets = AssetDatabase.GetAllAssetPaths() .Where(ap => !AssetDatabase.IsValidFolder(ap)) .Where(ap => ap.StartsWith(assetPath)) .Where(ap => !assets.Contains(ap)) .Where(ap => !sourceFiles.Contains(ap)) .Where(ap => !assemblyFiles.Contains(ap)) .Where(ap => recurseDirectories || Path.GetDirectoryName(ap).Replace('\\', '/').Equals(assetPath)) .SelectMany(ap => AssetDatabase.GetDependencies(ap) .Where(dap => !explicitAssets.Contains(dap)) .Where(dap => !explicitDownstreamAssets.Contains(dap)) ) .Where(ap => { var extension = Path.GetExtension(ap); return(!excludedExtensions.Contains(extension)); }) .Where(ap => !assets.Contains(ap)) ; assets.AddRange(bundleAssets); } else { var validAssets = AssetDatabase.GetDependencies(assetPath) .Where(dap => !explicitDownstreamAssets.Contains(dap)) .Where(dap => !explicitAssets.Contains(dap)) .Where(ap => !assets.Contains(ap)) .Where(ap => { var extension = Path.GetExtension(ap); return(!excludedExtensions.Contains(extension)); }) .Where(ap => !sourceFiles.Contains(ap)) .Where(ap => !assemblyFiles.Contains(ap)) .Where(ap => AssetDatabase.GetMainAssetTypeAtPath(ap) != typeof(UnityPackage)) ; assets.AddRange(validAssets); } } } build.assetNames = assets.ToArray(); build.assetBundleName = def.assetBundleName; builds[i] = build; fileCount += build.assetNames.Length; foreach (var asset in build.assetNames) { logBuilder.AppendLine(asset); } } logBuilder.AppendLine($"Constructed {builds.Length} AssetBundleBuilds with {fileCount} files."); if (!simulate) { var stablePath = BundleArtifactPath.Resolve(pipeline, this); Directory.CreateDirectory(stablePath); BuildPipeline.BuildAssetBundles(stablePath, builds, AssetBundleBuildOptions, buildTarget); foreach (var outputPath in assetBundleDef.StagingPaths.Select(path => path.Resolve(pipeline, this))) { CopyFilesRecursively(stablePath, outputPath); } } Debug.Log(logBuilder.ToString()); } }
/// <returns>Returns a dictionary of type name inside MRTK DLLs mapped to additional data.</returns> private static Dictionary <string, AssemblyInformation> ProcessCompiledDLLs(string temporaryDirectoryName, string outputDirectory, Dictionary <string, string> asmDefMappings) { Assembly[] dlls = CompilationPipeline.GetAssemblies(); string tmpDirPath = Path.Combine(Application.dataPath, temporaryDirectoryName); if (Directory.Exists(tmpDirPath)) { Directory.Delete(tmpDirPath); } Directory.CreateDirectory(tmpDirPath); try { Utilities.EnsureCleanDirectory(outputDirectory); foreach (Assembly dll in dlls) { if (dll.name.Contains("MixedReality")) { string dllPath = Utilities.GetFullPathFromAssetsRelative($"Assets/../MSBuild/Publish/InEditor/WindowsStandalone32/{dll.name}.dll"); File.Copy(dllPath, Path.Combine(tmpDirPath, $"{dll.name}.dll"), true); File.Copy(dllPath, Path.Combine(outputDirectory, $"{dll.name}.dll")); File.Copy(Path.ChangeExtension(dllPath, ".pdb"), Path.Combine(outputDirectory, $"{dll.name}.pdb")); } } // Load these directories AssetDatabase.Refresh(); Dictionary <string, AssemblyInformation> toReturn = new Dictionary <string, AssemblyInformation>(); foreach (Assembly dll in dlls) { if (dll.name.Contains("MixedReality")) { if (!asmDefMappings.TryGetValue($"{dll.name}.dll", out string newDllGuid)) { throw new InvalidOperationException($"No guid based on .asmdef was generated for DLL '{dll.name}'."); } AssemblyInformation assemblyInformation = new AssemblyInformation(dll.name, newDllGuid); Object[] assets = AssetDatabase.LoadAllAssetsAtPath(Path.Combine("Assets", temporaryDirectoryName, $"{dll.name}.dll")); foreach (Object asset in assets) { MonoScript monoScript = asset as MonoScript; if (!(monoScript is null) && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(monoScript, out string guid, out long fileId)) { Type type = monoScript.GetClass(); if (type == null) { Debug.LogError($"Encountered a MonoScript we get a null Type from: '{monoScript.name}'"); } // check for a namespace, MRTK or the DotNetAdapter namespace else if ((type.Namespace == null) || (!type.Namespace.Contains("Microsoft.MixedReality.Toolkit") && !type.Namespace.Contains("Microsoft.Windows.MixedReality"))) { throw new InvalidDataException($"Type {type.Name} is not a member of an approved (typically, 'Microsoft.MixedReality.Toolkit') namespace"); } else { assemblyInformation.CompiledClasses.Add(type.FullName, new ClassInformation() { Name = type.Name, Namespace = type.Namespace, FileId = fileId, Guid = newDllGuid }); } } } toReturn.Add(dll.name, assemblyInformation); } } return(toReturn); } finally { Directory.Delete(tmpDirPath, true); AssetDatabase.Refresh(); } }
private Dictionary <string, CSProjectInfo> CreateUnityProjects() { // Not all of these will be converted to C# objects, only the ones found to be referenced Dictionary <string, AssemblyDefinitionInfo> asmDefInfoMap = new Dictionary <string, AssemblyDefinitionInfo>(); SortedSet <AssemblyDefinitionInfo> asmDefDirectoriesSorted = new SortedSet <AssemblyDefinitionInfo>(Comparer <AssemblyDefinitionInfo> .Create((a, b) => a.Directory.FullName.CompareTo(b.Directory.FullName))); HashSet <string> builtInPackagesWithoutSource = new HashSet <string>(); // Parse the builtInPackagesFirst DirectoryInfo builtInPackagesDirectory = new DirectoryInfo(Utilities.BuiltInPackagesPath); foreach (DirectoryInfo packageDirectory in builtInPackagesDirectory.GetDirectories()) { FileInfo[] asmDefFiles = packageDirectory.GetFiles("*.asmdef", SearchOption.AllDirectories); if (asmDefFiles.Length == 0) { builtInPackagesWithoutSource.Add(packageDirectory.Name.ToLower()); continue; } foreach (FileInfo fileInfo in asmDefFiles) { AssemblyDefinitionInfo assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(fileInfo, this, null, true); asmDefDirectoriesSorted.Add(assemblyDefinitionInfo); asmDefInfoMap.Add(Path.GetFileNameWithoutExtension(fileInfo.Name), assemblyDefinitionInfo); } } Dictionary <string, string> packageCacheVersionedMap = new Dictionary <string, string>(); foreach (string directory in Directory.GetDirectories(Utilities.PackageLibraryCachePath)) { string directoryName = Path.GetFileName(directory); packageCacheVersionedMap.Add(directoryName.Split('@')[0], directoryName); } Dictionary <string, Assembly> unityAssemblies = CompilationPipeline.GetAssemblies().ToDictionary(t => t.name); Dictionary <string, CSProjectInfo> projectsMap = new Dictionary <string, CSProjectInfo>(); Queue <string> projectsToProcess = new Queue <string>(); // Parse the unity assemblies foreach (KeyValuePair <string, Assembly> pair in unityAssemblies) { if (!asmDefInfoMap.TryGetValue(pair.Key, out AssemblyDefinitionInfo assemblyDefinitionInfo)) { string asmDefPath = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(pair.Key); if (string.IsNullOrEmpty(asmDefPath)) { if (!pair.Key.StartsWith("Assembly-CSharp")) { throw new InvalidOperationException($"Failed to retrieve AsmDef for script assembly: {pair.Key}"); } Guid guid; switch (pair.Key) { case "Assembly-CSharp": guid = config.AssemblyCSharpGuid; break; case "Assembly-CSharp-firstpass": guid = config.AssemblyCSharpFirstPassGuid; break; case "Assembly-CSharp-Editor": guid = config.AssemblyCSharpEditorGuid; break; case "Assembly-CSharp-Editor-firstpass": guid = config.AssemblyCSharpFirstPassEditorGuid; break; default: throw new InvalidOperationException($"Predefined assembly '{assemblyDefinitionInfo.Name}' was not recognized, this generally means it should be added to the switch statement in CSProjectInfo:GetProjectType."); } assemblyDefinitionInfo = AssemblyDefinitionInfo.GetDefaultAssemblyCSharpInfo(pair.Value, guid); projectsToProcess.Enqueue(pair.Key); } else { assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(new FileInfo(Utilities.GetFullPathFromKnownRelative(asmDefPath)), this, pair.Value); if (asmDefPath.StartsWith("Assets/")) { // Add as mandatory projectsToProcess.Enqueue(pair.Key); } } asmDefDirectoriesSorted.Add(assemblyDefinitionInfo); asmDefInfoMap.Add(pair.Key, assemblyDefinitionInfo); } } // This will parse additional asmdefs that are not part of current compilation set, but we still need foreach (string asmdefGuid in AssetDatabase.FindAssets("t:asmdef")) { string asmDefPath = AssetDatabase.GUIDToAssetPath(asmdefGuid); string asmDefKey = Path.GetFileNameWithoutExtension(asmDefPath); if (!asmDefInfoMap.ContainsKey(asmDefKey)) { AssemblyDefinitionInfo assemblyDefinitionInfo = AssemblyDefinitionInfo.Parse(new FileInfo(Utilities.GetFullPathFromKnownRelative(asmDefPath)), this, null); asmDefDirectoriesSorted.Add(assemblyDefinitionInfo); asmDefInfoMap.Add(asmDefKey, assemblyDefinitionInfo); } } // Now we have all of the assembly definiton files, let's run a quick validation. ValidateAndPatchAssemblyDefinitions(asmDefInfoMap); int index = 0; ProcessSortedAsmDef(asmDefDirectoriesSorted.ToArray(), ref index, (uri) => true, (a) => { }); while (projectsToProcess.Count > 0) { string projectKey = projectsToProcess.Dequeue(); if (!projectsMap.ContainsKey(projectKey)) { GetProjectInfo(projectsMap, asmDefInfoMap, builtInPackagesWithoutSource, projectKey); } } return(projectsMap); }
private void DrawOptions(DllManipulatorOptions options) { var guiEnabledStack = new Stack <bool>(); guiEnabledStack.Push(GUI.enabled); if (EditorApplication.isPlaying) { GUI.enabled = false; } options.mockAllNativeFunctions = EditorGUILayout.Toggle(TARGET_ALL_NATIVE_FUNCTIONS_GUI_CONTENT, options.mockAllNativeFunctions); if (EditorGUILayout.Toggle(TARGET_ONLY_EXECUTING_ASSEMBLY_GUI_CONTENT, options.assemblyPaths.Length == 0)) { options.assemblyPaths = new string[0]; } else { var prevIndent1 = EditorGUI.indentLevel; EditorGUI.indentLevel++; if (_allKnownAssemblies == null || _lastKnownAssembliesRefreshTime + ASSEMBLIES_REFRESH_INTERVAL < DateTime.Now) { var playerCompiledAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Player) .Select(a => PathUtils.NormallizeUnityAssemblyPath(a.outputPath)); var editorCompiledAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Editor) .Select(a => PathUtils.NormallizeUnityAssemblyPath(a.outputPath)); var assemblyAssets = Resources.FindObjectsOfTypeAll <PluginImporter>() .Where(p => !p.isNativePlugin) .Select(p => PathUtils.NormallizeUnityAssemblyPath(p.assetPath)); string[] defaultAssemblyPrefixes = { "UnityEngine.", "UnityEditor.", "Unity.", "com.unity.", "Mono.", "nunit." }; _allKnownAssemblies = playerCompiledAssemblies .Concat(assemblyAssets) .Concat(editorCompiledAssemblies) .OrderBy(path => Array.FindIndex(defaultAssemblyPrefixes, p => path.Substring(path.LastIndexOf('/') + 1).StartsWith(p))) .ToArray(); _lastKnownAssembliesRefreshTime = DateTime.Now; } if (options.assemblyPaths.Length == 0) { var first = GetFirstAssemblyToList(_allKnownAssemblies); if (first != null) { options.assemblyPaths = new[] { first } } ; } _showTargetAssemblies = EditorGUILayout.Foldout(_showTargetAssemblies, TARGET_ASSEMBLIES_GUI_CONTENT); if (_showTargetAssemblies) { var prevIndent2 = EditorGUI.indentLevel; EditorGUI.indentLevel++; var selectedAssemblies = options.assemblyPaths.Where(p => _allKnownAssemblies.Any(a => PathUtils.DllPathsEqual(a, p))).ToList(); var notSelectedAssemblies = _allKnownAssemblies.Except(selectedAssemblies).ToArray(); DrawList(selectedAssemblies, i => { var values = new[] { selectedAssemblies[i] } .Concat(notSelectedAssemblies) .Select(a => a.Substring(a.LastIndexOf('/') + 1)) .ToArray(); var selectedIndex = EditorGUILayout.Popup(0, values); return(selectedIndex == 0 ? selectedAssemblies[i] : notSelectedAssemblies[selectedIndex - 1]); }, notSelectedAssemblies.Length > 0, () => notSelectedAssemblies[0]); options.assemblyPaths = selectedAssemblies.ToArray(); EditorGUI.indentLevel = prevIndent2; } EditorGUI.indentLevel = prevIndent1; } options.onlyInEditor = EditorGUILayout.Toggle(ONLY_IN_EDITOR, options.onlyInEditor); options.dllPathPattern = EditorGUILayout.TextField(DLL_PATH_PATTERN_GUI_CONTENT, options.dllPathPattern); options.loadingMode = (DllLoadingMode)EditorGUILayout.EnumPopup(DLL_LOADING_MODE_GUI_CONTENT, options.loadingMode); #if UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX options.posixDlopenFlags = (PosixDlopenFlags)EditorGUILayout.EnumPopup(POSIX_DLOPEN_FLAGS_GUI_CONTENT, options.posixDlopenFlags); #endif guiEnabledStack.Push(GUI.enabled); if (options.loadingMode != DllLoadingMode.Preload) { options.threadSafe = false; GUI.enabled = false; } options.threadSafe = EditorGUILayout.Toggle(THREAD_SAFE_GUI_CONTENT, options.threadSafe); GUI.enabled = guiEnabledStack.Pop(); options.enableCrashLogs = EditorGUILayout.Toggle(CRASH_LOGS_GUI_CONTENT, options.enableCrashLogs); if (options.enableCrashLogs) { var prevIndent = EditorGUI.indentLevel; EditorGUI.indentLevel += 1; options.crashLogsDir = EditorGUILayout.TextField(CRASH_LOGS_DIR_GUI_CONTENT, options.crashLogsDir); options.crashLogsStackTrace = EditorGUILayout.Toggle(CRASH_LOGS_STACK_TRACE_GUI_CONTENT, options.crashLogsStackTrace); EditorGUI.indentLevel = prevIndent; } GUI.enabled = guiEnabledStack.Pop(); }
public override void Execute(Pipeline pipeline) { var excludedExtensions = new[] { ".dll", ".cs", ".meta" }; AssetDatabase.SaveAssets(); var assetBundleDefs = pipeline.Datums.OfType <AssetBundleDefinitions>().ToArray(); var bundleArtifactPath = BundleArtifactPath.Resolve(pipeline, this); Directory.CreateDirectory(bundleArtifactPath); var builds = new AssetBundleBuild[assetBundleDefs.Sum(abd => abd.assetBundles.Length)]; var buildsIndex = 0; for (int defIndex = 0; defIndex < assetBundleDefs.Length; defIndex++) { var assetBundleDef = assetBundleDefs[defIndex]; var playerAssemblies = CompilationPipeline.GetAssemblies(); var assemblyFiles = playerAssemblies.Select(pa => pa.outputPath).ToArray(); var sourceFiles = playerAssemblies.SelectMany(pa => pa.sourceFiles).ToArray(); var fileCount = 0; var logBuilder = new StringBuilder(); logBuilder.AppendLine("Constructing AssetBundles"); for (int i = 0; i < assetBundleDef.assetBundles.Length; i++) { var def = assetBundleDef.assetBundles[i]; var explicitAssets = assetBundleDef.assetBundles.Where((ab, abi) => abi != i).SelectMany(ab => ab.assets).Select(asset => AssetDatabase.GetAssetPath(asset)).ToArray(); var build = builds[buildsIndex]; var assets = new List <string>(); logBuilder.AppendLine($"Building bundle: {def.assetBundleName}"); var firstAsset = def.assets.FirstOrDefault(x => x is SceneAsset); if (firstAsset != null) { assets.Add(AssetDatabase.GetAssetPath(firstAsset)); } else { foreach (var asset in def.assets) { var assetPath = AssetDatabase.GetAssetPath(asset); if (AssetDatabase.IsValidFolder(assetPath)) { assets.AddRange(Directory.GetFiles(assetPath, "*", SearchOption.AllDirectories) .SelectMany(ap => AssetDatabase.GetDependencies(ap).Union(new[] { ap }))); } else if (asset is UnityPackage up) { if (up.exportPackageOptions.HasFlag(ExportPackageOptions.Recurse)) { foreach (var upAsset in up.AssetFiles) { var path = AssetDatabase.GetAssetPath(upAsset); if (AssetDatabase.IsValidFolder(path)) { assets.AddRange(Directory.GetFiles(path, "*", SearchOption.AllDirectories) .SelectMany(ap => AssetDatabase.GetDependencies(ap).Union(new[] { ap }))); } else { assets.Add(path); } } } } else { assets.AddRange(AssetDatabase.GetDependencies(assetPath) .Where(ap => AssetDatabase.GetMainAssetTypeAtPath(ap) != typeof(UnityPackage)) .Union(new[] { assetPath })); } } } build.assetNames = assets .Select(ap => ap.Replace("\\", "/")) //.Where(dap => !explicitDownstreamAssets.Contains(dap)) .Where(dap => !ArrayUtility.Contains(explicitAssets, dap) && !ArrayUtility.Contains(excludedExtensions, Path.GetExtension(dap)) && !ArrayUtility.Contains(sourceFiles, dap) && !ArrayUtility.Contains(assemblyFiles, dap) && !AssetDatabase.IsValidFolder(dap)) .Distinct() .ToArray(); build.assetBundleName = def.assetBundleName; builds[buildsIndex] = build; buildsIndex++; fileCount += build.assetNames.Length; foreach (var asset in build.assetNames) { logBuilder.AppendLine(asset); } } logBuilder.AppendLine($"Constructed {builds.Length} AssetBundleBuilds with {fileCount} files."); Debug.Log(logBuilder.ToString()); } if (!simulate) { var allBuilds = builds.ToArray(); BuildPipeline.BuildAssetBundles(bundleArtifactPath, allBuilds, AssetBundleBuildOptions, buildTarget); for (pipeline.ManifestIndex = 0; pipeline.ManifestIndex < pipeline.Manifests.Length; pipeline.ManifestIndex++) { var manifest = pipeline.Manifest; foreach (var assetBundleDef in manifest.Data.OfType <AssetBundleDefinitions>()) { var bundleNames = assetBundleDef.assetBundles.Select(ab => ab.assetBundleName).ToArray(); foreach (var outputPath in assetBundleDef.StagingPaths.Select(path => path.Resolve(pipeline, this))) { foreach (string dirPath in Directory.GetDirectories(bundleArtifactPath, "*", SearchOption.AllDirectories)) { Directory.CreateDirectory(dirPath.Replace(bundleArtifactPath, outputPath)); } foreach (string filePath in Directory.GetFiles(bundleArtifactPath, "*", SearchOption.AllDirectories)) { bool found = false; foreach (var bundleName in bundleNames) { if (filePath.IndexOf(bundleName, System.StringComparison.OrdinalIgnoreCase) >= 0) { found = true; break; } } if (!found) { continue; } string destFileName = filePath.Replace(bundleArtifactPath, outputPath); Directory.CreateDirectory(Path.GetDirectoryName(destFileName)); FileUtil.ReplaceFile(filePath, destFileName); } var manifestSource = Path.Combine(bundleArtifactPath, $"{Path.GetFileName(bundleArtifactPath)}.manifest"); var manifestDestination = Path.Combine(outputPath, $"{manifest.Identity.Name}.manifest"); FileUtil.ReplaceFile(manifestSource, manifestDestination); } } } pipeline.ManifestIndex = -1; } }
private static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) { var sw = Stopwatch.StartNew(); if (Array.FindIndex(messages, IsErrorMessage) != -1) { return; } var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); if (assemblyName == null || assemblyName == UniMobRuntimeAssemblyName) { return; } //if (assemblyName == UniMobEditorAssemblyName) //{ // // should we reload scripts when Weaver changed? // // it allow package update but assemblies will reload twice // // on project startup // SessionState.SetBool(UniMobWeavedFlagName, false); // return; //} if (assemblyPath.Contains("-Editor") || assemblyPath.Contains(".Editor")) { return; } var assemblies = CompilationPipeline.GetAssemblies(); var uniMobRuntime = FindUniMobRuntime(assemblies); if (uniMobRuntime == null) { Debug.LogError("Failed to find UniMob runtime assembly"); return; } if (!File.Exists(uniMobRuntime.outputPath)) { return; } var dependencyPaths = new HashSet <string> { Path.GetDirectoryName(assemblyPath) }; var shouldWeave = false; for (var asmIndex = 0; asmIndex < assemblies.Length; asmIndex++) { var assembly = assemblies[asmIndex]; if (assembly.outputPath != assemblyPath) { continue; } for (var i = 0; i < assembly.compiledAssemblyReferences.Length; i++) { var referencePath = assembly.compiledAssemblyReferences[i]; dependencyPaths.Add(Path.GetDirectoryName(referencePath)); } for (var i = 0; i < assembly.assemblyReferences.Length; i++) { var reference = assembly.assemblyReferences[i]; if (reference.outputPath == uniMobRuntime.outputPath) { shouldWeave = true; } } break; } if (!shouldWeave) { return; } Weave(assemblyPath, dependencyPaths); #if UNIMOB_WEAVER_LOGGING_ENABLED Debug.Log($"Weaved {assemblyPath} in {sw.ElapsedMilliseconds}ms"); #endif }
public static void Build() { var getFilePath = Application.dataPath + "/" + HotFixCodePath; Debug.Log("getFilePath" + getFilePath); string[] scritpsFilePaths = Directory.GetFiles(getFilePath, "*.cs", SearchOption.AllDirectories).Where( x => !x.Contains("AssemblyInfo") && !x.Contains("TemporaryGeneratedFile")).ToArray(); #region 根据csproj过滤工程 //var csProjTxt= File.ReadAllText(Application.dataPath + "/" +HotFixCsproj); //XMLParser p =new XMLParser(); //p.Parse(csProjTxt); //var projXml = p.ToXml(); //projXml.GetChildNodeList("ItemGroup"); #endregion AssemblyBuilder assemblyBuilder = new AssemblyBuilder("Assets/Resources/Data/HotfixCode/Hotfix_dll.bytes", scritpsFilePaths); assemblyBuilder.buildTarget = EditorUserBuildSettings.activeBuildTarget; List <string> assemblyNamesList = new List <string>(); foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies()) { if ((assembly.flags & AssemblyFlags.EditorAssembly) == AssemblyFlags.None) { if (assembly.name.Contains("spine")) { continue; } assemblyNamesList.Add("Temp/UnityVS_bin/Debug/" + assembly.name + ".dll"); } } //EditorBuildRules assemblyBuilder.additionalReferences = assemblyNamesList.ToArray(); assemblyBuilder.flags = AssemblyBuilderFlags.DevelopmentBuild; //assemblyBuilder.c assemblyBuilder.buildFinished += delegate(string assemblyPath, CompilerMessage[] compilerMessages) { var errorCount = compilerMessages.Count(m => m.type == CompilerMessageType.Error); var warningCount = compilerMessages.Count(m => m.type == CompilerMessageType.Warning); Debug.LogFormat("Assembly build finished for {0}", assemblyPath); Debug.LogFormat("Warnings: {0} - Errors: {0}", errorCount, warningCount); if (errorCount > 0) { foreach (var _compilerMessage in compilerMessages) { if (_compilerMessage.type == CompilerMessageType.Error) { Debug.LogErrorFormat("File {0} Msg {1} ", _compilerMessage.file, _compilerMessage.message); } else { Debug.LogFormat("File {0} Msg {1} ", _compilerMessage.file, _compilerMessage.message); } } } }; if (assemblyBuilder.Build()) { Debug.Log("BuildSuccess"); } else { Debug.LogErrorFormat("Failed to start build of assembly {0}!", assemblyBuilder.assemblyPath); } }