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

feat(install): Add support for x64 microarchitectures #5674

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

### Features

- **install:** Add support for x64 microarchitectures ([#5674](https://github.com/ScoopInstaller/Scoop/pull/5674))
- **scoop-search:** Use SQLite for caching apps to speed up local search ([#5851](https://github.com/ScoopInstaller/Scoop/issues/5851), [#5918](https://github.com/ScoopInstaller/Scoop/issues/5918), [#5946](https://github.com/ScoopInstaller/Scoop/issues/5946), [#5949](https://github.com/ScoopInstaller/Scoop/issues/5949), [#5955](https://github.com/ScoopInstaller/Scoop/issues/5955), [#5966](https://github.com/ScoopInstaller/Scoop/issues/5966), [#5967](https://github.com/ScoopInstaller/Scoop/issues/5967), [#5981](https://github.com/ScoopInstaller/Scoop/issues/5981))
- **core:** New cache filename format ([#5929](https://github.com/ScoopInstaller/Scoop/issues/5929), [#5944](https://github.com/ScoopInstaller/Scoop/issues/5944))
- **decompress:** Use innounp-unicode as default Inno Setup Unpacker ([#6028](https://github.com/ScoopInstaller/Scoop/issues/6028))
Expand Down
75 changes: 48 additions & 27 deletions bin/checkhashes.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function err ([String] $name, [String[]] $message) {
Write-Host ($message -join "`r`n") -ForegroundColor Red
}

$MANIFESTS = @()
$MANIFESTS = [System.Collections.ArrayList]::new()
foreach ($single in Get-ChildItem $Dir -Filter "$App.json" -Recurse) {
$name = $single.BaseName
$file = $single.FullName
Expand All @@ -67,20 +67,31 @@ foreach ($single in Get-ChildItem $Dir -Filter "$App.json" -Recurse) {
# Skip nighly manifests, since their hash validation is skipped
if ($manifest.version -eq 'nightly') { continue }

$urls = @()
$hashes = @()
$urls = [System.Collections.ArrayList]::new()
$hashes = [System.Collections.ArrayList]::new()

if ($manifest.url) {
$manifest.url | ForEach-Object { $urls += $_ }
$manifest.hash | ForEach-Object { $hashes += $_ }
$manifest.url | ForEach-Object { $urls.Add($_) }
$manifest.hash | ForEach-Object { $hashes.Add($_) }
} elseif ($manifest.architecture) {
# First handle 64bit
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
hash $manifest '64bit' | ForEach-Object { $hashes += $_ }
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
hash $manifest '32bit' | ForEach-Object { $hashes += $_ }
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
hash $manifest 'arm64' | ForEach-Object { $hashes += $_ }
script:url $manifest '64bit' | ForEach-Object { $urls.Add($_) }
hash $manifest '64bit' | ForEach-Object { $hashes.Add($_) }

script:url $manifest '64bit-v2' | ForEach-Object { $urls.Add($_) }
hash $manifest '64bit-v2' | ForEach-Object { $hashes.Add($_) }

script:url $manifest '64bit-v3' | ForEach-Object { $urls.Add($_) }
hash $manifest '64bit-v3' | ForEach-Object { $hashes.Add($_) }

script:url $manifest '64bit-v4' | ForEach-Object { $urls.Add($_) }
hash $manifest '64bit-v4' | ForEach-Object { $hashes.Add($_) }

script:url $manifest '32bit' | ForEach-Object { $urls.Add($_) }
hash $manifest '32bit' | ForEach-Object { $hashes.Add($_) }

script:url $manifest 'arm64' | ForEach-Object { $urls.Add($_) }
hash $manifest 'arm64' | ForEach-Object { $hashes.Add($_) }
} else {
err $name 'Manifest does not contain URL property.'
continue
Expand All @@ -92,13 +103,13 @@ foreach ($single in Get-ChildItem $Dir -Filter "$App.json" -Recurse) {
continue
}

$MANIFESTS += @{
app = $name
file = $file
manifest = $manifest
urls = $urls
hashes = $hashes
}
$MANIFESTS.Add(@{
app = $name
file = $file
manifest = $manifest
urls = $urls
hashes = $hashes
})
}

# clear any existing events
Expand All @@ -107,9 +118,9 @@ Get-Event | ForEach-Object { Remove-Event $_.SourceIdentifier }
foreach ($current in $MANIFESTS) {
$count = 0
# Array of indexes mismatched hashes.
$mismatched = @()
$mismatched = [System.Collections.ArrayList]::new()
# Array of computed hashes
$actuals = @()
$actuals = [System.Collections.ArrayList]::new()

$current.urls | ForEach-Object {
$algorithm, $expected = get_hash $current.hashes[$count]
Expand All @@ -130,9 +141,9 @@ foreach ($current in $MANIFESTS) {
$expected = "$algorithm`:$expected"
}

$actuals += $actual_hash
$actuals.Add($actual_hash)
if ($actual_hash -ne $expected) {
$mismatched += $count
$mismatched.Add($count)
}
$count++
}
Expand Down Expand Up @@ -161,16 +172,26 @@ foreach ($current in $MANIFESTS) {
$current.manifest.hash = $actuals
} else {
$platforms = ($current.manifest.architecture | Get-Member -MemberType NoteProperty).Name
# Defaults to zero, don't know, which architecture is available
$64bit_count = 0
$32bit_count = 0
$arm64_count = 0
# Defaults to zero, don't know which architecture is available yet
$64bit_v4_count = $64bit_v3_count = $64bit_v2_count = $64bit_count = $32bit_count = $arm64_count = 0

# 64bit is get, donwloaded and added first
# 64bit is checked, downloaded and added first
if ($platforms.Contains('64bit')) {
$64bit_count = $current.manifest.architecture.'64bit'.hash.Count
$current.manifest.architecture.'64bit'.hash = $actuals[0..($64bit_count - 1)]
}
if ($platforms.Contains('64bit-v2')) {
$64bit_v2_count = $current.manifest.architecture.'64bit-v2'.hash.Count
$current.manifest.architecture.'64bit-v2'.hash = $actuals[0..($64bit_v2_count - 1)]
}
if ($platforms.Contains('64bit-v3')) {
$64bit_v3_count = $current.manifest.architecture.'64bit-v3'.hash.Count
$current.manifest.architecture.'64bit-v3'.hash = $actuals[0..($64bit_v3_count - 1)]
}
if ($platforms.Contains('64bit-v4')) {
$64bit_v4_count = $current.manifest.architecture.'64bit-v4'.hash.Count
$current.manifest.architecture.'64bit-v4'.hash = $actuals[0..($64bit_v4_count - 1)]
}
if ($platforms.Contains('32bit')) {
$32bit_count = $current.manifest.architecture.'32bit'.hash.Count
$current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..($64bit_count + $32bit_count - 1)]
Expand Down
22 changes: 12 additions & 10 deletions bin/checkurls.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,25 @@ function test_dl([String] $url, $cookies) {

foreach ($man in $Queue) {
$name, $manifest = $man
$urls = @()
$ok = 0
$failed = 0
$errors = @()
$urls = [System.Collections.ArrayList]::new()
$ok = $failed = 0
$errors = [System.Collections.ArrayList]::new()

if ($manifest.url) {
$manifest.url | ForEach-Object { $urls += $_ }
$manifest.url | ForEach-Object { $urls.Add($_) }
} else {
script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
script:url $manifest '64bit' | ForEach-Object { $urls.Add($_) }
script:url $manifest '64bit-v2' | ForEach-Object { $urls.Add($_) }
script:url $manifest '64bit-v3' | ForEach-Object { $urls.Add($_) }
script:url $manifest '64bit-v4' | ForEach-Object { $urls.Add($_) }
script:url $manifest '32bit' | ForEach-Object { $urls.Add($_) }
script:url $manifest 'arm64' | ForEach-Object { $urls.Add($_) }
}

$urls | ForEach-Object {
$url, $status, $msg = test_dl $_ $manifest.cookie
if ($msg) { $errors += "$msg ($url)" }
if ($status -eq 'OK' -or $status -eq 'OpeningData') { $ok += 1 } else { $failed += 1 }
if ($msg) { $errors.Add("$msg ($url)") }
if ($status -eq 'OK' -or $status -eq 'OpeningData') { ++$ok } else { ++$failed }
}

if (($ok -eq $urls.Length) -and $SkipValid) { continue }
Expand Down
2 changes: 1 addition & 1 deletion lib/autoupdate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ function Invoke-AutoUpdate {
$hasNote = $true
}
if ($Manifest.autoupdate.architecture) {
'64bit', '32bit', 'arm64' | ForEach-Object {
'64bit-v4', '64bit-v3', '64bit-v2', '64bit', '32bit', 'arm64' | ForEach-Object {
if ($Manifest.autoupdate.architecture.$_.note) {
$note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
$hasNote = $true
Expand Down
39 changes: 30 additions & 9 deletions lib/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1039,12 +1039,30 @@ function get_shim_path() {

function Get-DefaultArchitecture {
$arch = get_config DEFAULT_ARCHITECTURE
$system = if (${env:ProgramFiles(Arm)}) {
'arm64'
} elseif ([System.Environment]::Is64BitOperatingSystem) {
'64bit'
} else {
'32bit'
$system = & {
switch -Exact ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture) {
'Arm64' { return 'arm64' }
'X64' {
$out = '64bit'
$kernel32 = Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);' -Name 'Kernel32' -Namespace 'Win32' -PassThru
return & {
# PF_AVX512F_INSTRUCTIONS_AVAILABLE
if ($kernel32::IsProcessorFeaturePresent(41)) {
return $out + '-v4'
}
# PF_AVX2_INSTRUCTIONS_AVAILABLE
if ($kernel32::IsProcessorFeaturePresent(40)) {
return $out + '-v3'
}
# PF_SSE4_2_INSTRUCTIONS_AVAILABLE
if ($kernel32::IsProcessorFeaturePresent(38)) {
return $out + '-v2'
}
return $out
}
}
'X32' { return '32bit' }
}
}
if ($null -eq $arch) {
$arch = $system
Expand All @@ -1065,9 +1083,12 @@ function Format-ArchitectureString($Architecture) {
}
$Architecture = $Architecture.ToString().ToLower()
switch ($Architecture) {
{ @('64bit', '64', 'x64', 'amd64', 'x86_64', 'x86-64') -contains $_ } { return '64bit' }
{ @('32bit', '32', 'x86', 'i386', '386', 'i686') -contains $_ } { return '32bit' }
{ @('arm64', 'arm', 'aarch64') -contains $_ } { return 'arm64' }
{ ([System.Collections.Generic.HashSet[String]][string[]]@('64bit-v4', '64bit_v4', 'avx512', 'amd64-v4', 'amd64_v4', 'x64-v4', 'x64_v4', 'x86_64-v4', 'x86-64_v4')).Contains($_) } { return '64bit-v4' }
{ ([System.Collections.Generic.HashSet[String]][string[]]@('64bit-v3', '64bit_v3', 'avx2', 'amd64-v3', 'amd64_v3', 'x64-v3', 'x64_v3', 'x86_64-v3', 'x86-64_v3')).Contains($_) } { return '64bit-v3' }
{ ([System.Collections.Generic.HashSet[String]][string[]]@('64bit-v2', '64bit_v2', 'sse4.2', 'sse4_2', 'sse4-2', 'amd64-v2', 'amd64_v2', 'x64-v2', 'x64_v2', 'x86_64-v2', 'x86-64_v2')).Contains($_) } { return '64bit-v2' }
{ ([System.Collections.Generic.HashSet[String]][string[]]@('64bit', '64', 'x64', 'amd64', 'x86_64', 'x86-64')).Contains($_) } { return '64bit' }
{ ([System.Collections.Generic.HashSet[String]][string[]]@('32bit', '32', 'x86', 'i386', '386', 'i686')).Contains($_) } { return '32bit' }
{ ([System.Collections.Generic.HashSet[String]][string[]]@('arm64', 'arm', 'aarch64')).Contains($_) } { return 'arm64' }
default { throw [System.ArgumentException] "Invalid architecture: '$Architecture'" }
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function Invoke-Installer {
[psobject]
$Manifest,
[Alias('Arch', 'Architecture')]
[ValidateSet('32bit', '64bit', 'arm64')]
[ValidateSet('32bit', '64bit-v4', '64bit-v3', '64bit-v2', '64bit', 'arm64')]
[string]
$ProcessorArchitecture,
[string]
Expand Down Expand Up @@ -155,7 +155,7 @@ function Invoke-HookScript {
[PSCustomObject] $Manifest,
[Parameter(Mandatory = $true)]
[Alias('Arch', 'Architecture')]
[ValidateSet('32bit', '64bit', 'arm64')]
[ValidateSet('32bit', '64bit-v4', '64bit-v3', '64bit-v2', '64bit', 'arm64')]
[string]
$ProcessorArchitecture
)
Expand Down
32 changes: 22 additions & 10 deletions lib/manifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,28 @@ function arch_specific($prop, $manifest, $architecture) {
}

function Get-SupportedArchitecture($manifest, $architecture) {
if ($architecture -eq 'arm64' -and ($manifest | ConvertToPrettyJson) -notmatch '[''"]arm64["'']') {
# Windows 10 enables existing unmodified x86 apps to run on Arm devices.
# Windows 11 adds the ability to run unmodified x64 Windows apps on Arm devices!
# Ref: https://learn.microsoft.com/en-us/windows/arm/overview
if ($WindowsBuild -ge 22000) {
# Windows 11
$architecture = '64bit'
} else {
# Windows 10
$architecture = '32bit'
if (!$manifest.architecture.$architecture) {
if ($architecture -eq 'arm64') {
# Windows 10 enables existing unmodified x86 apps to run on Arm devices.
# Windows 11 adds the ability to run unmodified x64 Windows apps on Arm devices!
# Ref: https://learn.microsoft.com/en-us/windows/arm/overview
$architecture = if ($WindowsBuild -ge 22000) {
# Windows 11
'64bit'
} else {
# Windows 10
'32bit'
}
} elseif ($architecture[-3] -eq '-') {
$success = $false
for ($i = $architecture[-1] - [byte][char]'0'; $i -gt 1; --$i) {
$testArch = "64bit-v$i"
if ($manifest.architecture.$testArch) {
$success = $true
break
}
}
$architecture = if ($success) { $testArch } else { '64bit' }
}
}
if (![String]::IsNullOrEmpty((arch_specific 'url' $manifest $architecture))) {
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-config.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
# When a conflict is detected during updating, Scoop will auto-stash the uncommitted changes.
# (Default is $false, which will abort the update)
#
# default_architecture: 64bit|32bit|arm64
# default_architecture: 32bit|64bit-v4|64bit-v3|64bit-v2|64bit|arm64
# Allow to configure preferred architecture for application installation.
# If not specified, architecture is determined by system.
#
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-download.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# -f, --force Force download (overwrite cache)
# -s, --skip-hash-check Skip hash verification (use with caution!)
# -u, --no-update-scoop Don't update Scoop before downloading if it's outdated
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it
# -a, --arch <32bit|64bit-v4|64bit-v3|64bit-v2|64bit|arm64> Use the specified architecture, if the app supports it

. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' (indirectly)
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# -k, --no-cache Don't use the download cache
# -s, --skip-hash-check Skip hash validation (use with caution!)
# -u, --no-update-scoop Don't update Scoop before installing if it's outdated
# -a, --arch <32bit|64bit|arm64> Use the specified architecture, if the app supports it
# -a, --arch <32bit|64bit-v4|64bit-v3|64bit-v2|64bit|arm64> Use the specified architecture, if the app supports it

. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1" # 'autoupdate.ps1' 'manifest.ps1' (indirectly)
Expand Down
33 changes: 33 additions & 0 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,15 @@
"64bit": {
"$ref": "#/definitions/autoupdateArch"
},
"64bit-v2": {
"$ref": "#/definitions/autoupdateArch"
},
"64bit-v3": {
"$ref": "#/definitions/autoupdateArch"
},
"64bit-v4": {
"$ref": "#/definitions/autoupdateArch"
},
"arm64": {
"$ref": "#/definitions/autoupdateArch"
}
Expand Down Expand Up @@ -542,6 +551,15 @@
"64bit": {
"$ref": "#/definitions/architecture"
},
"64bit-v2": {
"$ref": "#/definitions/architecture"
},
"64bit-v3": {
"$ref": "#/definitions/architecture"
},
"64bit-v4": {
"$ref": "#/definitions/architecture"
},
"arm64": {
"$ref": "#/definitions/architecture"
}
Expand Down Expand Up @@ -655,6 +673,21 @@
"url": false
}
},
"64bit-v2": {
"properties": {
"url": false
}
},
"64bit-v3": {
"properties": {
"url": false
}
},
"64bit-v4": {
"properties": {
"url": false
}
},
"32bit": {
"properties": {
"url": false
Expand Down
Loading