こんにちはRockinWoolです。C++のプログラムが大きくなりそうだったので、クラスを作ってわかりやすく管理してやろう!と思ったわけですよ。しかし、なんか見知らぬエラーが連発してなんじゃこりゃってなったので、対策方法をメモして残しておきます。先に言っておきますが、かなり初心者レベルのことに今更気づいてドヤ顔しているので内容は結構恥ずかしいです。

おかしい。クラスを読み取ってくれない。

最近読んだリーダブルコードにもありました通り、本質的では無いコードはutilに突っ込んでメインは読みやすくしたい。そのためにはクラス化してpublicな関数とprivateな関数に分けてやろう!と意気込んだわけです。しかし、問題が。下記のようなプログラム構成にしたのですが、関数の定義が見つからないよというエラーが出てしまうのです。

-main.cpp
-util.h
-CMakeLists.txt
-util(folder)
|-myclass.cpp
main.cpp:(.text+0x6d): undefined reference to `Myclass::hoge(std::__cxx11::basic_string, std::allocator >)'

「関数が定義されていない」というのであれば関数は定義されていないのでしょう。さて、何が問題だったのか?

CMakeLists.txtにライブラリファイルの登録をする必要があった

上記のミスはCMakeLists.txtに設定を追記していなかったことにより発生しておりました。下記にChatGPTとの会話を載せておきます。簡単に言えばadd_executable以外にもadd_libraryとtarget_link_librariesの2つを設定する必要がありました。

したがって、CMakeLists.txtは次のように書き換える必要があります。

cmake_minimum_required(VERSION 3.2)
project(pybind_test VERSION 0.1.0)
# ライブラリとしてクラスの実装を含む
add_library(Myclass myclass.cpp)

# プログラムの実行可能ファイルを作成し、リンクする
add_executable(MAIN main.cpp)
target_link_libraries(MAIN Myclass)

ここまでやれば、コードさえミスってなければエラーは出ないはず・・・。
・・・・。
エラーが出ました。

error: ‘Myclass’ has not been declared

ヘッダファイルからのincludeは不要

さて、上記のエラーを解決するのにはかなりの時間を要しました。というのも、このCやC++の仕様が気持ち悪くて何回躓いても納得できない!過去の自分と同じエラーで引っかかったので悔しいを通り越して怒りになっているのですが、サンプルプログラムを作ったりしながら試行錯誤を続けているうちに気づくことができたのは偉かった。
エラーの原因ですが、utils.hに#include util/myclass.cppを書いていたのが原因でした。utils.hを読んだ時にクラスの定義より先にmyclass.cppの中のMyclass::hoge()関数を読もうとして、「Myclassなんて無いんだけど?」ってなったのが先のエラーです。確かにあとから見ればそんなの当たり前に感じますよね。でも、これってCMakeLists.txtに追記した内容を理解していないと遭遇してしまうと思うんです。
pythonを書き慣れている私からすると、親子関係にあるプログラムは親でimport宣言をして子の関数を呼び出せるようにするのが当たり前。ということはutils.hで宣言する関数も実際に書かれているmyclass.cppからimportしなければならないのでは?と考えてしまうのです。(今でもその感覚は抜けていない)
なので、ヘッダファイルで行っているのはあくまで関数のプロトタイプ宣言であり、utils.hとmyclass.cppでライブラリを作ったあと、utils.hとmain.cppでメインを作って、それらをリンクさせるという一連のCMakeLists.txtの動作を理解しないと、この違和感は払拭できないわけです。

まとめ

結局このエラーを解消するのに半日使ってしまったので、今となっては完全にやる気が削がれてしまいました。しかし、この経験をバネに日記を書いて次回につなげて行こうと思います。それではここまで長々とお付き合いいただきありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です