Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to use packages like Microsoft.Net.Compilers.Toolset #3

Merged
merged 5 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 235 additions & 28 deletions Assets/CSharpCompilerSettings/AsmdefEx.Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,48 @@ public static void Set(this object self, string memberName, object value, Member
}
}

internal static class CustomCompiler
internal enum CompilerType
{
NetFramework,
NetCore,
}

internal readonly struct CompilerInfo
{
public readonly CompilerType Type;
public readonly string Path;

public CompilerInfo(CompilerType type, string path)
{
Type = type;
Path = path;
}
}

internal readonly struct CompilerFilter
{
public readonly CompilerType Type;
public readonly string RelatedPath;

public CompilerFilter(CompilerType type, string relatedPath)
{
Type = type;
RelatedPath = relatedPath;
}
}

internal static class DotnetRuntime
{
static string s_InstallPath;

public static string GetInstalledPath(string packageId)
public static string GetInstalledPath()
{
if (!string.IsNullOrEmpty(s_InstallPath) && File.Exists(s_InstallPath))
return s_InstallPath;

try
{
s_InstallPath = Install(packageId);
s_InstallPath = Install();
}
catch (Exception ex)
{
Expand All @@ -90,19 +120,186 @@ public static string GetInstalledPath(string packageId)
return s_InstallPath;
}

private static string Install(string packageId)
private static string GetDotnetDownloadUrl()
{
const string pattern = "https://dotnetcli.azureedge.net/dotnet/Runtime/{0}/dotnet-runtime-{0}-{1}-x64.{2}";


// todo: replace hardcoded 3.1.8 with maximum available version
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
return string.Format(pattern, "3.1.8", "win", "zip");
case RuntimePlatform.OSXEditor:
return string.Format(pattern, "3.1.8", "osx", "tar.gz");
case RuntimePlatform.LinuxEditor:
return string.Format(pattern, "3.1.8", "linux", "tar.gz");
default:
throw new NotSupportedException($"{Application.platform} is not supported");
}
}

private static string Install()
{
var currentDirectory = Directory.GetCurrentDirectory();
var sep = Path.DirectorySeparatorChar;
var url = GetDotnetDownloadUrl();
var downloadPath = Path.Combine("Temp", Path.GetFileName(Path.GetTempFileName()));
var installPath = Path.Combine("Library", "DotNetRuntime");
var dotnetPath = Path.Combine(installPath, Application.platform == RuntimePlatform.WindowsEditor
? "dotnet.exe"
: "dotnet");

// C# compiler is already installed.
if (File.Exists(dotnetPath))
{
Core.LogDebug($"dotnet runtime is already installed at {dotnetPath}");
return dotnetPath;
}

if (Directory.Exists(installPath))
Directory.Delete(installPath, true);

var cb = ServicePointManager.ServerCertificateValidationCallback;
ServicePointManager.ServerCertificateValidationCallback = (_, __, ___, ____) => true;
try
{
Core.LogInfo("Install dotnet runtime");

// Download C# compiler package from nuget.
{
Core.LogInfo("Download {0}", url);
EditorUtility.DisplayProgressBar("Dotnet Installer", "Downloading", 0.2f);

try
{
using (var client = new WebClient())
{
client.DownloadFile(url, downloadPath);
}
}
catch
{
Core.LogInfo("Download {0} (alternative)", url);
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
ShellHelper.ExecuteCommand("PowerShell.exe", string.Format("curl -O {0} {1}", downloadPath, url));
break;
case RuntimePlatform.OSXEditor:
ShellHelper.ExecuteCommand("curl", string.Format("-o {0} -L {1}", downloadPath, url));
break;
case RuntimePlatform.LinuxEditor:
ShellHelper.ExecuteCommand("wget", string.Format("-O {0} {1}", downloadPath, url));
break;
}
}
}

// Extract nuget package (unzip).
{
Core.LogInfo("Extract {0} to {1} with 7z", downloadPath, installPath);
EditorUtility.DisplayProgressBar("Dotnet Installer", string.Format("Extract {0}", downloadPath), 0.4f);
ExtractArchive(downloadPath, installPath);
}

Core.LogInfo($"Dotnet has been installed at {installPath}.");
}
catch
{
throw new Exception(string.Format("Dotnet installation failed."));
}
finally
{
ServicePointManager.ServerCertificateValidationCallback = cb;
EditorUtility.ClearProgressBar();
}

if (File.Exists(dotnetPath))
return dotnetPath;

throw new FileNotFoundException(string.Format("Dotnet is not found at {0}", dotnetPath));
}

