make_library.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 #####################################################################
4 # Software License Agreement (BSD License)
5 #
6 # Copyright (c) 2011, Willow Garage, Inc.
7 # All rights reserved.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 #
13 # * Redistributions of source code must retain the above copyright
14 # notice, this list of conditions and the following disclaimer.
15 # * Redistributions in binary form must reproduce the above
16 # copyright notice, this list of conditions and the following
17 # disclaimer in the documentation and/or other materials provided
18 # with the distribution.
19 # * Neither the name of Willow Garage, Inc. nor the names of its
20 # contributors may be used to endorse or promote products derived
21 # from this software without specific prior written permission.
22 #
23 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 # POSSIBILITY OF SUCH DAMAGE.
35 
36 from __future__ import print_function
37 
38 __author__ = "mferguson@willowgarage.com (Michael Ferguson)"
39 
40 import roslib
41 import roslib.srvs
42 import roslib.message
43 import traceback
44 
45 import os, sys, re
46 
47 # for copying files
48 import shutil
49 
50 def type_to_var(ty):
51  lookup = {
52  1 : 'uint8_t',
53  2 : 'uint16_t',
54  4 : 'uint32_t',
55  8 : 'uint64_t',
56  }
57  return lookup[ty]
58 
59 #####################################################################
60 # Data Types
61 
63  """ For data values. """
64 
65  def __init__(self, name, ty, value):
66  self.name = name
67  self.type = ty
68  self.value = value
69 
70  def make_declaration(self, f):
71  f.write(' enum { %s = %s };\n' % (self.name, self.value))
72 
74  """ Our datatype is a C/C++ primitive. """
75 
76  def __init__(self, name, ty, bytes):
77  self.name = name
78  self.type = ty
79  self.bytes = bytes
80 
81  def make_initializer(self, f, trailer):
82  f.write(' %s(0)%s\n' % (self.name, trailer))
83 
84  def make_declaration(self, f):
85  f.write(' typedef %s _%s_type;\n _%s_type %s;\n' % (self.type, self.name, self.name, self.name) )
86 
87  def serialize(self, f):
88  cn = self.name.replace("[","").replace("]","").split(".")[-1]
89  if self.type != type_to_var(self.bytes):
90  f.write(' union {\n')
91  f.write(' %s real;\n' % self.type)
92  f.write(' %s base;\n' % type_to_var(self.bytes))
93  f.write(' } u_%s;\n' % cn)
94  f.write(' u_%s.real = this->%s;\n' % (cn,self.name))
95  for i in range(self.bytes):
96  f.write(' *(outbuffer + offset + %d) = (u_%s.base >> (8 * %d)) & 0xFF;\n' % (i, cn, i) )
97  else:
98  for i in range(self.bytes):
99  f.write(' *(outbuffer + offset + %d) = (this->%s >> (8 * %d)) & 0xFF;\n' % (i, self.name, i) )
100  f.write(' offset += sizeof(this->%s);\n' % self.name)
101 
102  def deserialize(self, f):
103  cn = self.name.replace("[","").replace("]","").split(".")[-1]
104  if self.type != type_to_var(self.bytes):
105  f.write(' union {\n')
106  f.write(' %s real;\n' % self.type)
107  f.write(' %s base;\n' % type_to_var(self.bytes))
108  f.write(' } u_%s;\n' % cn)
109  f.write(' u_%s.base = 0;\n' % cn)
110  for i in range(self.bytes):
111  f.write(' u_%s.base |= ((%s) (*(inbuffer + offset + %d))) << (8 * %d);\n' % (cn,type_to_var(self.bytes),i,i) )
112  f.write(' this->%s = u_%s.real;\n' % (self.name, cn) )
113  else:
114  f.write(' this->%s = ((%s) (*(inbuffer + offset)));\n' % (self.name,self.type) )
115  for i in range(self.bytes-1):
116  f.write(' this->%s |= ((%s) (*(inbuffer + offset + %d))) << (8 * %d);\n' % (self.name,self.type,i+1,i+1) )
117  f.write(' offset += sizeof(this->%s);\n' % self.name)
118 
119 
121  """ For when our data type is another message. """
122 
123  def make_initializer(self, f, trailer):
124  f.write(' %s()%s\n' % (self.name, trailer))
125 
126  def serialize(self, f):
127  f.write(' offset += this->%s.serialize(outbuffer + offset);\n' % self.name)
128 
129  def deserialize(self, f):
130  f.write(' offset += this->%s.deserialize(inbuffer + offset);\n' % self.name)
131 
132 
134  """ AVR C/C++ has no native 64-bit support, we automatically convert to 32-bit float. """
135 
136  def make_initializer(self, f, trailer):
137  f.write(' %s(0)%s\n' % (self.name, trailer))
138 
139  def make_declaration(self, f):
140  f.write(' typedef float _%s_type;\n _%s_type %s;\n' % (self.name, self.name, self.name) )
141 
142  def serialize(self, f):
143  f.write(' offset += serializeAvrFloat64(outbuffer + offset, this->%s);\n' % self.name)
144 
145  def deserialize(self, f):
146  f.write(' offset += deserializeAvrFloat64(inbuffer + offset, &(this->%s));\n' % self.name)
147 
148 
150  """ Need to convert to signed char *. """
151 
152  def make_initializer(self, f, trailer):
153  f.write(' %s("")%s\n' % (self.name, trailer))
154 
155  def make_declaration(self, f):
156  f.write(' typedef const char* _%s_type;\n _%s_type %s;\n' % (self.name, self.name, self.name) )
157 
158  def serialize(self, f):
159  cn = self.name.replace("[","").replace("]","")
160  f.write(' uint32_t length_%s = strlen(this->%s);\n' % (cn,self.name))
161  f.write(' varToArr(outbuffer + offset, length_%s);\n' % cn)
162  f.write(' offset += 4;\n')
163  f.write(' memcpy(outbuffer + offset, this->%s, length_%s);\n' % (self.name,cn))
164  f.write(' offset += length_%s;\n' % cn)
165 
166  def deserialize(self, f):
167  cn = self.name.replace("[","").replace("]","")
168  f.write(' uint32_t length_%s;\n' % cn)
169  f.write(' arrToVar(length_%s, (inbuffer + offset));\n' % cn)
170  f.write(' offset += 4;\n')
171  f.write(' for(unsigned int k= offset; k< offset+length_%s; ++k){\n'%cn) #shift for null character
172  f.write(' inbuffer[k-1]=inbuffer[k];\n')
173  f.write(' }\n')
174  f.write(' inbuffer[offset+length_%s-1]=0;\n'%cn)
175  f.write(' this->%s = (char *)(inbuffer + offset-1);\n' % self.name)
176  f.write(' offset += length_%s;\n' % cn)
177 
178 
180 
181  def __init__(self, name, ty, bytes):
182  self.name = name
183  self.type = ty
184  self.sec = PrimitiveDataType(name+'.sec','uint32_t',4)
185  self.nsec = PrimitiveDataType(name+'.nsec','uint32_t',4)
186 
187  def make_initializer(self, f, trailer):
188  f.write(' %s()%s\n' % (self.name, trailer))
189 
190  def make_declaration(self, f):
191  f.write(' typedef %s _%s_type;\n _%s_type %s;\n' % (self.type, self.name, self.name, self.name) )
192 
193  def serialize(self, f):
194  self.sec.serialize(f)
195  self.nsec.serialize(f)
196 
197  def deserialize(self, f):
198  self.sec.deserialize(f)
199  self.nsec.deserialize(f)
200 
201 
203 
204  def __init__(self, name, ty, bytes, cls, array_size=None):
205  self.name = name
206  self.type = ty
207  self.bytes = bytes
208  self.size = array_size
209  self.cls = cls
210 
211  def make_initializer(self, f, trailer):
212  if self.size == None:
213  f.write(' %s_length(0), %s(NULL)%s\n' % (self.name, self.name, trailer))
214  else:
215  f.write(' %s()%s\n' % (self.name, trailer))
216 
217  def make_declaration(self, f):
218  if self.size == None:
219  f.write(' uint32_t %s_length;\n' % self.name)
220  f.write(' typedef %s _%s_type;\n' % (self.type, self.name))
221  f.write(' _%s_type st_%s;\n' % (self.name, self.name)) # static instance for copy
222  f.write(' _%s_type * %s;\n' % (self.name, self.name))
223  else:
224  f.write(' %s %s[%d];\n' % (self.type, self.name, self.size))
225 
226  def serialize(self, f):
227  c = self.cls(self.name+"[i]", self.type, self.bytes)
228  if self.size == None:
229  # serialize length
230  f.write(' *(outbuffer + offset + 0) = (this->%s_length >> (8 * 0)) & 0xFF;\n' % self.name)
231  f.write(' *(outbuffer + offset + 1) = (this->%s_length >> (8 * 1)) & 0xFF;\n' % self.name)
232  f.write(' *(outbuffer + offset + 2) = (this->%s_length >> (8 * 2)) & 0xFF;\n' % self.name)
233  f.write(' *(outbuffer + offset + 3) = (this->%s_length >> (8 * 3)) & 0xFF;\n' % self.name)
234  f.write(' offset += sizeof(this->%s_length);\n' % self.name)
235  f.write(' for( uint32_t i = 0; i < %s_length; i++){\n' % self.name)
236  c.serialize(f)
237  f.write(' }\n')
238  else:
239  f.write(' for( uint32_t i = 0; i < %d; i++){\n' % (self.size) )
240  c.serialize(f)
241  f.write(' }\n')
242 
243  def deserialize(self, f):
244  if self.size == None:
245  c = self.cls("st_"+self.name, self.type, self.bytes)
246  # deserialize length
247  f.write(' uint32_t %s_lengthT = ((uint32_t) (*(inbuffer + offset))); \n' % self.name)
248  f.write(' %s_lengthT |= ((uint32_t) (*(inbuffer + offset + 1))) << (8 * 1); \n' % self.name)
249  f.write(' %s_lengthT |= ((uint32_t) (*(inbuffer + offset + 2))) << (8 * 2); \n' % self.name)
250  f.write(' %s_lengthT |= ((uint32_t) (*(inbuffer + offset + 3))) << (8 * 3); \n' % self.name)
251  f.write(' offset += sizeof(this->%s_length);\n' % self.name)
252  f.write(' if(%s_lengthT > %s_length)\n' % (self.name, self.name))
253  f.write(' this->%s = (%s*)realloc(this->%s, %s_lengthT * sizeof(%s));\n' % (self.name, self.type, self.name, self.name, self.type))
254  f.write(' %s_length = %s_lengthT;\n' % (self.name, self.name))
255  # copy to array
256  f.write(' for( uint32_t i = 0; i < %s_length; i++){\n' % (self.name) )
257  c.deserialize(f)
258  f.write(' memcpy( &(this->%s[i]), &(this->st_%s), sizeof(%s));\n' % (self.name, self.name, self.type))
259  f.write(' }\n')
260  else:
261  c = self.cls(self.name+"[i]", self.type, self.bytes)
262  f.write(' for( uint32_t i = 0; i < %d; i++){\n' % (self.size) )
263  c.deserialize(f)
264  f.write(' }\n')
265 
266 #####################################################################
267 # Messages
268 
269 class Message:
270  """ Parses message definitions into something we can export. """
271  global ROS_TO_EMBEDDED_TYPES
272 
273  def __init__(self, name, package, definition, md5):
274 
275  self.name = name # name of message/class
276  self.package = package # package we reside in
277  self.md5 = md5 # checksum
278  self.includes = list() # other files we must include
279 
280  self.data = list() # data types for code generation
281  self.enums = list()
282 
283  # parse definition
284  for line in definition:
285  # prep work
286  line = line.strip().rstrip()
287  value = None
288  if line.find("#") > -1:
289  line = line[0:line.find("#")]
290  if line.find("=") > -1:
291  try:
292  value = line[line.find("=")+1:]
293  except:
294  value = '"' + line[line.find("=")+1:] + '"';
295  line = line[0:line.find("=")]
296 
297  # find package/class name
298  line = line.replace("\t", " ")
299  l = line.split(" ")
300  while "" in l:
301  l.remove("")
302  if len(l) < 2:
303  continue
304  ty, name = l[0:2]
305  if value != None:
306  self.enums.append( EnumerationType(name, ty, value))
307  continue
308 
309  try:
310  type_package, type_name = ty.split("/")
311  except:
312  type_package = None
313  type_name = ty
314  type_array = False
315  if type_name.find('[') > 0:
316  type_array = True
317  try:
318  type_array_size = int(type_name[type_name.find('[')+1:type_name.find(']')])
319  except:
320  type_array_size = None
321  type_name = type_name[0:type_name.find('[')]
322 
323  # convert to C type if primitive, expand name otherwise
324  try:
325  code_type = ROS_TO_EMBEDDED_TYPES[type_name][0]
326  size = ROS_TO_EMBEDDED_TYPES[type_name][1]
327  cls = ROS_TO_EMBEDDED_TYPES[type_name][2]
328  for include in ROS_TO_EMBEDDED_TYPES[type_name][3]:
329  if include not in self.includes:
330  self.includes.append(include)
331  except:
332  if type_package == None:
333  type_package = self.package
334  if type_package+"/"+type_name not in self.includes:
335  self.includes.append(type_package+"/"+type_name)
336  cls = MessageDataType
337  code_type = type_package + "::" + type_name
338  size = 0
339  if type_array:
340  self.data.append( ArrayDataType(name, code_type, size, cls, type_array_size ) )
341  else:
342  self.data.append( cls(name, code_type, size) )
343 
344  def _write_serializer(self, f):
345  # serializer
346  f.write(' virtual int serialize(unsigned char *outbuffer) const\n')
347  f.write(' {\n')
348  f.write(' int offset = 0;\n')
349  for d in self.data:
350  d.serialize(f)
351  f.write(' return offset;\n');
352  f.write(' }\n')
353  f.write('\n')
354 
355  def _write_deserializer(self, f):
356  # deserializer
357  f.write(' virtual int deserialize(unsigned char *inbuffer)\n')
358  f.write(' {\n')
359  f.write(' int offset = 0;\n')
360  for d in self.data:
361  d.deserialize(f)
362  f.write(' return offset;\n');
363  f.write(' }\n')
364  f.write('\n')
365 
366  def _write_std_includes(self, f):
367  f.write('#include <stdint.h>\n')
368  f.write('#include <string.h>\n')
369  f.write('#include <stdlib.h>\n')
370  f.write('#include "ros/msg.h"\n')
371 
372  def _write_msg_includes(self,f):
373  for i in self.includes:
374  f.write('#include "%s.h"\n' % i)
375 
376  def _write_constructor(self, f):
377  f.write(' %s()%s\n' % (self.name, ':' if self.data else ''))
378  if self.data:
379  for d in self.data[:-1]:
380  d.make_initializer(f, ',')
381  self.data[-1].make_initializer(f, '')
382  f.write(' {\n }\n\n')
383 
384  def _write_data(self, f):
385  for d in self.data:
386  d.make_declaration(f)
387  for e in self.enums:
388  e.make_declaration(f)
389  f.write('\n')
390 
391  def _write_getType(self, f):
392  f.write(' const char * getType(){ return "%s/%s"; };\n'%(self.package, self.name))
393 
394  def _write_getMD5(self, f):
395  f.write(' const char * getMD5(){ return "%s"; };\n'%self.md5)
396 
397  def _write_impl(self, f):
398  f.write(' class %s : public ros::Msg\n' % self.name)
399  f.write(' {\n')
400  f.write(' public:\n')
401  self._write_data(f)
402  self._write_constructor(f)
403  self._write_serializer(f)
404  self._write_deserializer(f)
405  self._write_getType(f)
406  self._write_getMD5(f)
407  f.write('\n')
408  f.write(' };\n')
409 
410  def make_header(self, f):
411  f.write('#ifndef _ROS_%s_%s_h\n'%(self.package, self.name))
412  f.write('#define _ROS_%s_%s_h\n'%(self.package, self.name))
413  f.write('\n')
414  self._write_std_includes(f)
415  self._write_msg_includes(f)
416 
417  f.write('\n')
418  f.write('namespace %s\n' % self.package)
419  f.write('{\n')
420  f.write('\n')
421  self._write_impl(f)
422  f.write('\n')
423  f.write('}\n')
424 
425  f.write('#endif\n')
426 
427 class Service:
428  def __init__(self, name, package, definition, md5req, md5res):
429  """
430  @param name - name of service
431  @param package - name of service package
432  @param definition - list of lines of definition
433  """
434 
435  self.name = name
436  self.package = package
437 
438  sep_line = len(definition)
439  sep = re.compile('---*')
440  for i in range(0, len(definition)):
441  if (None!= re.match(sep, definition[i]) ):
442  sep_line = i
443  break
444  self.req_def = definition[0:sep_line]
445  self.resp_def = definition[sep_line+1:]
446 
447  self.req = Message(name+"Request", package, self.req_def, md5req)
448  self.resp = Message(name+"Response", package, self.resp_def, md5res)
449 
450  def make_header(self, f):
451  f.write('#ifndef _ROS_SERVICE_%s_h\n' % self.name)
452  f.write('#define _ROS_SERVICE_%s_h\n' % self.name)
453 
454  self.req._write_std_includes(f)
455  includes = self.req.includes
456  includes.extend(self.resp.includes)
457  includes = list(set(includes))
458  for inc in includes:
459  f.write('#include "%s.h"\n' % inc)
460 
461  f.write('\n')
462  f.write('namespace %s\n' % self.package)
463  f.write('{\n')
464  f.write('\n')
465  f.write('static const char %s[] = "%s/%s";\n'%(self.name.upper(), self.package, self.name))
466 
467  def write_type(out, name):
468  out.write(' const char * getType(){ return %s; };\n'%(name))
469  _write_getType = lambda out: write_type(out, self.name.upper())
470  self.req._write_getType = _write_getType
471  self.resp._write_getType = _write_getType
472 
473  f.write('\n')
474  self.req._write_impl(f)
475  f.write('\n')
476  self.resp._write_impl(f)
477  f.write('\n')
478  f.write(' class %s {\n' % self.name )
479  f.write(' public:\n')
480  f.write(' typedef %s Request;\n' % self.req.name )
481  f.write(' typedef %s Response;\n' % self.resp.name )
482  f.write(' };\n')
483  f.write('\n')
484 
485  f.write('}\n')
486 
487  f.write('#endif\n')
488 
489 
490 #####################################################################
491 # Make a Library
492 
493 def MakeLibrary(package, output_path, rospack):
494  pkg_dir = rospack.get_path(package)
495 
496  # find the messages in this package
497  messages = list()
498  if os.path.exists(pkg_dir+"/msg"):
499  print('Exporting %s\n'%package)
500  sys.stdout.write(' Messages:')
501  sys.stdout.write('\n ')
502  for f in os.listdir(pkg_dir+"/msg"):
503  if f.endswith(".msg"):
504  msg_file = pkg_dir + "/msg/" + f
505  # add to list of messages
506  print('%s,'%f[0:-4], end='')
507  definition = open(msg_file).readlines()
508  msg_class = roslib.message.get_message_class(package+'/'+f[0:-4])
509  if msg_class:
510  md5sum = msg_class._md5sum
511  messages.append( Message(f[0:-4], package, definition, md5sum) )
512  else:
513  err_msg = "Unable to build message: %s/%s\n" % (package, f[0:-4])
514  sys.stderr.write(err_msg)
515 
516  # find the services in this package
517  if (os.path.exists(pkg_dir+"/srv/")):
518  if messages == list():
519  print('Exporting %s\n'%package)
520  else:
521  print('\n')
522  sys.stdout.write(' Services:')
523  sys.stdout.write('\n ')
524  for f in os.listdir(pkg_dir+"/srv"):
525  if f.endswith(".srv"):
526  srv_file = pkg_dir + "/srv/" + f
527  # add to list of messages
528  print('%s,'%f[0:-4], end='')
529  definition, service = roslib.srvs.load_from_file(srv_file)
530  definition = open(srv_file).readlines()
531  srv_class = roslib.message.get_service_class(package+'/'+f[0:-4])
532  if srv_class:
533  md5req = srv_class._request_class._md5sum
534  md5res = srv_class._response_class._md5sum
535  messages.append( Service(f[0:-4], package, definition, md5req, md5res ) )
536  else:
537  err_msg = "Unable to build service: %s/%s\n" % (package, f[0:-4])
538  sys.stderr.write(err_msg)
539  print('\n')
540  elif messages != list():
541  print('\n')
542 
543  # generate for each message
544  output_path = output_path + "/" + package
545  for msg in messages:
546  if not os.path.exists(output_path):
547  os.makedirs(output_path)
548  header = open(output_path + "/" + msg.name + ".h", "w")
549  msg.make_header(header)
550  header.close()
551 
552 def rosserial_generate(rospack, path, mapping):
553  # horrible hack -- make this die
554  global ROS_TO_EMBEDDED_TYPES
555  ROS_TO_EMBEDDED_TYPES = mapping
556 
557  # gimme messages
558  failed = []
559  for p in sorted(rospack.list()):
560  try:
561  MakeLibrary(p, path, rospack)
562  except Exception as e:
563  failed.append(p + " ("+str(e)+")")
564  print('[%s]: Unable to build messages: %s\n' % (p, str(e)))
565  print(traceback.format_exc())
566  print('\n')
567  if len(failed) > 0:
568  print('*** Warning, failed to generate libraries for the following packages: ***')
569  for f in failed:
570  print(' %s'%f)
571  raise Exception("Failed to generate libraries for: " + str(failed))
572  print('\n')
573 
574 def rosserial_client_copy_files(rospack, path):
575  os.makedirs(path+"/ros")
576  os.makedirs(path+"/tf")
577  files = ['duration.cpp',
578  'time.cpp',
579  'ros/duration.h',
580  'ros/msg.h',
581  'ros/node_handle.h',
582  'ros/publisher.h',
583  'ros/service_client.h',
584  'ros/service_server.h',
585  'ros/subscriber.h',
586  'ros/time.h',
587  'tf/tf.h',
588  'tf/transform_broadcaster.h']
589  mydir = rospack.get_path("rosserial_client")
590  for f in files:
591  shutil.copy(mydir+"/src/ros_lib/"+f, path+f)
592 
def __init__(self, name, ty, bytes)
def MakeLibrary(package, output_path, rospack)
def rosserial_generate(rospack, path, mapping)
def __init__(self, name, ty, bytes, cls, array_size=None)
def __init__(self, name, package, definition, md5)
def __init__(self, name, package, definition, md5req, md5res)
def rosserial_client_copy_files(rospack, path)


rosserial_client
Author(s): Michael Ferguson, Adam Stambler
autogenerated on Mon Jun 10 2019 14:53:19