ビルドツールとしてのcolcon


はじめに

colconといえば、ROS2パッケージをビルドするときに使うツールとして使われています。
が、ROSパッケージでなくてもC++(cmake)やPython(setup.py)プロジェクトであれば使うことができます。
複数のプロジェクトを正しい順序でビルドするケースが多い場合に非常に有用です。
この記事では、ROS2パッケージビルド以外の使い方、複数のC++プロジェクトのビルド方法について紹介します。

colconとは

colconとは、複数のパッケージ間、プロジェクト間の依存関係(*1)を解決して正しい順序でビルドできたり、テストを実行できるビルドツールです。
例えば、4つプロジェクトA,B,C,Dが以下のように依存している場合、

A,B,C,Dのトップディレクトリで

colcon build

の1つのコマンド(*2)を打つだけで、Aをビルドし、BとCとビルドを同時にビルドしたあと、Dをビルドすることができます。

これをterminal上でやろうとすると、Aのディレクトリにいって、buildをディレクトリをつくって移動して、cmake ..して、make && make installしたと、Bのディレクトリに移動して....と非常に大変です。

(*1) ただし、ここでの依存とは、そのワークスペース内のプロジェクト間でそれ以外の依存ライブラリについては事前にインストールする必要があります。
(*2) colconのオプションについては、
ここの記事が詳しいです。

使い方

基本的な使い方は、上記の通りで複数のプロジェクトの親ディレクトリでcolcon buildです。
各パッケージが依存関係の記述がしっかりしていれば、10個や20個以上の複数のプロジェクトのビルドだってこれだけで実行できます。

しかし、一つでも依存関係の抜け漏れがあると成功しません。そこで、colconがCMakeList.txtやsetup.pyのどこを見てパッケージをとして検出するのか、以下にまとめました。

CMakeList.txtの場合

CMakeList.txtを見つけると、それをパッケージとみなします。cmakeプロジェクト名がそのパッケージの名前、find_packageで呼んでいるパッケージがそのパッケージの依存パッケージとなります。

実はこれが結構な問題で、プロジェクト間でこの名前が一致している必要があります。
例えば、次のような足し算ライブラリmyaddがあるとします。

add.hpp
int add(int a, int b);
add.cpp
#include "add.hpp"
int add(int a, int b) { return a + b; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(myadd) #<-----------------------------------------------ここ
add_library(myadd SHARED add.cpp)
set_target_properties(myadd PROPERTIES
        PUBLIC_HEADER add.hpp
)
install(TARGETS myadd EXPORT  myaddExport
        LIBRARY        DESTINATION lib
        INCLUDES       DESTINATION include
        PUBLIC_HEADER  DESTINATION include)
install(EXPORT  myaddExport
        FILE    myadd-config.cmake
        DESTINATION share/cmake/myadd
        EXPORT_LINK_INTERFACE_LIBRARIES
)

次にこのmyaddを使う引き算プロジェクトがあります

sub.hpp
int sub(int a, int b);
sub.cpp
#include "add.hpp"
#include "sub.hpp"
int sub(int a, int b) { return add(a, -b); }
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(mysub)
find_package(myadd REQUIRED) # <--------------------------------ここ
add_library(mysub SHARED sub.cpp)
target_link_libraries(mysub PRIVATE myadd)
set_target_properties(mysub PROPERTIES
        PUBLIC_HEADER sub.hpp
)
install(TARGETS mysub EXPORT  mysubExport
        LIBRARY        DESTINATION lib
        INCLUDES       DESTINATION include
        PUBLIC_HEADER  DESTINATION include)
install(EXPORT  mysubExport
        FILE    mysub-config.cmake
        DESTINATION share/cmake/mysub
        EXPORT_LINK_INTERFACE_LIBRARIES
)

このようにmysubのCMakeList.txtのfind_packageのパッケージ名とmyaddのプロジェクト名が同じでないと正しく見つかりません。

myaddのCMakeList.txtのプロジェクト名を変える(またはmyaddのライブラリ名を変える)だけで、次のようなエラーが出力されます。

$ colcon build
Starting >>> aa      
Starting >>> mysub
--- stderr: mysub                                                       
CMake Error at CMakeLists.txt:3 (find_package):
  By not providing "Findmyadd.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "myadd", but
  CMake did not find one.

  Could not find a package configuration file provided by "myadd" with any of
  the following names:

    myaddConfig.cmake
    myadd-config.cmake

Setup.pyの場合

nameがパッケージの名前。install_requires内の名前が依存関係として検出されます。

colcon.pkgの場合

colcon.pkgに書いた"name"にパッケージ名, "type"にビルドタイプ、"dependencies"に依存関係が検出されます。colcon.pkgは、CMakeList.txtやsetup.pyと同ディレクトリある場合、優先されます。

自作プロジェクトの場合、上記のようなCMakeList.txtやsetup.py変更は可能ですが、外部プロジェクトの場合は容易ではありません。このようなとき、colcon.pkgを使うといいのではないかと考えています。またCMakeList.txtを変更するよりもcolcon.pkgを新たに作ったほうが、変更によるビルドの失敗のリスクを下げれたり、そもそも手っ取り早いかもしれません。

(*1) colcon.pkgだけなく、pacacke.xmlなどのパッケージも優先されれます。

まとめ

colconを使うことで、依存関係依然として書く必要(大変さ)がありますが、そのビルドを自動化できます。

備考

その他のcolconコマンド

colcon build以外のコマンドとしては

  • colcon list:パッケージのリストの表示
  • colcon info:詳細なcolconが認識している依存関係まで含めた情報の表示

があります。これらについてはここを見たほうがよいです。

COLCON_IGNORE

COLCON_IGNOREという空のファイルがあるパッケージはビルドから除外されます。