ROS 2 rclcpp + rcl - humble  humble
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 <functional>
19 #include <memory>
20 #include <sstream>
21 #include <stdexcept>
22 #include <string>
23 #include <tuple>
24 #include <utility>
25 
26 #include "ament_index_cpp/get_package_prefix.hpp"
27 #include "ament_index_cpp/get_resources.hpp"
28 #include "rcpputils/shared_library.hpp"
29 #include "rcpputils/find_library.hpp"
30 #include "rosidl_runtime_cpp/message_type_support_decl.hpp"
31 
32 namespace rclcpp
33 {
34 
35 namespace
36 {
37 
38 // Look for the library in the ament prefix paths.
39 std::string get_typesupport_library_path(
40  const std::string & package_name, const std::string & typesupport_identifier)
41 {
42  const char * dynamic_library_folder;
43 #ifdef _WIN32
44  dynamic_library_folder = "/bin/";
45 #elif __APPLE__
46  dynamic_library_folder = "/lib/";
47 #else
48  dynamic_library_folder = "/lib/";
49 #endif
50 
51  std::string package_prefix;
52  try {
53  package_prefix = ament_index_cpp::get_package_prefix(package_name);
54  } catch (ament_index_cpp::PackageNotFoundError & e) {
55  throw std::runtime_error(e.what());
56  }
57 
58  const std::string library_path = rcpputils::path_for_library(
59  package_prefix + dynamic_library_folder,
60  package_name + "__" + typesupport_identifier);
61  if (library_path.empty()) {
62  throw std::runtime_error(
63  "Typesupport library for " + package_name + " does not exist in '" + package_prefix +
64  "'.");
65  }
66  return library_path;
67 }
68 
69 std::tuple<std::string, std::string, std::string>
70 extract_type_identifier(const std::string & full_type)
71 {
72  char type_separator = '/';
73  auto sep_position_back = full_type.find_last_of(type_separator);
74  auto sep_position_front = full_type.find_first_of(type_separator);
75  if (sep_position_back == std::string::npos ||
76  sep_position_back == 0 ||
77  sep_position_back == full_type.length() - 1)
78  {
79  throw std::runtime_error(
80  "Message type is not of the form package/type and cannot be processed");
81  }
82 
83  std::string package_name = full_type.substr(0, sep_position_front);
84  std::string middle_module = "";
85  if (sep_position_back - sep_position_front > 0) {
86  middle_module =
87  full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
88  }
89  std::string type_name = full_type.substr(sep_position_back + 1);
90 
91  return std::make_tuple(package_name, middle_module, type_name);
92 }
93 
94 } // anonymous namespace
95 
96 std::shared_ptr<rcpputils::SharedLibrary>
97 get_typesupport_library(const std::string & type, const std::string & typesupport_identifier)
98 {
99  auto package_name = std::get<0>(extract_type_identifier(type));
100  auto library_path = get_typesupport_library_path(package_name, typesupport_identifier);
101  return std::make_shared<rcpputils::SharedLibrary>(library_path);
102 }
103 
104 const rosidl_message_type_support_t *
106  const std::string & type,
107  const std::string & typesupport_identifier,
108  rcpputils::SharedLibrary & library)
109 {
110  std::string package_name;
111  std::string middle_module;
112  std::string type_name;
113  std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
114 
115  auto mk_error = [&package_name, &type_name](auto reason) {
116  std::stringstream rcutils_dynamic_loading_error;
117  rcutils_dynamic_loading_error <<
118  "Something went wrong loading the typesupport library for message type " << package_name <<
119  "/" << type_name << ". " << reason;
120  return rcutils_dynamic_loading_error.str();
121  };
122 
123  try {
124  std::string symbol_name = typesupport_identifier + "__get_message_type_support_handle__" +
125  package_name + "__" + (middle_module.empty() ? "msg" : middle_module) + "__" + type_name;
126 
127  const rosidl_message_type_support_t * (* get_ts)() = nullptr;
128  // This will throw runtime_error if the symbol was not found.
129  get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
130  return get_ts();
131  } catch (std::runtime_error &) {
132  throw std::runtime_error{mk_error("Library could not be found.")};
133  }
134 }
135 
136 } // namespace rclcpp
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
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_typesupport_handle(const std::string &type, const std::string &typesupport_identifier, rcpputils::SharedLibrary &library)
Extract the type support handle from the library.