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 |
これで動いた。
調べたら、これと全く同じ問題が解説されていた。
またしてもC/C++で落とし穴に落ちた. Cで書かれたライブラリをC++で普通に使っていて,普通に使えていたわけだが, そのライブラリのあるヘッダをインクルードした瞬間にg++が undefined reference to 'function name'のコンパイルエラーで止まる. gccを使えばコンパイルできるが,C++の標準ライブラリを使いたいので ぜひともg++でコンパイルしたい.調べてみると,どうやらCとC++の互換の微妙な部分にいきついた. 「Name Mangling,名前修飾」という機能の有無が関係しているようだ. 簡単に言うと,Cでは重複する関数... gccでビルドされたライブラリをg++から呼ぼうとするとundefined reference - keisu... - keisukeのブログ |
つまり、「extern "C"」がなかった時は、変な名前のシンボル名でSSD1306_Update()が紐づけられ、それを使って他のファイルのコンパイルも進んで行ったけど、変な名前のシンボル名になったために関数の定義と結びつくことができなかったと。
でも「extern "C"」を使ったことでシンボル名と関数名が一致し、やっと関数の定義と結びつくことができたと。
なるほどなぁ〜。
どおりでエラーの出力がおかしかったわけだ。
他の正しく動いてたCファイルの関数を意図的にエラーを起こさせてみると「undefined reference to ○○」の○○の部分は関数名のみなのに、SSD1306_Update()に関しては引数まで出てきちゃってたからなんかおかしいと思ったんだ。
○○の部分っていうのは関数名ではなくシンボル名。
SSD1306_Update()はC++側の名前マングリングで引数もろともシンボル名にされてしまったから、undefinedの時は引数まで出てきていたというわけだ。
他の正しく動いてたやつはちゃんとCの関数として関数名のみでシンボル名が構成されていたから関数名のみ出てたわけだ。
一応ヒントは出ていたんだなぁ〜。
気づかなかったけど。