Arduino でサブディレクトリにファイル分割する方法

ソフトウェアを開発する際、ファイル分割しさらにサブディレクトリに整理したくなることがあるかと思います。特に C/C++ では a.hpp, a.cpp, b.hpp, b.cpp のように一機能に対して複数ファイルになることが多いので、早い段階で整理したくなります。
しかし Arduino では、普通にサブディレクトリを作成しても全然ビルドしてくれません。そこで Arduino の仕様を探索しましたので対処策をいざ投下
TL;DR
プロジェクトのルートディレクトリに src
ディレクトリを作成し、その中にサブディレクトリを配置します。こうするとサブディレクトリ下に配置したソースファイルも再帰的にビルド対象に含んでくれます。
project
├── project.ino
└── src <-- これだけ!
├── common
│ ├── vector2d.hpp
│ └── vector2d.cpp
├── hardware
│ ├── motor.hpp
│ └── motor.cpp
└── network
├── mdns.hpp
├── mdns.cpp
├── http_server.hpp
└── http_server.cpp
ヘッダをインクルードする際は各ファイルからの相対パスでインクルードします。
ino ファイルからの場合こうです。
#include "src/common/vector2d.hpp"
#include "src/hardware/motor.hpp"
#include "src/network/mdns.hpp"
#include "src/network/http_server.hpp"
サブディレクトリ内のソースファイルの場合こうです。
// src/hardware/motor.cpp
#include "motor.hpp"
#include "../common/vector2d.hpp"
うまくいかないケース
例えば次のようにディレクトリを分割したとします。やりますよね、私やりました。
project
├── project.ino
├── common
│ ├── vector2d.hpp
│ └── vector2d.cpp
├── hardware
│ ├── motor.hpp
│ └── motor.cpp
└── network
├── mdns.hpp
├── mdns.cpp
├── http_server.hpp
└── http_server.cpp
project.ino ファイルはこんな感じ。
#include "common/vector2d.hpp"
#include "hardware/motor.hpp"
#include "network/mdns.hpp"
#include "network/http_server.hpp"
この状態でビルドすると、サブディレクトリ下のソースファイルがビルド対象に含まれず、リンクエラーになります。それもマングリング後の読みたくないやつ
ただ、ヘッダファイルのインクルードはできます。つまりソースファイルを完全排除してヘッダオンリーで実装している場合は問題ありません。
仕様をのぞく時、仕様もまた*
Arduino の仕様を覗いてみると、src
ディレクトリ以下のソースファイルは再帰的にビルドされるとあります。
Sketch specification (Arduino CLI docs)
注意点 1
src ディレクトリ以下に配置したソースファイルは Arduino IDE から見えなくなります。そこでオヌヌメは VSCode でプロジェクトを開き、Arduino IDE でビルドすることです。
注意点 2
src
ディレクトリはインクルードディレクトリにならない点に注意です。相対パスでインクルードする必要があります。
いいえ
// src/hardware/motor.cpp
#include "hardware/motor.hpp"
#include "common/vector2d.hpp"
プレティーグッド
// src/hardware/motor.cpp
#include "motor.hpp"
#include "../common/vector2d.hpp"
注意点 3
サブディレクトリの名前を変更したとき、Arduino はこれを検知してくれません。なので以前のオブジェクトファイルが残ってしまい、リンクエラーになります。
↓ の中にオブジェクトファイルがキャッシュされるので、エラーになったら削除してください。パスが違う場合はリンクエラーのメッセージを読むと書いてあります。
C:\Users\<USERNAME>\AppData\Local\arduino\sketches\
まとめ
- Arduino のビルドシステムは
src
ディレクトリ以下を再帰的に探索する - ソースは
src
配下に置き、ヘッダは相対パスでインクルードする - キャッシュの残骸でリンクエラーになることもあるので注意
ご覧いただきありがとうございました。