Example #1
0
        public void OnPreprocessBuild(BuildReport report)
        {
            var target = report.summary.platform;
            var path   = report.summary.outputPath;

            if (BuildType == TrimmerBuildType.None)
            {
                NonTrimmerBuild(target);
            }

            // Run options' PreprocessBuild
            includesAnyOption = false;
            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                var inclusion = currentProfile == null ? OptionInclusion.Remove : currentProfile.GetInclusionOf(option, target);
                includesAnyOption |= ((inclusion & OptionInclusion.Option) != 0);

                if ((option.Capabilities & OptionCapabilities.ConfiguresBuild) != 0)
                {
                    option.PreprocessBuild(report, inclusion);
                }
            }

            GenerateBuildInfo(report.summary.guid);

            string defines = null;

    #if UNITY_2020_1_OR_NEWER
            var extraScriptingDefines = OptionHelper.currentBuildOptions.extraScriptingDefines;
            if (extraScriptingDefines != null && extraScriptingDefines.Length > 0)
            {
                defines = extraScriptingDefines.Join();
            }
    #else
            var targetGroup = BuildPipeline.GetBuildTargetGroup(target);
            defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);
    #endif

            Debug.Log(string.Format(
                          "Trimmer: Building profile '{0}' for '{1}' to '{2}'\nIncluded: {3}\nSymbols: {4}",
                          currentProfile != null ? currentProfile.name : "null",
                          target, path,
                          GetCurrentEditProfile()
                          .Where(o => {
                if (currentProfile == null)
                {
                    return(false);
                }
                var inclusion = currentProfile.GetInclusionOf(o, target);
                return(inclusion.HasFlag(OptionInclusion.Feature) || inclusion.HasFlag(OptionInclusion.Option));
            })
                          .Select(o => o.Name)
                          .Join(),
                          defines
                          ));
        }
Example #2
0
        /// <summary>
        /// Determine all the scripting define symbols set by a build profile for the given build target.
        /// </summary>
        static void GetScriptingDefineSymbols(BuildProfile buildProfile, BuildTarget target, HashSet <string> symbols)
        {
            var includesAnyOption = false;

            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                var inclusion = buildProfile == null ? OptionInclusion.Remove : buildProfile.GetInclusionOf(option, target);
                includesAnyOption |= ((inclusion & OptionInclusion.Option) != 0);

                option.GetScriptingDefineSymbols(inclusion, symbols);
            }

            if (!includesAnyOption)
            {
                symbols.Add(NO_TRIMMER);
            }
        }
Example #3
0
        /// <summary>
        /// Build a profile with the given build options, synchronously starting the build.
        /// </summary>
        /// <remarks>
        /// The `BuildPlayerOptions` will be passed through the profile's Options'
        /// <see cref="Option.PrepareBuild"/>, which can modify it before the build is started.
        ///
        /// > [!NOTE]
        /// > If you do not set `options.locationPathName` and no option sets
        /// > it in the `PrepareBuild` callback, then a save dialog will be shown.
        ///
        /// > [!WARNING]
        /// > With this method it's possible to build for a build target even if this
        /// > target is not the active build target. This can lead to issues where
        /// > build code for the given target is not run.
        /// </remarks>
        public static BuildReport BuildSync(BuildProfile buildProfile, BuildPlayerOptions options)
        {
            // Prepare build
            BuildType      = TrimmerBuildType.Profile;
            currentProfile = buildProfile;

            // Add Trimmer scripting define symbols
            AddScriptingDefineSymbols(buildProfile, ref options);

            // Run options' PrepareBuild
            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                if ((option.Capabilities & OptionCapabilities.ConfiguresBuild) == 0)
                {
                    continue;
                }
                var inclusion = buildProfile == null ? OptionInclusion.Remove : buildProfile.GetInclusionOf(option, options.target);
                options = option.PrepareBuild(options, inclusion);
            }

            // Ask for location if none has been set
            if (string.IsNullOrEmpty(options.locationPathName))
            {
                if (Application.isBatchMode)
                {
                    // Cannot pick path in batch mode
                    throw new Exception($"Trimmer: No build path set by profile or in build player options.");
                }
                else
                {
                    options.locationPathName = PickBuildLocation(options.target);
                    if (string.IsNullOrEmpty(options.locationPathName))
                    {
                        Debug.Log("Cancelled build location dialog");
                        return(null);
                    }
                }
            }

            // Make sure the path has the right extension
            // Call internal method:
            // string PostprocessBuildPlayer.GetExtensionForBuildTarget(BuildTargetGroup targetGroup, BuildTarget target, BuildOptions options)
            var PostprocessBuildPlayer = typeof(BuildPipeline).Assembly.GetType("UnityEditor.PostprocessBuildPlayer");

            if (PostprocessBuildPlayer == null)
            {
                Debug.LogWarning("Could not find PostprocessBuildPlayer to determine build file extension.");
            }
            else
            {
                var GetExtensionForBuildTarget = PostprocessBuildPlayer.GetMethod("GetExtensionForBuildTarget", BindingFlags.Public | BindingFlags.Static);
                if (GetExtensionForBuildTarget == null)
                {
                    Debug.LogWarning("Could not find GetExtensionForBuildTarget to determine build file extension.");
                }
                else
                {
                    var args = new object[] { options.targetGroup, options.target, options.options };
                    var ext  = (string)GetExtensionForBuildTarget.Invoke(null, args);

                    var current = Path.GetExtension(options.locationPathName);
                    if (current.Length > 0)
                    {
                        current = current.Substring(1); // Remove leading dot
                    }

                    if (!string.IsNullOrEmpty(ext) &&
                        Path.GetExtension(options.locationPathName).EqualsIgnoringCase(current))
                    {
                        options.locationPathName += "." + ext;
                    }
                }
            }

            // Run the build
            OptionHelper.currentBuildOptions = options;

            var report = BuildPipeline.BuildPlayer(options);

            if (report.summary.result != BuildResult.Succeeded)
            {
                OnBuildError(report);
            }
            else
            {
                Debug.Log(string.Format("Trimmer: Built {0} to '{1}'", options.target, options.locationPathName));
                buildProfile.SetLastBuildPath(options.target, options.locationPathName);
            }

            currentProfile = null;
            OptionHelper.currentBuildOptions = default;
            return(report);
        }