private static void ExtractArchive(string archivePath, string extractToPath)
{
var appPath = EditorApplication.applicationContentsPath.Replace('/', Path.DirectorySeparatorChar);

switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
var args = string.Format("x {0} -o{1}", archivePath, extractToPath);
ShellHelper.ExecuteCommand(appPath + "\\Tools\\7z.exe", args);
break;
case RuntimePlatform.OSXEditor:
case RuntimePlatform.LinuxEditor:
// 7za doesn't preserve permission but tar does
Directory.CreateDirectory(extractToPath);
args = string.Format("-pzxf {0} -C {1}", archivePath, extractToPath);
ShellHelper.ExecuteCommand("tar", args);
break;
}
}
}

internal static class CustomCompiler
{
static CompilerInfo? s_compilerInfo;
static string s_cachedPackageId;

private static readonly CompilerFilter[] CompilerFilters = new[]
{
new CompilerFilter(CompilerType.NetCore, Path.Combine("tasks", "netcoreapp3.1", "bincore", "csc.dll")),
new CompilerFilter(CompilerType.NetCore, Path.Combine("tasks", "netcoreapp2.1", "bincore", "csc.dll")),
new CompilerFilter(CompilerType.NetFramework, Path.Combine("tools", "csc.exe")),
};

public static CompilerInfo? GetInstalledPath(string packageId)
{
if (s_compilerInfo != null && File.Exists(s_compilerInfo.Value.Path) && s_cachedPackageId == packageId)
return s_compilerInfo;

try
{
s_compilerInfo = Install(packageId);
}
catch (Exception ex)
{
Core.LogExeption(ex);
}

s_cachedPackageId = packageId;
return s_compilerInfo;
}

private static bool TryFindCompilerInPackageFolder(string packagePath, out CompilerInfo compilerInfo)
{
foreach (var filter in CompilerFilters)
{
var cscPath = Path.Combine(packagePath, filter.RelatedPath);
if (!File.Exists(cscPath))
continue;

compilerInfo = new CompilerInfo(filter.Type, cscPath);
return true;
}

compilerInfo = default(CompilerInfo);
return false;
}

private static CompilerInfo Install(string packageId)
{
var sep = Path.DirectorySeparatorChar;
var url = "https://globalcdn.nuget.org/packages/" + packageId.ToLower() + ".nupkg";
var downloadPath = ("Temp/" + Path.GetFileName(Path.GetTempFileName())).Replace('/', sep);
var installPath = ("Library/" + packageId).Replace('/', sep);
var cscToolExe = (installPath + "/tools/csc.exe").Replace('/', sep);

// C# compiler is already installed.
if (File.Exists(cscToolExe))
if (TryFindCompilerInPackageFolder(installPath, out var compilerInfo))
{
Core.LogDebug("C# compiler '{0}' is already installed at {1}", packageId, cscToolExe);
return cscToolExe;
Core.LogDebug("C# compiler '{0}' is already installed at {1}", packageId, compilerInfo.Path);
return compilerInfo;
}

if (Directory.Exists(installPath))
Expand Down Expand Up @@ -132,13 +329,13 @@ private static string Install(string packageId)
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
ExecuteCommand("PowerShell.exe", string.Format("curl -O {0} {1}", downloadPath, url));
ShellHelper.ExecuteCommand("PowerShell.exe", string.Format("curl -O {0} {1}", downloadPath, url));
break;
case RuntimePlatform.OSXEditor:
ExecuteCommand("curl", string.Format("-o {0} -L {1}", downloadPath, url));
ShellHelper.ExecuteCommand("curl", string.Format("-o {0} -L {1}", downloadPath, url));
break;
case RuntimePlatform.LinuxEditor:
ExecuteCommand("wget", string.Format("-O {0} {1}", downloadPath, url));
ShellHelper.ExecuteCommand("wget", string.Format("-O {0} {1}", downloadPath, url));
break;
}
}
Expand All @@ -155,11 +352,11 @@ private static string Install(string packageId)
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
ExecuteCommand(appPath + "\\Tools\\7z.exe", args);
ShellHelper.ExecuteCommand(appPath + "\\Tools\\7z.exe", args);
break;
case RuntimePlatform.OSXEditor:
case RuntimePlatform.LinuxEditor:
ExecuteCommand(appPath + "/Tools/7za", args);
ShellHelper.ExecuteCommand(appPath + "/Tools/7za", args);
break;
}
}
Expand All @@ -176,13 +373,16 @@ private static string Install(string packageId)
EditorUtility.ClearProgressBar();
}

if (File.Exists(cscToolExe))
return cscToolExe;
if (TryFindCompilerInPackageFolder(installPath, out compilerInfo))
return compilerInfo;

