ROS 2 rclcpp + rcl - rolling  rolling-b14af74a
ROS 2 C++ Client Library with ROS Client Library
typesupport_helpers.cpp
1 // Copyright 2018, Bosch Software Innovations GmbH.
2 // Copyright 2021, Apex.AI Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "rclcpp/typesupport_helpers.hpp"
17 
18 #include <algorithm>
19 #include <functional>
20 #include <memory>
21 #include <sstream>
22 #include <stdexcept>
23 #include <string>
24 #include <tuple>
25 #include <utility>
26 
27 #include "ament_index_cpp/get_package_prefix.hpp"
28 #include "ament_index_cpp/get_resources.hpp"
29 #include "rcpputils/shared_library.hpp"
30 #include "rcpputils/find_library.hpp"
31 #include "rosidl_runtime_cpp/message_type_support_decl.hpp"
32 
33 namespace rclcpp
34 {
35 
36 namespace
37 {
38 
39 const void * get_typesupport_handle_impl(
40  const std::string & type,
41  const std::string & typesupport_identifier,
42  const std::string & typesupport_name,
43  const std::string & symbol_part_name,
44  const std::string & middle_module_additional,
45  rcpputils::SharedLibrary & library)
46 {
47  std::string package_name;
48  std::string middle_module;
49  std::string type_name;
50  std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
51 
52  if (middle_module.empty()) {
53  middle_module = middle_module_additional;
54  }
55 
56  auto mk_error = [&package_name, &type_name, &typesupport_name](auto reason) {
57  std::stringstream rcutils_dynamic_loading_error;
58  rcutils_dynamic_loading_error <<
59  "Something went wrong loading the typesupport library for " <<
60  typesupport_name << " type " << package_name <<
61  "/" << type_name << ". " << reason;
62  return rcutils_dynamic_loading_error.str();
63  };
64 
65  try {
66  std::string symbol_name = typesupport_identifier + symbol_part_name +
67  package_name + "__" + middle_module + "__" + type_name;
68  const void * (* get_ts)() = nullptr;
69  // This will throw runtime_error if the symbol was not found.
70  get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
71  return get_ts();
72  } catch (std::runtime_error &) {
73  throw std::runtime_error{mk_error("Library could not be found.")};
74  }
75 }
76 
77 // Trim leading and trailing whitespace from the string.
78 std::string string_trim(std::string_view str_v)
79 {
80  auto begin = std::find_if_not(str_v.begin(), str_v.end(), [](unsigned char ch) {
81  return std::isspace(ch);
82  });
83  auto end = std::find_if_not(str_v.rbegin(), str_v.rend(), [](unsigned char ch) {
84  return std::isspace(ch);
85  }).base();
86  if (begin >= end) {
87  return {};
88  }
89  return std::string(begin, end);
90 }
91 
92 } // anonymous namespace
93 
94 std::tuple<std::string, std::string, std::string>
95 extract_type_identifier(const std::string & full_type)
96 {
97  char type_separator = '/';
98  auto sep_position_back = full_type.find_last_of(type_separator);
99  auto sep_position_front = full_type.find_first_of(type_separator);
100  if (sep_position_back == std::string::npos ||
101  sep_position_front == 0 ||
102  sep_position_back == 0 ||
103  sep_position_back == full_type.length() - 1)
104  {
105  throw std::runtime_error(
106  "Message type is not of the form package/type and cannot be processed");
107  }
108 
109  std::string package_name = full_type.substr(0, sep_position_front);
110  std::string middle_module = "";
111  if (sep_position_back - sep_position_front > 0) {
112  middle_module =
113  full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
114  }
115  std::string type_name = full_type.substr(sep_position_back + 1);
116 
117  return std::make_tuple(
118  string_trim(package_name), string_trim(middle_module), string_trim(type_name));
119 }
120 
122  const std::string & package_name, const std::string & typesupport_identifier)
123 {
124  const char * dynamic_library_folder;
125 #ifdef _WIN32
126  dynamic_library_folder = "/bin/";
127 #elif __APPLE__
128  dynamic_library_folder = "/lib/";
129 #else
130  dynamic_library_folder = "/lib/";
131 #endif
132 
133  std::string package_prefix;
134  try {
135  package_prefix = ament_index_cpp::get_package_prefix(package_name);
136  } catch (ament_index_cpp::PackageNotFoundError & e) {
137  throw std::runtime_error(e.what());
138  }
139 
140  const std::string library_path = rcpputils::path_for_library(
141  package_prefix + dynamic_library_folder,
142  package_name + "__" + typesupport_identifier);
143  if (library_path.empty()) {
144  throw std::runtime_error(
145  "Typesupport library for " + package_name + " does not exist in '" + package_prefix +
146  "'.");
147  }
148  return library_path;
149 }
150 
151 std::shared_ptr<rcpputils::SharedLibrary>
152 get_typesupport_library(const std::string & type, const std::string & typesupport_identifier)
153 {
154  auto package_name = std::get<0>(extract_type_identifier(type));
155  auto library_path = get_typesupport_library_path(package_name, typesupport_identifier);
156  return std::make_shared<rcpputils::SharedLibrary>(library_path);
157 }
158 
159 const rosidl_message_type_support_t * get_message_typesupport_handle(
160  const std::string & type,
161  const std::string & typesupport_identifier,
162  rcpputils::SharedLibrary & library)
163 {
164  static const std::string typesupport_name = "message";
165  static const std::string symbol_part_name = "__get_message_type_support_handle__";
166  static const std::string middle_module_additional = "msg";
167 
168  return static_cast<const rosidl_message_type_support_t *>(get_typesupport_handle_impl(
169  type, typesupport_identifier, typesupport_name, symbol_part_name,
170  middle_module_additional, library
171  ));
172 }
173 
174 const rosidl_service_type_support_t * get_service_typesupport_handle(
175  const std::string & type,
176  const std::string & typesupport_identifier,
177  rcpputils::SharedLibrary & library)
178 {
179  static const std::string typesupport_name = "service";
180  static const std::string symbol_part_name = "__get_service_type_support_handle__";
181  static const std::string middle_module_additional = "srv";
182 
183  return static_cast<const rosidl_service_type_support_t *>(get_typesupport_handle_impl(
184  type, typesupport_identifier, typesupport_name, symbol_part_name,
185  middle_module_additional, library
186  ));
187 }
188 
189 const rosidl_action_type_support_t * get_action_typesupport_handle(
190  const std::string & type,
191  const std::string & typesupport_identifier,
192  rcpputils::SharedLibrary & library)
193 {
194  static const std::string typesupport_name = "action";
195  static const std::string symbol_part_name = "__get_action_type_support_handle__";
196  static const std::string middle_module_additional = "action";
197 
198  return static_cast<const rosidl_action_type_support_t *>(get_typesupport_handle_impl(
199  type, typesupport_identifier, typesupport_name, symbol_part_name,
200  middle_module_additional, library
201  ));
202 }
203 
204 } // namespace rclcpp
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string get_typesupport_library_path(const std::string &package_name, const std::string &typesupport_identifier)
Look for the library in the ament prefix paths and return the path to the type support library.
RCLCPP_PUBLIC std::shared_ptr< rcpputils::SharedLibrary > get_typesupport_library(const std::string &type, const std::string &typesupport_identifier)
Load the type support library for the given type.
RCLCPP_PUBLIC const rosidl_message_type_support_t * get_message_typesupport_handle(const std::string &type, const std::string &typesupport_identifier, rcpputils::SharedLibrary &library)
Extracts the message type support handle from the library.
RCLCPP_PUBLIC const rosidl_service_type_support_t * get_service_typesupport_handle(const std::string &type, const std::string &typesupport_identifier, rcpputils::SharedLibrary &library)
Extracts the service type support handle from the library.
RCLCPP_PUBLIC const rosidl_action_type_support_t * get_action_typesupport_handle(const std::string &type, const std::string &typesupport_identifier, rcpputils::SharedLibrary &library)
Extracts the action type support handle from the library.
RCLCPP_PUBLIC std::tuple< std::string, std::string, std::string > extract_type_identifier(const std::string &full_type)
Extract the package name, middle module, and type name from a full type string.