msg_gen.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # Software License Agreement (BSD License)
3 #
4 # Copyright (c) 2009, Willow Garage, Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # * Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above
14 # copyright notice, this list of conditions and the following
15 # disclaimer in the documentation and/or other materials provided
16 # with the distribution.
17 # * Neither the name of Willow Garage, Inc. nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 #
34 
35 
38 
39 import sys
40 import os
41 import traceback
42 
43 import roslib.msgs
44 import roslib.packages
45 import roslib.gentools
46 from rospkg import RosPack
47 
48 try:
49  from cStringIO import StringIO #Python 2.x
50 except ImportError:
51  from io import StringIO #Python 3.x
52 
53 MSG_TYPE_TO_CPP = {'byte': 'int8_t', 'char': 'uint8_t',
54  'bool': 'uint8_t',
55  'uint8': 'uint8_t', 'int8': 'int8_t',
56  'uint16': 'uint16_t', 'int16': 'int16_t',
57  'uint32': 'uint32_t', 'int32': 'int32_t',
58  'uint64': 'uint64_t', 'int64': 'int64_t',
59  'float32': 'float',
60  'float64': 'double',
61  'string': 'std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other > ',
62  'time': 'ros::Time',
63  'duration': 'ros::Duration'}
64 
65 def msg_type_to_cpp(type):
66  """
67  Converts a message type (e.g. uint32, std_msgs/String, etc.) into the C++ declaration
68  for that type (e.g. uint32_t, std_msgs::String_<ContainerAllocator>)
69 
70  @param type: The message type
71  @type type: str
72  @return: The C++ declaration
73  @rtype: str
74  """
75  (base_type, is_array, array_len) = roslib.msgs.parse_type(type)
76  cpp_type = None
77  if (roslib.msgs.is_builtin(base_type)):
78  cpp_type = MSG_TYPE_TO_CPP[base_type]
79  elif (len(base_type.split('/')) == 1):
80  if (roslib.msgs.is_header_type(base_type)):
81  cpp_type = ' ::std_msgs::Header_<ContainerAllocator> '
82  else:
83  cpp_type = '%s_<ContainerAllocator> '%(base_type)
84  else:
85  pkg = base_type.split('/')[0]
86  msg = base_type.split('/')[1]
87  cpp_type = ' ::%s::%s_<ContainerAllocator> '%(pkg, msg)
88 
89  if (is_array):
90  if (array_len is None):
91  return 'std::vector<%s, typename ContainerAllocator::template rebind<%s>::other > '%(cpp_type, cpp_type)
92  else:
93  return 'boost::array<%s, %s> '%(cpp_type, array_len)
94  else:
95  return cpp_type
96 
97 def cpp_message_declarations(name_prefix, msg):
98  """
99  Returns the different possible C++ declarations for a message given the message itself.
100 
101  @param name_prefix: The C++ prefix to be prepended to the name, e.g. "std_msgs::"
102  @type name_prefix: str
103  @param msg: The message type
104  @type msg: str
105  @return: A tuple of 3 different names. cpp_message_decelarations("std_msgs::", "String") returns the tuple
106  ("std_msgs::String_", "std_msgs::String_<ContainerAllocator>", "std_msgs::String")
107  @rtype: str
108  """
109  pkg, basetype = roslib.names.package_resource_name(msg)
110  cpp_name = ' ::%s%s'%(name_prefix, msg)
111  if (pkg):
112  cpp_name = ' ::%s::%s'%(pkg, basetype)
113  return ('%s_'%(cpp_name), '%s_<ContainerAllocator> '%(cpp_name), '%s'%(cpp_name))
114 
115 def write_begin(s, spec, file):
116  """
117  Writes the beginning of the header file: a comment saying it's auto-generated and the include guards
118 
119  @param s: The stream to write to
120  @type s: stream
121  @param spec: The spec
122  @type spec: roslib.msgs.MsgSpec
123  @param file: The file this message is being generated for
124  @type file: str
125  """
126  s.write("/* Auto-generated by genmsg_cpp for file %s */\n"%(file))
127  s.write('#ifndef %s_MESSAGE_%s_H\n'%(spec.package.upper(), spec.short_name.upper()))
128  s.write('#define %s_MESSAGE_%s_H\n'%(spec.package.upper(), spec.short_name.upper()))
129 
130 def write_end(s, spec):
131  """
132  Writes the end of the header file: the ending of the include guards
133 
134  @param s: The stream to write to
135  @type s: stream
136  @param spec: The spec
137  @type spec: roslib.msgs.MsgSpec
138  """
139  s.write('#endif // %s_MESSAGE_%s_H\n'%(spec.package.upper(), spec.short_name.upper()))
140 
142  """
143  Writes the includes that all messages need
144 
145  @param s: The stream to write to
146  @type s: stream
147  """
148  s.write('#include <string>\n')
149  s.write('#include <vector>\n')
150  s.write('#include <map>\n')
151  s.write('#include <ostream>\n')
152  s.write('#include "ros/serialization.h"\n')
153  s.write('#include "ros/builtin_message_traits.h"\n')
154  s.write('#include "ros/message_operations.h"\n')
155  s.write('#include "ros/time.h"\n\n')
156  s.write('#include "ros/macros.h"\n\n')
157  s.write('#include "ros/assert.h"\n\n')
158 
159 def write_includes(s, spec):
160  """
161  Writes the message-specific includes
162 
163  @param s: The stream to write to
164  @type s: stream
165  @param spec: The message spec to iterate over
166  @type spec: roslib.msgs.MsgSpec
167  """
168  for field in spec.parsed_fields():
169  if (not field.is_builtin):
170  if (field.is_header):
171  s.write('#include "std_msgs/Header.h"\n')
172  else:
173  (pkg, name) = roslib.names.package_resource_name(field.base_type)
174  pkg = pkg or spec.package # convert '' to package
175  s.write('#include "%s/%s.h"\n'%(pkg, name))
176 
177  s.write('\n')
178 
179 
180 def write_struct(s, spec, cpp_name_prefix, extra_deprecated_traits = {}):
181  """
182  Writes the entire message struct: declaration, constructors, members, constants and (deprecated) member functions
183  @param s: The stream to write to
184  @type s: stream
185  @param spec: The message spec
186  @type spec: roslib.msgs.MsgSpec
187  @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
188  @type cpp_name_prefix: str
189  """
190 
191  msg = spec.short_name
192  s.write('template <class ContainerAllocator>\n')
193  s.write('struct %s_ {\n'%(msg))
194  s.write(' typedef %s_<ContainerAllocator> Type;\n\n'%(msg))
195 
196  write_constructors(s, spec, cpp_name_prefix)
197  write_members(s, spec)
199 
200  #rospack = RosPack()
201  #gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package, compute_files=False, rospack=rospack)
202  #md5sum = roslib.gentools.compute_md5(gendeps_dict, rospack=rospack)
203  #full_text = compute_full_text_escaped(gendeps_dict)
204 
205  # write_deprecated_member_functions(s, spec, dict(list({'MD5Sum': md5sum, 'DataType': '%s/%s'%(spec.package, spec.short_name), 'MessageDefinition': full_text}.items()) + list(extra_deprecated_traits.items())))
206 
207  (cpp_msg_unqualified, cpp_msg_with_alloc, cpp_msg_base) = cpp_message_declarations(cpp_name_prefix, msg)
208  s.write(' typedef boost::shared_ptr<%s> Ptr;\n'%(cpp_msg_with_alloc))
209  s.write(' typedef boost::shared_ptr<%s const> ConstPtr;\n'%(cpp_msg_with_alloc))
210 
211  s.write('}; // struct %s\n'%(msg))
212 
213  s.write('typedef %s_<std::allocator<void> > %s;\n\n'%(cpp_msg_base, msg))
214  s.write('typedef boost::shared_ptr<%s> %sPtr;\n'%(cpp_msg_base, msg))
215  s.write('typedef boost::shared_ptr<%s const> %sConstPtr;\n\n'%(cpp_msg_base, msg))
216 
217 def default_value(type):
218  """
219  Returns the value to initialize a message member with. 0 for integer types, 0.0 for floating point, false for bool,
220  empty string for everything else
221 
222  @param type: The type
223  @type type: str
224  """
225  if type in ['byte', 'int8', 'int16', 'int32', 'int64',
226  'char', 'uint8', 'uint16', 'uint32', 'uint64']:
227  return '0'
228  elif type in ['float32', 'float64']:
229  return '0.0'
230  elif type == 'bool':
231  return 'false'
232 
233  return ""
234 
235 def takes_allocator(type):
236  """
237  Returns whether or not a type can take an allocator in its constructor. False for all builtin types except string.
238  True for all others.
239 
240  @param type: The type
241  @type: str
242  """
243  return not type in ['byte', 'int8', 'int16', 'int32', 'int64',
244  'char', 'uint8', 'uint16', 'uint32', 'uint64',
245  'float32', 'float64', 'bool', 'time', 'duration']
246 
247 def write_initializer_list(s, spec, container_gets_allocator):
248  """
249  Writes the initializer list for a constructor
250 
251  @param s: The stream to write to
252  @type s: stream
253  @param spec: The message spec
254  @type spec: roslib.msgs.MsgSpec
255  @param container_gets_allocator: Whether or not a container type (whether it's another message, a vector, array or string)
256  should have the allocator passed to its constructor. Assumes the allocator is named _alloc.
257  @type container_gets_allocator: bool
258  """
259 
260  i = 0
261  for field in spec.parsed_fields():
262  if (i == 0):
263  s.write(' : ')
264  else:
265  s.write(' , ')
266 
267  val = default_value(field.base_type)
268  use_alloc = takes_allocator(field.base_type)
269  if (field.is_array):
270  if (field.array_len is None and container_gets_allocator):
271  s.write('%s(_alloc)\n'%(field.name))
272  else:
273  s.write('%s()\n'%(field.name))
274  else:
275  if (container_gets_allocator and use_alloc):
276  s.write('%s(_alloc)\n'%(field.name))
277  else:
278  s.write('%s(%s)\n'%(field.name, val))
279  i = i + 1
280 
281 def write_fixed_length_assigns(s, spec, container_gets_allocator, cpp_name_prefix):
282  """
283  Initialize any fixed-length arrays
284 
285  @param s: The stream to write to
286  @type s: stream
287  @param spec: The message spec
288  @type spec: roslib.msgs.MsgSpec
289  @param container_gets_allocator: Whether or not a container type (whether it's another message, a vector, array or string)
290  should have the allocator passed to its constructor. Assumes the allocator is named _alloc.
291  @type container_gets_allocator: bool
292  @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
293  @type cpp_name_prefix: str
294  """
295  # Assign all fixed-length arrays their default values
296  for field in spec.parsed_fields():
297  if (not field.is_array or field.array_len is None):
298  continue
299 
300  val = default_value(field.base_type)
301  if (container_gets_allocator and takes_allocator(field.base_type)):
302  # String is a special case, as it is the only builtin type that takes an allocator
303  if (field.base_type == "string"):
304  string_cpp = msg_type_to_cpp("string")
305  s.write(' %s.assign(%s(_alloc));\n'%(field.name, string_cpp))
306  else:
307  (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, field.base_type)
308  s.write(' %s.assign(%s(_alloc));\n'%(field.name, cpp_msg_with_alloc))
309  elif (len(val) > 0):
310  s.write(' %s.assign(%s);\n'%(field.name, val))
311 
312 def write_constructors(s, spec, cpp_name_prefix):
313  """
314  Writes any necessary constructors for the message
315 
316  @param s: The stream to write to
317  @type s: stream
318  @param spec: The message spec
319  @type spec: roslib.msgs.MsgSpec
320  @param cpp_name_prefix: The C++ prefix to use when referring to the message, e.g. "std_msgs::"
321  @type cpp_name_prefix: str
322  """
323 
324  msg = spec.short_name
325 
326  # Default constructor
327  s.write(' %s_()\n'%(msg))
328  write_initializer_list(s, spec, False)
329  s.write(' {\n')
330  write_fixed_length_assigns(s, spec, False, cpp_name_prefix)
331  s.write(' }\n\n')
332 
333  # Constructor that takes an allocator constructor
334  s.write(' %s_(const ContainerAllocator& _alloc)\n'%(msg))
335  write_initializer_list(s, spec, True)
336  s.write(' {\n')
337  write_fixed_length_assigns(s, spec, True, cpp_name_prefix)
338  s.write(' }\n\n')
339 
340 def write_member(s, field):
341  """
342  Writes a single member's declaration and type typedef
343 
344  @param s: The stream to write to
345  @type s: stream
346  @param type: The member type
347  @type type: str
348  @param name: The name of the member
349  @type name: str
350  """
351  cpp_type = msg_type_to_cpp(field.type)
352  s.write(' typedef %s _%s_type;\n'%(cpp_type, field.name))
353  s.write(' %s %s;\n\n'%(cpp_type, field.name))
354 
355 def write_members(s, spec):
356  """
357  Write all the member declarations
358 
359  @param s: The stream to write to
360  @type s: stream
361  @param spec: The message spec
362  @type spec: roslib.msgs.MsgSpec
363  """
364  [write_member(s, field) for field in spec.parsed_fields()]
365 
366 def escape_string(str):
367  str = str.replace('\\', '\\\\')
368  str = str.replace('"', '\\"')
369  return str
370 
371 def write_constant_declaration(s, constant):
372  """
373  Write a constant value as a static member
374 
375  @param s: The stream to write to
376  @type s: stream
377  @param constant: The constant
378  @type constant: roslib.msgs.Constant
379  """
380 
381  # integral types get their declarations as enums to allow use at compile time
382  if (constant.type in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64']):
383  s.write(' enum { %s = %s };\n'%(constant.name, constant.val))
384  else:
385  s.write(' static const %s %s;\n'%(msg_type_to_cpp(constant.type), constant.name))
386 
388  """
389  Write all the constants from a spec as static members
390 
391  @param s: The stream to write to
392  @type s: stream
393  @param spec: The message spec
394  @type spec: roslib.msgs.MsgSpec
395  """
396  [write_constant_declaration(s, constant) for constant in spec.constants]
397  s.write('\n')
398 
399 def write_constant_definition(s, spec, constant):
400  """
401  Write a constant value as a static member
402 
403  @param s: The stream to write to
404  @type s: stream
405  @param constant: The constant
406  @type constant: roslib.msgs.Constant
407  """
408 
409  # integral types do not need a definition, since they've been defined where they are declared
410  if (constant.type not in ['byte', 'int8', 'int16', 'int32', 'int64', 'char', 'uint8', 'uint16', 'uint32', 'uint64', 'string']):
411  s.write('template<typename ContainerAllocator> const %s %s_<ContainerAllocator>::%s = %s;\n'%(msg_type_to_cpp(constant.type), spec.short_name, constant.name, constant.val))
412  elif (constant.type == 'string'):
413  s.write('template<typename ContainerAllocator> const %s %s_<ContainerAllocator>::%s = "%s";\n'%(msg_type_to_cpp(constant.type), spec.short_name, constant.name, escape_string(constant.val)))
414 
416  """
417  Write all the constants from a spec as static members
418 
419  @param s: The stream to write to
420  @type s: stream
421  @param spec: The message spec
422  @type spec: roslib.msgs.MsgSpec
423  """
424  [write_constant_definition(s, spec, constant) for constant in spec.constants]
425  s.write('\n')
426 
427 def is_fixed_length(spec):
428  """
429  Returns whether or not the message is fixed-length
430 
431  @param spec: The message spec
432  @type spec: roslib.msgs.MsgSpec
433  @param package: The package of the
434  @type package: str
435  """
436  types = []
437  for field in spec.parsed_fields():
438  if (field.is_array and field.array_len is None):
439  return False
440 
441  if (field.base_type == 'string'):
442  return False
443 
444  if (not field.is_builtin):
445  types.append(field.base_type)
446 
447  types = set(types)
448  for type in types:
449  type = roslib.msgs.resolve_type(type, spec.package)
450  (_, new_spec) = roslib.msgs.load_by_type(type, spec.package)
451  if (not is_fixed_length(new_spec)):
452  return False
453 
454  return True
455 
457  """
458  Writes the deprecated member functions for backwards compatibility
459  """
460  for field in spec.parsed_fields():
461  if (field.is_array):
462  s.write(' ROS_DEPRECATED uint32_t get_%s_size() const { return (uint32_t)%s.size(); }\n'%(field.name, field.name))
463 
464  if (field.array_len is None):
465  s.write(' ROS_DEPRECATED void set_%s_size(uint32_t size) { %s.resize((size_t)size); }\n'%(field.name, field.name))
466  s.write(' ROS_DEPRECATED void get_%s_vec(%s& vec) const { vec = this->%s; }\n'%(field.name, msg_type_to_cpp(field.type), field.name))
467  s.write(' ROS_DEPRECATED void set_%s_vec(const %s& vec) { this->%s = vec; }\n'%(field.name, msg_type_to_cpp(field.type), field.name))
468 
469  for k, v in traits.items():
470  s.write('private:\n')
471  s.write(' static const char* __s_get%s_() { return "%s"; }\n'%(k, v))
472  s.write('public:\n')
473  s.write(' ROS_DEPRECATED static const std::string __s_get%s() { return __s_get%s_(); }\n\n'%(k, k))
474  s.write(' ROS_DEPRECATED const std::string __get%s() const { return __s_get%s_(); }\n\n'%(k, k))
475 
476  s.write(' ROS_DEPRECATED virtual uint8_t *serialize(uint8_t *write_ptr, uint32_t seq) const\n {\n')
477  s.write(' ros::serialization::OStream stream(write_ptr, 1000000000);\n')
478  for field in spec.parsed_fields():
479  s.write(' ros::serialization::serialize(stream, %s);\n'%(field.name))
480  s.write(' return stream.getData();\n }\n\n')
481 
482  s.write(' ROS_DEPRECATED virtual uint8_t *deserialize(uint8_t *read_ptr)\n {\n')
483  s.write(' ros::serialization::IStream stream(read_ptr, 1000000000);\n');
484  for field in spec.parsed_fields():
485  s.write(' ros::serialization::deserialize(stream, %s);\n'%(field.name))
486  s.write(' return stream.getData();\n }\n\n')
487 
488  s.write(' ROS_DEPRECATED virtual uint32_t serializationLength() const\n {\n')
489  s.write(' uint32_t size = 0;\n');
490  for field in spec.parsed_fields():
491  s.write(' size += ros::serialization::serializationLength(%s);\n'%(field.name))
492  s.write(' return size;\n }\n\n')
493 
494 def compute_full_text_escaped(gen_deps_dict):
495  """
496  Same as roslib.gentools.compute_full_text, except that the
497  resulting text is escaped to be safe for C++ double quotes
498 
499  @param get_deps_dict: dictionary returned by get_dependencies call
500  @type get_deps_dict: dict
501  @return: concatenated text for msg/srv file and embedded msg/srv types. Text will be escaped for double quotes
502  @rtype: str
503  """
504  definition = roslib.gentools.compute_full_text(gen_deps_dict)
505  lines = definition.split('\n')
506  s = StringIO()
507  for line in lines:
508  line = escape_string(line)
509  s.write('%s\\n\\\n'%(line))
510 
511  val = s.getvalue()
512  s.close()
513  return val
514 
515 def is_hex_string(str):
516  for c in str:
517  if c not in '0123456789abcdefABCDEF':
518  return False
519 
520  return True
521 
522 def write_trait_char_class(s, class_name, cpp_msg_with_alloc, value, write_static_hex_value = False):
523  """
524  Writes a class trait for traits which have static value() members that return const char*
525 
526  e.g. write_trait_char_class(s, "MD5Sum", "std_msgs::String_<ContainerAllocator>", "hello") yields:
527  template<class ContainerAllocator>
528  struct MD5Sum<std_msgs::String_<ContainerAllocator> >
529  {
530  static const char* value() { return "hello"; }
531  static const char* value(const std_msgs::String_<ContainerAllocator>&) { return value(); }
532  };
533 
534  @param s: The stream to write to
535  @type s: stream
536  @param class_name: The name of the trait class to write
537  @type class_name: str
538  @param cpp_msg_with_alloc: The C++ declaration of the message, including the allocator template
539  @type cpp_msg_with_alloc: str
540  @param value: The value to return in the string
541  @type value: str
542  @param write_static_hex_value: Whether or not to write a set of compile-time-checkable static values. Useful for,
543  for example, MD5Sum. Writes static const uint64_t static_value1... static_valueN
544  @type write_static_hex_value: bool
545  @raise ValueError if write_static_hex_value is True but value contains characters invalid in a hex value
546  """
547  s.write('template<class ContainerAllocator>\nstruct %s<%s> {\n'%(class_name, cpp_msg_with_alloc))
548  s.write(' static const char* value() \n {\n return "%s";\n }\n\n'%(value))
549  s.write(' static const char* value(const %s&) { return value(); } \n'%(cpp_msg_with_alloc))
550  if (write_static_hex_value):
551  if (not is_hex_string(value)):
552  raise ValueError('%s is not a hex value'%(value))
553 
554  iter_count = len(value) / 16
555  for i in range(0, int(iter_count)):
556  start = i*16
557  s.write(' static const uint64_t static_value%s = 0x%sULL;\n'%((i+1), value[start:start+16]))
558  s.write('};\n\n')
559 
560 def write_trait_true_class(s, class_name, cpp_msg_with_alloc):
561  """
562  Writes a true/false trait class
563 
564  @param s: stream to write to
565  @type s: stream
566  @param class_name: Name of the trait class
567  @type class_name: str
568  @param cpp_msg_with_alloc: The C++ declaration of the message, including the allocator template
569  @type cpp_msg_with_alloc: str
570  """
571  s.write('template<class ContainerAllocator> struct %s<%s> : public TrueType {};\n'%(class_name, cpp_msg_with_alloc))
572 
573 def write_traits(s, spec, cpp_name_prefix, datatype = None, rospack=None):
574  """
575  Writes all the traits classes for a message
576 
577  @param s: The stream to write to
578  @type s: stream
579  @param spec: The message spec
580  @type spec: roslib.msgs.MsgSpec
581  @param cpp_name_prefix: The C++ prefix to prepend to a message to refer to it (e.g. "std_msgs::")
582  @type cpp_name_prefix: str
583  @param datatype: The string to write as the datatype of the message. If None (default), pkg/msg is used.
584  @type datatype: str
585  """
586  # generate dependencies dictionary
587  gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package, compute_files=False, rospack=rospack)
588  md5sum = roslib.gentools.compute_md5(gendeps_dict, rospack=rospack)
589  full_text = compute_full_text_escaped(gendeps_dict)
590 
591  if (datatype is None):
592  datatype = '%s'%(spec.full_name)
593 
594  (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
595  s.write('namespace ros\n{\n')
596  s.write('namespace message_traits\n{\n')
597 
598  write_trait_true_class(s, 'IsMessage', cpp_msg_with_alloc)
599  write_trait_true_class(s, 'IsMessage', cpp_msg_with_alloc + " const")
600 
601  write_trait_char_class(s, 'MD5Sum', cpp_msg_with_alloc, md5sum, True)
602  write_trait_char_class(s, 'DataType', cpp_msg_with_alloc, datatype)
603  write_trait_char_class(s, 'Definition', cpp_msg_with_alloc, full_text)
604 
605  if (spec.has_header()):
606  write_trait_true_class(s, 'HasHeader', cpp_msg_with_alloc)
607  write_trait_true_class(s, 'HasHeader', ' const' + cpp_msg_with_alloc)
608 
609  if (is_fixed_length(spec)):
610  write_trait_true_class(s, 'IsFixedSize', cpp_msg_with_alloc)
611 
612  s.write('} // namespace message_traits\n')
613  s.write('} // namespace ros\n\n')
614 
615 def write_operations(s, spec, cpp_name_prefix):
616  (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
617  s.write('namespace ros\n{\n')
618  s.write('namespace message_operations\n{\n')
619 
620  # Write the Printer operation
621  s.write('\ntemplate<class ContainerAllocator>\nstruct Printer<%s>\n{\n'%(cpp_msg_with_alloc))
622  s.write(' template<typename Stream> static void stream(Stream& s, const std::string& indent, const %s& v) \n {\n'%cpp_msg_with_alloc)
623  for field in spec.parsed_fields():
624  cpp_type = msg_type_to_cpp(field.base_type)
625  if (field.is_array):
626  s.write(' s << indent << "%s[]" << std::endl;\n'%(field.name))
627  s.write(' for (size_t i = 0; i < v.%s.size(); ++i)\n {\n'%(field.name))
628  s.write(' s << indent << " %s[" << i << "]: ";\n'%field.name)
629  indent_increment = ' '
630  if (not field.is_builtin):
631  s.write(' s << std::endl;\n')
632  s.write(' s << indent;\n')
633  indent_increment = ' ';
634  s.write(' Printer<%s>::stream(s, indent + "%s", v.%s[i]);\n'%(cpp_type, indent_increment, field.name))
635  s.write(' }\n')
636  else:
637  s.write(' s << indent << "%s: ";\n'%field.name)
638  indent_increment = ' '
639  if (not field.is_builtin or field.is_array):
640  s.write('s << std::endl;\n')
641  s.write(' Printer<%s>::stream(s, indent + "%s", v.%s);\n'%(cpp_type, indent_increment, field.name))
642  s.write(' }\n')
643  s.write('};\n\n')
644 
645  s.write('\n')
646 
647  s.write('} // namespace message_operations\n')
648  s.write('} // namespace ros\n\n')
649 
650 def write_serialization(s, spec, cpp_name_prefix):
651  """
652  Writes the Serializer class for a message
653 
654  @param s: Stream to write to
655  @type s: stream
656  @param spec: The message spec
657  @type spec: roslib.msgs.MsgSpec
658  @param cpp_name_prefix: The C++ prefix to prepend to a message to refer to it (e.g. "std_msgs::")
659  @type cpp_name_prefix: str
660  """
661  (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
662 
663  s.write('namespace ros\n{\n')
664  s.write('namespace serialization\n{\n\n')
665 
666  s.write('template<class ContainerAllocator> struct Serializer<%s>\n{\n'%(cpp_msg_with_alloc))
667 
668  s.write(' template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)\n {\n')
669  for field in spec.parsed_fields():
670  s.write(' stream.next(m.%s);\n'%(field.name))
671  s.write(' }\n\n')
672 
673  s.write(' ROS_DECLARE_ALLINONE_SERIALIZER\n')
674 
675  s.write('}; // struct %s_\n'%(spec.short_name))
676 
677  s.write('} // namespace serialization\n')
678  s.write('} // namespace ros\n\n')
679 
680 def write_ostream_operator(s, spec, cpp_name_prefix):
681  (cpp_msg_unqualified, cpp_msg_with_alloc, _) = cpp_message_declarations(cpp_name_prefix, spec.short_name)
682  s.write('template<typename ContainerAllocator>\nstd::ostream& operator<<(std::ostream& s, const %s& v)\n{\n'%(cpp_msg_with_alloc))
683  s.write(' ros::message_operations::Printer<%s>::stream(s, "", v);\n return s;}\n\n'%(cpp_msg_with_alloc))
684 
685 def generate(msg_path):
686  """
687  Generate a message
688 
689  @param msg_path: The path to the .msg file
690  @type msg_path: str
691  """
692  (package_dir, package) = roslib.packages.get_dir_pkg(msg_path)
693  (_, spec) = roslib.msgs.load_from_file(msg_path, package)
694 
695  s = StringIO()
696  write_begin(s, spec, msg_path)
698  write_includes(s, spec)
699 
700  cpp_prefix = '%s::'%(package)
701 
702  s.write('namespace %s\n{\n'%(package))
703  write_struct(s, spec, cpp_prefix)
705  write_ostream_operator(s, spec, cpp_prefix)
706  s.write('} // namespace %s\n\n'%(package))
707 
708  rospack = RosPack()
709  write_traits(s, spec, cpp_prefix, rospack=rospack)
710  write_serialization(s, spec, cpp_prefix)
711  write_operations(s, spec, cpp_prefix)
712 
713  # HACK HACK HACK. The moving of roslib/Header causes many problems. We end up having to make roslib/Header act exactly
714  # like std_msgs/Header (as in, constructor that takes it, as well as operator std_msgs::Header()), and it needs to be
715  # available wherever std_msgs/Header.h has been included
716  if (package == "std_msgs" and spec.short_name == "Header"):
717  s.write("#define STD_MSGS_INCLUDING_HEADER_DEPRECATED_DEF 1\n")
718  s.write("#include <std_msgs/header_deprecated_def.h>\n")
719  s.write("#undef STD_MSGS_INCLUDING_HEADER_DEPRECATED_DEF\n\n")
720 
721  write_end(s, spec)
722 
723  output_dir = '%s/msg_gen/cpp/include/%s'%(package_dir, package)
724  if (not os.path.exists(output_dir)):
725  # if we're being run concurrently, the above test can report false but os.makedirs can still fail if
726  # another copy just created the directory
727  try:
728  os.makedirs(output_dir)
729  except OSError as e:
730  pass
731 
732  f = open('%s/%s.h'%(output_dir, spec.short_name), 'w')
733  f.write(s.getvalue() + "\n")
734 
735  s.close()
736 
738  for arg in argv[1:]:
739  generate(arg)
740 
741 if __name__ == "__main__":
742  roslib.msgs.set_verbose(False)
743  generate_messages(sys.argv)
744 
def write_initializer_list(s, spec, container_gets_allocator)
Definition: msg_gen.py:247
def write_serialization(s, spec, cpp_name_prefix)
Definition: msg_gen.py:650
def default_value(type)
Definition: msg_gen.py:217
def write_constant_declaration(s, constant)
Definition: msg_gen.py:371
def write_constant_declarations(s, spec)
Definition: msg_gen.py:387
def write_constant_definition(s, spec, constant)
Definition: msg_gen.py:399
def write_constant_definitions(s, spec)
Definition: msg_gen.py:415
def write_begin(s, spec, file)
Definition: msg_gen.py:115
def write_member(s, field)
Definition: msg_gen.py:340
def write_members(s, spec)
Definition: msg_gen.py:355
def write_generic_includes(s)
Definition: msg_gen.py:141
def msg_type_to_cpp(type)
Definition: msg_gen.py:65
def write_constructors(s, spec, cpp_name_prefix)
Definition: msg_gen.py:312
def write_deprecated_member_functions(s, spec, traits)
Definition: msg_gen.py:456
def is_fixed_length(spec)
Definition: msg_gen.py:427
ROSCPP_DECL void set(const std::string &key, const XmlRpc::XmlRpcValue &v)
Set an arbitrary XML/RPC value on the parameter server.
Definition: param.cpp:67
def write_end(s, spec)
Definition: msg_gen.py:130
def write_traits(s, spec, cpp_name_prefix, datatype=None, rospack=None)
Definition: msg_gen.py:573
def generate(msg_path)
Definition: msg_gen.py:685
def write_operations(s, spec, cpp_name_prefix)
Definition: msg_gen.py:615
def write_ostream_operator(s, spec, cpp_name_prefix)
Definition: msg_gen.py:680
def is_hex_string(str)
Definition: msg_gen.py:515
def compute_full_text_escaped(gen_deps_dict)
Definition: msg_gen.py:494
def escape_string(str)
Definition: msg_gen.py:366
def write_includes(s, spec)
Definition: msg_gen.py:159
def write_trait_char_class(s, class_name, cpp_msg_with_alloc, value, write_static_hex_value=False)
Definition: msg_gen.py:522
def write_fixed_length_assigns(s, spec, container_gets_allocator, cpp_name_prefix)
Definition: msg_gen.py:281
def takes_allocator(type)
Definition: msg_gen.py:235
def cpp_message_declarations(name_prefix, msg)
Definition: msg_gen.py:97
def write_trait_true_class(s, class_name, cpp_msg_with_alloc)
Definition: msg_gen.py:560
def write_struct(s, spec, cpp_name_prefix, extra_deprecated_traits={})
Definition: msg_gen.py:180
def generate_messages(argv)
Definition: msg_gen.py:737


roscpp
Author(s): Morgan Quigley, Josh Faust, Brian Gerkey, Troy Straszheim, Dirk Thomas
autogenerated on Mon Feb 28 2022 23:33:27