GameDevEducation / UnityTutorial_BuildingViaCode

MIT License
4 stars 3 forks source link

Issue compiling StandaloneLinux64 #3

Open peq42 opened 1 year ago

peq42 commented 1 year ago

When trying to compile for that platform, the build fails saying that the toolchain may not be installed(it is). It works normally when manually building using unity's default build window

IainMcManus commented 1 year ago

@peq42 would you be able to give me some additional info and I'll try and track it down? Main things being:

I've run into that issue in some Unity versions when building for Android due to an issue with some of the pipelines so it may be similar.

peq42 commented 1 year ago

Unity version: 2022.1.20f1 Render pipeline: URP Running on Windows 10, but I had the android platform selected for the build target

I ran into a similar issue when building for android(if I didnt have the android platform selected, it wouldnt build, saying the android SDK wasnt installed) but I made a fix and will make a pull request for it

IainMcManus commented 1 year ago

I've tried a few times with a couple of different projects (UTP ones as as well as the base repo) but I haven't been able to reproduce either of the issues so far. It manages to build in each case for all of the platforms regardless of the starting platform. Would it be possible to paste in the full text of the error message? That might give me some leads.

peq42 commented 1 year ago

I get the following 4 errors thrown when trying to build for linux through the script(through unity's default window, it works just fine):

Error 1: error: Could not set up a toolchain for Architecture x64. Make sure you have the right build tools installed for il2cpp builds. Details: UnityEditor.BuildPipeline:BuildPlayer (UnityEditor.BuildPlayerOptions) BuildTools:BuildIndividualTarget (UnityEditor.BuildTarget) (at Assets/Plugins/editor/BuildTools.cs:176) BuildTools/d__6:MoveNext () (at Assets/Plugins/editor/BuildTools.cs:116) Unity.EditorCoroutines.Editor.EditorCoroutine/YieldProcessor:MoveNext (System.Collections.IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:80) Unity.EditorCoroutines.Editor.EditorCoroutine:ProcessIEnumeratorRecursive (System.Collections.IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:134) Unity.EditorCoroutines.Editor.EditorCoroutine:MoveNext () (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:115) UnityEditor.EditorApplication:Internal_CallUpdateFunctions ()

Error 2:

Internal build system error. BuildProgram exited with code -2146233088. error: Could not set up a toolchain for Architecture x64. Make sure you have the right build tools installed for il2cpp builds. Details: Could not find a clang compiler at /usr/bin/clang.exe Unity.IL2CPP.Bee.BuildLogic.ToolchainNotFoundException: Could not find a clang compiler at /usr/bin/clang.exe at Unity.IL2CPP.Bee.BuildLogic.Linux.LinuxBuildLogic.UserAvailableToolchainFor(Architecture architecture, NPath toolChainPath, NPath sysRootPath) at PlayerBuildProgramLibrary.PlayerBuildProgramBase.GetIl2CppToolChain(PlatformBuildLogic platform, Architecture architecture, NPath toolChainPath, NPath sysrootPath) at PlayerBuildProgramLibrary.PlayerBuildProgramBase.SetupIl2CppBuild() at PlayerBuildProgramLibrary.PlayerBuildProgramBase.SetupPlayerBuild() at LinuxPlayerBuildProgram.SetupPlayerBuild() at PlayerBuildProgramLibrary.PlayerBuildProgramBase.RunBuildProgram() at PlayerBuildProgramTypeWrapper.Run(String[] args) at Program.Main(String[] args) UnityEditor.BuildPipeline:BuildPlayer (UnityEditor.BuildPlayerOptions) BuildTools:BuildIndividualTarget (UnityEditor.BuildTarget) (at Assets/Plugins/editor/BuildTools.cs:176) BuildTools/d__6:MoveNext () (at Assets/Plugins/editor/BuildTools.cs:116) Unity.EditorCoroutines.Editor.EditorCoroutine/YieldProcessor:MoveNext (System.Collections.IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:80) Unity.EditorCoroutines.Editor.EditorCoroutine:ProcessIEnumeratorRecursive (System.Collections.IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:134) Unity.EditorCoroutines.Editor.EditorCoroutine:MoveNext () (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:115) UnityEditor.EditorApplication:Internal_CallUpdateFunctions ()

Error 3: BuildFailedException: Incremental Player build failed! UnityEditor.Modules.BeeBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args) (at <686f40992bed4a6ebc158b4beb1e91db>:0) UnityEditor.Modules.DefaultBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditor.BuildProperties& outProperties) (at <686f40992bed4a6ebc158b4beb1e91db>:0) UnityEditor.PostprocessBuildPlayer.Postprocess (UnityEditor.BuildTargetGroup targetGroup, UnityEditor.BuildTarget target, System.Int32 subtarget, System.String installPath, System.String companyName, System.String productName, System.Int32 width, System.Int32 height, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <686f40992bed4a6ebc158b4beb1e91db>:0) UnityEditor.BuildPipeline:BuildPlayer(BuildPlayerOptions) BuildTools:BuildIndividualTarget(BuildTarget) (at Assets/Plugins/editor/BuildTools.cs:176)

