Skip to content

Commit

Permalink
Merge pull request #3 from VolodymyrBS/develop
Browse files Browse the repository at this point in the history
Allow to use packages like Microsoft.Net.Compilers.Toolset
  • Loading branch information
mob-sakai committed Oct 2, 2020
2 parents 415a1fb + b783431 commit 4b16c83
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 31 deletions.
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
}

0 comments on commit 4b16c83

Please sign in to comment.