mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 23:18:56 -07:00
239 lines
9.8 KiB
PowerShell
239 lines
9.8 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Puts back the Roslyn script compiler that Windows Defender quarantines out of the Unity
|
|
package cache, so the editor can compile the project at all.
|
|
|
|
.DESCRIPTION
|
|
Unity 2020.3 compiles C# by launching an *external* compiler, and because this project
|
|
installs `com.unity.roslyn` (a transitive dependency of `com.unity.entities`) that compiler
|
|
is the one shipped inside the package:
|
|
|
|
<ProjectRoot>\Library\PackageCache\com.unity.roslyn@<hash>\Compiler~\win64\csc.exe
|
|
|
|
Defender quarantines unsigned executables out of Unity package folders on this machine - the
|
|
recorded casualties are `com.unity.burst\.Runtime\hostwin\llvm-lipo.exe` and `dsymutil.exe`
|
|
(heuristic PUA signatures, ThreatID 2147972435) and, for this project, that `csc.exe`. It has
|
|
to be deleted rather than absent from the package: the registry tarball does ship it
|
|
(`package/Compiler~/win64/csc.exe`).
|
|
|
|
With it gone, Unity logs the same failure for every assembly it was about to build:
|
|
|
|
Starting external compile of Unity.Jobs.CodeGen.dll: ...\Compiler~\win64\csc.exe ...
|
|
Exception when running external compiler: System.ComponentModel.Win32Exception
|
|
(0x80004005): Native error= The system cannot find the file specified.
|
|
|
|
and then, because nothing compiled at all, reports the misleading
|
|
|
|
Unable to resolve reference 'Unity.Mathematics' / 'Unity.Collections' / ...
|
|
|
|
for every `com.recroom.*` assembly, while `Library\ScriptAssemblies` stays empty apart from
|
|
`BuiltinAssemblies.stamp`. So: an empty ScriptAssemblies folder plus a wall of unresolvable
|
|
references means "the compiler never ran", not "the packages are broken".
|
|
|
|
This script restores the file from `-FromPath`, or from the Unity editor install's own
|
|
`Editor\Data\Tools\Roslyn\csc.exe` (a different build of the same 3.8 apphost, verified to
|
|
drive the package's newer `csc.dll`), and then proves it runs by asking it for its version.
|
|
|
|
The Unity-install copy is 3.8.0-dev.20527.1 as well, so the compiler behaviour is unchanged;
|
|
only the ~170 KB launcher differs. Prefer `-FromPath` with the authentic file if you have the
|
|
package tarball to hand:
|
|
https://cdn.packages.unity.com/tarballs/com.unity.roslyn/com.unity.roslyn-0.2.2-preview/8b5b337db92cbdec37b54235ec8b826c92c6ddef.tgz
|
|
(`tar -xzf <tgz> package/Compiler~/win64/csc.exe`, md5 8c4361cc37113f8467feb1d22b4e83da)
|
|
|
|
This is a repair, not a cure: Defender will do it again on the next full scan, and a Unity
|
|
package re-resolve copies the damaged file back out of the shared cache. Add the exclusions
|
|
this script prints at the end, and re-run with -IncludeGlobalCache, to close both loops.
|
|
|
|
.PARAMETER ProjectRoot
|
|
Candidate project roots, tried in order; the first one that exists and holds the roslyn
|
|
package cache is used.
|
|
|
|
.PARAMETER FromPath
|
|
Use this csc.exe instead of the Unity editor install's copy.
|
|
|
|
.PARAMETER IncludeGlobalCache
|
|
Also repair the shared package cache under %LOCALAPPDATA%\Unity\cache\packages, which is
|
|
where a re-resolve would otherwise copy the missing file back from.
|
|
|
|
.PARAMETER Force
|
|
Overwrite csc.exe even when one is already present and working.
|
|
|
|
.EXAMPLE
|
|
pwsh -File tools/repair-unity-script-compiler.ps1
|
|
pwsh -File tools/repair-unity-script-compiler.ps1 -FromPath C:\tmp\csc.exe -IncludeGlobalCache -Force
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string[]] $ProjectRoot = @(
|
|
'C:\RecRoom\Documents\EggFiles\ProjectTemplate',
|
|
'C:\RecRoom\OneDrive\Documents\EggFiles\ProjectTemplate'
|
|
),
|
|
[string] $FromPath,
|
|
[switch] $IncludeGlobalCache,
|
|
[switch] $Force
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
|
|
$expectedMd5 = '8c4361cc37113f8467feb1d22b4e83da'
|
|
|
|
function Write-Status {
|
|
param([string] $Level, [string] $Message)
|
|
Write-Host ("[{0}] {1}" -f $Level, $Message)
|
|
}
|
|
|
|
function Find-RoslynCompilerDir {
|
|
<# The roslyn package folder inside a project, or $null. #>
|
|
param([string] $Root)
|
|
|
|
$pkgRoot = Join-Path $Root 'Library\PackageCache'
|
|
if (-not (Test-Path -LiteralPath $pkgRoot)) { return $null }
|
|
|
|
$dirs = Get-ChildItem -LiteralPath $pkgRoot -Directory -Filter 'com.unity.roslyn@*' -ErrorAction SilentlyContinue |
|
|
ForEach-Object { Join-Path $_.FullName 'Compiler~\win64' } |
|
|
Where-Object { Test-Path -LiteralPath $_ }
|
|
|
|
if (-not $dirs) { return $null }
|
|
return @($dirs)[0]
|
|
}
|
|
|
|
function Find-UnityInstallCompiler {
|
|
<# Tools\Roslyn\csc.exe from the editor version this project is pinned to. #>
|
|
param([string] $Root)
|
|
|
|
$versionFile = Join-Path $Root 'ProjectSettings\ProjectVersion.txt'
|
|
$version = $null
|
|
if (Test-Path -LiteralPath $versionFile) {
|
|
$line = Get-Content -LiteralPath $versionFile | Where-Object { $_ -match '^m_EditorVersion:' } | Select-Object -First 1
|
|
if ($line) { $version = ($line -split ':', 2)[1].Trim() }
|
|
}
|
|
|
|
$roots = @()
|
|
if ($version) {
|
|
$roots += "C:\Program Files\Unity $version"
|
|
$roots += "C:\Program Files\Unity\Hub\Editor\$version"
|
|
}
|
|
$roots += @(Get-ChildItem 'C:\Program Files\Unity*' -Directory -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName })
|
|
|
|
foreach ($r in $roots) {
|
|
$candidate = Join-Path $r 'Editor\Data\Tools\Roslyn\csc.exe'
|
|
if (Test-Path -LiteralPath $candidate) { return $candidate }
|
|
}
|
|
return $null
|
|
}
|
|
|
|
function Test-Compiler {
|
|
<# Runs the compiler's own version probe: the launcher only works if it can reach its csc.dll. #>
|
|
param([string] $Path)
|
|
|
|
try {
|
|
$output = & $Path -version 2>&1
|
|
} catch {
|
|
return [pscustomobject]@{ Ok = $false; Detail = $_.Exception.Message }
|
|
}
|
|
$text = ($output | Out-String).Trim()
|
|
if ($LASTEXITCODE -ne 0 -or $text -notmatch 'Visual C# Compiler version|^\d+\.\d+') {
|
|
$detail = if ($text) { $text } else { "exited with code $LASTEXITCODE and no output" }
|
|
return [pscustomobject]@{ Ok = $false; Detail = $detail }
|
|
}
|
|
return [pscustomobject]@{ Ok = $true; Detail = $text }
|
|
}
|
|
|
|
function Repair-CompilerDir {
|
|
param([string] $Dir, [string] $Source)
|
|
|
|
$target = Join-Path $Dir 'csc.exe'
|
|
if ((Test-Path -LiteralPath $target) -and -not $Force) {
|
|
$probe = Test-Compiler -Path $target
|
|
if ($probe.Ok) {
|
|
Write-Status 'PASS' "already present and working: $target ($($probe.Detail))"
|
|
return $false
|
|
}
|
|
Write-Status 'WARN' "present but not usable ($($probe.Detail)) - replacing it"
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $Dir)) {
|
|
New-Item -ItemType Directory -Path $Dir -Force | Out-Null
|
|
}
|
|
|
|
Copy-Item -LiteralPath $Source -Destination $target -Force
|
|
$probe = Test-Compiler -Path $target
|
|
if (-not $probe.Ok) {
|
|
throw "Restored $target but it still does not run: $($probe.Detail)"
|
|
}
|
|
|
|
$md5 = (Get-FileHash -LiteralPath $target -Algorithm MD5).Hash.ToLowerInvariant()
|
|
if ($md5 -eq $expectedMd5) {
|
|
Write-Status 'PASS' "restored the authentic $target ($md5)"
|
|
} else {
|
|
Write-Status 'PASS' "restored $target (md5 $md5; the Unity install build, not the package one)"
|
|
}
|
|
return $true
|
|
}
|
|
|
|
# ---- main -------------------------------------------------------------------------
|
|
|
|
Write-Host ''
|
|
|
|
$project = $null
|
|
foreach ($candidate in $ProjectRoot) {
|
|
if (-not (Test-Path -LiteralPath $candidate)) { continue }
|
|
if (Find-RoslynCompilerDir -Root $candidate) { $project = $candidate; break }
|
|
}
|
|
if (-not $project) {
|
|
throw "No project with an extracted com.unity.roslyn package found. Tried:`n $($ProjectRoot -join "`n ")"
|
|
}
|
|
|
|
$compilerDir = Find-RoslynCompilerDir -Root $project
|
|
Write-Status 'INFO' "project : $project"
|
|
Write-Status 'INFO' "compiler : $compilerDir"
|
|
|
|
$source = $FromPath
|
|
if ($source) {
|
|
if (-not (Test-Path -LiteralPath $source)) { throw "-FromPath '$source' does not exist." }
|
|
Write-Status 'INFO' "source : $source (-FromPath)"
|
|
} else {
|
|
$source = Find-UnityInstallCompiler -Root $project
|
|
if (-not $source) {
|
|
throw @"
|
|
No csc.exe available to restore from. Either install the editor version named in
|
|
ProjectSettings\ProjectVersion.txt, or pass -FromPath pointing at a copy of the package's
|
|
win64\csc.exe taken from the registry tarball.
|
|
"@
|
|
}
|
|
Write-Status 'INFO' "source : $source (Unity editor install)"
|
|
}
|
|
|
|
$repaired = Repair-CompilerDir -Dir $compilerDir -Source $source
|
|
if (-not $repaired) {
|
|
Write-Status 'INFO' 'nothing to do for this project'
|
|
}
|
|
|
|
if ($IncludeGlobalCache) {
|
|
$globalRoot = Join-Path $env:LOCALAPPDATA 'Unity\cache\packages\packages.unity.com'
|
|
$globalDirs = Get-ChildItem -LiteralPath $globalRoot -Directory -Filter 'com.unity.roslyn@*' -ErrorAction SilentlyContinue |
|
|
ForEach-Object { Join-Path $_.FullName 'Compiler~\win64' }
|
|
if (-not $globalDirs) {
|
|
Write-Status 'WARN' "no com.unity.roslyn under $globalRoot"
|
|
}
|
|
foreach ($d in $globalDirs) { Repair-CompilerDir -Dir $d -Source $source | Out-Null }
|
|
}
|
|
|
|
# Unity will not pick the compiler up until it recompiles; ScriptAssemblies should then fill in.
|
|
$scriptAssemblies = Join-Path $project 'Library\ScriptAssemblies'
|
|
if (Test-Path -LiteralPath $scriptAssemblies) {
|
|
$built = @(Get-ChildItem -LiteralPath $scriptAssemblies -Filter '*.dll' -ErrorAction SilentlyContinue).Count
|
|
if ($built -eq 0) {
|
|
Write-Status 'INFO' 'Library\ScriptAssemblies is still empty - reopen the project (Unity recompiles on focus)'
|
|
} else {
|
|
Write-Status 'INFO' "Library\ScriptAssemblies holds $built assemblies"
|
|
}
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Status 'INFO' 'Windows Defender is what removes this file. In an ELEVATED PowerShell:'
|
|
Write-Host " Add-MpPreference -ExclusionPath '$project'"
|
|
Write-Host " Add-MpPreference -ExclusionPath `"$env:LOCALAPPDATA\Unity\cache`""
|
|
Write-Status 'INFO' 'the same rule also emptied com.unity.burst\.Runtime\hostwin (llvm-lipo/dsymutil, needed for Apple targets only)'
|