Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug BuildPipeline.BuildPlayer Won't Load "sysroot toolchain" Packages

Discussion in 'Editor & General Support' started by aydin_khp, Jan 29, 2021.

  1. aydin_khp

    aydin_khp

    Joined:
    May 15, 2020
    Posts:
    29
    Hi,

    I am using IL2CPP in my project and use a Windows 10 machine for my development. I don't have any problems building the game for Linux Target using Editor interface (I have installed sysroot component for this purpose).

    However I have some issues with building for Linux using BuildPipeline.BuildPlayer; More specifically, when the active build target (the selected target in the Build Setting window) is Windows and I call BuildPipeline.BuildPlayer I get the "Exception: C++ code builder is unable to build C++ code for Linux: Could not find valid clang executable at clang.exe" error in console and "Building linux il2cpp player requires a linux sysroot package to be installed" in Build Settings window; I don't see these errors and successfully build the Linux version when I manually change the active target to Linux before calling BuildPipeline.BuildPlayer.

    I wanted to first report this issue and then ask if there are any work arounds I can use so that I can use BuildPipeline.BuildPlayer without manual intervention?

    Look forward to hearing from you.

    Regards,
    Aydin
     
  2. aydin_khp

    aydin_khp

    Joined:
    May 15, 2020
    Posts:
    29
    I investigated this issue for a bit; It seems BuildPipeline.BuildPlayer does not wait for InitializePlatformSupportModules to finish its job before starting to build the game.

    It appears to me that InitializePlatformSupportModules is not completely baked into the target change handling code because even in Built Settings window, when I change the target to Linux, sometime it shows the "Building linux il2cpp player requires a linux sysroot package to be installed" error for a short period then removes it and enables the build buttons.

    So one possible workaround for my problem - other than fixing the bug - is that in my script:
    1. Change the active target to Linux using EditorUserBuildSettings.SwitchActiveBuildTarget
    2. Wait for InitializePlatformSupportModules for finish its job then
    3. Then call the BuildPipeline.BuildPlayer
    But I am not sure if there are any events I can listen to in order to find out InitializePlatformSupportModules has finished its job. I tried to use Progress class for this but it is not working the way I want; After the call to EditorUserBuildSettings.SwitchActiveBuildTarget, the "Background Tasks Progress Indicator" (tiny circle usually at the bottom right corner of the screen) shows progress but the tasks list is empty so the Progress events are not get called when the hidden tasks (which I think is InitializePlatformSupportModules finishes).
     
    Last edited: Jan 30, 2021
  3. aydin_khp

    aydin_khp

    Joined:
    May 15, 2020
    Posts:
    29
    Another update:
    • It seems BuildPipeline.BuildPlayer does not even try to initialize sysroot modules at all; I am not even sure if it calls UnityEditor.Modules.ModuleManager:InitializePlatformSupportModules.
    • Apparently the module initialization (i.e. calling UnityEditor.Modules.ModuleManager:InitializePlatformSupportModules) that happens after changing targets using EditorUserBuildSettings.SwitchActiveBuildTarget resets many things in the editor which makes me unable to wait for module initializations before calling BuildPipeline.BuildPlayer; For example:
      • Handlers for Application.logMessageReceived won't get called after module initialization; It seems all the subscribers to this C# event are get removed.
      • The EditorCoroutines stop working when the module initialization happens.
     
  4. peq42

    peq42

    Joined:
    Mar 4, 2022
    Posts:
    74
  5. unity_CDVKxN7snkcptA

    unity_CDVKxN7snkcptA

    Joined:
    Mar 24, 2020
    Posts:
    13
    Bring this post up for I'm meeting same issue too. Using teamcity for automatic build and it now block at linux IL2CPP build, saying: "Exception: C++ code builder is unable to build C++ code for Linux: Could not find valid clang executable at clang.exe" though the package is actually in the project.
    So... with the info above, I guess add build target parameter in headless command(or set this parameter in teamcity build step configurations) should solve it?
    In teamcity it says "Specify an active build target before loading the project.". Not sure with the command line will this work.
     
    Last edited: Feb 8, 2023
  6. Leslie-Young

    Leslie-Young

    Joined:
    Dec 24, 2008
    Posts:
    1,148
    I've managed to build for Linux without error using BuildPlayer by waiting till after domain reload.
    Note: In my case I am starting the builds from the menu. Did not test batch building all target platforms from menu yet but I guess it will involve more saving to file and waiting for reloads.
    • Save to file the info about what it is you want to build.
    • Do EditorUserBuildSettings.SwitchActiveBuildTarget
    • Have a [InitializeOnLoadMethod] method that adds another to EditorApplication.delayCall
    • In the delay called method you read the saved file to find what must be build, and do the build (delete the saved file!)
    Something like this ...

    Code (CSharp):
    1. private static void Build(Store store, Target target, bool demo)
    2. {
    3.     // store info about what should be build
    4.     if (!SaveBuildInfo(new BuildInfo { store = store, target = target, demo = demo }))
    5.     {
    6.         return;
    7.     }
    8.  
    9.     // start build now if active build target is correct
    10.     if (EditorUserBuildSettings.activeBuildTarget == ToBuildTarget(target))
    11.     {
    12.         Build();
    13.     }
    14.  
    15.     // else, switch to correct target. this will trigger a domain relaod during which the build will start
    16.     else
    17.     {
    18.         EditorUserBuildSettings.SwitchActiveBuildTarget(ToBuildTargetGroup(target), ToBuildTarget(target));
    19.     }
    20. }
    21.  
    22. [InitializeOnLoadMethod]
    23. private static void CheckBuildOnLoad()
    24. {
    25.     EditorApplication.delayCall += Build;
    26. }
    27.  
    28. private static void Build()
    29. {
    30.     EditorApplication.delayCall -= Build;
    31.  
    32.     var nfo = LoadBuildInfo();
    33.     if (nfo == null) return;
    34.  
    35.     // get rid of the file now so that next domain load don't trigger a build
    36.     ClearBuildInfo();
    37.  
    38.     if (EditorUserBuildSettings.activeBuildTarget != ToBuildTarget(nfo.target))
    39.     {
    40.         Debug.LogError($"Build failed: {EditorUserBuildSettings.activeBuildTarget} != {ToBuildTarget(nfo.target)}");
    41.         return;
    42.     }
    43.  
    44.     ..
    45.     ..
    46.     ..
    47.     var report = BuildPipeline.BuildPlayer(ops);
    48.     ..
    49.     ..
    50. }
    51.  
    52. private static void ClearBuildInfo()
    53. {
    54.     var path = Application.dataPath.Replace("\\", "/").Replace("/Assets", $"/Temp/ply_build_info.json");
    55.     if (File.Exists(path))
    56.     {
    57.         try
    58.         {
    59.             File.Delete(path);
    60.         }
    61.         catch
    62.         {
    63.             Debug.LogError("Failed to delete build info file.");
    64.         }
    65.     }
    66. }
    67.  
    68. private static bool SaveBuildInfo(BuildInfo nfo)
    69. {
    70.     var path = Application.dataPath.Replace("\\", "/").Replace("/Assets", $"/Temp/ply_build_info.json");
    71.     var json = JsonUtility.ToJson(nfo);
    72.  
    73.     try
    74.     {
    75.         File.WriteAllText(path, json);
    76.         return true;
    77.     }
    78.     catch
    79.     {
    80.         Debug.LogError("Failed to write build info file.");
    81.         return false;
    82.     }
    83. }
    84.  
    85. private static BuildInfo LoadBuildInfo()
    86. {
    87.     var path = Application.dataPath.Replace("\\", "/").Replace("/Assets", $"/Temp/ply_build_info.json");
    88.     if (File.Exists(path))
    89.     {
    90.         try
    91.         {
    92.             var json = File.ReadAllText(path);
    93.             return JsonUtility.FromJson<BuildInfo>(json);
    94.         }
    95.         catch
    96.         {
    97.             Debug.LogError("Failed to load build info file.");
    98.             return null;
    99.         }
    100.     }
    101.     else
    102.     {
    103.         return null;
    104.     }
    105. }