野良packageへ依存したROS packageのビルドを簡単にする

# 野良packageへ依存したROS package

そもそもタイトルのこれがなんなのか，というと，ようはオレオレROS packageをいくつも作っていき，それらが依存関係を持ったもの，です．
一人で開発している分にはそれらがどう依存しても構わないのですが，他の人にもそのパッケージをビルドしてもらおうとすると，依存関係を解決してもらわないといけません．ここでは，そういった依存関係を簡単に解決する，というよりはちゃんと記述できる方法を紹介し，それを利用した依存関係の自動解決・インストール方法を説明します．

ちなみに個人的にROS kineticを使っているので，ここで紹介する方法はkineticでのみ動作確認しています．

# 依存関係を記述する

## package.xml をちゃんと書く

ROSにはもともと依存関係を package.xml に記述する仕組みがあります．まずはこれに則って，きちんと記述しましょう．なお， package.xml にはフォーマットのバージョンが1と2があります．ROS kinetic では， catkin_create_pkg で生成すると，勝手にバージョン1のテンプレートを使われてしまいますが，[公式サイト](http://wiki.ros.org/catkin/package.xml)にしたがって，バージョン2で書くようにしましょう．とくに依存関係で手間が減らせます．

まずは，ここに必ず必要な依存パッケージを記述しましょう．自分が作った，もしくは公式リポジトリにはなくgithubなどにあるような野良のパッケージであっても，そのパッケージ内にある package.xml の ```<name>``` タグで指定されたパッケージ名称を記載すればOKです．

なお，ROS側の公式サイトではわかりにくいのですが， [package.xml の依存関係の要素には，ROSと関係ない外部のライブラリなども記載が可能です](https://docs.ros.org/kinetic/api/catkin/html/howto/format2/system_library_dependencies.html)．
例えば，ROSでもよく使われている数学ライブラリであるEigenなんかも，

```
<build_depend>eigen</build_depend>
```

のように記載できます．
ここに記載する名称はrosdistroというリポジトリに登録されている名称を利用します．
eigenみたいなものの場合は上記のようにかき，gstreamerのようなものの場合は

```
<build_depend>libgstreamer0.10-dev</build_depend>
```

のように，記載することとなっています。

これはeigenの場合はrosdistroのここ
https://github.com/ros/rosdistro/blob/e5d7c67287b561ccac89f4392db5bc880e544065/rosdep/base.yaml#L755
で定義され、gstreamerの場合にはここ
https://github.com/ros/rosdistro/blob/e4868e94545642945e1bbe40624b72160f6e686e/rosdep/base.yaml#L2787
に定義されています。
gstreamerの場合は必要な依存対象に応じて適切な記述をする必要があることがわかります。

## パッケージのありかを示す

後述の依存関係の自動インストールの段階で，リポジトリにあるパッケージであればapt-getでインストールされるのですが，そうではないものについてはgit cloneしてきてビルドすることになります．当然ながら， package.xml には依存するパッケージ名しか記述していないため，その依存パッケージがどこのリポジトリに置かれているのか明示する必要があります．

そこで利用するのが ```.rosinstall``` ファイルです．これはかつてROSそのものをインストールするときに使われていたファイルなのですが，これを使うことでパッケージとリポジトリの対応を取ることができます．

```.rosinstall``` ファイルの中身はyamlで記述されたテキストファイルです．フォーマットは[公式サイト](https://docs.ros.org/independent/api/rosinstall/html/rosinstall_file_format.html)に記載がありますが，正直説明が足りてません．ちなみに，git以外にもsvn等のリポジトリにも対応していますが，試したことはないです．

gitの説明だけ抜き出してくると，ファイルフォーマットは下記のように説明されています．

```yaml
- git: {local-name: /some/local/aboslute/path, uri: http://some/uri, version: 123}
```

yamlなので，もうちょっと見やすいように展開すると

```yaml
- git:
  local-name: /some/local/aboslute/path
  uri: http://some/uri
  version: 123
```

となります．
結論からいうと，

- local-name にはパッケージ名称
- uri にはgithub等のリポジトリアドレス(sshでもhttpsでも可)
- version にはブランチ・タグ名

を記載することで，野良パッケージの名称とリポジトリを対応付けることが可能となります．例えば，格安中華LiDARのドライバリポジトリを参照するのであれば

```
- git:
  local-name: ydlidar
  uri: git@github.com:EAIBOT/ydlidar.git
  version: 1.3.1
```

のようになります．バージョンは番号だけじゃなく、masterなどももちろん指定できます．

さらに，```.rosinstall``` ファイルは，ドットファイルである必要はないため適当に名前をつけることができます．これらを利用して，自分が作ったパッケージがhogeなら，次のようなディレクトリ構成にして，そこの package.xml と ```.rosinstall``` ファイルに依存関係を書きます．

```
hoge
├ src
│ ├ hoge.cpp
├ CMakeLists.txt
├ hoge.rosinstall
└ package.xml
```

ここでは ```hoge.rosinstall``` とパッケージ名に揃えましたが，その必要性はありません．が，このパッケージの依存関係が記載されている，ということがわかりやすいと思うのでこうしています．

# 依存関係をインポートする

これまでの方法をつかってしっかり依存関係を記述したならば，あとはそれを利用して自動的に依存するパッケージ類をインポートしましょう．

以前はroswsやwstoolを使用していましたが、[vcstool](https://github.com/dirk-thomas/vcstool)が非常に便利なのでこちらを利用することをおすすめします。ROSの公式ドキュメントでも現在はvcstoolを利用するように誘導されます。[ROS公式のvcstoolの使い方](https://wiki.ros.org/vcstool)もあるので、そちらも読んでみると良いと思います。

vcstool自身はROSから切り離されたツールとなっており、ROS以外でも依存するインターネット上のリポジトリへの依存関係を記述するのに利用できるようになっています。そのため、vcstoolでの標準的な依存リストの拡張子は `.repos` になっていますが、ROSで使う場合には互換性も考えて `.rosinstall` を使い続けるのが良さそうです。

## vcstool をインストールする

vcstoolはPythonで書かれたアプリケーションなのでpipでインストール可能です。

```bash
sudo pip install -U vcstool
```

もしくはUbuntuであればaptからもインストールできます。

```bash
# noetic
sudo apt install python3-vcstool

# noetic 以前 (kineticとか)
sudo apt install python-vcstool
```

## 例

以下，```~/catkin_ws/src/hoge```にhogeという自作パッケージがあり，それが他のライブラリに依存している例として説明します．

```bash
cd ~/catkin_ws
vcs import src < src/hoge/hoge.rosinstall
```

以上のコマンドで、`hoge` パッケージにある `hoge.rosinstall` ファイルに記述された依存リポジトリが `src` 以下に自動的にインポート(git clone)されます。

あとはpackage.xmlに書かれた公式リポジトリにある依存関係をインストールすればビルドができるようになります。このインストール作業についてはrosdepというROSのツールを使うことで簡単に可能です。rosdepについては[追加で記事を書いた](https://qiita.com/strv/items/ccd89c55957bd8dfada0)のでそちらを参照してください．

あとは普段つかっているツールでビルドするだけです．catkin_makeを使っている場合，ビルド順序の問題でビルドがこける場合があります．その時は数回実行してみると解決するとおもいます．catkin_make_isolatedやcatkin buildならそのへんは賢く解決してくれます．

# おまけ

野良パッケージが依存する野良パッケージが野良パッケージに依存している、ということも起きてきます。その場合、各リポジトリに `.rosinstall` が置かれていれば、順次 `vcs import` していけばすべての必要なパッケージをインポートできるのでやはり便利です。
ただ、それも階層が深くなると面倒なので、繰り返しimportするだけのスクリプトを作ってみたので公開しています。

https://github.com/strv/vcstool-utils

この `import_all.sh` を使えば、一度コマンドを実行するだけで、インポートしたリポジトリについても再帰的に `vcs import` を実行します。

## 使い方

シェルスクリプトなので、cloneして実行するだけです。(もちろんダウンロードとかでも良いです)

```bash
git clone https://github.com/strv/vcstool-utils.git
./vcstool-utils/import_all.sh -s .rosinstall ~/catkin_ws/src
```

デフォルトではvcstoolの標準的なリポジトリファイルである `.repos` を探すようになっているので、オプションで `-s .rosinstall` を与えます。

あとはrosdepを使ってその他の依存関係をインストールしてビルドする、という点については同じです。

# まとめ

ということで，依存関係の書き方と，それをもとにしたインストール方法を紹介しました．

これまでは rosws を使った方法を説明していましたが、久しぶりに公式ドキュメントを追いかけたらいつの間にか vcstool に誘導されるようになっており、それが非常に便利だったのでこの記事も更新することにしました。