Skip to content

Commit 3d6cd58

Browse files
dguidoclaude
andcommitted
feat: add ARM64 architecture support with emulation
- Detect ARM64 architecture and provide helpful warnings - Automatically use Rosetta 2 on macOS for x86_64 emulation - Support qemu-x86_64 on Linux for ARM64 systems - Show one-time warning with installation instructions - Gracefully handle missing emulation layer with clear guidance This makes solc-select usable on ARM64 systems including: - Apple Silicon Macs (M1/M2/M3) - ARM64 Linux servers and VMs - Raspberry Pi and other ARM devices 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 072c585 commit 3d6cd58

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

solc_select/__main__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
)
1212
from .solc_select import (
1313
current_version,
14+
get_emulation_prefix,
1415
get_installable_versions,
1516
halt_incompatible_system,
1617
halt_old_architecture,
@@ -101,11 +102,12 @@ def solc() -> None:
101102
path = ARTIFACTS_DIR.joinpath(f"solc-{version}", f"solc-{version}")
102103
halt_old_architecture(path)
103104
halt_incompatible_system(path)
105+
106+
# Use emulation if needed for ARM64 systems
107+
cmd = get_emulation_prefix() + [str(path)] + sys.argv[1:]
108+
104109
try:
105-
subprocess.run(
106-
[str(path)] + sys.argv[1:],
107-
check=True,
108-
)
110+
subprocess.run(cmd, check=True)
109111
except subprocess.CalledProcessError as e:
110112
sys.exit(e.returncode)
111113
else:

solc_select/solc_select.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import argparse
2+
import contextlib
23
import hashlib
34
import json
45
import os
6+
import platform
57
import re
68
import shutil
9+
import subprocess
710
import sys
811
import urllib.request
912
from pathlib import Path
@@ -28,6 +31,102 @@
2831
Path.mkdir(ARTIFACTS_DIR, parents=True, exist_ok=True)
2932

3033

34+
def get_arch() -> str:
35+
"""Get the current system architecture."""
36+
machine = platform.machine().lower()
37+
if machine in ["x86_64", "amd64"]:
38+
return "amd64"
39+
elif machine in ["aarch64", "arm64"]:
40+
return "arm64"
41+
elif machine in ["i386", "i686"]:
42+
return "386"
43+
return machine
44+
45+
46+
def check_emulation_available() -> bool:
47+
"""Check if x86_64 emulation is available."""
48+
if get_arch() != "arm64":
49+
return False
50+
51+
# On macOS, check for Rosetta 2
52+
if sys.platform == "darwin":
53+
# Check if we can run x86_64 binaries
54+
try:
55+
result = subprocess.run(["arch", "-x86_64", "true"], capture_output=True, check=False)
56+
return result.returncode == 0
57+
except (FileNotFoundError, OSError):
58+
return False
59+
60+
# On Linux, check for qemu-x86_64
61+
try:
62+
result = subprocess.run(
63+
["which", "qemu-x86_64"], capture_output=True, text=True, check=False
64+
)
65+
return result.returncode == 0
66+
except (FileNotFoundError, OSError):
67+
return False
68+
69+
70+
def get_emulation_prefix() -> list:
71+
"""Get the command prefix for emulation if needed."""
72+
if get_arch() != "arm64":
73+
return []
74+
75+
# On macOS, use arch command for Rosetta 2
76+
if sys.platform == "darwin" and check_emulation_available():
77+
return ["arch", "-x86_64"]
78+
79+
# On Linux, use qemu
80+
if sys.platform.startswith("linux") and check_emulation_available():
81+
return ["qemu-x86_64"]
82+
83+
return []
84+
85+
86+
def warn_about_arm64(force: bool = False) -> None:
87+
"""Warn ARM64 users about compatibility and suggest solutions."""
88+
if get_arch() != "arm64":
89+
return
90+
91+
# Check if we've already warned
92+
warning_file = SOLC_SELECT_DIR.joinpath(".arm64_warning_shown")
93+
if not force and warning_file.exists():
94+
return
95+
96+
print("\n⚠️ WARNING: ARM64 Architecture Detected", file=sys.stderr)
97+
print("=" * 50, file=sys.stderr)
98+
99+
if check_emulation_available():
100+
if sys.platform == "darwin":
101+
print("✓ Rosetta 2 detected - will use emulation for x86 binaries", file=sys.stderr)
102+
else:
103+
print("✓ qemu-x86_64 detected - will use emulation for x86 binaries", file=sys.stderr)
104+
print(" Note: Performance will be slower than native execution", file=sys.stderr)
105+
else:
106+
if sys.platform == "darwin":
107+
print(
108+
"✗ solc binaries are x86_64 only, and Rosetta 2 is not available", file=sys.stderr
109+
)
110+
else:
111+
print("✗ solc binaries are x86_64 only, and qemu is not installed", file=sys.stderr)
112+
print("\nTo use solc-select on ARM64, you can:", file=sys.stderr)
113+
print(" 1. Install qemu for x86_64 emulation:", file=sys.stderr)
114+
if sys.platform.startswith("linux"):
115+
print(" sudo apt-get install qemu-user-static # Debian/Ubuntu", file=sys.stderr)
116+
print(" sudo dnf install qemu-user-static # Fedora", file=sys.stderr)
117+
print(" sudo pacman -S qemu-user-static # Arch", file=sys.stderr)
118+
elif sys.platform == "darwin":
119+
print(" Use Rosetta 2 (installed automatically on Apple Silicon)", file=sys.stderr)
120+
print(" 2. Use an x86_64 Docker container", file=sys.stderr)
121+
print(" 3. Use a cloud-based development environment", file=sys.stderr)
122+
print("=" * 50, file=sys.stderr)
123+
print(file=sys.stderr)
124+
125+
# Mark that we've shown the warning
126+
with contextlib.suppress(OSError):
127+
warning_file.touch()
128+
129+
31130
def validate_url_scheme(url: str) -> None:
32131
"""Validate that URL uses a safe scheme (http or https only)."""
33132
parsed = urlparse(url)
@@ -107,6 +206,10 @@ def artifact_path(version: str) -> Path:
107206

108207

109208
def install_artifacts(versions: [str], silent: bool = False) -> bool:
209+
# Warn ARM64 users about compatibility on first install
210+
if get_arch() == "arm64" and not silent:
211+
warn_about_arm64()
212+
110213
releases = get_available_versions()
111214
versions = [get_latest_release() if ver == "latest" else ver for ver in versions]
112215

0 commit comments

Comments
 (0)