Skip to content

Commit

Permalink
Allow using newer solc on macOS without Rosetta
Browse files Browse the repository at this point in the history
`solc` universal binaries are now available, starting from 0.8.24.
Allow Macs without Rosetta to run those binaries.
  • Loading branch information
elopez committed Jan 2, 2025
1 parent ba3c63a commit 5047beb
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 9 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ To automatically install and use a version, run `solc-select use <version> --alw

### Running on ARM (Mac M1/M2)

`solc` requires Rosetta to be installed. See the FAQ on [how to install Rosetta](#oserror-errno-86-bad-cpu-type-in-executable).
`solc` older than 0.8.24 requires Rosetta to be installed. See the FAQ on [how to install Rosetta](#oserror-errno-86-bad-cpu-type-in-executable).

## Usage

Expand Down Expand Up @@ -85,10 +85,12 @@ Feel free to stop by our [Slack channel](https://empirehacking.slack.com/) for h
### OSError: [Errno 86] Bad CPU type in executable

On newer `solc-select` versions, this might show as `solc binaries for macOS are
Intel-only. Please install Rosetta on your Mac to continue.`
Intel-only. Please install Rosetta on your Mac to continue.` or `solc binaries
previous to 0.8.24 for macOS are Intel-only. Please install Rosetta on your Mac
to continue.`

`solc` requires Rosetta to be installed. To see whether you have Rosetta
installed on your Mac, run
`solc` releases earlier than 0.8.24 require Rosetta to be installed. To see
whether you have Rosetta installed on your Mac, run

```bash
pgrep -q oahd && echo Rosetta is installed || echo Rosetta is NOT installed
Expand Down
2 changes: 1 addition & 1 deletion solc_select/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def solc() -> None:
(version, _) = res
path = ARTIFACTS_DIR.joinpath(f"solc-{version}", f"solc-{version}")
halt_old_architecture(path)
halt_incompatible_system()
halt_incompatible_system(path)
try:
subprocess.run(
[str(path)] + sys.argv[1:],
Expand Down
17 changes: 13 additions & 4 deletions solc_select/solc_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
CRYTIC_SOLC_ARTIFACTS,
CRYTIC_SOLC_JSON,
)
from .utils import mac_can_run_intel_binaries
from .utils import mac_binary_is_universal, mac_can_run_intel_binaries

Path.mkdir(ARTIFACTS_DIR, parents=True, exist_ok=True)

Expand All @@ -32,10 +32,19 @@ def halt_old_architecture(path: Path) -> None:
)


def halt_incompatible_system() -> None:
if soliditylang_platform() == MACOSX_AMD64 and not mac_can_run_intel_binaries():
def halt_incompatible_system(path: Path) -> None:
if soliditylang_platform() == MACOSX_AMD64:
# If Rosetta is available, we can run all solc versions
if mac_can_run_intel_binaries():
return

# If this is a newer universal solc (>=0.8.24) we can always run it
# https://github.com/ethereum/solidity/issues/12291#issuecomment-2223328961
if mac_binary_is_universal(path):
return

raise argparse.ArgumentTypeError(
"solc binaries for macOS are Intel-only. Please install Rosetta on your Mac to continue. Refer to the solc-select README for instructions."
"solc binaries previous to 0.8.24 for macOS are Intel-only. Please install Rosetta on your Mac to continue. Refer to the solc-select README for instructions."
)
# TODO: check for Linux aarch64 (e.g. RPi), presence of QEMU+binfmt

Expand Down
11 changes: 11 additions & 0 deletions solc_select/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pathlib import Path
import platform
import subprocess
import sys
Expand All @@ -6,6 +7,16 @@
from packaging.version import Version


def mac_binary_is_universal(path: Path):
"""Check if the Mac binary is Universal or not. Will throw an exception if run on non-macOS."""
assert sys.platform == "darwin"
result = subprocess.run(["/usr/bin/file", str(path)], capture_output=True, check=False)
is_universal = all(
text in result.stdout.decode() for text in ("Mach-O universal binary", "x86_64", "arm64")
)
return result.returncode == 0 and is_universal


def mac_can_run_intel_binaries() -> bool:
"""Check if the Mac is Intel or M1 with available Rosetta. Will throw an exception if run on non-macOS."""
assert sys.platform == "darwin"
Expand Down

0 comments on commit 5047beb

Please sign in to comment.