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 ## ROS message source code generation for C++
36 ##
37 ## Converts ROS .msg files in a package into C++ source code implementations.
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
autogenerated on Sun Aug 26 2018 03:03:33