309 lines
9.5 KiB
C#
309 lines
9.5 KiB
C#
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Diagnostics;
|
||
|
using System.IO;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using UnityEngine;
|
||
|
using UnityEditorInternal;
|
||
|
using UnityEditor;
|
||
|
using NiceIO.Sysroot;
|
||
|
#if UNITY_STANDALONE_LINUX_API
|
||
|
using UnityEditor.LinuxStandalone;
|
||
|
#endif
|
||
|
|
||
|
namespace UnityEditor.Il2Cpp
|
||
|
{
|
||
|
|
||
|
/// <summary>
|
||
|
/// Describe a payload location and destination
|
||
|
/// </summary>
|
||
|
public struct PayloadDescriptor
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Path of payload tarball
|
||
|
/// </summary>
|
||
|
internal NPath path;
|
||
|
/// <summary>
|
||
|
/// Path directory where payload is to be installed
|
||
|
/// </summary>
|
||
|
internal NPath dir;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initialization status
|
||
|
/// </summary>
|
||
|
enum InitializationStatus
|
||
|
{
|
||
|
Uninitialized,
|
||
|
Failed,
|
||
|
Succeeded
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Base class for sysroot and toolchain packages
|
||
|
/// </summary>
|
||
|
public class SysrootPackage
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
: Sysroot
|
||
|
#endif
|
||
|
{
|
||
|
private static bool IsLinuxIL2CPPPresent()
|
||
|
{
|
||
|
string targetDir = $"{BuildPipeline.GetPlaybackEngineDirectory(BuildTargetGroup.Standalone, BuildTarget.StandaloneLinux64, BuildOptions.None)}/Variations/il2cpp";
|
||
|
if (Directory.Exists(targetDir))
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public static bool ShouldLogDebugMessage()
|
||
|
{
|
||
|
return !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("UNITY_SYSROOT_DEBUG"));
|
||
|
}
|
||
|
|
||
|
[InitializeOnLoadMethod]
|
||
|
private static void IssueWarningIfLinuxIL2CPPNotPresent()
|
||
|
{
|
||
|
if (ShouldLogDebugMessage() && !IsLinuxIL2CPPPresent())
|
||
|
{
|
||
|
UnityEngine.Debug.LogWarning($"Linux Compiler Toolchain package(s) present, but required Linux-IL2CPP is missing");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of package
|
||
|
/// </summary>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
string Name => "com.unity.sysroot";
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of host platform (linux, win, macos)
|
||
|
/// </summary>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
string HostPlatform => "";
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of host architecture
|
||
|
/// </summary>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
string HostArch => "";
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of target platform (linux, win, macos)
|
||
|
/// </summary>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
string TargetPlatform => "";
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of target architecture
|
||
|
/// </summary>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
string TargetArch => "";
|
||
|
|
||
|
/// <summary>
|
||
|
/// Supplies arguments to il2cpp.exe
|
||
|
/// </summary>
|
||
|
/// <returns>Next argument to il2cpp.exe</returns>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
IEnumerable<string> GetIl2CppArguments() { return null; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of payload tarball
|
||
|
/// </summary>
|
||
|
protected string Payload => "payload.tar.7z";
|
||
|
|
||
|
private List<PayloadDescriptor> _payloads = new List<PayloadDescriptor>();
|
||
|
private InitializationStatus _initStatus = InitializationStatus.Uninitialized;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initialize package
|
||
|
/// </summary>
|
||
|
/// <returns>Success or failure of initialization</returns>
|
||
|
public
|
||
|
#if UNITY_STANDALONE_LINUX_API || UNITY_WEBGL_API
|
||
|
override
|
||
|
#else
|
||
|
virtual
|
||
|
#endif
|
||
|
bool Initialize()
|
||
|
{
|
||
|
if (_initStatus != InitializationStatus.Uninitialized)
|
||
|
return _initStatus == InitializationStatus.Succeeded;
|
||
|
|
||
|
foreach (PayloadDescriptor pd in _payloads)
|
||
|
{
|
||
|
if (!Directory.Exists(pd.dir.ToString(SlashMode.Native)) && !InstallPayload(pd))
|
||
|
{
|
||
|
UnityEngine.Debug.LogError($"Failed to initialize package: {Name}");
|
||
|
_initStatus = InitializationStatus.Failed;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_initStatus = InitializationStatus.Succeeded;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Compute path of payload tarball
|
||
|
/// </summary>
|
||
|
/// <param name="packageName">The name of the package</param>
|
||
|
/// <returns>Path of payload tarball</returns>
|
||
|
internal NPath PayloadPath(string packageName)
|
||
|
{
|
||
|
return new NPath(Path.GetFullPath($"Packages/{packageName}")).Combine("data~/payload.tar.7z");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Register payload tarball and destination (installed location)
|
||
|
/// </summary>
|
||
|
/// <param name="packageName">The name of the package</param>
|
||
|
/// <param name="payloadDir">The directory to install the payload in relative to sysroot cache</param>
|
||
|
public void RegisterPayload(string packageName, string payloadDir)
|
||
|
{
|
||
|
_payloads.Add(new PayloadDescriptor{path = PayloadPath(packageName).ToString(SlashMode.Native), dir = PayloadInstallDirectory(payloadDir).ToString(SlashMode.Native)});
|
||
|
}
|
||
|
|
||
|
private bool RunShellCommand(string command, string workDir = null)
|
||
|
{
|
||
|
var p = new Process();
|
||
|
p.StartInfo.UseShellExecute = false;
|
||
|
#if UNITY_EDITOR_WIN
|
||
|
p.StartInfo.CreateNoWindow = true;
|
||
|
p.StartInfo.FileName = "cmd";
|
||
|
p.StartInfo.Arguments = $"/c \"{command}\"";
|
||
|
#else
|
||
|
p.StartInfo.FileName = "/bin/sh";
|
||
|
p.StartInfo.Arguments = $"-c \'{command}\'";
|
||
|
#endif
|
||
|
p.StartInfo.WorkingDirectory = string.IsNullOrEmpty(workDir) ? Environment.CurrentDirectory : workDir;
|
||
|
p.Start();
|
||
|
p.WaitForExit();
|
||
|
bool result = p.ExitCode == 0;
|
||
|
if (!result && ShouldLogDebugMessage())
|
||
|
UnityEngine.Debug.LogError($"Failed to execute command command=\"{p.StartInfo.FileName}\" arguments=\"{p.StartInfo.Arguments}\"");
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private bool DecompressSysroot(NPath payload, NPath workDir)
|
||
|
{
|
||
|
if (!RunShellCommand(CommandCreateDirectory(workDir)))
|
||
|
{
|
||
|
UnityEngine.Debug.LogError($"Failed to create directory {workDir}");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!RunShellCommand(CommandUncompressTarball(payload, workDir), workDir.ToString(SlashMode.Native)))
|
||
|
{
|
||
|
UnityEngine.Debug.LogError($"Failed to uncompress payload");
|
||
|
RunShellCommand(CommandRemoveDirectoryTree(workDir));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return PostDecompressActions(workDir);
|
||
|
}
|
||
|
|
||
|
private bool InstallPayload(PayloadDescriptor pd)
|
||
|
{
|
||
|
return DecompressSysroot(pd.path, pd.dir);
|
||
|
}
|
||
|
|
||
|
private string CommandCreateDirectory(NPath dir)
|
||
|
{
|
||
|
_initStatus = InitializationStatus.Failed;
|
||
|
#if UNITY_EDITOR_WIN
|
||
|
return $"mkdir {dir.InQuotes(SlashMode.Native)}";
|
||
|
#else
|
||
|
return $"mkdir -p {dir.InQuotes()}";
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
private string Get7zPath()
|
||
|
{
|
||
|
#if UNITY_EDITOR_WIN
|
||
|
string command = "7z";
|
||
|
#else
|
||
|
string command = "7za";
|
||
|
#endif
|
||
|
return new NPath($"{EditorApplication.applicationContentsPath}/Tools/{command}").InQuotes(SlashMode.Native);
|
||
|
}
|
||
|
|
||
|
private string CommandUncompressTarball(NPath tarball, NPath destDir)
|
||
|
{
|
||
|
#if UNITY_EDITOR_WIN
|
||
|
return $"{Get7zPath()} x -y {tarball.InQuotes(SlashMode.Native)} -so | {Get7zPath()} x -y -aoa -ttar -si";
|
||
|
#else
|
||
|
return $"{Get7zPath()} x -y {tarball.InQuotes()} -so | tar xf - --directory={destDir.InQuotes()}";
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
private string CommandRemoveDirectoryTree(NPath dir)
|
||
|
{
|
||
|
#if UNITY_EDITOR_WIN
|
||
|
return $"rd /s /q {dir.InQuotes(SlashMode.Native)}";
|
||
|
#else
|
||
|
return $"rm -rf {dir.InQuotes()}";
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
private bool PostDecompressActions(NPath workDir)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private string UserAppDataFolder()
|
||
|
{
|
||
|
return
|
||
|
#if UNITY_EDITOR_OSX
|
||
|
$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Library/Unity";
|
||
|
#else
|
||
|
$"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/unity3d";
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns path of installed payload
|
||
|
/// </summary>
|
||
|
/// <param name="payloadDir">The directory to install the payload in relative to sysroot cache</param>
|
||
|
/// <returns>Fully-qualified path of install directory</returns>
|
||
|
internal NPath PayloadInstallDirectory(string payloadDir)
|
||
|
{
|
||
|
string cacheDir = Environment.GetEnvironmentVariable("UNITY_SYSROOT_CACHE");
|
||
|
if (string.IsNullOrEmpty(cacheDir))
|
||
|
cacheDir = $"{UserAppDataFolder()}/cache/sysroots";
|
||
|
return new NPath($"{cacheDir}/{payloadDir}");
|
||
|
}
|
||
|
}
|
||
|
}
|