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>

得られる効果

環境変数の汚染がマシになる*1

全パッケージの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ではマージインストールを併用した場合,オーバーレイが優先されなくなってしまうという報告がなされているのである.

詳しく

今回のバグを再現するために作られたリポジトリを簡素化して説明する

GitHub - jacobperron/overlay_bug_reproduction: Reproducing a dependency bug involving an overlay workspace

以下のような構成のワークスペースとパッケージを考える

それぞれのパッケージの情報として,パッケージの名前,パッケージのインクルードパス(パス),他のパッケージへの依存を書いている.

ここで,理想的な依存関係は当然こうなる

理想のの依存関係

しかし,実際は以下のようになってしまうというのが今回の問題である.

実際の依存関係

では,どうしてそんなことが起こっているのか,更に細かく見ていく.
Dパッケージを中心に書くとこうなる

では,次にそれぞれがヘッダファイルを持っていると考えてコンパイラの気持ちになってみる.

d.hppは以下の手順でプリプロセスでインクルードが展開されていく

インクルードの展開の過程

ここで,③のA/a.hppの展開を更に詳しく見てみる

まず,A/a.hppを展開するにはファイルがどこにあるか探すわけだが,コンパイラは依存パスを順番に精査していく. 本来なら,オーバーレイのAパッケージがある~/ros2_ws/install/A/includeA/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でヘッダファイルのインストール先が変化したことに気付いた筆者はこうしてこの記事を書くことになったわけである.

*1:envコマンドで確認推奨

*2:これはオーバーレイされる順番にインクルード・ディレクトリをCMake上でソートすることによって実現されている,はず