Skip to content
File

Blob: scripts/setup_tooling.py

python93 lines
1#!/usr/bin/env python3
2"""Set up the pinned Linux x86_64 S3 toolchain without changing global defaults."""
3import argparse
4import hashlib
5import os
6from pathlib import Path
7import platform
8import shutil
9import subprocess
10import sys
11import urllib.request
12from project import (ROOT, IDF_REVISION, RUST_RELEASE, RUST_TOOLCHAIN,
13 ESPUP_VERSION, ESPUP_SHA256, sdk_root, verify_checkout, idf_environment,
14 rust_libclang, VENDOR, DSP_REVISION, CODEC_REVISION)
15 
16 
17def run(command, **kwargs):
18 subprocess.run([str(part) for part in command], check=True, **kwargs)
19 
20 
21def checkout(path, url, revision):
22 if not path.exists():
23 path.parent.mkdir(parents=True, exist_ok=True)
24 run(["git", "init", path])
25 run(["git", "-C", path, "remote", "add", "origin", url])
26 run(["git", "-C", path, "fetch", "--depth", "1", "origin", revision])
27 run(["git", "-C", path, "checkout", "--detach", "FETCH_HEAD"])
28 verify_checkout(path, revision)
29 
30 
31def main():
32 parser = argparse.ArgumentParser(description=__doc__)
33 parser.add_argument("--check", action="store_true", help="Verify native source pins, Rust and libclang without downloading")
34 args = parser.parse_args()
35 if platform.system() != "Linux" or platform.machine() != "x86_64":
36 raise SystemExit("This setup helper supports Linux x86_64. See firmware/README.md for toolchain details.")
37 required = ["git", "cmake", "make", "gcc", "g++", "pkg-config", "rustup", "cargo"]
38 missing = [command for command in required if not shutil.which(command)]
39 if missing:
40 raise SystemExit("Install these prerequisites first: " + ", ".join(missing))
41 sdk = sdk_root()
42 if args.check:
43 verify_checkout(sdk / "esp-idf", IDF_REVISION)
44 verify_checkout(VENDOR / "esp-dsp", DSP_REVISION)
45 verify_checkout(VENDOR / "esp-adf-libs", CODEC_REVISION)
46 idf_environment()
47 version = subprocess.check_output(["rustup", "run", RUST_TOOLCHAIN, "rustc", "--version"], text=True)
48 if f"({RUST_RELEASE})" not in version:
49 raise SystemExit("Rust compiler differs from the pinned release")
50 print("Pinned ESP-IDF, DSP, codecs, and Xtensa Rust toolchains are ready.")
51 return
52 checkout(VENDOR / "esp-dsp", "https://github.com/espressif/esp-dsp.git", DSP_REVISION)
53 checkout(VENDOR / "esp-adf-libs", "https://github.com/espressif/esp-adf-libs.git", CODEC_REVISION)
54 checkout(sdk / "esp-idf", "https://github.com/espressif/esp-idf.git", IDF_REVISION)
55 run(["git", "-C", sdk / "esp-idf", "submodule", "update", "--init", "--recursive", "--depth", "1"])
56 version = subprocess.run(["rustup", "run", RUST_TOOLCHAIN, "rustc", "--version"], capture_output=True, text=True)
57 try:
58 rust_libclang()
59 clang_ready = True
60 except SystemExit:
61 clang_ready = False
62 if version.returncode or f"({RUST_RELEASE})" not in version.stdout or not clang_ready:
63 espup = ROOT / ".tools/espup"
64 espup.parent.mkdir(exist_ok=True)
65 if not espup.exists() or hashlib.sha256(espup.read_bytes()).hexdigest() != ESPUP_SHA256:
66 url = f"https://github.com/esp-rs/espup/releases/download/v{ESPUP_VERSION}/espup-x86_64-unknown-linux-gnu"
67 with urllib.request.urlopen(url, timeout=60) as response:
68 binary = response.read()
69 if hashlib.sha256(binary).hexdigest() != ESPUP_SHA256:
70 raise SystemExit("espup download checksum mismatch")
71 espup.write_bytes(binary)
72 espup.chmod(0o755)
73 # --std installs Rust and Xtensa libclang; ESP-IDF supplies GCC.
74 run([espup, "install", "--std", "--targets", "esp32s3", "--toolchain-version", RUST_RELEASE,
75 "--name", RUST_TOOLCHAIN, "--export-file", ROOT / ".tools/export-esp-radio.sh"])
76 rust_libclang()
77 try:
78 idf_environment()
79 except SystemExit:
80 env = os.environ.copy()
81 env.update(IDF_TOOLS_PATH=str(sdk / "tools"), PIP_CACHE_DIR=str(sdk / "pip-cache"))
82 run(["bash", sdk / "esp-idf/install.sh", "esp32s3"], env=env)
83 esptool = ROOT / ".tools/esptool/bin/python"
84 if not esptool.exists():
85 run([sys.executable, "-m", "venv", esptool.parent.parent])
86 run([esptool, "-m", "pip", "install", "esptool==5.4.0", "pyserial==3.5"])
87 run(["cargo", "fetch", "--locked", "--manifest-path", ROOT / "firmware/Cargo.toml"])
88 print("Firmware tooling ready. Existing Rust defaults and shell profiles were preserved.")
89 
90 
91if __name__ == "__main__":
92 main()