PlatformIOは、多くのマイコンと多くのフレームワークを、同じようなインターフェースで扱うことができる環境であり、IDEだけでなくコマンドラインからでも使えるので、、なかなか便利なツールである。さて、これを使ってESP32で開発を行っているわけだが、ちょっとした問題に行き当たったのでシェアしてみよう。
I like C++ language
いろいろなプログラミング言語はあるけれど、私が一番手になじんでいるのはC++である。できることならいつもC++を使って遺体、そうも言ってられない局面は多いけど。ということで、今回も無意識にC++を使い始めていた。これが今回の問題なのである。
やったこと
コマンドラインから以下のように操作した。
$ platformio init -b esp32dev
$ sed s/arduino/espidf/g < platformio.ini > platformio.tmp
$ mv platformio.tmp platformio.ini
ようするに、esp-idfで新しいプロジェクトを作ったわけである。
続いて、srcディレクトリいかにmain.cppというファイルを置いた。
#include <iostream>
int app_main()
{
std::cout << "Hello ESP32 world" << std::endl;
return 0;
}
これをコンパイルするとエラーになる。
Linking .pio/build/esp32dev/firmware.elf
.pio/build/esp32dev/libesp32.a(cpu_start.o):(.literal.main_task+0x18): undefined reference to `app_main'
.pio/build/esp32dev/libesp32.a(cpu_start.o): In function `main_task':
cpu_start.c:(.text.main_task+0x5f): undefined reference to `app_main'
collect2: error: ld returned 1 exit status
*** [.pio/build/esp32dev/firmware.elf] Error 1
なぜエラーになるのか?
esp-idfのスタートアップであるcpu_start.cは、名前が示すようにCで書かれている。ということは、このプログラムからはC++で書かれているapp_main()が見つけられない。シンボル名が違うのだ。CとC++の混在環境を作ろうとすると起こる問題。ならば、
extern "C"
してやればよい。
#include <iostream>
extern "C" {
int app_main()
{
std::cout << "Hello ESP32 world" << std::endl;
return 0;
}
}
めでたくコンパイルできるはず!
追記
platformioを使ってのサンプルであるが、もちろんESP-IDFをそのまま使ってももちろん結果は同じである。