rosmsg_cpp.cpp
Go to the documentation of this file.
2 
3 #include <iostream>
4 #include <cstdlib>
5 
6 #include <Python.h>
7 
8 #include <ros/package.h>
9 #include <ros/platform.h>
10 
11 namespace ros
12 {
13 namespace message
14 {
15 
16 static bool pythonInitialized = [](){
17  // the ROS_ROOT workaround is needed (probably) just on ROS buildfarm
18  std::string tmp;
19  if (!ros::get_environment_variable(tmp, "ROS_ROOT"))
20  {
21  std::cerr << "ROS_ROOT not found" << std::endl;
22  std::string rosDistro;
23  if (!ros::get_environment_variable(rosDistro, "ROS_DISTRO"))
24  {
25  rosDistro = ROS_DISTRO;
26  std::cerr << "ROS_DISTRO not found, setting " << rosDistro << std::endl;
27  }
28  const auto rosRoot = "/opt/ros/" + rosDistro + "/share/ros";
29  std::cerr << "Setting ROS_ROOT to " << rosRoot << std::endl;
30  ::setenv("ROS_ROOT", rosRoot.c_str(), false);
31  }
32  Py_Initialize();
33  return true;
34 }();
35 
36 PyObject* stringToPython(const std::string& input)
37 {
38 #if PY_MAJOR_VERSION >= 3
39  return PyUnicode_FromStringAndSize(input.c_str(), input.size());
40 #else
41  return PyString_FromStringAndSize(input.c_str(), input.size());
42 #endif
43 }
44 
45 std::string stringFromPython(PyObject* input)
46 {
47  if (input == nullptr)
48  return {};
49  Py_ssize_t size;
50 #if PY_MAJOR_VERSION >= 3
51  const char* data;
52  data = PyUnicode_AsUTF8AndSize(input, &size);
53 #else
54  char* data;
55  PyString_AsStringAndSize(input, &data, &size);
56 #endif
57  return {data, static_cast<size_t>(size)};
58 }
59 
60 PyObject* pythonBorrowAttrString(PyObject* o, const std::string& name)
61 {
62  PyObject *r = PyObject_GetAttrString(o, name.c_str());
63  Py_XDECREF(r);
64  return r;
65 }
66 
68 {
69  if (PyErr_Occurred())
70  PyErr_Print();
71 }
72 
73 PyObject* getMsgField(const std::string& messageType, const std::string& field)
74 {
75  if (messageType.empty())
76  return {};
77 
78  const auto slashPos = messageType.find('/');
79  if (slashPos == std::string::npos)
80  {
81  std::cerr << "Message type [" << messageType << "] does not contain a slash. It has to be of form "
82  << "package/MessageType." << std::endl;
83  return {};
84  }
85 
86  const auto package = messageType.substr(0, slashPos);
87  const auto baseMessageType = messageType.substr(slashPos + 1);
88 
89  if (package.empty())
90  {
91  std::cerr << "Package is empty for message type [" << messageType << "]" << std::endl;
92  return {};
93  }
94 
95  if (baseMessageType.empty())
96  {
97  std::cerr << "Message type after package is empty for message type [" << messageType << "]" << std::endl;
98  return {};
99  }
100 
101  if (ros::package::getPath(package).empty())
102  {
103  std::cerr << "Could not find package [" << package << "] for message type [" << messageType << "]" << std::endl;
104  return {};
105  }
106 
107  // now we know that the package where the message should be exists
108 
109  PyObject* def {nullptr};
110 
111  auto pName = stringToPython(package + ".msg");
112  auto pModule = PyImport_Import(pName);
113  Py_DECREF(pName);
114 
115  if (pModule != nullptr) {
116  auto pMessageClass = pythonBorrowAttrString(pModule, baseMessageType);
117  if (pMessageClass != nullptr) {
118  auto pMsgDef = pythonBorrowAttrString(pMessageClass, field);
119  if (pMsgDef != nullptr)
120  {
121  def = pMsgDef;
122  Py_INCREF(pMsgDef);
123  }
124  else
125  {
127  std::cerr << "Error reading message definition from " << package << ".msg." << baseMessageType << " !"
128  << std::endl;
129  }
130  }
131  else {
133  std::cerr << "Failed to load message class " << package << ".msg." << baseMessageType << " !" << std::endl;
134  }
135  }
136  else
137  {
139  std::cerr << "Failed to load module " << package << ".msg !" << std::endl;
140  }
141  Py_XDECREF(pModule);
142 
143  return def;
144 }
145 
146 std::string getFullDef(const std::string& messageType)
147 {
148  auto pMsgDef = getMsgField(messageType, "_full_text");
149  auto def = stringFromPython(pMsgDef);
150  Py_XDECREF(pMsgDef);
151  return def;
152 }
153 
154 std::string getMD5Sum(const std::string& messageType)
155 {
156  auto pMD5Sum = getMsgField(messageType, "_md5sum");
157  auto md5Sum = stringFromPython(pMD5Sum);
158  Py_XDECREF(pMD5Sum);
159  return md5Sum;
160 }
161 
162 bool hasHeader(const std::string& messageType)
163 {
164  auto pHasHeader = getMsgField(messageType, "_has_header");
165  if (pHasHeader == nullptr)
166  return false;
167  auto hasHeader = PyObject_IsTrue(pHasHeader);
168  Py_XDECREF(pHasHeader);
169  return hasHeader;
170 }
171 
172 std::vector<std::string> getFieldNames(const std::string& messageType)
173 {
174  std::vector<std::string> fieldNames;
175  auto pFieldNames = getMsgField(messageType, "__slots__");
176  if (pFieldNames != nullptr && PyList_Check(pFieldNames))
177  {
178  for(Py_ssize_t i = 0; i < PyList_Size(pFieldNames); i++) {
179  const auto pFieldName = PyList_GetItem(pFieldNames, i);
180  if (pFieldName != nullptr)
181  fieldNames.push_back(stringFromPython(pFieldName));
182  }
183  }
184  Py_XDECREF(pFieldNames);
185  return fieldNames;
186 }
187 
188 std::vector<std::string> getFieldTypes(const std::string& messageType)
189 {
190  std::vector<std::string> fieldTypes;
191  auto pFieldTypes = getMsgField(messageType, "_slot_types");
192  if (pFieldTypes != nullptr && PyList_Check(pFieldTypes))
193  {
194  for(Py_ssize_t i = 0; i < PyList_Size(pFieldTypes); i++) {
195  const auto pFieldType = PyList_GetItem(pFieldTypes, i);
196  if (pFieldType != nullptr)
197  fieldTypes.push_back(stringFromPython(pFieldType));
198  }
199  }
200  Py_XDECREF(pFieldTypes);
201  return fieldTypes;
202 }
203 
204 std::string getMsgFile(const std::string& messageType)
205 {
206  if (messageType.empty())
207  return {};
208 
209  const auto slashPos = messageType.find('/');
210  if (slashPos == std::string::npos)
211  {
212  std::cerr << "Message type [" << messageType << "] does not contain a slash. It has to be of form "
213  << "package/MessageType." << std::endl;
214  return {};
215  }
216 
217  const auto package = messageType.substr(0, slashPos);
218  const auto baseMessageType = messageType.substr(slashPos + 1);
219 
220  if (package.empty())
221  {
222  std::cerr << "Package is empty for message type [" << messageType << "]" << std::endl;
223  return {};
224  }
225 
226  if (baseMessageType.empty())
227  {
228  std::cerr << "Message type after package is empty for message type [" << messageType << "]" << std::endl;
229  return {};
230  }
231 
232  const auto& packagePath = ros::package::getPath(package);
233  if (packagePath.empty())
234  {
235  std::cerr << "Could not find package [" << package << "] for message type [" << messageType << "]" << std::endl;
236  return {};
237  }
238 
239  const char sep =
240 #ifdef _WIN32
241  '\\';
242 #else
243  '/';
244 #endif
245 
246  auto path = packagePath + sep + "msg" + sep + baseMessageType + ".msg";
247 
248  // check for existence
249  struct stat buffer;
250  if (stat(path.c_str(), &buffer) != 0)
251  path = "";
252 
253  return path;
254 }
255 
256 std::string getMD5Text(const std::string& messageType)
257 {
258  if (messageType.empty())
259  return {};
260 
261  const auto msgFile = getMsgFile(messageType);
262  if (msgFile.empty())
263  {
264  std::cerr << "Could not find message proto file for message type [" << messageType << "]" << std::endl;
265  return {};
266  }
267 
268  std::string def {};
269 
270  auto pName = stringToPython("roslib.gentools");
271  auto pModule = PyImport_Import(pName);
272  Py_DECREF(pName);
273 
274  if (pModule != nullptr) {
275  auto pDict = PyModule_GetDict(pModule);
276  pName = stringToPython("get_file_dependencies");
277  auto pFunc = PyDict_GetItem(pDict, pName);
278  Py_DECREF(pName);
279  if (pFunc != nullptr)
280  {
281  pName = stringToPython(msgFile);
282  auto pGetDepsDict = PyObject_CallFunctionObjArgs(pFunc, pName, nullptr);
283  Py_DECREF(pName);
284 
285  if (pGetDepsDict != nullptr)
286  {
287  pName = stringToPython("spec");
288  auto pSpec = PyDict_GetItem(pGetDepsDict, pName);
289  Py_DECREF(pName);
290 
291  if (pSpec != nullptr)
292  {
293  pName = stringToPython("compute_md5_text");
294  auto pFunc2 = PyDict_GetItem(pDict, pName);
295  Py_DECREF(pName);
296  if (pFunc2 != nullptr)
297  {
298  auto pMD5Text = PyObject_CallFunctionObjArgs(pFunc2, pGetDepsDict, pSpec, nullptr);
299  if (pMD5Text != nullptr)
300  {
301  def = stringFromPython(pMD5Text);
302  } else printPythonError();
303  Py_XDECREF(pMD5Text);
304  } else printPythonError();
305  } else printPythonError();
306  } else printPythonError();
307  Py_XDECREF(pGetDepsDict);
308  } else printPythonError();
309  }
310  else
311  {
313  std::cerr << "Failed to load module roslib.gentools !" << std::endl;
314  }
315  Py_XDECREF(pModule);
316 
317  return def;
318 }
319 
320 }
321 }
ros::message::pythonBorrowAttrString
PyObject * pythonBorrowAttrString(PyObject *o, const std::string &name)
Definition: rosmsg_cpp.cpp:60
ros::message::printPythonError
void printPythonError()
Definition: rosmsg_cpp.cpp:67
ros::package::getPath
ROSLIB_DECL std::string getPath(const std::string &package_name)
ros
ros::message::getMD5Text
std::string getMD5Text(const std::string &messageType)
Return the exact text from which the MD5 sum of the message is computed.
Definition: rosmsg_cpp.cpp:256
ros::message::stringToPython
PyObject * stringToPython(const std::string &input)
Definition: rosmsg_cpp.cpp:36
ros::message::pythonInitialized
static bool pythonInitialized
Definition: rosmsg_cpp.cpp:16
ros::message::getFieldNames
std::vector< std::string > getFieldNames(const std::string &messageType)
Return the names of fields of the message type (non-recursive).
Definition: rosmsg_cpp.cpp:172
package
string package
ros::message::stringFromPython
std::string stringFromPython(PyObject *input)
Definition: rosmsg_cpp.cpp:45
ros::message::getFieldTypes
std::vector< std::string > getFieldTypes(const std::string &messageType)
Return the types of fields of the message type (non-recursive).
Definition: rosmsg_cpp.cpp:188
ros::message::getFullDef
std::string getFullDef(const std::string &messageType)
Return the full recursive definition of the message type - the same as genpy generates.
Definition: rosmsg_cpp.cpp:146
rosmsg_cpp.h
ros::message::hasHeader
bool hasHeader(const std::string &messageType)
Tell whether the given message type has a header field.
Definition: rosmsg_cpp.cpp:162
package.h
ros::message::getMsgFile
std::string getMsgFile(const std::string &messageType)
Get the path to the .msg file corresponding to the given message type.
Definition: rosmsg_cpp.cpp:204
ros::get_environment_variable
bool get_environment_variable(std::string &str, const char *environment_variable)
platform.h
ros::message::getMsgField
PyObject * getMsgField(const std::string &messageType, const std::string &field)
Definition: rosmsg_cpp.cpp:73
ros::message::getMD5Sum
std::string getMD5Sum(const std::string &messageType)
Return the MD5 sum of the message type - the same as genpy generates.
Definition: rosmsg_cpp.cpp:154


rosmsg_cpp
Author(s): Martin Pecka
autogenerated on Mon Apr 17 2023 02:30:24