d__6:MoveNext() (at Assets/Plugins/editor/BuildTools.cs:116) Unity.EditorCoroutines.Editor.YieldProcessor:MoveNext(IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:80) Unity.EditorCoroutines.Editor.EditorCoroutine:ProcessIEnumeratorRecursive(IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:134) Unity.EditorCoroutines.Editor.EditorCoroutine:MoveNext() (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:115) UnityEditor.EditorApplication:Internal_CallUpdateFunctions() Error 4: Build for StandaloneLinux64 failed UnityEngine.Debug:LogError (object) BuildTools:BuildIndividualTarget (UnityEditor.BuildTarget) (at Assets/Plugins/editor/BuildTools.cs:185) BuildTools/d__6:MoveNext () (at Assets/Plugins/editor/BuildTools.cs:116) Unity.EditorCoroutines.Editor.EditorCoroutine/YieldProcessor:MoveNext (System.Collections.IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:80) Unity.EditorCoroutines.Editor.EditorCoroutine:ProcessIEnumeratorRecursive (System.Collections.IEnumerator) (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:134) Unity.EditorCoroutines.Editor.EditorCoroutine:MoveNext () (at Library/PackageCache/com.unity.editorcoroutines@1.0.0/Editor/EditorCoroutine.cs:115) UnityEditor.EditorApplication:Internal_CallUpdateFunctions ()
peq42 commented 1 year ago

