123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Reflection;
- using UnityEditor;
- using Debug = UnityEngine.Debug;
- namespace CurvedUI.ConditionalCompilation
- {
- /// <summary>
- /// Conditional Compilation Utility (CCU) by Unity
- /// https://github.com/Unity-Technologies/EditorXR/blob/development/Scripts/Utilities/Editor/ConditionalCompilationUtility.cs
- ///
- /// The Conditional Compilation Utility (CCU) will add defines to the build settings once dependendent classes have been detected.
- /// In order for this to be specified in any project without the project needing to include the CCU, at least one custom attribute
- /// must be created in the following form:
- ///
- /// [Conditional(UNITY_CCU)] // | This is necessary for CCU to pick up the right attributes
- /// public class OptionalDependencyAttribute : Attribute // | Must derive from System.Attribute
- /// {
- /// public string dependentClass; // | Required field specifying the fully qualified dependent class
- /// public string define; // | Required field specifying the define to add
- /// }
- ///
- /// Then, simply specify the assembly attribute(s) you created:
- /// [assembly: OptionalDependency("UnityEngine.InputNew.InputSystem", "USE_NEW_INPUT")]
- /// [assembly: OptionalDependency("Valve.VR.IVRSystem", "ENABLE_STEAMVR_INPUT")]
- /// </summary>
- [InitializeOnLoad]
- public static class ConditionalCompilationUtility
- {
- const string k_EnableCCU = "UNITY_CCU";
- public static bool enabled {
- get
- {
- var buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
- return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Contains(k_EnableCCU);
- }
- }
- public static string[] defines { private set; get; }
- static ConditionalCompilationUtility()
- {
- var buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
- var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';').ToList();
- if (!defines.Contains(k_EnableCCU, StringComparer.OrdinalIgnoreCase))
- {
- defines.Add(k_EnableCCU);
- PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", defines.ToArray()));
- // This will trigger another re-compile, which needs to happen, so all the custom attributes will be visible
- return;
- }
- var ccuDefines = new List<string> { k_EnableCCU };
- var conditionalAttributeType = typeof(ConditionalAttribute);
- const string kDependentClass = "dependentClass";
- const string kDefine = "define";
- var attributeTypes = GetAssignableTypes(typeof(Attribute), type =>
- {
- var conditionals = (ConditionalAttribute[])type.GetCustomAttributes(conditionalAttributeType, true);
- foreach (var conditional in conditionals)
- {
- if (string.Equals(conditional.ConditionString, k_EnableCCU, StringComparison.OrdinalIgnoreCase))
- {
- var dependentClassField = type.GetField(kDependentClass);
- if (dependentClassField == null)
- {
- Debug.LogErrorFormat("[CCU] Attribute type {0} missing field: {1}", type.Name, kDependentClass);
- return false;
- }
- var defineField = type.GetField(kDefine);
- if (defineField == null)
- {
- Debug.LogErrorFormat("[CCU] Attribute type {0} missing field: {1}", type.Name, kDefine);
- return false;
- }
- }
- return true;
- }
- return false;
- });
- var dependencies = new Dictionary<string, string>();
- ForEachAssembly(assembly =>
- {
- var typeAttributes = assembly.GetCustomAttributes(false).Cast<Attribute>();
- foreach (var typeAttribute in typeAttributes)
- {
- if (attributeTypes.Contains(typeAttribute.GetType()))
- {
- var t = typeAttribute.GetType();
- // These fields were already validated in a previous step
- var dependentClass = t.GetField(kDependentClass).GetValue(typeAttribute) as string;
- var define = t.GetField(kDefine).GetValue(typeAttribute) as string;
- if (!string.IsNullOrEmpty(dependentClass) && !string.IsNullOrEmpty(define) && !dependencies.ContainsKey(dependentClass))
- dependencies.Add(dependentClass, define);
- }
- }
- });
- ForEachAssembly(assembly =>
- {
- foreach (var dependency in dependencies)
- {
- var type = assembly.GetType(dependency.Key);
- if (type != null)
- {
- var define = dependency.Value;
- if (!defines.Contains(define, StringComparer.OrdinalIgnoreCase))
- defines.Add(define);
- ccuDefines.Add(define);
- }
- }
- });
- ConditionalCompilationUtility.defines = ccuDefines.ToArray();
- PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", defines.ToArray()));
- }
- static void ForEachAssembly(Action<Assembly> callback)
- {
- var assemblies = AppDomain.CurrentDomain.GetAssemblies();
- foreach (var assembly in assemblies)
- {
- try
- {
- callback(assembly);
- }
- catch (ReflectionTypeLoadException)
- {
- // Skip any assemblies that don't load properly
- continue;
- }
- }
- }
- static void ForEachType(Action<Type> callback)
- {
- ForEachAssembly(assembly =>
- {
- var types = assembly.GetTypes();
- foreach (var t in types)
- callback(t);
- });
- }
- static IEnumerable<Type> GetAssignableTypes(Type type, Func<Type, bool> predicate = null)
- {
- var list = new List<Type>();
- ForEachType(t =>
- {
- if (type.IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract && (predicate == null || predicate(t)))
- list.Add(t);
- });
- return list;
- }
- }
- }
|