Contents
CMakeLists.txtの概要
ファイルCMakeLists.txtは、ソフトウエアパッケージをビルドするためのCMakeビルドシステムへのインプットです。どのようなCMake準拠のパッケージでも、1つ以上のCMakeLists.txtファイルを含んでいて、コードをどのようにビルドするか、どこにそれをインストールするかが記述されています。catkinプロジェクトで使われているCMakeLists.txtファイルは、標準のありきたりなCMakeLists.txtファイルにいくつかの制約が加わったものです。
全体的な構造と指定方法
CMakeLists.txtファイルは、このフォーマットに従わなければなりません。このフォーマット通りでなければ、パッケージは正しくビルドすることが出来ません。設定の順番は重要です。
必要な CMake Versionの指定 (cmake_minimum_required)
Package Name (project())
ビルドに必要な他の CMake/Catkin packages を見つける (find_package())
Message/Service/Action の生成 (add_message_files(), add_service_files(), add_action_files())
message/service/action generation の呼び出し (generate_messages())
パッケージのビルドに必要な情報の指定 (catkin_package())
ライブラリや実行ファイルのビルド (add_library()/add_executable()/target_link_libraries())
テストコードのビルド (catkin_add_gtest())
Install ルール (install())
CMake Version
すべてのcatkin CMakeLists.txtファイルは、必要なCMakeの要求されているバージョンの記述で始めねばなりません。Catkinはバージョン2.8.3以上を必要としています。
cmake_minimum_required(VERSION 2.8.3)
Package name
CMake Versionの次の項目は、CMake project functionによって指定されるパッケージの名前です。robot_brainと名付けたパッケージを作っていると宣言しましょう。
project(robot_brain)
CMakeの覚書: CMakeスクリプトの中で、どこで必要であっても ${PROJECT_NAME} 変数を使って、後からこのプロジェクト名を参照出来ます。
依存している CMake Packageを見つける
CMake Packages
find_package function を使って、プロジェクトをビルドする際に他のどのCMakeパッケージが必要かをここで指定する必要があります。catkinパッケージには必ず依存します:
find_package(catkin REQUIRED)
もし、自分のパッケージが他のcatkinパッケージに依存しているなら、それらはcatkinのコンポーネント(CMakeでの)に自動的に変更されます。これらの依存パッケージを使う場合には、パッケージに対してfind_packageを適用する代わりにコンポーネントとしてそのパッケージを指定すると簡単です。例えば、nodeletパッケージを使うなら:
find_package(catkin REQUIRED COMPONENTS nodelet)
NB: find_packageにはビルドに必要なコンポーネントだけを指定してください。ランタイムで依存するパッケージを指定するべきでありません。
このようにも記述できますが、
find_package(catkin REQUIRED) find_package(nodelet REQUIRED)
依存パッケージを複数指定するには不便でしょう。
find_package() は何をしているのか?
find_packageを通してCMakeがパッケージを見つけたら、そのパッケージについての情報を与えるいくつかのCMake環境変数が生成されます。これらの環境変数はCMakeスクリプトの中で後から利用できます。環境変数は、パッケージのエクスポートされたヘッダーファイルがどこにあるか、ソースファイルがどこにあるか、パッケージがどんなライブラリに依存するか、そしてそれらのライブラリのパスを記述します。この名称は常に<PACKAGE NAME>_<PROPERTY>の慣例に従います:
<NAME>_FOUND - ライブラリが見つかったかどうか。見つかればtrueをセット、見つからなければ出力されない
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES - パッケージによってエクスポートされたインクルードパス
<NAME>_LIBRARIES or <NAME>_LIBS - パッケージによってエクスポートされたライブラリ
<NAME>_DEFINITIONS - 追加のコンパイルフラグ
なぜCatkinパッケージはコンポーネントとして指定されるのか?
Catkinパッケージは実際のところcatkinのコンポーネントではなく、catkinでの膨大なタイピング時間を省くために、CMakeのコンポーネント機能を活用して設計されたものです。
複数のcatkinパッケージを扱う場合、catkinのコンポーネントとしてそれらのcatkinパッケージをfind_packageすれば、catkin_接頭辞のついた環境変数が1セットだけ作成されるので好都合です 。例えば、「自分のコード内でnodeletを使っている」としましょう。このパッケージを見つける推奨された方法は以下のようになります:
find_package(catkin REQUIRED COMPONENTS nodelet)
これは、nodeletによりエクスポートされたincludeパス、ライブラリなどが、catkin_と付いた変数としても追加されることを意味しています。例えば、catkin_INCLUDE_DIRSはcatkinのincludeパスだけではなく、nodeletのincludeパスも含みます!これは後で役立つでしょう。
上記の代わりに、nodeletそれ自身のfind_packageをすることもできます :
find_package(nodelet)
この場合、nodeletパス、ライブラリなどがcatkin_と付いた変数には追加されません。
この結果、nodelet_INCLUDE_DIRS、nodelet_LIBRARIESなどが生成されますが、同様の変数が、以下の書式でも生成されます。
find_package(catkin REQUIRED COMPONENTS nodelet)
Boost
C++とBoostを使うならば、Boostをfind_package()で呼び出し、コンポーネントとしてBoostのどの機能を使っているかを指定する必要があります。例えば、Boostスレッドを使いたい場合は、次のように指定します:
find_package(Boost REQUIRED COMPONENTS thread)
catkin_package()
catkin_package()はcatkinで提供されたCMakeマクロです。pkg-configとCMakeファイルを生成するのに必要なcatkin固有の情報をビルドシステムに伝えるために必要です。
add_library() または add_executable()によって宣言されるいかなるターゲットよりも前に、この関数を呼び出さなくてはなりません。 この関数は、5つのオプションの引数を持ちます:
INCLUDE_DIRS - このパッケージのためのエクスポートされるinclude パス (i.e. cflags)
LIBRARIES - プロジェクトからエクスポートされるライブラリ
CATKIN_DEPENDS - このプロジェクトが依存している他のcatkinプロジェクト
DEPENDS - このプロジェクトが依存している非catkin CMakeのプロジェクト
CFG_EXTRAS - 追加の設定オプション
完全なマクロのドキュメンテーションは、ここで確認できます。
たとえば:
catkin_package( INCLUDE_DIRS include LIBRARIES ${PROJECT_NAME} CATKIN_DEPENDS roscpp nodelet DEPENDS eigen opencv)
これは、パッケージフォルダ内の "include" フォルダがエクスポートされたヘッダーが収まる場所であることを示しています。CMake環境変数${PROJECT_NAME}は、事前にproject()関数にいったい何が渡されたかを評価します。この場合では "robot_brain" にあたるものです。"roscpp" + "nodelet"は、このパッケージをビルドし実行するために存在する必要があるパッケージであり、"eigen" + "opencv" は、このパッケージをビルドし実行するために存在する必要があるシステム依存性です。
ビルドターゲットの指定
ビルドターゲットの指定方法にはいろいろありますが、通常は以下の2つのどちらかです:
- Executable Target - 実行可能プログラム
- Library Target - 実行可能なターゲットがビルド時または実行時に使用するライブラリ
ターゲットの名前付け
非常に重要なこととして、catkinの中のビルドターゲットの名前は、それらがビルド/インストールされるフォルダを問わず一意でなければならないということです。これはCMakeの要件です。しかしながら、ターゲットの一意な名前付けが必要なのはCMakeの内部だけです。set_target_properties()関数を使って、ターゲットを他の別の名前にして保持することができます:
例:
set_target_properties(rviz_image_view PROPERTIES OUTPUT_NAME image_view PREFIX "")
これはビルドやインストール時の出力で、ターゲットの名前をrviz_image_view から image_viewへ変更します。
Custom output directory
実行ファイルとライブラリのデフォルトの出力ディレクトリが通常どおりの妥当な値に設定されているため、特定のケースではカスタマイズされなければなりません。すなわちPythonバインディングを含むライブラリは、Pythonがインポートすることのできる別のフォルダにおかれなければなりません:
例:
set_target_properties(python_module_library PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION})
Include パスと Library パス
ターゲットを指定する前に、ターゲットのためのリソース、特にヘッダファイルおよびライブラリをどこで見つけることができるのかを指定する必要があります。
- Include Paths - (一般的にC/C++の)コードをビルドするためのヘッダファイルがどこで見つけられるか
- Library Paths - 実行可能なターゲットをビルドするのに必要なライブラリがどこにあるか?
include_directories(<dir1>, <dir2>, ..., <dirN>)
link_directories(<dir1>, <dir2>, ..., <dirN>)
include_directories()
include_directoriesへの引数は、find_package呼び出しによって生成される*_INCLUDE_DIRS変数と、インクルードする必要があるすべての追加ディレクトリでなければなりません。catkinとBoostを使っているなら、そのinclude_directories()の呼び出しは以下のようになるはずです:
include_directories(include ${Boost_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS})
一番最初の引数 "include" は、パッケージ内のinclude/ディレクトリがパスの一部でもあることを示しています。
link_directories()
CMakelink_directories()機能は、追加のライブラリパスを追加するために使われることができます。しかし、これは推奨されません。 全てのcatkinパッケージ、CMakeパッケージは、find_packageされたときに加えられたリンク情報を自動的に持つことになります。単に、target_link_libraries()でライブラリに対してリンクしてください。
例:
link_directores(~/my_libs)
link_directories()上でtarget_link_libraries() 使う詳細な例については、 this cmake thread を参照してください。
実行ファイルのターゲット
ビルドすべき実行可能なターゲットを指定するために、CMake関数のadd_executable()を使わなければなりません。
add_executable(myProgram src/main.cpp src/some_file.cpp src/another_file.cpp)
これは、3つのソースファイル src/main.cpp、src/some_file.cppとsrc/another_file.cppからビルドされるmyProgramと呼ばれる実行可能なターゲットをビルドします。
ライブラリターゲット
CMake関数add_library()は、ビルドする際のライブラリを指定するために使います。デフォルトで、catkinは共有ライブラリをビルドします。
add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})
target_link_libraries
実行可能なターゲットがどのライブラリにリンクするかを指定するために、target_link_libraries_functionを使ってください。これは一般にadd_executable()の呼びだしの後に実行されます。 もし ros is not found(rosが見つかりません)と出る場合は、${catkin_LIBRARIES}を追加してください。
Syntax:
target_link_libraries(<executableTargetName>, <lib1>, <lib2>, ... <libN>)
例:
add_executable(foo src/foo.cpp) add_library(moo src/moo.cpp) target_link_libraries(foo moo) -- これはfooを libmoo.soにリンクする
リンクすべきディレクトリ情報がfind_package()経由で自動的に取り込まれるので、ほとんどの使用事例においてlink_directories()を使う必要がないことに注意してください。
Messages, Services, Action のターゲット
ROSのメッセージ(.msg)、サービス(.srv)とアクション(.action)ファイルは、ビルドされROSパッケージによって使われる前に、特別なプリプロセッサのビルドステップを必要とします。これらのマクロのポイントは、プログラミング言語固有のファイルを生成することで、これで選択したプログラミング言語でのメッセージ、サービス、アクションの使用が可能になります。ビルドシステムは、すべての利用可能なジェネレータ(例えばgencpp、genpy、genlispなど)を使って、バインディングを生成していきます。
メッセージ、サービス、およびアクションをそれぞれ処理するために提供された3つのマクロがあります:
add_message_files
add_service_files
add_action_files
そして、これらのマクロの後に、生成を実施するマクロの呼び出し続けなければなりません。
generate_messages()
重要な必要条件と制約
正しく生成を行うために、これらのマクロはcatkin_package()マクロの**前に**来なければなりません
find_package(catkin REQUIRED COMPONENTS ...) add_message_files(...) add_service_files(...) add_action_files(...) generate_messages(...) catkin_package(...) ...
catkin_package()マクロは、message_runtimeへの依存を示すCATKIN_DEPENDSがなければなりません
catkin_package( ... CATKIN_DEPENDS message_runtime ... ...)
単独でまたはcatkinのコンポーネントとして、message_generationパッケージのためにfind_package()を使わなければなりません:
find_package(catkin REQUIRED COMPONENTS message_generation)
package.xml ファイルはmessage_generation上のビルド依存とmessage_runtime上のランタイム依存を含まなければなりません。依存性がほかのパッケージを通して取り込まれるならば、これは必要ではありません
実行ファイルがメッセージあるいはサービスを使い、かつメッセージやサービスをビルドするパッケージがあるなら、自動的に生成されるメッセージターゲットへの明示的な依存性を作成し、正しい順序でビルドされるようにする必要があります。(some_target はでadd_executable()で設定されたターゲットの名前):
add_dependencies(some_target ${PROJECT_NAME}_generate_messages_cpp)
使用例
パッケージが"msg"というディレクトリ内で"MyMessage1.msg" と "MyMessage2.msgと命名された2つのメッセージを持ち、これらのメッセージがstd_msgs と sensor_msgs に依存し、"srv" というディレクトリ内で "MyService.srv" と命名された1つのサービスを持つ時、以下のようなCMakeLists.txtが必要になります:
1 # Get the information about this package's buildtime dependencies
2 find_package(catkin REQUIRED
3 COMPONENTS message_generation std_msgs sensor_msgs)
4
5 # Declare the message files to be built
6 add_message_files(FILES
7 MyMessage1.msg
8 MyMessage2.msg
9 )
10
11 # Declare the service files to be built
12 add_service_files(FILES
13 MyService.srv
14 )
15
16 # Actually generate the language-specific message and service files
17 generate_messages(DEPENDENCIES std_msgs sensor_msgs)
18
19 # Declare that this catkin package's runtime dependencies
20 catkin_package(
21 CATKIN_DEPENDS message_runtime std_msgs sensor_msgs
22 )
さらに、アクションのactionlibをビルドし、"action"ディレクトリの中に"MyAction.action"と呼ばれるアクションの仕様ファイルを持ちたい場合は、actionlib_msgsをコンポーネントのリストに加えてcatkinでfind_packageされるようにして、generate_messages(...)の呼び出しの前に以下の記述を加えなければなりません。
add_action_files(FILES MyAction.action )
さらに、パッケージはactionlib_msgsへのビルド依存が必要です。
単体テスト
gtestベースの単体テストを扱うためのcatkin特有のマクロ、catkin_add_gtest()があります。
catkin_add_gtest(myUnitTest test/utest.cpp)
Optional Step: インストール可能なターゲットを指定する
ビルドの後、ターゲットはcatkinワークスペースのdevelスペースの中に配置されます。しかしながら、しばしばターゲットをシステムにインストールして、ターゲットを他で使ったり、システムレベルインストールをテストするためにローカルフォルダで使いたいことがあります (インストールパスについての情報はREP 122を参照)。すなわち、もし自分のコードの"make install" を実行できるようにしたいなら、ターゲットがどこに収まるべきかを指定する必要があります、
これはCMake のinstall() 関数を使い、引数を伴って行われます。
TARGETS - どのターゲットをインストールするか
ARCHIVE DESTINATION - 静的ライブラリとDLL (Windows) .lib のスタブ
LIBRARY DESTINATION - 非DLL 共有ライブラリとモジュール
RUNTIME DESTINATION - 実行可能ターゲットと DLL (Windows) 形式の共有ライブラリ
例として:
install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
これらの標準的な行き先のフォルダのほかに、いくつかのファイルは特定のフォルダにインストールされなければなりません。すなわちPythonバインディングを含むライブラリは、Pythonがインポートすることのできる別のフォルダにおかれなければなりません:
install(TARGETS python_module_library ARCHIVE DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION} )
Pythonの実行可能Scriptのインストール
Pythonコードについては、CMakeがどのファイルがターゲットで、ターゲットのタイプは何なのかを決定するためにadd_library() and add_executable()関数を使えないので、インストール規則が違っているように見えます。その代わりに、CMakeLists.txtファイルの中で以下のような記述を使います:
catkin_install_python(PROGRAMS scripts/myscript DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
Pythonスクリプトとモジュールのインストールについての詳細な情報とフォルダレイアウトの最良の練習が、このcatkin manualの中にあります。
ヘッダファイルのインストール
ヘッダファイルも"include"フォルダにインストールされ、これはしばしばフォルダ全体のファイルのインストールによって行われます(ファイル名パターンで部分的にフィルタされ、SVNのサブフォルダ群を除きます)。これは以下の様なインストール規則によって行われます:
install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} PATTERN ".svn" EXCLUDE )
install(DIRECTORY include/ DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION} PATTERN ".svn" EXCLUDE )
roslaunch ファイルやその他のリソースのインストール
launchファイルといったその他のリソースは、${CATKIN_PACKAGE_SHARE_DESTINATIONにインストールされます:
install(DIRECTORY launch/ DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch PATTERN ".svn" EXCLUDE)