EDIT: 最新のESP-IDF(5.0)ではそもそも起動チェックで撥ねられるようになった
最近M5Stackを買ったのでその開発環境をCygwinで用意することにした。特にメリットは無いのでWindowsユーザは素直にWindowsネイティブ環境を使った方が良いと思う。
また、 今のところArduinoランタイムは最新のIDFでビルドできないため使えない 。真面目にやれば多分できるけど個人的にArduino部分は使わない予定なので。。
とりあえず、Cygwin上のgcc、binutils、CMake、Ninjaでアプリケーションをビルドしてmonitorするところまではできた。この辺のノウハウはLinuxやmacOSのようなサポートされた環境でも超最新のESP-IDFを追いたければ役に立つかもしれない。
ESP32開発環境の構成
ESP32の開発環境は、
の2つのリポジトリに分かれて公開されている。(他にもOpenOCDとかも有るがとりあえずM5StackではJTAG使えないんで。。)
これらのリポジトリには:
- コンパイラ等のツールチェイン(Crosstool-NGでビルドしたやつ)
- CMakeで構築されたビルドシステム
- Pythonで書かれた各種ツール(monitorやflashツールなど)
- FreeRTOS等のライブラリ(= コンポーネント)
が含まれる。ツールチェインはCrosstool-NGでビルドする必要があるが、それ以外のコンポーネント(2. 〜 4.)は基本的に本家のESP-IDFリポジトリ( https://github.com/espressif/esp-idf )とそのsubmodule群に格納されていて、Crosstool-NGをビルドしてesp-idfリポジトリを(recursiveに)チェックアウトするだけでSDKが揃うようになっている。
ツールチェインの準備(Crosstool-NG)
ESP32の公式サイトにLinux向けの crosstool-ngを使用してXtensaのツールチェーンを用意する方法 が書かれているので基本的にはその通りにすれば良い。ただしいくつかハマる点があった。
ビルドの依存関係としては、基本的にはRPM系Linuxで似た名前をしているパッケージを探して導入しておけばOKだが、手元では help2man
と curses-devel
を追加でインストールする必要があった。
ひととおりのビルドが完了したあと、 PATH
にツールチェインが含まれていることを確認する。
oku@stripe ~
$ xtensa-esp32-elf-
xtensa-esp32-elf-addr2line.exe xtensa-esp32-elf-gcov.exe
xtensa-esp32-elf-ar.exe xtensa-esp32-elf-gcov-dump.exe
xtensa-esp32-elf-as.exe xtensa-esp32-elf-gcov-tool.exe
xtensa-esp32-elf-c++.exe xtensa-esp32-elf-gdb.exe
xtensa-esp32-elf-c++filt.exe xtensa-esp32-elf-gprof.exe
xtensa-esp32-elf-cc.exe xtensa-esp32-elf-ld.bfd.exe
xtensa-esp32-elf-cpp.exe xtensa-esp32-elf-ld.exe
xtensa-esp32-elf-ct-ng.config xtensa-esp32-elf-nm.exe
xtensa-esp32-elf-elfedit.exe xtensa-esp32-elf-objcopy.exe
xtensa-esp32-elf-g++.exe xtensa-esp32-elf-objdump.exe
xtensa-esp32-elf-gcc.exe xtensa-esp32-elf-ranlib.exe
xtensa-esp32-elf-gcc-8.2.0.exe xtensa-esp32-elf-readelf.exe
xtensa-esp32-elf-gcc-ar.exe xtensa-esp32-elf-size.exe
xtensa-esp32-elf-gcc-nm.exe xtensa-esp32-elf-strings.exe
xtensa-esp32-elf-gcc-ranlib.exe xtensa-esp32-elf-strip.exe
ビルドシステムは PATH
からこれらのツールを検索する。
Cygwinで大小文字を区別するファイルシステムを使用する
Crosstool-NGでは、ファイル名の大小文字を区別しないファイルシステム上ではビルドできないようになっている。macOSでは専用のディスクイメージを作ってマウントするといった方法を使うが、CygwinではWSL1の機能を使用して大小文字の区別をするファイルシステムを使用できる(NTFS限定)。
Crosstool-NGのビルドディレクトリで、
chattr +C .
のように、 chattr
コマンドに C
オプションを渡すと、指定したディレクトリ以下でファイル名の大小文字が区別されるようになる。
なぜかlibintlがリンクされない問題 (最新版で修正済)
EDIT: 最新の esp-2021r2
で 修正 されているのを確認。
Crosstool-NGはメニューベースのコンフィギュレータ(Kconfig)が付属していて、それがcursesを使用している。これがどうも正常にCygwin上でビルドされないらしく、手動で -lintl
を追加しないとビルドできなかった。
/cygdrive/f/m5/esp32/crosstool-NG/kconfig/conf.c:90: undefined reference to `libintl_gettext'
いわゆるGNUビルドシステムでは環境変数 LDFLAGS
でリンカのコマンドライン引数を追加できるので、それを利用して、
LDFLAGS=-lintl ./configure --enable-local && make
で動作するKconfigをビルドできた。
Newlibが正常にビルドできない問題 (最新版で修正済)
EDIT: 最新の esp-2021r2
で修正されているのを確認。
Crosstool-NGでツールチェインをビルドしていると、何故かNewlibの内部でビルドに失敗する症状が出た。
[ERROR] configure.in:17: error: possibly undefined macro: LIB_AC_PROG_CC
[ERROR] make[4]: *** [Makefile:167: /cygdrive/f/m5/esp32/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/libgloss/xtensa/configure] Error 1
エラーメッセージにある LIB_AC_PROG_CC
自体はリポジトリ内の aclocal.m4
で宣言されていてパスも通っているので無いってことは無いと思うんだけど。。とりあえず、近所の riscv
ディレクトリからコピーしてお茶を濁すことにした。
cd ~/esp32/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/libgloss/xtensa
cp ../riscv/aclocal.m4 .
(最近発生した) isl
がダウンロードに失敗する
INRIAのサーバが無くなってしまったのでislのダウンロードに失敗するようになった。
とりあえず git からチェックアウトするようにして適当に処理した。
Pythonパッケージのインストール
ESP32の開発環境ツールの依存関係は requirements.txt
に書かれているので、それを単に pip
でインストールすれば良い。ただ、Cygwinでは gevent
のインストールに失敗するので、
GEVENTSETUP_EMBED_LIBUV=0 python3.8 -m pip install --verbose -r ~/esp32/esp-idf/requirements.txt
のように、 GEVENTSETUP_EMBED_LIBUV=0
を環境変数として設定した状態でインストールする必要がある。
CMakeプロジェクトのビルド
ESP32の開発環境はCMakeベースではあるものの、標準の環境では project()
コマンドを置き換えて必要な設定を自動でやるといった特殊化が目立つ実装になっている。公式のドキュメントには 通常のCMakeプロジェクトでESP32開発環境を使う方法 の解説もちゃんとあるため、ESP32以外の環境もターゲットするプロジェクトであればこちらのドキュメントに従って組み込んだ方が良いかもしれない。
- https://github.com/okuoku/esp32test/tree/5abff8b65306bb45c77e09facadce205a371c3b0
- submoduleとしてESP-IDF自体も入れている https://github.com/okuoku/esp32test/tree/5abff8b65306bb45c77e09facadce205a371c3b0/external
今回は、"チェックアウトするだけでESP-IDFも含めて準備ができるリポジトリ"を用意してみた。こうすることで、特定バージョンのESP-IDFと同時に管理できて便利かもしれない。
環境変数のoverride
重要なポイントは、通常のESP32開発環境では環境変数 IDF_PATH
の設定が必要になっているが、このリポジトリは自動的に環境変数を設定してビルドするようになっている点と言える。esp-idfにはOSやTCPスタックのような大量のコードが含まれているため、構成管理上は複数バージョンの混在を意識したい。
Configure中の環境変数
Configure中の環境変数は、CMakeの set
コマンドで書き換えることができる。ESP-IDFのCMake環境はconfigure中にいくつかpythonツールを呼び出し、それらも IDF_PATH
環境変数に依存しているためこの対応が必要になる。
set(idf_path ${CMAKE_CURRENT_LIST_DIR}/external/esp-idf)
set(ENV{IDF_PATH} ${idf_path})
CMakeのcustom commandターゲットの環境変数
ESP32のツールチェイン(gcc
やbinutils
)はIDF_PATH
に依存していないが、イメージ作成ツール等のいくつかのビルド中に呼ばれるツールが IDF_PATH
環境変数に依存している。このため、これらのツールを起動する際にも環境変数をoverrideする必要がある。
今回は、環境変数をoverrideした上で runtool.sh
を呼ぶようにプロパティ RULE_LAUNCH_CUSTOM
を設定した(ドキュメントではMakefileにしか効かないと書かれているが、実際にはNinjaでも使用できる)
# Generate custom launcher
set(launcher_file ${CMAKE_CURRENT_BINARY_DIR}/runtool.sh)
set(launcher_src "#!/bin/sh\nexport ESPPORT=${PORT}\nexport IDF_PATH=${idf_path}\nexec \"$@\"\n")
file(WRITE ${launcher_file} ${launcher_src})
set_property(GLOBAL
PROPERTY RULE_LAUNCH_CUSTOM
${launcher_file})
生成されるruntool.sh
は以下のような内容になる:
#!/bin/sh
export ESPPORT=/dev/ttyS4
export IDF_PATH=/home/oku/repos/esp32test/external/esp-idf
exec "$@"
今回はESP32をCOM5に接続しているので、Cygwin的には /dev/ttyS4
に見える。環境変数 ESPPORT
は ninja flash
で起動できるファームウェア書き込みツールで使用できる。シリアルモニタも ninja monitor
で起動できるが、手元の環境ではCMakeに指定したpythonを見てくれなかったので、専用のcustom commandを用意している( https://github.com/okuoku/esp32test/blob/5abff8b65306bb45c77e09facadce205a371c3b0/CMakeLists.txt#L33-L39 )。
かんそう
今回Crosstool-NGにnewlibのビルドまでやらせているが、気持ちとしてはnewlibのバージョンもGitで管理したい。。そもそもCrosstool-NGでgccやgdbをビルドしなくても、手でビルドすれば同じことではあるので、もっと新しいgccを使ったりした方が面白いかもしれない。
SDKのインストールがGitのチェックアウトで終わるのは便利ではあるけど、Pythonのパッケージとかツールチェインの準備などは避けようが無くてなんとも惜しい気はする。