52
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ROS講座97 CMakeList.txtとpackage.xmlの書き方

Last updated at Posted at 2019-06-12

環境

この記事は以下の環境で動いています。

項目
CPU Core i5-8250U
Ubuntu 16.04
ROS Kinetic

インストールについてはROS講座02 インストールを参照してください。
またこの記事のプログラムはgithubにアップロードされています。ROS講座11 gitリポジトリを参照してください。

概要

ROSのパッケージを製作するためにはCMakeList.txtとpackage.xmlを記述する必要があります。しかしこれらの記述についてまとまって書かれている情報が少ないのでここでまとめてみます。

2つのファイルの役割

2つのファイルはそれぞれ役割が違います。以下のように2つのファイルは使われるところが違いますが、2つのファイルに書かれる依存の整合性を保つ仕組みはありません(これはROSの欠点の1つといえます)。これらのファイルを正確に記述する必要があります。

rospack listを実行した場合

$ROS_PACKAGE_PATHにあるディレクトリの中でpackage.xmlが探され、これがあることでROSパッケージだと認識されます。roscdなどで特定のROSパッケージにcdする場合のパスもこれを使って探されます。

caktin_makeを実行した場合

まずcatkin_ws/src以下のROSパッケージのpackage.xmlに書かれている依存を読んでcatkinマクロを解決して、ビルドする対象と順番を決めます。その後各ROSパッケージのCMakeList.txtがCmakeにかけられます。

package.xmlの役割

package.xmlは以下の役割があります。

  • システム依存の記述系
    あくまでROSシステムとしての依存を扱います。ビルドの依存は以下のCMakeList.txtで扱います。roscdやrospack等のコマンドで参照されるのはこちらです。
  • プラグインやパスのエクスポートの記述
    例えばnodeletなどでは「nodelet」パッケージのノードから、「ユーザーが作った」パッケージのプラグインを参照して実行します。この時nodeletがプラグインの存在を通知するのにpackage.xmlのexportの機能を使います。
  • その他の記述
    メンテナンスなどの人が参照する部分です。

最小構成

package.xmlの最小構成
<package format="2">
  <name>foo_core</name>
  <version>1.2.4</version>
  <description>
  This package provides foo capability.
  </description>
  <maintainer email="ivana@osrf.org">Ivana Bildbotz</maintainer>
  <license>BSD</license>
</package>

ROSwikiより

  • packageタグのフォーマット属性
    package.xmlにはversion1とversion2があり、両者の構文を混ぜるとエラーになります。現在は2が主流なのでそちらで解説します。
  • nameタグ
    パッケージ名を決定します。実はパッケージのディレクトリ名はパッケージ名に影響せずに、ここで書いた名前がパッケージの名前となります。
  • versionタグ・descripionタグ・maintainerタグ・licenseタグ
    自由に記述できます。

依存の記述

依存タグは以下の7つがあります。

  • <buildtool_depend>
    ビルドツールの指定をします。通常はcatkinのみを指定します。
  • <build_depend>
    ビルド時の依存の指定をします。基本的にCMakeList.txtで指定するものは全てここで指定しておく必要があります。
  • <build_export_depend>
    ビルド依存のエクスポートの指定をします。
  • <exec_depend>
    実行時の依存の指定をします。pythonのノードを使うときには要注意です。version1では<run_depend>となっていたものです。バージョンを混ぜるとエラーになるので注意です。
  • <depend>
    これを書くと<build_depend><build_export_depend><exec_depend>の3つを指定したのと同じ効果になります。
  • <test_depend>
    テスト実行時の依存を指定します。
  • <doc_depend>
    doxygen等のドキュメント作成用の依存を指定します。
依存の記述の例
<package format="2">
 <!-- 省略 -->

  <buildtool_depend>catkin</buildtool_depend>
  <depend>roscpp</depend>
  <depend>std_msgs</depend>
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <exec_depend>rospy</exec_depend>
</package>

依存を正確に記述するためには<build_depend><exec_depend>を使い分ける必要がありますが、実用的には全部を<depend>で指定すれば問題ありません。

依存しているパッケージへのエクスポート

依存しているパッケージへのプラグインなどのエクスポートをすることが出来ます。
例えば以下の様に記述すると各ROSパッケージで<export>タグの中で<gazebo_ros gazebo_media_path="*******" />と書いてある内容の一覧を取得できます。

エクスポートの検索
plugins --attrib=gazebo_model_path gazebo_ros

CMakeList.txtの役割

これはcatkin_makeをするときに使用されるものです。名前の通りcmakeで使われるファイルです。逆に言うとそれ以外では使いません。
cmakeの標準の書式にcatkin特有のマクロが含まれているのに注意です。
このファイルに記述する記述は以下のように分けれらます。

  • 依存の記述
  • ビルド前に行われる作業
  • 依存のエクスポートの記述
  • ビルドする対象
  • ビルド対象の依存

最小構成

最小構成
cmake_minimum_required(VERSION 2.8.3)
project(package_A)

1行目は最小バージョンンの指定です。rosのversionによって違いますが、kineticでは標準では2.8.3と書くようです。
2行目はパッケージ名を書きます。

実行ファイルを生成する最小構成

最小構成
cmake_minimum_required(VERSION 2.8.3)
project(package_A)
find_package(catkin REQUIRED COMPONENTS
  roscpp
)
include_directories(
  ${catkin_INCLUDE_DIRS}
)
add_executable(main src/main.cpp)
target_link_libraries(main
  ${catkin_LIBRARIES}
)
ソースの例(package_A/src/main.cpp)
#include <stdio.h>
#include <ros/ros.h>
int main(int argc, char **argv){
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  return 0;
}

