Skip to content

Commit ef51aa0

Browse files
authored
Fix architecture detection by using .NET runtime architecture instead of system architecture (#544)
## Problem Analysis The previous fix (#543) attempted to solve architecture detection issues by using system architecture, but **root cause analysis** reveals the real problem: **Confirmed user system:** - Hardware: ARM64 Mac (M1/M2) - `uname -m` returns `arm64` - .NET Binary: x86_64 - `lipo -archs /usr/local/bin/dotnet` returns `x86_64` - .NET Runtime: `RID: osx-x64` - running under Rosetta translation - Error: `have 'arm64', need 'x86_64'` **What was happening:** 1. Extension detected ARM64 system → downloaded ARM64 Dafny binaries 2. .NET runtime was x64 (Rosetta) → tried to load ARM64 libraries 3. Architecture mismatch → `incompatible architecture` error ## Root Cause The issue isn't system architecture detection - it's that **.NET can run under Rosetta translation** on ARM64 Macs. When this happens: - System architecture: ARM64 - .NET runtime architecture: x64 - **We need x64 Dafny binaries, not ARM64** ## Solution **Detect .NET runtime architecture instead of system architecture:** 1. **Use `dotnet --info`** to get actual .NET runtime information 2. **Parse RID (Runtime Identifier):** `osx-x64` vs `osx-arm64` 3. **Parse Architecture field:** `x64` vs `Arm64` 4. **Download matching Dafny binaries** for the .NET runtime architecture 5. **Fallback chain:** .NET detection → system detection → `os.arch()` ## Why This Fixes The Issue - **ARM64 Mac + Native .NET:** Downloads ARM64 Dafny ✅ - **ARM64 Mac + Rosetta .NET:** Downloads x64 Dafny ✅ - **x64 Mac:** Downloads x64 Dafny ✅ - **Other platforms:** Unchanged behavior ✅ This addresses the actual compatibility requirement: **Dafny binaries must match .NET runtime architecture, not system hardware architecture.** ## Confirmed Fix With the user's confirmed data (`RID: osx-x64`), this fix will: 1. Parse `osx-x64` from `dotnet --info` output 2. Extract `x64` architecture 3. Download `dafny-4.11.0-x64-macos-13.zip` instead of `dafny-4.11.0-arm64-macos-13.zip` 4. Resolve the architecture mismatch error ## Testing The fix includes comprehensive logging to help debug architecture detection issues and verify the correct architecture is being selected. Supersedes #543 with the correct approach based on root cause analysis.
1 parent 7c7e219 commit ef51aa0

File tree

1 file changed

+33
-8
lines changed

1 file changed

+33
-8
lines changed

src/language/githubReleaseInstaller.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,28 +126,53 @@ export class GitHubReleaseInstaller {
126126
const baseUri = LanguageServerConstants.DownloadBaseUri;
127127
const [ tag, version ] = await this.getConfiguredTagAndVersion();
128128
const suffix = getDafnyPlatformSuffix(version);
129-
const arch = await this.getSystemArchitecture();
129+
const arch = await this.getDotnetArchitecture();
130130
return `${baseUri}/${tag}/dafny-${version}-${arch}-${suffix}.zip`;
131131
}
132132

133-
private async getSystemArchitecture(): Promise<string> {
133+
private async getDotnetArchitecture(): Promise<string> {
134134
if(os.type() === 'Darwin') {
135-
// On macOS, use system command to get actual hardware architecture
136-
// to avoid issues with VS Code running under Rosetta
135+
// On macOS, detect .NET runtime architecture to handle Rosetta translation
136+
// This is crucial because ARM64 Macs may run .NET in x64 mode via Rosetta
137137
try {
138138
const { exec } = await import('child_process');
139139
const { promisify } = await import('util');
140140
const execAsync = promisify(exec);
141-
const { stdout } = await execAsync('uname -m');
142-
const systemArch = stdout.trim();
141+
142+
// First try to get .NET runtime architecture
143+
const { stdout } = await execAsync('dotnet --info');
144+
145+
// Look for RID (Runtime Identifier) which shows the actual .NET runtime architecture
146+
const ridRegex = /RID:\s*osx-(x64|arm64)/;
147+
const ridMatch = ridRegex.exec(stdout);
148+
if(ridMatch) {
149+
this.writeStatus(`Detected .NET RID: osx-${ridMatch[1]}`);
150+
return ridMatch[1]; // Returns 'x64' or 'arm64'
151+
}
152+
153+
// Fallback: look for Architecture field
154+
const archRegex = /Architecture:\s*(x64|Arm64)/i;
155+
const archMatch = archRegex.exec(stdout);
156+
if(archMatch) {
157+
const detectedArch = archMatch[1].toLowerCase() === 'arm64' ? 'arm64' : 'x64';
158+
this.writeStatus(`Detected .NET Architecture: ${detectedArch}`);
159+
return detectedArch;
160+
}
161+
162+
this.writeStatus('Could not parse .NET architecture from dotnet --info output');
163+
this.writeStatus('Falling back to system architecture detection');
164+
165+
// Fallback to system architecture detection using same execAsync
166+
const { stdout: systemStdout } = await execAsync('uname -m');
167+
const systemArch = systemStdout.trim();
143168
return systemArch === 'x86_64' ? 'x64' : systemArch === 'arm64' ? 'arm64' : 'x64';
144169
} catch(error: unknown) {
145-
// Fallback to Node.js detection
146-
this.writeStatus(`Failed to detect system architecture via uname: ${error}`);
170+
this.writeStatus(`Failed to detect architecture: ${error}`);
147171
this.writeStatus('Falling back to Node.js process architecture detection');
148172
return os.arch();
149173
}
150174
}
175+
151176
// For non-macOS systems, use Node.js detection (preserve original behavior)
152177
return os.arch();
153178
}

0 commit comments

Comments
 (0)