ROS 2 rclcpp + rcl - rolling  rolling-20536064
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 <filesystem>
20 #include <functional>
21 #include <memory>
22 #include <sstream>
23 #include <stdexcept>
24 #include <string>
25 #include <tuple>
26 #include <utility>
27 
28 #include "ament_index_cpp/get_package_prefix.hpp"
29 #include "ament_index_cpp/get_resources.hpp"
30 #include "rcpputils/shared_library.hpp"
31 #include "rcpputils/find_library.hpp"
32 #include "rosidl_runtime_cpp/message_type_support_decl.hpp"
33 
34 namespace rclcpp
35 {
36 
37 namespace
38 {
39 
40 const void * get_typesupport_handle_impl(
41  const std::string & type,
42  const std::string & typesupport_identifier,
43  const std::string & typesupport_name,
44  const std::string & symbol_part_name,
45  const std::string & middle_module_additional,
46  rcpputils::SharedLibrary & library)
47 {
48  std::string package_name;
49  std::string middle_module;
50  std::string type_name;
51  std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
52 
53  if (middle_module.empty()) {
54  middle_module = middle_module_additional;
55  }
56 
57  auto mk_error = [&package_name, &type_name, &typesupport_name](auto reason) {
58  std::stringstream rcutils_dynamic_loading_error;
59  rcutils_dynamic_loading_error <<
60  "Something went wrong loading the typesupport library for " <<
61  typesupport_name << " type " << package_name <<
62  "/" << type_name << ". " << reason;
63  return rcutils_dynamic_loading_error.str();
64  };
65 
66  try {
67  std::string symbol_name = typesupport_identifier + symbol_part_name +
68  package_name + "__" + middle_module + "__" + type_name;
69  const void * (* get_ts)() = nullptr;
70  // This will throw runtime_error if the symbol was not found.
71  get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
72  return get_ts();
73  } catch (std::runtime_error &) {
74  throw std::runtime_error{mk_error("Library could not be found.")};
75  }
76 }
77 
78 // Trim leading and trailing whitespace from the string.
79 std::string string_trim(std::string_view str_v)
80 {
81  auto begin = std::find_if_not(str_v.begin(), str_v.end(), [](unsigned char ch) {
82  return std::isspace(ch);
83  });
84  auto end = std::find_if_not(str_v.rbegin(), str_v.rend(), [](unsigned char ch) {
85  return std::isspace(ch);
86  }).base();
87  if (begin >= end) {
88  return {};
89  }
90  return std::string(begin, end);
91 }
92 
93 } // anonymous namespace
94 
95 std::tuple<std::string, std::string, std::string>
96 extract_type_identifier(const std::string & full_type)
97 {
98  char type_separator = '/';
99  auto sep_position_back = full_type.find_last_of(type_separator);
100  auto sep_position_front = full_type.find_first_of(type_separator);
101  if (sep_position_back == std::string::npos ||
102  sep_position_front == 0 ||
103  sep_position_back == 0 ||
104  sep_position_back == full_type.length() - 1)
105  {
106  throw std::runtime_error(
107  "Message type is not of the form package/type and cannot be processed");
108  }
109 
110  std::string package_name = full_type.substr(0, sep_position_front);
111  std::string middle_module = "";
112  if (sep_position_back - sep_position_front > 0) {
113  middle_module =
114  full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
115  }
116  std::string type_name = full_type.substr(sep_position_back + 1);
117 
118  return std::make_tuple(
119  string_trim(package_name), string_trim(middle_module), string_trim(type_name));
120 }
121 
123  const std::string & package_name, const std::string & typesupport_identifier)
124 {
125  const char * dynamic_library_folder;
126 #ifdef _WIN32
127  dynamic_library_folder = "bin";
128 #elif __APPLE__
129  dynamic_library_folder = "lib";
130 #else
131  dynamic_library_folder = "lib";
132 #endif
133 
134  std::filesystem::path package_prefix;
135  try {
136  ament_index_cpp::get_package_prefix(package_name, package_prefix);
137  } catch (ament_index_cpp::PackageNotFoundError & e) {
138  throw std::runtime_error(e.what());
139  }
140 
141  const std::string library_path = rcpputils::path_for_library(
142  (package_prefix / dynamic_library_folder).string(),
143  package_name + "__" + typesupport_identifier);
144  if (library_path.empty()) {
145  throw std::runtime_error(
146  "Typesupport library for " + package_name + " does not exist in '" +
147  package_prefix.string() + "'.");
148  }
149  return library_path;
150 }
151 
152 std::shared_ptr<rcpputils::SharedLibrary>
153 get_typesupport_library(const std::string & type, const std::string & typesupport_identifier)
154 {
155  auto package_name = std::get<0>(extract_type_identifier(type));
156  auto library_path = get_typesupport_library_path(package_name, typesupport_identifier);
157  return std::make_shared<rcpputils::SharedLibrary>(library_path);
158 }
159 
160 const rosidl_message_type_support_t * get_message_typesupport_handle(
161  const std::string & type,
162  const std::string & typesupport_identifier,
163  rcpputils::SharedLibrary & library)
164 {
165  static const std::string typesupport_name = "message";
166  static const std::string symbol_part_name = "__get_message_type_support_handle__";
167  static const std::string middle_module_additional = "msg";
168 
169  return static_cast<const rosidl_message_type_support_t *>(get_typesupport_handle_impl(
170  type, typesupport_identifier, typesupport_name, symbol_part_name,
171  middle_module_additional, library
172  ));
173 }
174 
175 const rosidl_service_type_support_t * get_service_typesupport_handle(
176  const std::string & type,
177  const std::string & typesupport_identifier,
178  rcpputils::SharedLibrary & library)
179 {
180  static const std::string typesupport_name = "service";
181  static const std::string symbol_part_name = "__get_service_type_support_handle__";
182  static const std::string middle_module_additional = "srv";
183 
184  return static_cast<const rosidl_service_type_support_t *>(get_typesupport_handle_impl(
185  type, typesupport_identifier, typesupport_name, symbol_part_name,
186  middle_module_additional, library
187  ));
188 }
189 
190 const rosidl_action_type_support_t * get_action_typesupport_handle(
191  const std::string & type,
192  const std::string & typesupport_identifier,
193  rcpputils::SharedLibrary & library)
194 {
195  static const std::string typesupport_name = "action";
196  static const std::string symbol_part_name = "__get_action_type_support_handle__";
197  static const std::string middle_module_additional = "action";
198 
199  return static_cast<const rosidl_action_type_support_t *>(get_typesupport_handle_impl(
200  type, typesupport_identifier, typesupport_name, symbol_part_name,
201  middle_module_additional, library
202  ));
203 }
204 
205 } // 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.