Eloquentまではこちら
ROS2における共有ライブラリ:--library-nodeオプションを使用しない方法はこちら
更新履歴:
2021/08/27:--library-nameオプションを使ったやり方に変更
ROS2の共有ライブラリを作成する.
共有ライブラリはクラスで作成するので,これまでのようにROS1風のものはない.
また,共有ライブラリは色々なところで使用されるのでnamespaceを用いている.
本当はこれまででもnamespaceを使用した方がよかったのだが,自分が使用するターゲットのみの場合必須でないので省略してきた.
namespaceに関してはROS2関係トップページへの「知っといてほしい知識」などを参考に.
共通ライブラリ概要
ここで作成する共有ライブラリの概要は以下のとおり.
ちなみに作成したライブラリを使用したターゲットはここで作成せず共有ライブラリのみの作成とする.
また作成するクラスは一つでも良かったが,後々のために二つ作成する(MinimalCompNode1, MinimalCompNode2).基本的には一つのライブラリに複数の機能が収められる.
一つ目(MinimalCompNode1)を作成し,二つ目(MinimalCompNode2)は後ほど追加することで,追加方法も述べる.
- 共有ライブラリのパッケージ名
- minimal_comp
- 共有ライブラリ名
- minimal_comp_node
- 共有ライブラリで使用できる機能・クラスを収めたソースファイル
- minimal_comp_node1.hppと.cpp
- クラス名:MinimalCompNode1
- minimal_comp_node2.hppと.cpp
- クラス名:MinimalCompNode2
- minimal_comp_node1.hppと.cpp
- パッケージ共通のnamespace
- minimal_comp
準備
$ cd ~/ros2_studies_ws/
$ ros2 pkg create minimal_comp --dependencies rclcpp --library-name minimal_comp_node1
共有ライブラリ
対象ファイル
- include/visibility_control.h
- Windows用ライブラリを作成するのに必要?
- include/minimal_comp_node1.hpp
- src/minimal_comp_node1.cpp
- CMakeLists.txt
- package.xml
後で追加
- include/minimal_comp_node2.hpp
- src/minimal_comp_node2.cpp
--library-name
オプションを使用しない場合,visibility_control.hが自動的に作成されない.そのため以下の手順が必要となる.
手動での共有ライブラリ作成
共有ライブラリ独特の手順
- visibility.hを作成する
- 公式からDLして自分のパッケージ用にアレンジするのが楽
- visibility_control.hとして保存
- 普通にクラスを作成する
- 外部に公開するのでsrc/以下にヘッダファイルを置くのではなくinclude/[パッケージ名]/以下にヘッダファイルを置く.
visibility.hの用意
自分で以下のファイルを用意するのでもよいが,公式のexamplesにあるminimal_compositionからvisibility.hをDLして自分用に改変することを推奨.
$ curl https://raw.githubusercontent.com/ros2/examples/master/rclcpp/composition/minimal_composition/include/minimal_composition/visibility.h > visibility.h
$ sed s/MINIMAL_COMPOSITION/MINIMAL_COMP/g visibility.h > visibility_control.h
一度にやるなら以下のとおり.
$ curl https://raw.githubusercontent.com/ros2/examples/master/rclcpp/composition/minimal_composition/include/minimal_composition/visibility.h | sed s/MINIMAL_COMPOSITION/MINIMAL_COMP/g > visibility_control.h
今回はパッケージ名がminimal_compであったので上記のようにsedを使用した.ここは自分のパッケージ名に合わせて変更すること.
$ sed s/MINIMAL_COMPOSITION/[自分のパッケージ名]/g visibility.h > my_visibility.h
自分で作成する場合は以下の通り.
ここでもパッケージ名minimal_compで作成しているので,自分のパッケージ名に合わせて適宜変更
// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MINIMAL_COMP__VISIBILITY_H_
#define MINIMAL_COMP__VISIBILITY_H_
#ifdef __cplusplus
extern "C"
{
#endif
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
// https://gcc.gnu.org/wiki/Visibility
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
#define MINIMAL_COMP_EXPORT __attribute__ ((dllexport))
#define MINIMAL_COMP_IMPORT __attribute__ ((dllimport))
#else
#define MINIMAL_COMP_EXPORT __declspec(dllexport)
#define MINIMAL_COMP_IMPORT __declspec(dllimport)
#endif
#ifdef MINIMAL_COMP_DLL
#define MINIMAL_COMP_PUBLIC MINIMAL_COMP_EXPORT
#else
#define MINIMAL_COMP_PUBLIC MINIMAL_COMP_IMPORT
#endif
#define MINIMAL_COMP_PUBLIC_TYPE MINIMAL_COMP_PUBLIC
#define MINIMAL_COMP_LOCAL
#else
#define MINIMAL_COMP_EXPORT __attribute__ ((visibility("default")))
#define MINIMAL_COMP_IMPORT
#if __GNUC__ >= 4
#define MINIMAL_COMP_PUBLIC __attribute__ ((visibility("default")))
#define MINIMAL_COMP_LOCAL __attribute__ ((visibility("hidden")))
#else
#define MINIMAL_COMP_PUBLIC
#define MINIMAL_COMP_LOCAL
#endif
#define MINIMAL_COMP_PUBLIC_TYPE
#endif
#ifdef __cplusplus
}
#endif
#endif // MINIMAL_COMP__VISIBILITY_H_
共有ライブラリ化するMinimalCompNode1
以下のひな形が出来ているので利用して作成.
ソースコード
- include/minimal_comp_node1.hpp
- src/minimal_comp_node1.cpp
#include <rclcpp/rclcpp.hpp>
#include "visibility_control.h"
namespace minimal_comp {
class MinimalCompNode1 : public rclcpp::Node{
public:
MINIMAL_COMP_PUBLIC
MinimalCompNode1(
const std::string &node_name="",
const rclcpp::NodeOptions& options=rclcpp::NodeOptions()
);
};
}
MINIMAL_COMP_PUBLIC
はWindows用ライブラリを作成するのに必要?Building libraries on Windows参考.
#include <rclcpp/rclcpp.hpp>
#include "minimal_comp/minimal_comp_node1.hpp"
namespace minimal_comp {
MinimalCompNode1::MinimalCompNode1(
const std::string &node_name,
const rclcpp::NodeOptions& options
): Node("minimal_comp1", node_name, options)
{
RCLCPP_INFO(this->get_logger(),"minimal comp 1 test");
}
}
package.xmlとCMakeLists.txt
以下は追加した・重要な部分のみ抜粋.
詳しくはament_cmake User Documentationを参照.
package.xml
<package format="3">
<depend>rclcpp</depend>
build_dependタグからdependタグへの変更についてはROS2 package.xmlとCMakeLists.txtのチートシートを参照のこと.
CMakeLists.txt
find_package(rclcpp REQUIRED)
add_library(minimal_comp_node SHARED
src/minimal_comp_node1.cpp
)
target_compile_definitions(minimal_comp_node
PRIVATE "MY_LIBRARY_BUILDING_LIBRARY"
)
target_compile_options(minimal_comp_node PUBLIC -Wall)
ament_target_dependencies(minimal_comp_node
rclcpp
)
target_include_directories(minimal_comp_node
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
if(NOT WIN32)
ament_environment_hooks(
"${ament_cmake_package_templates_ENVIRONMENT_HOOK_LIBRARY_PATH}"
)
endif()
ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)
ament_export_dependencies(
rclcpp
)
install(
DIRECTORY include/
DESTINATION include
)
install(TARGETS
minimal_comp_node
EXPORT export_${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
概要
簡単なメッセージを出力するだけのもの
target_compile_definitions(minimal_comp_node PRIVATE "MY_LIBRARY_BUILDING_LIBRARY")はWindows用ライブラリを作成するのに必要?Building libraries on Windowsを参照.
ament_export_*に関するFoxy Fitzroyからの変更について
- ament_export_interfaces
- ament_export_libraries
- ament_export_inclujde_directories
-
ament_export_dependencies- これは必要だった!
これがament_export_targetsの一つになった.使い方としては,ament_export_interfacesの代わりにament_export_targetsを使うような感じらしい.
詳しくは公式のDistributionのニュースのうち,Foxy Fitzroyでの変更:Classic CMake vs. modern CMakeを参照のこと.
共有ライブラリ化するMinimalCompNode2
二つ目は手動で作成してみる.
ソースコード
- include/minimal_comp_node2.hpp
- src/minimal_comp_node2.cpp
#include <rclcpp/rclcpp.hpp>
#include "visibility_control.h"
namespace minimal_comp {
class MinimalCompNode2 : public rclcpp::Node{
public:
MINIMAL_COMP_PUBLIC
MinimalCompNode2(
const std::string &node_name="",
const rclcpp::NodeOptions& options=rclcpp::NodeOptions()
);
};
}
#include <rclcpp/rclcpp.hpp>
#include "minimal_comp/minimal_comp_node2.hpp"
namespace minimal_comp {
MinimalCompNode2::MinimalCompNode2(
const std::string &node_name,
const rclcpp::NodeOptions& options
): Node("minimal_comp2", node_name, options)
{
RCLCPP_INFO(this->get_logger(),"minimal comp 2 test");
}
}
CMakeLists.txt
以下は追加した・重要な部分のみ抜粋.
詳しくはament_cmake User Documentationを参照.
CMakeLists.txt
add_library(minimal_comp_node SHARED
src/minimal_comp_node1.cpp
src/minimal_comp_node2.cpp
)
もろもろ
通常のfind_package,ament_target_dependencies以外に以下の要素がある.
- add_library
- target_compile_definitions
- target_compile_options
- target_include_directories
- ament_environment_hooks
- ament_export_interfaces
- ament_export_dependencies
- ament_export_libraries
- ament_export_include_directories
- install 2種類
説明:add_library
add_executableと同じように他で使用するライブラリ名を付けつつコンパイルに必要なソースファイルを記述.
ライブラリ名を使用するのは以下の要素.
- target_compile_definitions
- target_compile_options
- ament_target_dependencies
- target_include_directories
- ament_export_libraries
- install
説明:target_compile_*
コンパイル時の設定.他でもそのまま使用.
説明:target_include_directories
include/[パッケージ名]/以下のヘッダファイルは外部に公開するものである.他のパッケージはtarget_include_directoriesによって外部公開用のヘッダファイルにアクセスできる.共有ライブラリ自身にとってもinclude/[パッケージ名]/以下にヘッダファイルがあるので(src/以下にはないので),target_include_directoriesを指定する必要がある.
説明:ament_environment_hooks
OS依存の処理っぽい.他でもそのまま使用.
説明:install
最初のinstallは共有ライブラリを使用するパッケージ用にヘッダファイルをインストールするためのコマンド.
install(
DIRECTORY include/
DESTINATION include
)
二つ目のinstallは作成したライブラリをインストールするためのコマンド.
特にEXPORTはament_export_interfacesで使うためのもの.
名前はなんでもよいがライブラリ名にexport_を付けたものが用いられる.
理由はament_cmake User DocumentationのBuilding a Libraryを参照のこと.
install(TARGETS
minimal_comp_node
EXPORT export_minimal_comp_node
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
説明:ament_export_targets
ament_export_targetsは,installのEXPORTで指定したものにHAS_LIBRARY_TARGETを.
説明:ament_export_dependencies
共有ライブラリを使う側に依存関係を知らせ,使う側で改めて依存関係処理しなくて済むようにするもの.
ビルド
$ cd ~/ros2_studies_ws/
$ colcon build --symlink-install --packages-up-to minimal_comp
$ . install/setup.bash
複数のライブラリを作成する場合
一つのライブラリの中に複数の機能(クラス)を詰め込むのではなく,複数のライブラリ自体を一つのパッケージで作成する場合.
一つのライブラリのやり方の中で,以下に注目・変更
- ament_export_targets
- install
概要
作成したライブラリをインストールするためのinstallにて.
- TARGETS
- add_libraryのライブラリ名を複数記述
- EXPORT
- この項は全体で一つ.
- よって,例えばexport_[package名]などに.
- ament_export_targets
- EXPORTで名づけしたものを記述
- よって上記の例ではexport_[package名]
例
抜粋
ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)
install(TARGETS
model1
model2
EXPORT export_${PROJECT_NAME}
...
)
参考
-
teratail
- curlで特定のファイルをDL
- curlコマンド 使い方メモ
- sed, awk, grepの使い分け