I really wanted to be able to automate building for all platforms using the Build Pipeline but it seems a few snags are confusing me and I’m not sure how to proceed or what this pipeline API is really doing under the hood.
To start with, this is the code I use when I want to build for a certain target:
static BuildReport BuildPlayerForTarget(BuildTarget buildTarget, string path, string subdirPlatformName, string extension)
{
var buildOptions = BuildOptions.None;
var finalPath = path + "/" + gameFolderShortName + subdirPlatformName;
finalPath = finalPath + "/" + Application.productName + extension;
Debug.Log("BuildTarget Player Started: " + buildTarget.ToString() + " | " + finalPath);
return BuildPipeline.BuildPlayer(EditorBuildSettings.scenes, finalPath, buildTarget, buildOptions);
}
This gets run 3 times (PC, Mac, and Linux) when I use my custom menu option for building on preset options.
Issue #1 - No Linux Mono Build Target?
For the Linux run, I use BuildTarget.StandaloneLinux64, which according to this is the only supported Linux target currently. But when I ran it, it started complaining about IL2CPP not being installed. Checking my modules, it was correct. I only had Linux (Mono) installed. I looked through the build options but I couldn’t find anything that would let me target Mono instead of CPP from the BuildPipeline API, even though I’d assume I could still target Mono from the usual build popup window. So I went ahead and installed IL2CPP support:
Running it again, I encountered this error:
Exception: C++ code builder is unable to build C++ code for Linux: Could not find valid clang executable at clang.exe
UnityEditorInternal.Runner.RunProgram (UnityEditor.Utils.Program p, System.String exe, System.String args, System.String workingDirectory, UnityEditor.Scripting.Compilers.CompilerOutputParserBase parser) (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditorInternal.Runner.RunManagedProgram (System.String exe, System.String args, System.String workingDirectory, UnityEditor.Scripting.Compilers.CompilerOutputParserBase parser, System.Action`1[T] setupStartInfo) (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditorInternal.IL2CPPBuilder.RunIl2CppWithArguments (System.Collections.Generic.List`1[T] arguments, System.Action`1[T] setupStartInfo) (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditorInternal.IL2CPPBuilder.ConvertPlayerDlltoCpp (UnityEditor.Il2Cpp.Il2CppBuildPipelineData data) (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditorInternal.IL2CPPBuilder.Run () (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditorInternal.IL2CPPUtils.RunIl2Cpp (System.String stagingAreaData, UnityEditorInternal.IIl2CppPlatformProvider platformProvider, System.Action`1[T] modifyOutputBeforeCompile, UnityEditor.RuntimeClassRegistry runtimeClassRegistry) (at <55729f52d042492e9efc384182ae2feb>:0)
DesktopStandalonePostProcessor.RunIL2CPP (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditorInternal.IIl2CppPlatformProvider il2cppPlatformProvider, System.Collections.Generic.List`1[T] cppPlugins) (at <55729f52d042492e9efc384182ae2feb>:0)
DesktopStandalonePostProcessor.SetupStagingArea (UnityEditor.Modules.BuildPostProcessArgs args, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at <55729f52d042492e9efc384182ae2feb>:0)
DesktopStandalonePostProcessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args) (at <55729f52d042492e9efc384182ae2feb>:0)
Rethrow as BuildFailedException: Exception of type 'UnityEditor.Build.BuildFailedException' was thrown.
DesktopStandalonePostProcessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args) (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditor.Modules.DefaultBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditor.BuildProperties& outProperties) (at <55729f52d042492e9efc384182ae2feb>:0)
UnityEditor.PostprocessBuildPlayer.Postprocess (UnityEditor.BuildTargetGroup targetGroup, UnityEditor.BuildTarget target, 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 <55729f52d042492e9efc384182ae2feb>:0)
UnityEditor.BuildPipeline:BuildPlayer(EditorBuildSettingsScene[], String, BuildTarget, BuildOptions)
This other forum post made me start to worry that it wasn’t waiting for a platform switch to complete before building the player, however I also saw now that I didn’t install the sysroot toolchain package:
Fair enough I guess, but now I don’t see any option to revert back to Mono build to quickly get around this. There’s nothing in this window so did IL2CPP just override it? Is the only way to target Mono again to uninstall the IL2CPP package? There isn’t any option within Unity Hub to do that so I’d have to go digging around in the files which is a bit of a pain. To me it’s odd that having both modules installed doesn’t give you an option for either so any insight on this is appreciated.
Issue #2 - .app not working for Mac?
I have noticed as well that BuildPlayer seems to just not run when I target StandaloneOSX. I suspect that this has to do with some awkward behavior I’ve noticed when building normally in the past. When building for Windows or Linux, you are asked to put in a file name and it saves under .exe or .x86 etc. But when building for Mac from the Build menu it asks for a folder, and it doesn’t dump the .app into that folder but instead creates a duplicate folder with the same name but with the .app extension and puts the contents into that.
So could this be why the BuildPipeline is failing? Does it expect me to give it a plain folder name (without .app) where it will create a new one with .app at the end? I’m curious about the specifics of what the BuildPlayer function is trying to do here.
Issue #3 - Asset errors on Linux only
When I build for linux, a separate issue occurs, timestamped before the C++ code builder error.
The asset at Assets/Textures/UI/Fonts/SubtitleFonts/NotoSans-BoldItalic.ttf has been scheduled for reimport during the Refresh loop and Loading of it has been attempted.
Doing this can lead to the AssetDatabase returning two versions of the same asset.
Please ensure that code which attempts to reimport this asset does not run while the editor is Refreshing.
You can do so by checking the value of EditorApplication.isUpdating
UnityEditor.BuildPipeline:BuildPlayer (UnityEditor.EditorBuildSettingsScene[],string,UnityEditor.BuildTarget,UnityEditor.BuildOptions)
Could this be because BuildPlayer didn’t wait for target platform to switch like in the above post I linked? I don’t think I have any code that would be touching those assets at this time, so I’m not sure why they were scheduled for re-import. I will do more testing on manual builds to see if this is still the case outside of BuildPipeline API.
Thanks for any insight and help, the Build Pipeline is really neat but I’d like to be able to understand it better and avoid problems like this to help speed up and streamline my deployment.