実行ファイルをつくり、それをrosのライブラリとリンクする最小の例です。

  • find_package(catkin REQUIRED COMPONENTS <依存package1> <依存package2>)では依存するROSパッケージ名を記述します。
  • include_directories()ではインクルードパスを追加します。これが無いとros/ros.hとインクルードすることができません。
  • add_executable(<ターゲット名> <cppファイルのパス>) ビルドするターゲットを選択します
  • target_link_libraries(<ターゲット名> ${catkin_LIBRARIES})ではリンクするライブラリのパスを追加します。これが無いとros/ros.hをインクルードするのでAPIには到達しますが、内部の実装を読めずにエラーになります。

find_packageでのcatkinマクロの効果

以下のようにcatkinのマクロを使用せずにcmake標準の文法だけで同等の記述できます。

最小構成(catkinマクロを使わない例)
cmake_minimum_required(VERSION 2.8.3)
project(package_A)
find_package(roscpp)
include_directories(
  ${roscpp_INCLUDE_DIRS}
)
add_executable(main src/main.cpp)
target_link_libraries(main
  ${roscpp_LIBRARIES}
)

今回は依存がroscppだけなので上記のように短いですが、依存するパッケージが多くなると記述が長くなります。find_package(catkin REQUIRED COMPONENTS <依存package>)とするとパッケージの依存を追加してかつ${依存package_***}のパスを${catkin_***}に追加してくれます。このために${catkin_***}だけを書いていれば足ります。

してはfind_package(roscpp)だけでroscppへの依存を追加できますが、上記のようにcatkinマクロを使用することで、わざわざインクルードやライブラリの依存で${roscpp_INCLUDE_DIRS}${roscpp_LIBRARIES}

ライブラリを作成する例(使用する側への設定が抜けている)

ライブラリを生成する最小構成
cmake_minimum_required(VERSION 2.8.3)
project(package_A)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)
add_library(TestLib
  src/TestLib.cpp
)
target_link_libraries(TestLib
  ${catkin_LIBRARIES}
)
include/package_A/TestLib.h
#include <stdio.h>
#include <ros/ros.h>
#include <std_msgs/Int32.h>

std_msgs::Int32 ReturnInt(void);
src/TestLib.cpp
#include <package_A/TestLib.h>

#include <stdio.h>
#include <ros/ros.h>
#include <std_msgs/Int32.h>

std_msgs::Int32 ReturnInt(void){
    std_msgs::Int32 int_msg;
    int_msg.data = 0;
    return int_msg;
}

ライブラリの場合はadd_executableの代わりにadd_library(<ターゲット名> <cppファイルのパス1> <cppファイルのパス2>)と書きます。このように記述するとpakckage_A/lib<ターゲット名>.soといオブジェクトファイルが生成されます。複数の関数やクラスを1つのオブジェクトファイルで扱うことができます。
しかしこの記述では使用する側がいちいちincludeファイルのパスを手動で解決したり、このライブラリの依存をわざわざ調べてライブラリを使用する側で依存を書かないといけません。これをcatkinマクロで解決できます。

ライブラリを作成する例(使用する側への設定込み)

ライブラリを生成・使用側への設定をする最小構成
cmake_minimum_required(VERSION 2.8.3)
project(package_A)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)
catkin_package(
  INCLUDE_DIRS include
  LIBRARIES package_A
  CATKIN_DEPENDS roscpp std_msgs
)
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)
add_library(TestLib
  src/TestLib.cpp
)
target_link_libraries(TestLib
  ${catkin_LIBRARIES}
)

catkin_package()が加わりました。

  • INCLUDE_DIRS includeはにincludeを加えます。これでほかのパッケージからこのパッケージのincludeファイルが見えるようになります。
  • LIBRARIES package_Aは上記と同じようにライブラリのパスが自動で解決できるようになります。
  • CATKIN_DEPENDS roscpp std_msgsでは他のパッケージがこのパッケージに依存をした時に自動的にここで記述したパッケージも依存に加わります。

msg・srv・actファイルを作成する例(使用する側への依存の解決が抜けている)

この3つはそれぞれROS形式のファイルをhファイルに変換して、各ノードで読み込めるヘッダファイルをを生成します。この3つは同様のコマンドなのでmsgの生成を例に説明します。

msgファイルを生成
cmake_minimum_required(VERSION 2.8.3)
project(package_A)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
  message_generation
)
add_message_files(
  FILES
  Msg1.msg
)
generate_messages(
  DEPENDENCIES
  std_msgs
)
catkin_package(
  CATKIN_DEPENDS message_runtime std_msgs
)
  • find_packageではmessage_generationを追加する必要があります。
  • add_message_filesにmsgファイルのファイル名を指定します。
  • generate_messagesではmsgファイル内で使用しているmsgの依存を書く必要があります。
  • catkin_packageはこのパッケージを依存に追加するだけでmessage_runtimestd_msgsを自動で依存が追加されるようにします。

msgを使う側

msgファイルを使う
cmake_minimum_required(VERSION 2.8.3)
project(package_A)
find_package(catkin REQUIRED COMPONENTS
  roscpp
)
include_directories(
  ${catkin_INCLUDE_DIRS}
)
add_dependencies(main ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_executable(main src/main.cpp)
target_link_libraries(main
  ${catkin_LIBRARIES}
)

ここではpackage_Aの中のmsgをmainが使うとします。add_dependencies(main ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) が必要です。msgファイルはビルド時に生成されるものですので、ただpackage_Aに依存しても、ファイルを取得できません。package_Aのビルド後の生成物に依存をする必要があります。

参考

ROSwiki
依存の解説

目次ページへのリンク

ROS講座の目次へのリンク

52
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?