ESP32向けRust開発環境をNixで構築する
急いでいる方向け
次の手順で構築からビルドまで可能です(direnvを導入している必要があります)
nix flake new -t github:turtton/flake-templates#esp32-idf <appname>
作成されたフォルダ内でDirenvを有効にしてから(direnv allow
)、以下を実行します
cargo generate --init esp-rs/esp-idf-template cargo # See: https://github.com/esp-rs/esp-idf-template
Build environmentに入り、ビルドを実行します。
$ nix develop
$ cargo build
この環境では
cargo run
が利用できないため直接flash
コマンドを使う必要があることに注意して下さい。詳細は現状の問題点にて記載しています
構築手順
Rustプロジェクトの構築
cargo-generate
を用いたプロジェクト作成方法が公式テンプレートより案内されていますのでそれを使用します。
nix run nixpkgs#cargo-generate generate esp-rs/esp-idf-template cargo
Project Nameに指定した名前のディレクトリが存在するため移動しておきます。
Nixによるビルド可能な環境の構築
こちらでは自身が試行錯誤した時系列に沿って手順を案内します。
生成されたプロジェクトのrust-toolchain.toml
を確認してみると、以下のようになっているはずです。
[toolchain]
channel = "esp"
もしrustupなどでcargo等が導入済みであっても、espターゲットはデフォルトでは存在しないためビルドすることができません。
ということで、まずはespターゲットのツールチェインを導入する必要があります。
通常の方法であれば、espup
を用いて専用のツールチェインを導入し、環境変数を設定することでビルド可能な状態にしますが、こちらをNixの力を用いてやってみます。
esp32 rust nix
とかで雑に検索するとknarkzel/esp32というRepositoryに出会うはずです。
こちらではespressif/idf-rustというDockerImageから.cargo
と.rustup
ファイルを抽出して提供してくれています。とりあえずMinimal exampleにある通りにflake.nix
を作成してみましょう。
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
esp32 = {
url = "github:knarkzel/esp32";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
esp32,
}: let
pkgs = import nixpkgs {system = "x86_64-linux";};
idf-rust = esp32.packages.x86_64-linux.esp32;
in {
devShells.x86_64-linux.default = pkgs.mkShell {
buildInputs = [
idf-rust
];
shellHook = ''
export PATH="${idf-rust}/.rustup/toolchains/esp/bin:$PATH"
export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src"
'';
};
};
}
これでnix develop
を実行し、cargo build
してみると、途中までは順調に進むもののesp-idf-sys
のコンパイルが失敗してビルドできません。
エラー内容などで検索してみるとesp-idf-sysの#184に辿りつくと思います。
色々と議論されていますが、要はこいつがpython使ったりして外部依存を取ってくるので、FHSを満たしていないNixだと盛大にコケるってことがわかります。issueの最後の方にうまくいったflakeファイルが置かれていますので、今の環境と繋ぎ合わせて以下のようになります。
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
esp32 = {
url = "github:knarkzel/esp32";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{ self
, nixpkgs
, esp32
}:
let
pkgs = import nixpkgs {
system = "x86_64-linux";
};
idf-rust = esp32.packages.x86_64-linux.esp32;
fhs = pkgs.buildFHSUserEnv {
name = "fhs-shell";
targetPkgs = pkgs: with pkgs; [
gcc
pkg-config
gnumake
cmake
ninja
git
wget
idf-rust
cargo-generate
cargo-espflash
espflash
python3
python3Packages.pip
python3Packages.virtualenv
ldproxy
];
profile = ''
export LIBCLANG_PATH="${idf-rust}/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-17.0.1_20240419/esp-clang/lib"
export PATH="${idf-rust}/.rustup/toolchains/esp/bin:$PATH"
export PATH="${idf-rust}/.rustup/toolchains/esp/xtensa-esp-elf/esp-13.2.0_20230928/xtensa-esp-elf/bin:$PATH"
export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src"
'';
};
in
{
devShells.${pkgs.system} = {
default = fhs.env;
};
};
}
ちなみに元のissueでは
~/.rustup
を消したとかなんとか言ってますが今回の環境と関係ないので無視してもらって構いません。
再度nix develop
してbuild environmentに入りcargo build
を実行してみましょう。今度はビルドが通り、無事に環境構築完了です...が、以下のような注意点があります。
現状の問題点
環境構築後、nix develop
内でcargo run --release
をしてみると、/dev/ttyUSBn
へのアクセス権限が無いと言われます。
それならばと手動でsudo espflash flash --monitor target/xtensa-esp32-espidf/release/<appname>
とやってみても、そもそもsudoの実行がbuild environmentでは禁止されているため書き込みができません。
もしBuild environment内で
/dev/ttyUSBn
にアクセスする方法をご存じの方がいらしたらコメントなどで教えてください。
現状の回避策として、direnvを使用し、espflashをbuild envの外で使えるようにしてみます。
私のテンプレートから生成していない人は以下のようにコードを追記してください。
devShells.${pkgs.system} = {
default = fhs.env;
+ flash = pkgs.mkShell {
+ packages = [
+ pkgs.espflash
+ ];
+ };
};
if ! has nix_direnv_version || ! nix_direnv_version 3.0.5; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.5/direnvrc" "sha256-RuwIS+QKFj/T9M2TFXScjBsLR6V3A17YVoEW/Q6AZ1w="
fi
use flake .#flash
以下のようにコマンドをBuild environment外で実行します。
$ direnv allow
# 必要があれば`nix develop`してから`cargo build --release`してbuild environmentから出る
$ sudo espflash flash --monitor target/xtensa-esp32-espidf/release/<appname>
これでESP32への書き込みができるはずです。
終わりに
一部問題はあるものの、自身の環境を汚すことなく再現可能な開発環境を手に入れられたので一旦良しとして記事にしました。
そもそもESP32+Rust開発に関しては情報が少なく、ましてやNixを使う人は少数かと思いますが、DependencyHellや環境汚染の無いクリーンな環境に興味がある方は是非やってみてください。
Discussion