also, my buildtools.cs looks like this(I've modified it slightly):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using Unity.EditorCoroutines.Editor;

public class BuildTools : EditorWindow
{
    [MenuItem("Tools/Build Tools")]
    public static void OnShowTools()
    {
        EditorWindow.GetWindow<BuildTools>();
    }

    private BuildTargetGroup GetTargetGroupForTarget(BuildTarget target) => target switch
    {
        BuildTarget.Android => BuildTargetGroup.Android,
        BuildTarget.StandaloneWindows64 => BuildTargetGroup.Standalone,
        BuildTarget.WebGL => BuildTargetGroup.WebGL,
        BuildTarget.StandaloneLinux64 => BuildTargetGroup.Standalone,
        _ => BuildTargetGroup.Unknown
    };

    Dictionary<BuildTarget, bool> TargetsToBuild = new Dictionary<BuildTarget, bool>();
    List<BuildTarget> AvailableTargets = new List<BuildTarget>();

    private void OnEnable()
    {
        AvailableTargets.Clear();
        var buildTargets = System.Enum.GetValues(typeof(BuildTarget));
        foreach(var buildTargetValue in buildTargets)
        {
            BuildTarget target = (BuildTarget)buildTargetValue;

            // skip if unsupported
            if (!BuildPipeline.IsBuildTargetSupported(GetTargetGroupForTarget(target), target))
                continue;

            AvailableTargets.Add(target);

            // add the target if not in the build list
            if (!TargetsToBuild.ContainsKey(target))
                TargetsToBuild[target] = false;
        }

        // check if any targets have gone away
        if (TargetsToBuild.Count > AvailableTargets.Count)
        {
            // build the list of removed targets
            List<BuildTarget> targetsToRemove = new List<BuildTarget>();
            foreach(var target in TargetsToBuild.Keys)
            {
                if (!AvailableTargets.Contains(target))
                    targetsToRemove.Add(target);
            }

            // cleanup the removed targets
            foreach(var target in targetsToRemove)
                TargetsToBuild.Remove(target);
        }
    }

    private void OnGUI()
    {
        GUILayout.Label("Platforms to Build", EditorStyles.boldLabel);

        // display the build targets
        int numEnabled = 0;
        foreach(var target in AvailableTargets)
        {
            TargetsToBuild[target] = EditorGUILayout.Toggle(target.ToString(), TargetsToBuild[target]);

            if (TargetsToBuild[target])
                numEnabled++;
        }

        if (numEnabled > 0)
        {
            // attempt to build?
            string prompt = numEnabled == 1 ? "Build 1 Platform" : $"Build {numEnabled} Platforms";
            if (GUILayout.Button(prompt))
            {
                List<BuildTarget> selectedTargets = new List<BuildTarget>();
                foreach (var target in AvailableTargets)
                {
                    if (TargetsToBuild[target])
                        selectedTargets.Add(target);
                }

                EditorCoroutineUtility.StartCoroutine(PerformBuild(selectedTargets), this);
            }
        }
    }

    IEnumerator PerformBuild(List<BuildTarget> targetsToBuild)
    {
        // show the progress display
        int buildAllProgressID = Progress.Start("Build All", "Building all selected platforms", Progress.Options.Sticky);
        Progress.ShowDetails();
        yield return new EditorWaitForSeconds(1f);

        BuildTarget originalTarget = EditorUserBuildSettings.activeBuildTarget;

        // build each target
        for (int targetIndex = 0; targetIndex < targetsToBuild.Count; ++targetIndex)
        {
            var buildTarget = targetsToBuild[targetIndex];

            Progress.Report(buildAllProgressID, targetIndex + 1, targetsToBuild.Count);
            int buildTaskProgressID = Progress.Start($"Build {buildTarget.ToString()}", null, Progress.Options.Sticky, buildAllProgressID);
            yield return new EditorWaitForSeconds(1f);

            // perform the build
            if (!BuildIndividualTarget(buildTarget))
            {
                Progress.Finish(buildTaskProgressID, Progress.Status.Failed);
                Progress.Finish(buildAllProgressID, Progress.Status.Failed);

                if (EditorUserBuildSettings.activeBuildTarget != originalTarget)
                    EditorUserBuildSettings.SwitchActiveBuildTargetAsync(GetTargetGroupForTarget(originalTarget), originalTarget);

                yield break;
            }

            Progress.Finish(buildTaskProgressID, Progress.Status.Succeeded);
            yield return new EditorWaitForSeconds(1f);
        }

        Progress.Finish(buildAllProgressID, Progress.Status.Succeeded);

        if (EditorUserBuildSettings.activeBuildTarget != originalTarget)
            EditorUserBuildSettings.SwitchActiveBuildTargetAsync(GetTargetGroupForTarget(originalTarget), originalTarget);

        yield return null;
    }

    bool BuildIndividualTarget(BuildTarget target)
    {
        BuildPlayerOptions options = new BuildPlayerOptions();

        // get the list of scenes
        List<string> scenes = new List<string>();
        foreach (var scene in EditorBuildSettings.scenes)
            scenes.Add(scene.path);

        // configure the build
        options.scenes = scenes.ToArray();
        options.target = target;
        options.targetGroup = GetTargetGroupForTarget(target);

        // set the location path name
        EditorUserBuildSettings.SwitchActiveBuildTarget(GetTargetGroupForTarget(target), target);
        if (target == BuildTarget.Android)
        {

            string apkName = PlayerSettings.productName + ".apk";
            options.locationPathName = System.IO.Path.Combine("Builds", target.ToString(), apkName);
        }else if (target == BuildTarget.StandaloneWindows64)
        {
            options.locationPathName = System.IO.Path.Combine("Builds", target.ToString(), PlayerSettings.productName+".exe");
        }else if (target == BuildTarget.StandaloneLinux64)
        {
            options.locationPathName = System.IO.Path.Combine("Builds", target.ToString(), PlayerSettings.productName+".x86_64");
        }
        else
            options.locationPathName = System.IO.Path.Combine("Builds", target.ToString(), PlayerSettings.productName);

        if (BuildPipeline.BuildCanBeAppended(target, options.locationPathName) == CanAppendBuild.Yes)
            options.options = BuildOptions.AcceptExternalModificationsToPlayer;
        else
            options.options = BuildOptions.None;

        // start the build
        BuildReport report = BuildPipeline.BuildPlayer(options);

        // was the build successful?
        if (report.summary.result == BuildResult.Succeeded)
        {
            Debug.Log($"Build for {target.ToString()} completed in {report.summary.totalTime.Seconds} seconds");
            return true;
        }

        Debug.LogError($"Build for {target.ToString()} failed");

        return false;
    }
}
IainMcManus commented 1 year ago

It looks like the root cause may be the same issue as the one being described here.

The gist seems to be that while BuildPlayer does switch platform, it doesn't run the logic to setup the sysroot modules (needed for the build). And manually calling the function to initialise them isn't an option because it will kill editor coroutines. That tallies with what I've been able to reproduce in testing.

I'll have a try with other approaches and see if I can find a solution but it'll likely need a fix from Unity for it.

peq42 commented 1 year ago

Knowing unity this might never be fixed... that post is over a year old

IainMcManus commented 1 year ago

Hopefully not but potentially. I have a possible workaround I want to try with using C# tasks instead of editor coroutines but it'll depend on how Unity resets things from a scripting point of view, they may also not persist. But if I can get that to work then it may be able to be worked around.