Skip to content

Commit

Permalink
Introduce rclcpp_components to implement composition (#665)
Browse files Browse the repository at this point in the history
* Introduce rclcpp_components package

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Keep pointer to NodeWrapper vs NodeInterface.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Remove component registration from rclcpp

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Make topics names private-prefix.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Handle name and namespace with remap rules.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Linting.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Address reviewer feedback.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Change to smart pointers for managing memory.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Update to use rcpputils filesystem/split.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Address reviewer feedback and add docs.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Add tests around ComponentManager.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Lint.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Address reviewer feedback and add overflow check.

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Fix CI.

Signed-off-by: Michael Carroll <michael@openrobotics.org>
  • Loading branch information
mjcarroll committed Apr 4, 2019
1 parent d11a10a commit 0f25f71
Show file tree
Hide file tree
Showing 18 changed files with 1,243 additions and 56 deletions.
9 changes: 1 addition & 8 deletions rclcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,7 @@ if(BUILD_TESTING)
endif()
endif()

ament_package(
CONFIG_EXTRAS rclcpp-extras.cmake
)

install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)
ament_package()

install(
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/
Expand Down
26 changes: 0 additions & 26 deletions rclcpp/cmake/rclcpp_create_node_main.cmake

This file was deleted.

122 changes: 122 additions & 0 deletions rclcpp_components/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
cmake_minimum_required(VERSION 3.5)

project(rclcpp_components)

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake_ros REQUIRED)
find_package(ament_index_cpp REQUIRED)
find_package(class_loader REQUIRED)
find_package(composition_interfaces REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcpputils REQUIRED)

include_directories(include)

add_library(
component_manager
STATIC
src/component_manager.cpp
)
ament_target_dependencies(component_manager
"ament_index_cpp"
"class_loader"
"composition_interfaces"
"rclcpp"
"rcpputils"
)

add_executable(
component_container
src/component_container.cpp
)
target_link_libraries(component_container component_manager)
ament_target_dependencies(component_container
"rclcpp"
)

add_executable(
component_container_mt
src/component_container_mt.cpp
)
target_link_libraries(component_container_mt component_manager)
ament_target_dependencies(component_container_mt
"rclcpp"
)

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(component_container "stdc++fs")
target_link_libraries(component_container_mt "stdc++fs")
endif()

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()

set(components "")
add_library(test_component SHARED test/components/test_component.cpp)
ament_target_dependencies(test_component
"class_loader"
"rclcpp"
"rclcpp_components")
#rclcpp_components_register_nodes(test_component "test_rclcpp_components::TestComponent")
set(components "${components}test_rclcpp_components::TestComponentFoo;$<TARGET_FILE:test_component>\n")
set(components "${components}test_rclcpp_components::TestComponentBar;$<TARGET_FILE:test_component>\n")
set(components "${components}test_rclcpp_components::TestComponentNoNode;$<TARGET_FILE:test_component>\n")

file(GENERATE
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/test_ament_index/$<CONFIG>/share/ament_index/resource_index/rclcpp_components/${PROJECT_NAME}"
CONTENT "${components}")

set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
if(WIN32)
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
endif()

ament_add_gtest(test_component_manager test/test_component_manager.cpp
APPEND_ENV AMENT_PREFIX_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_ament_index/$<CONFIG>
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_component_manager)
target_link_libraries(test_component_manager component_manager)
target_include_directories(test_component_manager PRIVATE src)
endif()

ament_add_gtest(test_component_manager_api test/test_component_manager_api.cpp
APPEND_ENV AMENT_PREFIX_PATH=${CMAKE_CURRENT_BINARY_DIR}/test_ament_index/$<CONFIG>
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_component_manager_api)
target_link_libraries(test_component_manager_api component_manager)
target_include_directories(test_component_manager_api PRIVATE src)
endif()
endif()

# Install executables
install(
TARGETS component_container component_container_mt
RUNTIME DESTINATION lib/${PROJECT_NAME}
)

# Install include directories
install(
DIRECTORY include/
DESTINATION include
)

# Install cmake
install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)

# specific order: dependents before dependencies
ament_export_include_directories(include)
ament_export_dependencies(class_loader)
ament_export_dependencies(rclcpp)
ament_package(CONFIG_EXTRAS rclcpp_components-extras.cmake)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Open Source Robotics Foundation, Inc.
# Copyright 2019 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.
Expand All @@ -14,4 +14,5 @@

