まえがき
lint/formatは複数人で作業するときに重要ですが,開発環境を整えるのが少し煩わしかったり種類がいっぱいあればセットアップの方法もいっぱいあります.
ros2 pkg create <pakage_name> --build-type ament_cmakeで生成されるCMakeLists.txtやpackages.xmlにはちょこっと書かれていますが,自分はこれが何者なのか全くわかっていませんでした.
せっかくなので,この方法を出来るだけ活用できないか模索することにしました.
筆者環境
| architecture | amd64 |
| (Host OS) | Ubuntu24.04 |
| OS | ros:jazzyベースのdocker container上 |
| rosdistro | jazzy |
以下では例として主にclang-formatを扱っていきます.
他のlinterを選択する場合はclang-formatの部分を置き換えてください
CLI
純粋にコマンドラインをたたいてlint/formatを実行する方法です.
インストールは以下の通りです.
sudo apt install ros-<rosdistro>-ament-clang-format
そして以下のように実行します
ament-clang-format .
どのlinter/formmaterが用意されているかはament-lintのリポジトリを参照します.
あるいはapt list ros-<rosdistro>-ament-*でも確認できます(こちらだとclang-formatのバージョン指定ができることもわかる)
オプション指定などは各lint packageのdocs/index.rstを読みます
clang-format(https://github.com/ament/ament_lint/blob/rolling/ament_clang_format/doc/index.rst) の場合version指定などができることがわかります
TEST (CMakeLists.txt)
(これが自分にとっては理解まで時間がかかりました)
順番に説明していきます.
最小構成
ある一つのament_lintを使いたい場合は以下のように記述します
<test_depend>ament_cmake_clang_format</test_depend>
find_package(ament_cmake REQUIRED)
if(BUILD_TESTING)
find_package(ament_cmake_clang_format REQUIRED)
ament_clang_format()
endif()
これでcolcon testを実行するとlintも一つのtestとして実行されます.
ament_lint_common
よく使うであろうlinter/formatterをまとめたものです.ちなみにclang_formatは含まれていないのでこんな記述になります.
<test_depend>ament_lint_common</test_depend>
<test_depend>ament_cmake_clang_format</test_depend>
(CMakeLists.txtの記述は一旦省略)
これで下記リンク先に書かれている複数のament_lintを<test_depend>で追加しているのと同じになります.
ament_lint_auto
CMakeLists.txt内のlint関係の記述を簡潔にするためのツールです(自分はament_cmake_autoと混同していました)
ament_lint_auto_find_test_dependencies()を実行することで,package.xmlに書かれたament_lint系を見つけてきて実行するようになっています.
これらament_lint_commonとament_lint_autoを含んだものがros2 pkg createしたときに生成されてます.
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>ament_cmake_clang_format</test_depend>
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
set(ament_cmake_copyright_FOUND TRUE)
set(ament_cmake_cppcheck_FOUND TRUE)
set(ament_cmake_cpplint_FOUND TRUE)
set(ament_cmake_uncrustify_FOUND TRUE)
set(ament_cmake_clang_format_CONFIG_FILE .clang-format)
ament_lint_auto_find_test_dependencies()
endif()
ちなみにここでしれっとset(ament_cmake_clang_format_CONFIG_FILE .clang-format)と.clang-formatファイルを参照するように指定しています.
また自分の環境では.clang-formatでカスタマイズした部分がcpplintやuncrustifyと衝突するので,これらのlintをset(ament_cmake_xxx_FOUND TRUE)で実行しないようにしています.
(こんなに無効化するならament_lint_commonを指定せず個別に設定するほうが良かったかも…などと思っているところです)
pre-commit
これはnav2の記述にならいます.
ament_lintに関係する部分だけ抜粋するとこんな感じ
repos:
- repo: local
hooks:
- id: ament_clang_format
name: ament_clang_format
description: Code style checking using clang-format.
language: system
types: [c++]
entry: ament_clang_format --config .clang-format --reformat # gitリポジトリルートのの設定ファイルを参照する場合
- id: ament_flake8
name: ament_flake8
description: Check Python code style using flake8.
language: system
types: [python]
entry: ament_flake8
- id: ament_lint_cmake
name: ament_lint_cmake
description: Check CMake code style using cmakelint.
language: system
types: [cmake]
entry: ament_lint_cmake
- id: ament_pep257
name: ament_pep257
description: Check Python code style using pep257.
language: system
types: [python]
entry: ament_pep257
- id: ament_xmllint
name: ament_xmllint
description: Check XML markup using xmllint.
language: system
types: [xml]
entry: ament_xmllint
つまりはCLIの使い方をしています
ほかのlinter/formatterを使いたい場合も同様です
Github Actions
前章でTestに組み込んだのでCIでTestを回せばよいですが,Testのworkflowとは別に作っておきたい気持ちがありました.
無課金のprivateリポジトリなので
- なるべくworkflowにかかる時間を減らしたい(apt installなどの環境セットアップを最小限に)
- ある程度管理されてそう(公式?)なものを選ぶ
あたりを気にした結果,やはりnav2やturtlebot3と同じようにします.
利用するciはこれ
ament_lint:
name: ament_${{ matrix.linter }}
runs-on: ubuntu-latest
container:
image: rostooling/setup-ros-docker:ubuntu-noble-ros-jazzy-ros-base-latest
strategy:
fail-fast: false
matrix:
linter: [clang-format, flake8, lint_cmake, pep257, xmllint]
steps:
- uses: actions/checkout@v5
- uses: ros-tooling/action-ros-lint@0.1.4
with:
linter: ${{ matrix.linter }}
distribution: jazzy
package-name: "*"
arguments: ${{ matrix.linter == 'clang-format' && '--config .clang-format' || '' }}
clang-formatのconfigファイルを参照するためにargumentsを記述しています
おまけ:testをactionsで実行するよさげな方法
ちょっと脱線ですが,テストも実行しておきたかったのでこのCIを利用します.
name: Check Build Test and Coverage
on:
pull_request:
push:
branches:
- master
jobs:
build_and_test:
runs-on: ubuntu-latest
container:
image: rostooling/setup-ros-docker:ubuntu-noble-ros-jazzy-ros-base-latest
steps:
- uses: actions/checkout@v5
- name: Build and run tests
uses: ros-tooling/action-ros-ci@v0.4
with:
import-token: ${{ secrets.GITHUB_TOKEN }}
target-ros2-distro: jazzy
colcon-mixin-repository: https://raw.githubusercontent.com/colcon/colcon-mixin-repository/master/index.yaml
colcon-defaults: |
{
"build": {
"mixin": ["coverage-gcc", "coverage-pytest"]
},
"test": {
"mixin": ["coverage-pytest"]
}
}
lintに関しては二重に実行されることになりますが…
workflow起動ごとにROS 2をインストールするのを出来るだけ減らせるはずです.
参考リンク集
ROS 2のコードスタイルの推奨が書かれているところ
ament_lintについて説明しているROS 2のページ
ament_lintのリポジトリ
具体的にどう使っているのか知るために
navigation2(nav2)とturtlebot3のリポジトリも参考にしました.
日本語記述だとこのスライドが参考になりました
おわりに
パラメータファイルなどROSで多用するyamlのlintはamentシリーズになさそうで,探しているとPRはありました.
なんだか凍結状態ですが…
ament_lint_yamllintほしい!