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

Allow using newer solc on macOS without Rosetta #222

Merged
merged 1 commit into from
Jan 3, 2025
Merged
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
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
Loading