rmwを短めの時間でビルドする方法

# 概要

個人的にRMWがどんな設計・実装になっているのかを手を入れながら見てみたかったのでビルド環境を構築することにしました．最初はROS2のコアライブラリ群を公式のビルド手順に従ってビルドしたのですが私の手元の環境だと結構時間がかかったのでRMW部分だけビルドできないかと思って取り組んでみました．（本当は購入したロボットアームを動かしてみる等を考えてみたのですが間に合わなかったのでこちらのネタでお茶を濁そうと思います．）

# ROS2 RMW

ROS2のRMWは各種あるDDS/RTPSを抽象化するレイヤです．RMWがあることでより上位のレイヤは異なるベンダが提供しているDDS実装を意識せず済んでいます．[公式の記事](https://design.ros2.org/articles/ros_on_dds.html)の図でいうところのAbstract DDS APIを提供している部分になります（と理解しています．）．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34613/f711a63e-ea75-4787-9ad3-5b96be308970.png)

# RMWのビルド

RMWのリポジトリそのものにはビルド手順が書かれていません．

https://github.com/ros2/rmw

なのでまずはROS2公式のソースからビルドしてインストールする手順を取ることにしました．※今回は私の環境都合からRollingで試しています．

## 公式の手順にのとったビルド

ROS2 rolling の公式手順にのっとってビルドします．
今回はコンテナ内で特にユーザ等作成せずにビルドするのでsudoは抜いています．

https://docs.ros.org/en/rolling/Installation/Alternatives/Ubuntu-Development-Setup.html

今回は Ubuntu:22.04 で試します．

```
docker run --rm -it ubuntu:22.04 bin/bash
```

ここから公式の手順を踏みます．まずはlocaleの設定です．

```
locale  # check for UTF-8

sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

locale  # verify settings
```

次に apt リポジトリの設定を変更します．

```
apt update
apt install software-properties-common -y
add-apt-repository universe
```

universeを追加してよいか聞いてくるのでEnterを押下します．

```
root@9d306f159396:/# add-apt-repository universe
Adding component(s) 'universe' to all repositories.
Press [ENTER] to continue or Ctrl-c to cancel.
```

次にROSのアプトリポジトリを追加します．

```
apt update && sudo install curl -y
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null
```

次にROS2関連の開発ツールをインストールします．

```
apt update && apt install -y \
  python3-pip \
  python3-pytest-cov \
  python3-flake8-blind-except \
  python3-flake8-class-newline \
  python3-flake8-deprecated \
  python3-pytest-repeat \
  python3-pytest-rerunfailures \
  ros-dev-tools
```

途中タイムゾーンを聞かれるので入力します．
日本（東京）の場合は 6 -> 79 です.

```
Configuring tzdata
------------------

Please select the geographic area in which you live. Subsequent configuration questions will narrow this down by presenting a list of cities, representing the time zones
in which they are located.

  1. Africa  2. America  3. Antarctica  4. Australia  5. Arctic  6. Asia  7. Atlantic  8. Europe  9. Indian  10. Pacific  11. US  12. Etc
Geographic area: 6

Please select the city or region corresponding to your time zone.

  1. Aden    6. Aqtobe    11. Baku     16. Brunei      21. Damascus  26. Famagusta    31. Hong_Kong  36. Jayapura   41. Kashgar      46. Kuala_Lumpur  51. Makassar      56. Novosibirsk  61. Pyongyang  66. Riyadh     71. Singapore      76. Tehran    81. Ujung_Pandang  86. Vladivostok
  2. Almaty  7. Ashgabat  12. Bangkok  17. Chita       22. Dhaka     27. Gaza         32. Hovd       37. Jerusalem  42. Kathmandu    47. Kuching       52. Manila        57. Omsk         62. Qatar      67. Sakhalin   72. Srednekolymsk  77. Tel_Aviv  82. Ulaanbaatar    87. Yakutsk
  3. Amman   8. Atyrau    13. Barnaul  18. Choibalsan  23. Dili      28. Harbin       33. Irkutsk    38. Kabul      43. Khandyga     48. Kuwait        53. Muscat        58. Oral         63. Qostanay   68. Samarkand  73. Taipei         78. Thimphu   83. Urumqi         88. Yangon
  4. Anadyr  9. Baghdad   14. Beirut   19. Chongqing   24. Dubai     29. Hebron       34. Istanbul   39. Kamchatka  44. Kolkata      49. Macau         54. Nicosia       59. Phnom_Penh   64. Qyzylorda  69. Seoul      74. Tashkent       79. Tokyo     84. Ust-Nera       89. Yekaterinburg
  5. Aqtau   10. Bahrain  15. Bishkek  20. Colombo     25. Dushanbe  30. Ho_Chi_Minh  35. Jakarta    40. Karachi    45. Krasnoyarsk  50. Magadan       55. Novokuznetsk  60. Pontianak    65. Rangoon    70. Shanghai   75. Tbilisi        80. Tomsk     85. Vientiane      90. Yerevan
Time zone: 79
```

ソースコードと依存ライブラリを取得します．

```
mkdir -p ~/ros2_rolling/src
cd ~/ros2_rolling
vcs import --input https://raw.githubusercontent.com/ros2/ros2/rolling/ros2.repos src
rosdep init
rosdep update
rosdep install --from-paths src --ignore-src -y --skip-keys "fastcdr rti-connext-dds-6.0.1 urdfdom_headers"
```

ビルドを始めます．

```
cd ~/ros2_rolling/
time colcon build 
```

ビルドはrmwからみてより上位のrviz2なども対象なのでそこそこ時間がかかりました．

```
real    19m51.880s
user    293m44.619s
sys     39m36.138s
```

デフォルトだとテスト関連？のビルドも走るようなので無効にしてみます．

```
time colcon build --cmake-args "-DBUILD_TESTING=OFF"
```

半分くらいになりました．

```
Summary: 359 packages finished [9min 22s]
(中略)

real    9m22.695s
user    128m24.915s
sys     19m12.532s
```

## 短めのビルド

もう少し短めにできないかを試します．

```
apt update
apt install software-properties-common curl -y
```

ROSのアプトリポジトリを追加します

```
sh -c 'echo "deb [arch=amd64,arm64] http://repo.ros2.org/ubuntu/main `lsb_release -cs` main" > /etc/apt/sources.list.d/ros2-latest.list'
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add -
apt update
apt install -y libacl1-dev liblttng-ust-dev python3-vcstool git python3-rosdep python3-colcon-common-extensions
```

タイムゾーンを聞かれるので設定します（公式の手順と同じなので省略します）．

次にcolcon等のビルドに必要なツールを入れます（もっと絞れるかもしれません）．
https://colcon.readthedocs.io/en/released/user/installation.html

```
apt install -y \
  ros-rolling-ament-cmake \
  ros-rolling-ament-lint \
  ros-rolling-ament-lint-auto \
  ros-rolling-ament-cmake-ros \
  ros-rolling-ros-workspace \
  ros-rolling-ament-cmake-google-benchmark \
  ros-rolling-launch-testing-ament-cmake \
  ros-rolling-mimick-vendor \
  ros-rolling-ament-cmake-cppcheck \
  ros-rolling-ament-lint-cmake \
  ros-rolling-ament-lint-common \
  ros-rolling-test-interface-files \
  ros-dev-tools
```

rmwと依存ライブラリをcloneしてきます．
最初はcloneするリポジトリはrmwだけでなんとかビルドできないか試していたのですが，バイナリパッケージでrmwが依存するrcutilsやrosidlをインストールするとrmwが要求しているヘッダファイルがインストールされないようなのでこれらのリポジトリもcloneすることにしました．

```
mkdir -p ~/ros2_rolling/src
cd ~/ros2_rolling/src
git clone https://github.com/ros2/rcutils.git -b rolling
git clone https://github.com/ros2/rmw.git -b rolling
git clone https://github.com/ros2/rosidl.git -b rolling
git clone https://github.com/ros2/rosidl_dynamic_typesupport.git -b rolling
```

ビルドを始めます．

```
cd ~/ros2_rolling
time colcon build --cmake-args "-DBUILD_TESTING=OFF"
```

10秒程度でビルドが終わりました．だいぶ早くなりましたね，めでたしめでたし。

```
Summary: 19 packages finished [9.28s]
  2 packages had stderr output: rosidl_cli rosidl_pycommon

real    0m9.658s
user    0m16.600s
sys     0m5.642s
```

rmwの共有ライブラリ（librmw.so）もビルドできているようです．

```
 file build/rmw/librmw.so
build/rmw/librmw.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=c8289e957e637bdda9b28fbe4edb87b3df33a202, not stripped
```

# まとめ

RMWのお勉強のためになるべく少ない構成でビルドできないか試してみました．
結果ROS2のインストール手順に従ってビルドするよりも少ないコード規模で時間も1/10程度でビルドすることができました．ROS2初心者なので勝手がわからないところもありもっと良い方法があるかもしれませんが今日はここまで．