Example #4
0
        /// <summary>
        /// Entry point for Unity Cloud builds.
        /// </summary>
        /// <remarks>
        /// If you don't configure anything, Unity Cloud Build will build without a
        /// profile, all Options will use their default value and will be removed.
        ///
        /// Add the name of the Build Profile you want to build with to the target name
        /// in Unity Cloud Build, enclosed in double underscores, e.g. `__Profile Name__`.
        /// Note that since the target name can contain only alphanumeric characters,
        /// spaces, dashes and underscores, those characters cannot appear in the profile
        /// name either.
        ///
        /// Also note that the ability for Options to set build options is limited,
        /// currently only setting a custom  scene list is supported.
        /// </remarks>
        public static void UnityCloudBuild(BuildManifestObject manifest)
        {
            BuildType = TrimmerBuildType.CloudBuild;

            Debug.Log("UnityCloudBuild: Parsing profile name...");

            // Get profile name from could build target name
            string targetName;

            if (!manifest.TryGetValue("cloudBuildTargetName", out targetName))
            {
                Debug.LogError("Could not get target name from cloud build manifest.");
            }
            else
            {
                var match = Regex.Match(targetName, @"__([\w\-. ]+)__");
                if (match.Success)
                {
                    targetName = match.Groups[1].Value;
                    Debug.Log("Parsed build profile name from target name: " + targetName);
                }
            }

            Debug.Log("UnityCloudBuild: Looking for profile...");

            BuildProfile buildProfile = null;

            if (!string.IsNullOrEmpty(targetName))
            {
                buildProfile = BuildProfile.Find(targetName);
                if (buildProfile == null)
                {
                    Debug.LogError("Build Profile named '" + targetName + "' could not be found.");
                    return;
                }
            }

            if (buildProfile == null)
            {
                Debug.LogWarning("No Build Profile selected. Add the Build Profile enclosed in double underscores (__) to the target name.");
                return;
            }

            Debug.Log("UnityCloudBuild: Running PrepareBuild callbacks...");

            // Prepare build
            var options = GetDefaultOptions(EditorUserBuildSettings.activeBuildTarget);

            currentProfile = buildProfile;

            // Run options' PrepareBuild
            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                if ((option.Capabilities & OptionCapabilities.ConfiguresBuild) == 0)
                {
                    continue;
                }
                var inclusion = buildProfile == null ? OptionInclusion.Remove : buildProfile.GetInclusionOf(option, options.target);
                options = option.PrepareBuild(options, inclusion);
            }

            // Cloud Build doesn't allow changing BuildPlayerOptions.extraScriptingDefines,
            // so we have to apply scripting define symbols to player settings
            ApplyScriptingDefineSymbolsToPlayerSettings(buildProfile, options.target);

            Debug.Log("UnityCloudBuild: Apply scenes...");

            // Apply scenes
            if (options.scenes != null && options.scenes.Length > 0)
            {
                var scenes = new EditorBuildSettingsScene[options.scenes.Length];
                for (int i = 0; i < scenes.Length; i++)
                {
                    scenes[i] = new EditorBuildSettingsScene(
                        options.scenes[i],
                        true
                        );
                }
                EditorBuildSettings.scenes = scenes;
            }

            OptionHelper.currentBuildOptions = options;
            Debug.Log("UnityCloudBuild: Done!");
        }