throw new FileNotFoundException(string.Format("C# compiler '{0}' is not found at {1}", packageId, cscToolExe));
throw new FileNotFoundException(string.Format("C# compiler '{0}' is not found in {1}", packageId, installPath));
}
}

private static void ExecuteCommand(string exe, string args)
internal class ShellHelper
{
public static void ExecuteCommand(string exe, string args)
{
Core.LogInfo("Execute command: {0} {1}", exe, args);

Expand Down Expand Up @@ -250,9 +450,8 @@ private static void ChangeCompilerProcess(object compiler, object scriptAssembly
var psi = compiler.Get("process", fiProcess).Call("GetProcessStartInfo") as ProcessStartInfo;
LogDebug("current process: {0}", (psi.FileName + " " + psi.Arguments));

var command = (psi.FileName + " " + psi.Arguments)
.Replace(EditorApplication.applicationContentsPath, "@APP_CONTENTS@")
.Replace('\\', '/');
var command = (psi.FileName + " " + psi.Arguments).Replace('\\', '/')
.Replace(EditorApplication.applicationContentsPath.Replace('\\', '/'), "@APP_CONTENTS@");
var isDefaultCsc = Regex.IsMatch(command, "@APP_CONTENTS@/[^ ]*(mcs|csc)");

// csc is not Unity default. It is already modified.
Expand All @@ -262,10 +461,10 @@ private static void ChangeCompilerProcess(object compiler, object scriptAssembly
return;
}

var cscToolExe = CustomCompiler.GetInstalledPath(setting.PackageId);
var compilerInfo = CustomCompiler.GetInstalledPath(setting.PackageId);

// csc is not installed.
if (string.IsNullOrEmpty(cscToolExe))
if (!compilerInfo.HasValue)
{
LogDebug(" <color=#bbbb44><Skipped> custom csc is not installed.</color>");
return;
Expand All @@ -283,16 +482,24 @@ private static void ChangeCompilerProcess(object compiler, object scriptAssembly
text += "\n/preferreduilang:en-US";

// Change exe file path.
LogDebug("Change csc to {0}", cscToolExe);
if (Application.platform == RuntimePlatform.WindowsEditor)
LogDebug("Change csc to {0}", compilerInfo);
if (compilerInfo.Value.Type == CompilerType.NetFramework)
{
psi.FileName = Path.GetFullPath(cscToolExe);
psi.Arguments = "/shared /noconfig @" + responseFile;
if (Application.platform == RuntimePlatform.WindowsEditor)
{
psi.FileName = Path.GetFullPath(compilerInfo.Value.Path);
psi.Arguments = "/shared /noconfig @" + responseFile;
}
else
{
psi.FileName = Path.Combine(EditorApplication.applicationContentsPath, "MonoBleedingEdge/bin/mono");
psi.Arguments = compilerInfo.Value.Path + " /noconfig @" + responseFile;
}
}
else
{
psi.FileName = Path.Combine(EditorApplication.applicationContentsPath, "MonoBleedingEdge/bin/mono");
psi.Arguments = cscToolExe + " /noconfig @" + responseFile;
psi.FileName = Path.GetFullPath(DotnetRuntime.GetInstalledPath());
psi.Arguments = compilerInfo.Value.Path + " /noconfig @" + responseFile;
}

text = Regex.Replace(text, "\n", Environment.NewLine);
Expand Down
7 changes: 7 additions & 0 deletions Packages/CSharpCompilerSettings/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## [1.0.1](https://github.com/mob-sakai/CSharpCompilerSettingsForUnity/compare/v1.0.0...v1.0.1) (2020-09-17)


### Bug Fixes

* Not working on Windows ([b0d4eba](https://github.com/mob-sakai/CSharpCompilerSettingsForUnity/commit/b0d4ebacf6d940b14aecf6d79ef7fdb4ebddcaa3)), closes [#1](https://github.com/mob-sakai/CSharpCompilerSettingsForUnity/issues/1)

# 1.0.0 (2020-09-11)


Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion Packages/CSharpCompilerSettings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "com.coffee.csharp-compiler-settings",
"displayName": "C# Compiler Settings",
"description": "Change the C# compiler (csc) used in your Unity project, as you like!",
"version": "1.0.0",
"version": "1.0.1",
"unity": "2018.3",
"license": "MIT",
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions ProjectSettings/CSharpCompilerSettings.asset
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"m_UseDefaultCompiler": false,
"m_PackageName": "Microsoft.Net.Compilers",
"m_PackageVersion": "3.5.0",
"m_PackageName": "Microsoft.Net.Compilers.Toolset",
"m_PackageVersion": "3.7.0",
"m_LanguageVersion": 2147483647
}