🚫

bi_decl()は行分割してはならない

2024/09/21に公開

結論

Raspberry Pi Pico SDKのbi_dec()マクロを使う場合、括弧内で改行してはいけません。コンパイルエラーが起きます。

bi_decl()とは

Raspberry Pi Pico SDKには、バイナリファイルに情報を埋め込むメカニズムがあります。これはpicotoolという専用ツールを使って読みだすことができ、以下のようなファイルからプログラマが埋め込んだ情報を読み出すことができます。

  • バイナリファイル。
  • バイナリを書き込んだRasPi Pico。

picotoolで情報をファイルから読みだした例を以下に示します。

$ picotool info talkthrough_sample.uf2 
File talkthrough_sample.uf2:

Program Information
 name:          talkthrough_sample
 web site:      https://github.com/suikan4github/pico_driver-sample
 description:   Working with UMB-ADAU1361A board. ADAU1361A I2C address is 0x38.
 features:      UART stdin / stdout
 binary start:  0x10000000
 binary end:    0x10007ea0

picotoolは正体不明のバイナリファイルや、何が書き込まれたファイルかわからないようなRasPi Picoからでも情報を取り出すことができる便利なツールです。

そしてbi_decl()マクロは、このpicotoolのためにプログラムに情報を埋め込むツールです。

問題

問題を再現するプログラムをGitHubに公開しています。手元で実験する人は、ブランチをrpp_bi_declにしてください。

このプログラムはmain.cの22行目にbi_decl()があり、内部で改行しています。

  bi_decl(
    bi_program_url("https://github.com/suikan4github/failure-demo/tree/rpp_bi_decl"));

このプログラムをビルドすると、以下のようなエラーが出ます。

[build] /home/seiichi/git/failure-demo/src/main.c: In function 'main':
[build] /home/seiichi/git/failure-demo/src/main.c:23:5: error: '_error_bi_is_missing_enclosing_decl_23' undeclared (first use in this function); did you mean '_error_bi_is_missing_enclosing_decl_22'?
[build]    23 |     bi_program_url("https://github.com/suikan4github/failure-demo/tree/rpp_bi_decl"));
[build]       |     ^~~~~~~~~~~~~~
[build] /home/seiichi/git/failure-demo/src/main.c:23:5: note: each undeclared identifier is reported only once for each function it appears in
[build] /home/seiichi/git/failure-demo/src/main.c:22:3: error: '__bi_22' undeclared (first use in this function); did you mean '__bi_23'?
[build]    22 |   bi_decl(
[build]       |   ^~~~~~~
[build] ninja: build stopped: subcommand failed.

エラーメッセージは何を言っているのか

エラーメッセージは非常に不可解です。

error: '_error_bi_is_missing_enclosing_decl_23' undeclared (first use in this function);

一見、マクロ定義内の込み入ったエラーに見えるので素通りしてしまいがちです。しかし、実はここでは開発者が限られた手段を尽くしてプログラマにメッセージを伝えようとしているのです。メッセージから"_"を取り除いてみましょう。

error bi is missing enclosing decl 23.

これを開発者が言いたかったことに変換すると。

error : bi is missing enclosing decl at line 23.
// biマクロには自分自身を包むdeclが23行目に必要です。

"bi is missing enclosing decl at same line" としてくれればわかり易いのですが、マクロ定義を覗くと相当に苦労しているようなので同情の余地はあります。

ワークアラウンド

この問題を避ける方法は二つあります。

最初の簡単な方法は、bi_declの中身を全部同じ行にしてしまう事です。

  bi_decl(bi_program_url("https://github.com/suikan4github/failure-demo/tree/rpp_bi_decl"));

二つ目の方法は、bi_decl()の中で呼ばれているマクロの中で改行することです。

  bi_decl(bi_program_url(
           "https://github.com/suikan4github/failure-demo/tree/rpp_bi_decl"));

この方法がうまくいくのはちょっと変に思えます。しかし、上記エラーメッセージの主語はbi_decl()ではなく、bi_program_url()であったことを考えると、筋は通っています。

vscodeの自動整形を避ける

Visual Studio CodeのC++拡張機能を使うと、URLが長くなった時に行が自動分割されてエラーが起きます。そんなときには自動整形を局所的にオフできます。

  // clang-format off
  bi_decl(bi_program_url("https://github.com/suikan4github/failure-demo/tree/rpp_bi_decl"));
  // clang-format on

Discussion