Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce rclcpp_components to implement composition #665

Merged
merged 14 commits into from
Apr 4, 2019
Merged
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
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
{
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