ROS2でヘッダファイルのインストール先が変わったらしい
※この記事はCalendar for ROS2 | Advent Calendar 2022 - Qiita,2日目の記事である
※である調で書いてしまったので文章が多少高圧的に感じられるかもしれないがご容赦願いたい
ROS2 Humbleを早々と試している人々の中には既に気付いている方もいらっしゃるかもしれない.
そう,ヘッダファイルのインストール先が変わっているのである!!
嘘だと思うなら下の画像を見て欲しい.
GalacticとHumbleでフォルダ構成が違うことが分かっていただけると思う.
Galacticではstd_msgs
フォルダの直下にmsg
フォルダがあるのだが,Humbleではさらにもう一つstd_msgs
フォルダを挟んでいる.
この記事では,この変更がどうして行われたかを解説していく.
読み進める人への注意 : この記事は要求される事前知識が多い割に読んで得られる知見は少ない.ROSの勉強にはなると思うが...
事前知識
記事を読み進める前に頭に入れておきたい事前知識たち. 単語を見て理解できるなら飛ばしてもらって構わない.
マージインストール
詳細
コマンド
colcon build --merge-install
起こること
パッケージのインストール先が変わる 例えば,ヘッダファイルのインストール先は以下のようになる
インストールの種類 | ヘッダファイルのインストール先 |
---|---|
通常 | colcon_ws/install/<package_name>/include |
マージインストール | colcon_ws/install/include/<package_name> |
得られる効果
全パッケージのlib
フォルダを環境変数に入れようとすると,通常インストールの場合では
各パッケージにそれぞれに対して colcon_ws/install/<package_name>/lib
を追加する必要がある.
しかし,マージインストールしているとcolcon_ws/install/lib
を追加するだけで事足りる.
因みに自分が確認した限りでは通常インストールで膨れ上がる環境変数は以下の通り
- AMENT_PREFIX_PATH
- CMAKE_PREFIX_PATH
- PYTHONPATH
- LD_LIBRARY_PATH
ワークスペースのオーバーレイ / アンダーレイ
詳細
Creating a workspace — ROS 2 Documentation: Galactic documentation
簡単に言うと,ROSのワークスペースが複数あって,両方で source path/to/setup.bash
をした時,先にsource
したワークスペースのことを「アンダーレイ」,後にsource
したワークスペースのことを「オーバーレイ」と呼ぶ.
aptでインストールしたROSパッケージのバージョンが気に入らない時,手元のワークスペースにソースコードをcloneしてビルドすると思いますが, このような状況ではこの仕様がうまく働く.
もし,オーバーレイのパッケージが優先されない場合,オーバーレイである手元のワークスペースにソースコードからビルドしたにもかかわらず, アンダーレイにあるaptでインストールしたバージョンの使用を強制されるかもしれない.
何が問題だったのか?
ヘッダファイルのインストール先が変わる原因となる現象は下のIssueで報告されている. github.com
一言で言うと,「特定の状況でをファイルの参照先がおかしくなる」 のである.
特定の状況とは以下のようなものだ
このような状況は特におかしなものではない.
特に,aptでインストールされる/opt/ros/humble
以下のワークスペースはマージインストールと同じ状態になっており,aptでインストールしたパッケージをオーバーレイにクローンする
そして,ros2
コマンドでアンダーレイ / オーバーレイ両方のワークスペースに存在するパッケージを呼び出しても,オーバーレイのパッケージが優先されることで解決されるはずである.
しかし,今回のIssueではマージインストールを併用した場合,オーバーレイが優先されなくなってしまうという報告がなされているのである.
詳しく
今回のバグを再現するために作られたリポジトリを簡素化して説明する
以下のような構成のワークスペースとパッケージを考える
それぞれのパッケージの情報として,パッケージの名前,パッケージのインクルードパス(パス),他のパッケージへの依存を書いている.
ここで,理想的な依存関係は当然こうなる
しかし,実際は以下のようになってしまうというのが今回の問題である.
では,どうしてそんなことが起こっているのか,更に細かく見ていく.
Dパッケージを中心に書くとこうなる
では,次にそれぞれがヘッダファイルを持っていると考えてコンパイラの気持ちになってみる.
d.hppは以下の手順でプリプロセスでインクルードが展開されていく
ここで,③のA/a.hpp
の展開を更に詳しく見てみる
まず,A/a.hpp
を展開するにはファイルがどこにあるか探すわけだが,コンパイラは依存パスを順番に精査していく.
本来なら,オーバーレイのAパッケージがある~/ros2_ws/install/A/include
でA/a.hpp
が見つかって欲しい.
しかし,依存パスの順番的に,はじめにアンダーレイの /opt/ros/humble/include
を探索するのだが,
この配下にはA/a.hpp
が存在するため,間違ったファイルがヒットして展開なされてしまうというわけだ.
もちろん,ここでアンダーレイでマージインストールなされていなければ,Bのパスを通じて間違ったAのパスにつながることもないので問題は発生しない.
どう対策したのか?
対策の検討
問題に対して,OpenRoboticsのShaneLoretzs氏によって4つの対策案が挙げられています.
それぞれ簡単に紹介すると
- ①CMake でインクルード ディレクトリを並べ替える
- ②ヘッダファイルを1階層深い場所にインストールする
- ③colconでパッケージの重複を検知してどうにかする
- ④colconでパッケージの重複を検知して知らせる(そして解決はユーザーに任せる)
といった感じになる. 詳しくは原文を参照して欲しいが, ①③はかなり無理がある解決策で④は解決そのものを諦めている.
という事で,選ばれた②について説明していく. ちなみに,④も②の予防策として採用されることになっている.
選ばれた解決策
「ヘッダファイルを1階層深い場所にインストールする」とはどういうことかと言うと,
CMakeLists.txt
で
install(DIRECTORY include/ DESTINATION include)
と書いてヘッダファイルをインストールしていたところを,
install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME})
と書いて更に1階層深い場所にインストールする,ということである.
そう,これこそがタイトルにもある「ROS2でヘッダファイルのインストール先が変わったらしい」と言うことである!!!!
では気になるのは,なぜこれが問題の解決策になるのか?ということであろう.
インストール先が変えることによる効果
まず,対策前後のアンダーレイにおけるマージインストールの結果を見ていこう
対策の前後がそれぞれ記事の冒頭に示した比較画像のgalactic/humbleのようになっていることがわかるだろう.
また,install
文が変わったことによって,インストール先だけではなく,依存パスも変化する.
Dパッケージの場合は次のように変化する.
赤太字で示した場所が変化点である.
この変更によって,問題の原因であった「Bのパスを通じて間違ったAのパスにつながる」ことがなくなったことにお気づきだろうか?
インストールする階層を1つ深くするだけでマージインストール時にもユニークなパスになるようにできるとはよく考えたものである.
解決策の実装
さて,この解決策というのは,アンダーレイのワークスペースに格納される可能性のあるパッケージに実装されなければならない.
とりわけ,aptでインストールされて/opt/ros/humble
以下にマージインストールされるros/rosdistro
に掲載されたリポジトリ群は絶対にアンダーレイになってしまうわけで早急な実装が求められる.
かくして,ROSコミュニティの面々はひたすら解決策の実装に明け暮れるのであった...
ちょうど一年前の話である.
当時rollingだったそれらの解決策がマージされたパッケージたちは,humbleのパッケージとして世に放たれた.
マージから1年後,humbleでヘッダファイルのインストール先が変化したことに気付いた筆者はこうしてこの記事を書くことになったわけである.