VSCode+ Pico SDK でinclude 行のエラー
先日、VSCode + Raspberry pi pico SDKの環境を作ったが、その時にはまった話を恥ずかしいが書いておこうと思う。延べで、8時間以上は悩んだのだが、結果としてはGit の環境が悪かったようで、Gitをインストールしなおしたらあっけなく解決した。
現象
VSCodeに、マーケットプレイスから Raspberry pi Pico のSDKをインストール、インストールは何事もなく完了した。
作成した環境で、Raspberry PI pico (Wなし)のLED 点滅を作りビルドして、まったく問題なく動作を確認した。
この時点で、SDKの環境に問題が無い、と思い込んでしまったのが悪かった。
次に、Raspberry PI pico Wで、同じ操作を行い、プロジェクトウイザードからLED点滅のコードを作成した。
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "pico/cyw43_arch.h"
#include "blink.pio.h"
void blink_pin_forever(PIO pio, uint sm, uint offset, uint pin, uint freq) {
blink_program_init(pio, sm, offset, pin);
pio_sm_set_enabled(pio, sm, true);
すると #include "pico/cyw43_arch.h"
の行に波線が出て、このヘッダファイルがincludeできないという表記になってしまった。
もちろん、これをビルドしても、このエラーになってしまう。
<path>/blink.c:2:10: fatal error: pico/cyw43_arch.h: No such file or directory
2 | #include "pico/cyw43_arch.h"
| ^~~~~~~~~~~~~~~~~~~
調査
この手のエラーは、C/C++をやっているなら、一度はお目にかかるもので、はじめは大した問題とは思っていなかった。cmakeのファイルやら何やらを見て、includeを追加すればそれで済むと思っていた。
実際、reddit やgithubで同じ現象が報告されていた。
これらの記事では、主に次のような提案がされているが、残念ながら解決には至らない。
- target_link_librariesに、pico_cyw43_arch_noneを追加する
- CMAKE に、-DPICO_BOARD=pico_w を追加して実行する
- c_cpp_properties.jsonのincludePathに追加する
- compile_commands.jsonのコンパイル引数に -i としてインクルードパスを追加する
※後から思えば、「target_link_librariesに、pico_cyw43_arch_noneを追加する」はなかなか近い回答だったと言えるが、その時には正しく追加されているとしか思わなかった。
判明
色々調べていると、やはり、 target_link_librariesへのpico_cyw43_arch_noneが追加されていないとこのエラーが出るというのが本命筋に思えてくるため、再度、CMakeのログを確認した。
cmake clean rebuildでcmakeをやり直すと、cyw43-driver が正しく初期化されていない、というメッセージが出ていた。
しかも、「SDKのインストールフォルダで、git submodule update --initを実行しろ」と丁寧に書いてあった。
[cmake] cyw43-driver submodule has not been initialized; Pico W
wireless support will be unavailable
[cmake] hint: try 'git submodule update --init' from your SDK directory
そこで、言われたとおりに作業すると、次のようなエラーが発生する
git submodule update --init
Skipping command-line '"C:\Program Files\Git\usr\usr\bin\..\usr\bin\bash.exe"'
('C:\Program Files\Git\usr\usr\bin\..\usr\bin\bash.exe' not found)
Need a valid command-line; Edit the string resources accordingly
果たして、C:\Program Files\Git\usr\usr\bin\..\usr\bin\bash.exe
というフォルダが存在せず、現在のgit環境がマッチしていない、と言うことになる。
解決
この環境のgitはいつ入れたのか覚えていないが、まずは入れなおしてコマンドを再実行したところ、あっさりとコマンドは成功する。
git submodule update --init
Submodule 'lib/btstack' (https://github.com/bluekitchen/btstack.git) registered for path 'lib/btstack'
Submodule 'lib/cyw43-driver' (https://github.com/georgerobotics/cyw43-driver.git) registered for path 'lib/cyw43-driver'
Submodule 'lib/lwip' (https://github.com/lwip-tcpip/lwip.git) registered for path 'lib/lwip'
Submodule 'lib/mbedtls' (https://github.com/Mbed-TLS/mbedtls.git) registered for path 'lib/mbedtls'
Submodule 'tinyusb' (https://github.com/hathach/tinyusb.git) registered for path 'lib/tinyusb'
Cloning into 'C:/Users/hisay/.pico-sdk/sdk/2.0.0/lib/btstack'...
Cloning into 'C:/Users/hisay/.pico-sdk/sdk/2.0.0/lib/cyw43-driver'...
Cloning into 'C:/Users/hisay/.pico-sdk/sdk/2.0.0/lib/lwip'...
Cloning into 'C:/Users/hisay/.pico-sdk/sdk/2.0.0/lib/mbedtls'...
Cloning into 'C:/Users/hisay/.pico-sdk/sdk/2.0.0/lib/tinyusb'...
Submodule path 'lib/btstack': checked out '2b49e57bd1fae85ac32ac1f41cdb7c794de335f6'
Submodule path 'lib/cyw43-driver': checked out 'faf36381bad1f668a30172b6336c9a970966ef4c'
Submodule path 'lib/lwip': checked out '0a0452b2c39bdd91e252aef045c115f88f6ca773'
Submodule path 'lib/mbedtls': checked out '5a764e5555c64337ed17444410269ff21cb617b1'
Submodule path 'lib/tinyusb': checked out '4232642899362fa5e9cf0dc59bad6f1f6d32c563'
その後、VSCodeを再起動すると、includeの波線も消え、ビルド/実行できた
反省点とグチ
VSCodeに機能拡張を追加して最初にプロジェクトを作ったときに、SDKのダウンロードと環境設定が行われる。サブモジュールの初期化は、この時に行われるので、おそらく、この時にログをきちんと見ていれば、 submiduleの初期化が成功していなかったことはわかったはずだった。
また、実際、cmakeのクリーンとビルドは何回か実行したが、cmakeの途中で出ていたSDK サブモジュールのエラーについては、実行ログを読んで見ていなかった。cmakeのビルド成功という、最後のステータスコードだけで、問題が無いと思い込んでいたのも問題だった。
エラーメッセージ(しかも親切にも対処方法まで書いてある)を読んでいない私が悪い、それはわかった上で言わせてもらえば、大量に表示されるログの中の数行のエラー、しかも最終的な実行ステータスは success になっているのを、その場で気づけ、と言うのはかなり厳しい。
最近のビルド環境は、ビルドツールが高度に階層化され、オープンソースのツールが複数組み合わされ、ノータッチで一気に実行できる。各ツールが、何をどの順番で呼び出すのか、何をやっているのか理解せずに開発が始められる。しかし、便利なのは動いているときの話。 ひとたび、どこかに問題が発生すると、見つけるのが難しくなってしまう。 クローズドなIDE/SDK (MPLabXなど)では、環境設定などでの問題はその場でレポートされ解決されることが多く、問題が起こりにくいように思う。