# register node plugins
ament_index_register_resource(
"node_plugin" CONTENT "${_RCLCPP__NODE_PLUGINS}")
"rclcpp_components" CONTENT "${_RCLCPP_COMPONENTS__NODES}")

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Open Source Robotics Foundation, Inc.
# Copyright 2019 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.
Expand All @@ -13,38 +13,38 @@
# limitations under the License.

#
# Register a node plugin with the ament resource index.
# Register an rclcpp component with the ament resource index.
#
# The passed library can contain multiple plugins extending the node interface.
# The passed library can contain multiple nodes each registered via macro.
#
# :param target: the shared library target
# :type target: string
# :param ARGN: the unique plugin names being exported using class_loader
# :type ARGN: list of strings
#
macro(rclcpp_register_node_plugins target)
macro(rclcpp_components_register_nodes target)
if(NOT TARGET ${target})
message(
FATAL_ERROR
"rclcpp_register_node_plugins() first argument "
"rclcpp_components_register_nodes() first argument "
"'${target}' is not a target")
endif()
get_target_property(_target_type ${target} TYPE)
if(NOT _target_type STREQUAL "SHARED_LIBRARY")
message(
FATAL_ERROR
"rclcpp_register_node_plugins() first argument "
"rclcpp_components_register_nodes() first argument "
"'${target}' is not a shared library target")
endif()

if(${ARGC} GREATER 0)
_rclcpp_register_package_hook()
_rclcpp_components_register_package_hook()
set(_unique_names)
foreach(_arg ${ARGN})
if(_arg IN_LIST _unique_names)
message(
FATAL_ERROR
"rclcpp_register_node_plugins() the plugin names "
"rclcpp_components_register_nodes() the plugin names "
"must be unique (multiple '${_arg}')")
endif()
list(APPEND _unique_names "${_arg}")
Expand All @@ -54,8 +54,9 @@ macro(rclcpp_register_node_plugins target)
else()
set(_path "lib")
endif()
set(_RCLCPP__NODE_PLUGINS
"${_RCLCPP__NODE_PLUGINS}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
set(_RCLCPP_COMPONENTS__NODES
"${_RCLCPP_COMPONENTS__NODES}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
endforeach()
endif()
endmacro()

46 changes: 46 additions & 0 deletions rclcpp_components/include/rclcpp_components/node_factory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2019 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 RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
#define RCLCPP_COMPONENTS__NODE_FACTORY_HPP__

#include "rclcpp_components/node_instance_wrapper.hpp"

namespace rclcpp_components
{

/// The NodeFactory interface is used by the class loader to instantiate components.
/**
* The NodeFactory interface serves two purposes:
* * It allows for classes not derived from `rclcpp::Node` to be used as components.
* * It allows derived constructors to be called when components are loaded.
*/
class NodeFactory
{
public:
NodeFactory() = default;

virtual ~NodeFactory() = default;

/// Create an instance of a component
/**
* \param[in] options Additional options used in the construction of the component.
*/
virtual
NodeInstanceWrapper
create_node_instance(const rclcpp::NodeOptions & options) = 0;
};
} // namespace rclcpp_components

#endif // RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2019 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 RCLCPP_COMPONENTS__NODE_FACTORY_TEMPLATE_HPP__
#define RCLCPP_COMPONENTS__NODE_FACTORY_TEMPLATE_HPP__

#include <functional>
#include <memory>

#include "rclcpp_components/node_factory.hpp"

namespace rclcpp_components
{

/// NodeFactoryTemplate is a convenience class for instantiating components.
/**
* The NodeFactoryTemplate class can be used to provide the NodeFactory interface for
* components that implement a single-argument constructor and `get_node_base_interface`.
*/
template<typename NodeT>
class NodeFactoryTemplate : public NodeFactory
{
public:
NodeFactoryTemplate() = default;
virtual ~NodeFactoryTemplate() = default;

/// Create an instance of a component
/**
* \param[in] options Additional options used in the construction of the component.
*/
NodeInstanceWrapper
create_node_instance(const rclcpp::NodeOptions & options) override
{
auto node = std::make_shared<NodeT>(options);

return NodeInstanceWrapper(
node, std::bind(&NodeT::get_node_base_interface, node));
}
};
} // namespace rclcpp_components

#endif // RCLCPP_COMPONENTS__NODE_FACTORY_TEMPLATE_HPP__
Loading

0 comments on commit 0f25f71

Please sign in to comment.