C++でCのライブラリを組み込もうとして「undefined reference to ○○」にハマった
ESP-IDFベースのとあるC++プロジェクトで、Cのライブラリを組み込もうとした時、このエラーが起こった。
1 2 3 4 5 | /Users/username/project/build/modules/libmodules.a(oled.o):(.literal._ZN12oled6updateEv+0x0): undefined reference to `SSD1306_Update(SSD1306_Device*)' /Users/username/project/build/modules/libmodules.a(oled.o): In function 'oled::update()': /Users/username/project/modules/oled.cpp:29: undefined reference to 'SSD1306_Update(SSD1306_Device*)' collect2: error: ld returned 1 exit status make: *** [/Users/username/project/build/project.elf] Error 1 |
SSD1306_Update()が宣言されているヘッダ(ssd1306.h)のインクルードを忘れていないかとかタイポしてないかとか、色々試したけど動かず。
他の正常に動いているメソッドとかと散々比較して、最終的に「extern "C"」というのをつけ忘れていたことがわかった。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #ifndef _SSD1306_H_ #define _SSD1306_H_ #ifdef __cplusplus extern "C" { #endif ~中身は略~ #ifdef __cplusplus } #endif #endif |
これで動いた。
調べたら、これと全く同じ問題が解説されていた。
つまり、「extern "C"」がなかった時は、変な名前のシンボル名でSSD1306_Update()が紐づけられ、それを使って他のファイルのコンパイルも進んで行ったけど、変な名前のシンボル名になったために関数の定義と結びつくことができなかったと。
でも「extern "C"」を使ったことでシンボル名と関数名が一致し、やっと関数の定義と結びつくことができたと。
なるほどなぁ〜。
どおりでエラーの出力がおかしかったわけだ。
他の正しく動いてたCファイルの関数を意図的にエラーを起こさせてみると「undefined reference to ○○」の○○の部分は関数名のみなのに、SSD1306_Update()に関しては引数まで出てきちゃってたからなんかおかしいと思ったんだ。
○○の部分っていうのは関数名ではなくシンボル名。
SSD1306_Update()はC++側の名前マングリングで引数もろともシンボル名にされてしまったから、undefinedの時は引数まで出てきていたというわけだ。
他の正しく動いてたやつはちゃんとCの関数として関数名のみでシンボル名が構成されていたから関数名のみ出てたわけだ。
一応ヒントは出ていたんだなぁ〜。
気づかなかったけど。
この記事へのコメントはこちら