参考:https://esp-rs.github.io/book/introduction.https
安装前置依赖: 不需要先安装 esp-idf,后续构建 std 应用时会自动下载和安装 esp-idf。
# 提供 cargo generate 子命令
cargo install cargo-generate
# A tool that forwards linker arguments to the actual linker that is also given as an argument to
# ldproxy
cargo install ldproxy
# A tool that simplifies installing and maintaining the components required to develop Rust
# applications for the Xtensa and RISC-V architectures.
cargo install espup
brew install libuv # espflash 依赖它
cargo install espflash
cargo install cargo-espflash # 可选,后续可以直接使用命令 cargo espflash
espup 同时安装和维护 Xtensa and RISC-V architectures 两种 CPU 架构工具链,包括 esp fork 的 rust, GCC 和 LLVM 等。
Rust 官方编译器提供了对 RISC-V target 的 Tier2 支持,可以直接向官方 toolchain 添加对应 target:
rustup toolchain install nightly --component rust-src
# For no_std (bare-metal) applications
rustup target add riscv32imc-unknown-none-elf # For ESP32-C2 and ESP32-C3
rustup target add riscv32imac-unknown-none-elf # For ESP32-C6 and ESP32-H2
ESP32-S3 使用 xtensa 处理器,不再 Rust 官方 toolchain 支持范围内,ESP fork 了 Rust 编译器工具链来进行支持。
使用 espup 安装 esp channel:
# 清理旧版本
zj@a:~/esp$ espup uninstall
[info]: Uninstalling the Espressif Rust ecosystem
[info]: Uninstalling Xtensa LLVM
[info]: Uninstalling GCC
[info]: Uninstalling Xtensa Rust toolchain
[info]: Uninstallation successfully completed!
zj@a:~/esp$ rm -rf ~/.rustup/toolchains/*
# espup 是 Rust 程序,不会执行 python 代码,所以支持 socks 代理。开启代理后可以缩短下载时间。
zj@a:~/esp$ enable_socks_proxy
# 安装 ESP32 的 Rust toolchain
zj@a:~/esp$ espup install -l debug
[debug]: Creating export file
[info]: Installation successfully completed!
To get started, you need to set up some environment variables by running: '. /Users/alizj/export-esp.sh'
This step must be done every time you open a new terminal.
See other methods for setting the environment in https://esp-rs.github.io/book/installation/riscv-and-xtensa.html#3-set-up-the-environment-variables
# 修改自动生成的 ~/export-esp.sh 脚本
zj@a:~$ cat ~/export-esp.sh
# 删除 python venv 路径,防止后续 cargo build 安装 esp-idf 报错。
export DIR_TO_REMOVE=/Users/alizj/.venv/bin
PATH=$(echo "$PATH" | sed -e "s;:$DIR_TO_REMOVE;;" -e "s;$DIR_TO_REMOVE:;;" -e "s;$DIR_TO_REMOVE;;")
# 解决 Mac M1 cargo build 报错的问题:https://github.com/rust-lang/cc-rs/issues/1005
CRATE_CC_NO_DEFAULTS=1
# cargo build 过程中会安装 esp-idf python venv ,不支持 SOCKS 代理,故切换为 HTTP 代理。
enable_http_proxy
export LIBCLANG_PATH="/Users/alizj/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-16.0.4-20231113/esp-clang/lib"
export PATH="/Users/alizj/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin:$PATH"
为了方便使用,将 ~/export-esp.sh 脚本 mv 到 ~/esp 目录,同时添加两个 alias:
zj@a:~/esp$ mv ~/export-esp.sh ~/esp/
zj@a:~/esp$ grep esp ~/.bashrc
alias export_idf='. $HOME/esp/esp-idf/export.sh'
alias export_esp='. $HOME/esp/export-esp.sh'
后续每次使用 esp-rs 前都需要 source ~/esp/export-esp.sh
脚本。
修正 esp toolchain 缺失 rust-analyzer 的问题:esp 是 espup 安装的自定义 toolchain,不包含 rust-analyzer,需要建一个软链接:
zj@a:~$ rustup component add rust-analyzer
info: downloading component 'rust-analyzer'
info: installing component 'rust-analyzer'
zj@a:~/docs$ ls -l ~/.rustup/toolchains/stable-aarch64-apple-darwin/bin/
total 96M
-rwxr-xr-x 1 alizj 27M 5 5 12:11 cargo*
-rwxr-xr-x 1 alizj 1.1M 5 5 12:11 cargo-clippy*
-rwxr-xr-x 1 alizj 1.5M 5 5 12:11 cargo-fmt*
-rwxr-xr-x 1 alizj 11M 5 5 12:11 clippy-driver*
-rwxr-xr-x 1 alizj 39M 5 5 12:30 rust-analyzer*
-rwxr-xr-x 1 alizj 980 5 5 12:11 rust-gdb*
-rwxr-xr-x 1 alizj 2.2K 5 5 12:11 rust-gdbgui*
-rwxr-xr-x 1 alizj 1.1K 5 5 12:11 rust-lldb*
-rwxr-xr-x 1 alizj 626K 5 5 12:11 rustc*
-rwxr-xr-x 1 alizj 11M 5 5 12:11 rustdoc*
-rwxr-xr-x 1 alizj 6.3M 5 5 12:11 rustfmt*
zj@a:~/docs$ ln -sf ~/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rust-analyzer ~/.rustup/toolchains/esp/bin/rust-analyzer
也可以从 esp-rs/rust 源码编译安装 rust-analyer:
# 在 --tools 中指定 rust-analyzer 来编译安装 esp32 使用的 rust-analyzer
./configure --experimental-targets=Xtensa --release-channel=nightly --enable-extended
--tools=clippy,cargo,rustfmt,rust-analyzer --enable-lld
espup 安装的内容位于 ~/.espup
目录下,主要包含如下内容:
Espressif Rust fork
with support for Espressif targetsnightly toolchain
with support for RISC-V targetsLLVM fork
with support for Xtensa targetsGCC toolchain
that links the final binary
# 安装了两个 toolchain,分别是 nightly-x86_64-apple-darwin 和 esp
#
# nightly-x86_64-apple-darwin 是 rust 官方工具链,支持 riscv32xx 和 x86_64-apple-darwin 等 4 个 targets
# riscv32xx 是 esp32-c3 系列 RISC-V CPU 类型。
zj@a:~/esp$ rustup show
Default host: aarch64-apple-darwin
rustup home: /Users/alizj/.rustup
installed toolchains
--------------------
stable-aarch64-apple-darwin (default) # 标准工具链
nightly-aarch64-apple-darwin
esp # 自定义 esp 工具链
active toolchain
----------------
stable-aarch64-apple-darwin (default)
rustc 1.78.0 (9b00956e5 2024-04-29)
# espup 安装的 esp 工具链, esp 为 channel 名称
zj@a:~/esp$ ls -l ~/.rustup/toolchains/esp/
total 0
drwxr-xr-x 12 alizj 384 5 5 12:12 bin/ # esp fork 的 rust 交叉编译工具链
drwxr-xr-x 3 alizj 96 5 5 12:12 etc/
drwxr-xr-x 5 alizj 160 5 5 12:13 lib/
drwxr-xr-x 3 alizj 96 5 5 12:12 libexec/
drwxr-xr-x 5 alizj 160 5 5 12:12 share/
drwxr-xr-x 3 alizj 96 5 5 12:11 xtensa-esp-elf/ # esp fork 的支持 xtensa CPU 的 gcc 等工具链
drwxr-xr-x 3 alizj 96 5 5 12:11 xtensa-esp32-elf-clang/ # esp fork 的 clang LLVM 工具链
# esp fork 的 rust 交叉编译工具链
zj@a:~/esp$ ls -l ~/.rustup/toolchains/esp/bin/
total 63M
-rwxr-xr-x 1 alizj 30M 5 5 12:12 cargo*
-rwxr-xr-x 1 alizj 1.2M 5 5 12:12 cargo-clippy*
-rwxr-xr-x 1 alizj 1.6M 5 5 12:12 cargo-fmt*
-rwxr-xr-x 1 alizj 11M 5 5 12:12 clippy-driver*
-rwxr-xr-x 1 alizj 980 5 5 12:12 rust-gdb*
-rwxr-xr-x 1 alizj 2.2K 5 5 12:12 rust-gdbgui*
-rwxr-xr-x 1 alizj 1.1K 5 5 12:12 rust-lldb*
-rwxr-xr-x 1 alizj 584K 5 5 12:12 rustc*
-rwxr-xr-x 1 alizj 12M 5 5 12:12 rustdoc*
-rwxr-xr-x 1 alizj 7.1M 5 5 12:12 rustfmt*
zj@a:~/docs$ ls -l ~/.rustup/toolchains/esp/bin/
total 59M
-rwxr-xr-x 1 zhangjun 28M 2 8 14:51 cargo*
-rwxr-xr-x 1 zhangjun 1.1M 2 8 14:51 cargo-clippy*
-rwxr-xr-x 1 zhangjun 1.6M 2 8 14:51 cargo-fmt*
-rwxr-xr-x 1 zhangjun 11M 2 8 14:51 clippy-driver*
lrwxr-xr-x 1 zhangjun 80 2 8 16:58 rust-analyzer -> /Users/zhangjun/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rust-analyzer* # 链接到官方工具链的 rust-analyzer
-rwxr-xr-x 1 zhangjun 980 2 8 14:50 rust-gdb*
-rwxr-xr-x 1 zhangjun 2.2K 2 8 14:50 rust-gdbgui*
-rwxr-xr-x 1 zhangjun 1.1K 2 8 14:50 rust-lldb*
-rwxr-xr-x 1 zhangjun 664K 2 8 14:50 rustc*
-rwxr-xr-x 1 zhangjun 11M 2 8 14:50 rustdoc*
-rwxr-xr-x 1 zhangjun 6.9M 2 8 14:51 rustfmt*
# esp rustc 支持 x86_64/arm64/riscv64/xtensa-esp32s3-espidf/xtensa-esp32s3-none-elf target
# 后续可以在项目的 rust-toolchain.toml 和 .cargo/config.toml 中指定使用 esp channel 和对应的 target。
zj@a:~/docs$ ~/.rustup/toolchains/esp/bin/rustc --print target-list |grep -E 'xtensa|riscv'
riscv32gc-unknown-linux-gnu
riscv32gc-unknown-linux-musl
riscv32i-unknown-none-elf
riscv32im-unknown-none-elf
riscv32imac-esp-espidf
riscv32imac-unknown-none-elf
riscv32imac-unknown-xous-elf
riscv32imc-esp-espidf
riscv32imc-unknown-none-elf
riscv64-linux-android
riscv64gc-unknown-freebsd
riscv64gc-unknown-fuchsia
riscv64gc-unknown-hermit
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-linux-musl
riscv64gc-unknown-netbsd
riscv64gc-unknown-none-elf
riscv64gc-unknown-openbsd
riscv64imac-unknown-none-elf
xtensa-esp32-espidf
xtensa-esp32-none-elf
xtensa-esp32s2-espidf
xtensa-esp32s2-none-elf
xtensa-esp32s3-espidf # esp idf target,即 std 应用
xtensa-esp32s3-none-elf # none-elf 为 non_std 应用
xtensa-esp8266-none-elf
zj@a:~/esp$ ls -l ~/.espup/
total 0
lrwxr-xr-x 1 alizj 92 5 5 12:11 esp-clang -> /Users/alizj/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-16.0.4-20231113/esp-clang/lib/
# ~/esp/export-esp.sh 脚本将 LIBCLANG_PATH 环境变量指向 esp fork 的 LLVM 目录,这样后续 rustc 在编
# 译时自动链接 esp 的版本。(rustc 依赖 LLVM)。
zj@a:~/esp$ ls -l /Users/alizj/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-16.0.4-20231113/esp-clang/lib/
total 117M
drwxr-xr-x 3 alizj 96 5 5 12:11 clang/
-rw-r--r-- 1 alizj 50M 11 14 23:46 libLLVM.dylib
-rw-r--r-- 1 alizj 44M 11 14 23:46 libclang-cpp.dylib
-rw-r--r-- 1 alizj 24M 11 14 23:46 libclang.dylib
zj@a:~/esp$ cd ~/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin/
zj@a:~/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin$ ls -l *esp32s3*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-addr2line*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-ar*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-as*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-c++*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-c++filt*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-cc*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-cpp*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-elfedit*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-g++*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcc*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcc-13.2.0*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcc-ar*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcc-nm*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcc-ranlib*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcov*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcov-dump*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gcov-tool*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-gprof*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-ld*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-ld.bfd*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-lto-dump*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-nm*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-objcopy*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-objdump*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-ranlib*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-readelf*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-size*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-strings*
-rwxr-xr-x 1 alizj 361K 9 29 2023 xtensa-esp32s3-elf-strip*
zj@a:~/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin$
# export-esp.sh 将该 bin 目录添加 PATH 前面
zj@a:~$ cd esp/
zj@a:~/esp$ ls ~/.rustup/toolchains/esp/xtensa-esp-elf/esp-*/xtensa-esp-elf/xtensa-esp-elf/bin/
ar* as* ld* ld.bfd* nm* objcopy* objdump* ranlib* readelf* strip*
# 这些工具是 crosstool-NG 的 esp 版本
zj@a:~/docs$ ~/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/bin/ld --version
GNU ld (crosstool-NG esp-13.2.0_20230928) 2.41
Copyright (C) 2023 Free Software Foundation, Inc.
# 它们支持 elf32-xtensa target
zj@a:~/docs$ ~/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/bin/ld --help |grep supp
Enable support of non-contiguous memory regions
/Users/zhangjun/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/bin/ld: supported targets: elf32-xtensa-le elf32-xtensa-be elf32-little elf32-big srec symbolsrec verilog tekhex binary ihex plugin
/Users/zhangjun/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/xtensa-esp-elf/bin/ld: supported emulations: elf32xtensa
# esp rustc 支持 x86_64/arm64/riscv64/xtensa-esp32s3-espidf/xtensa-esp32s3-none-elf target
# 后续可以在项目的 rust-toolchain.toml 和 .cargo/config.toml 中指定使用 esp channel 和对应的 target。
zj@a:~/docs$ ~/.rustup/toolchains/esp/bin/rustc --print target-list |grep -E 'xtensa|riscv'
riscv32gc-unknown-linux-gnu
riscv32gc-unknown-linux-musl
riscv32i-unknown-none-elf
riscv32im-unknown-none-elf
riscv32imac-esp-espidf
riscv32imac-unknown-none-elf
riscv32imac-unknown-xous-elf
riscv32imc-esp-espidf
riscv32imc-unknown-none-elf
riscv64-linux-android
riscv64gc-unknown-freebsd
riscv64gc-unknown-fuchsia
riscv64gc-unknown-hermit
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-linux-musl
riscv64gc-unknown-netbsd
riscv64gc-unknown-none-elf
riscv64gc-unknown-openbsd
riscv64imac-unknown-none-elf
xtensa-esp32-espidf
xtensa-esp32-none-elf
xtensa-esp32s2-espidf
xtensa-esp32s2-none-elf
xtensa-esp32s3-espidf # espidf 后缀的 target 为使用 eps-idf 的 std 应用
xtensa-esp32s3-none-elf # none-elf 后缀的 target 为不使用 esp-idf 的 non_std 应用
xtensa-esp8266-none-elf
更新 esp-rs 工具链:
zj@a:~/esp$ enable_socks_proxy
zj@a:~/esp$ espup update