rtc-template.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- python -*-
00003 #
00004 #  @file rtc-template
00005 #  @brief rtc-template RTComponent source code generator tool
00006 #  @date $Date: 2007/07/23 08:06:27 $
00007 #  @author Noriaki Ando <n-ando@aist.go.jp>
00008 # 
00009 #  Copyright (C) 2004-2007
00010 #      Task-intelligence Research Group,
00011 #      Intelligent Systems Research Institute,
00012 #      National Institute of
00013 #          Advanced Industrial Science and Technology (AIST), Japan
00014 #      All rights reserved.
00015 # 
00016 #  $Id: rtc-template,v 1.8.2.2 2007/07/23 08:06:27 n-ando Exp $
00017 #
00018 
00019 #
00020 #  $Log: rtc-template,v $
00021 #  Revision 1.8.2.2  2007/07/23 08:06:27  n-ando
00022 #  Modified for win32 porting about rtm-config.
00023 #
00024 #  Revision 1.8.2.1  2007/07/20 17:29:03  n-ando
00025 #  A fix for win32 porting.
00026 #
00027 #  Revision 1.8  2007/04/27 00:56:35  n-ando
00028 #  Example shown in help message was modified for new version.
00029 #
00030 #  Revision 1.7  2007/04/23 07:31:28  n-ando
00031 #  Now "--conf" option can accept scope resolution operator of C++.
00032 #
00033 #  Revision 1.6  2007/04/23 01:41:21  n-ando
00034 #  New option "--config" and configuration template code were added.
00035 #
00036 #  Revision 1.5  2007/01/11 07:42:25  n-ando
00037 #  Modified for OMG RTC specificatin and OpenRTM-aist-0.4.0
00038 #  - Some command option was chaged and removed.
00039 #  - Now empty Struct class is used instead of *Profile classes for ezt dict.
00040 #  - Some bugs were fixed.
00041 #
00042 #  Revision 1.4  2005/09/08 09:24:18  n-ando
00043 #  - A bug fix for merge function.
00044 #
00045 #  Revision 1.3  2005/09/06 14:37:40  n-ando
00046 #  rtc-template's command options and data structure for ezt (Easy Template)
00047 #  are changed for RTComponent's service features.
00048 #  Now rtc-template can generate services' skeletons, stubs and
00049 #  implementation files.
00050 #  The implementation code generation uses omniidl's IDL parser.
00051 #
00052 #  Revision 1.2  2005/08/26 11:32:26  n-ando
00053 #  "rtc-template" was completely rewritten to use ezt (Easy Template) module.
00054 #  "ezt" module is originally included in "Subversion".
00055 #
00056 #  Now template code generator modules, which are named xxx_gen.py, are
00057 #  automatically imported from rtc-template, and command options and help
00058 #  menu are automatically generated.
00059 #
00060 #  New template code generator has to inherit base_gen class in
00061 #  "base_gen.py" module to utilize this framework.
00062 #
00063 #  Revision 1.1.1.1  2005/05/12 09:06:18  n-ando
00064 #  Public release.
00065 #
00066 #
00067 
00068 import getopt, sys
00069 import re
00070 import os
00071 
00072 platform = sys.platform
00073 
00074 class Struct:
00075   def __init__(self):
00076     return
00077 
00078 conf_path = ['']
00079 
00080 if platform == "win32":
00081   python_path = os.environ['PYTHONPATH'].split(";")
00082   pyhelper_path = python_path[0] + "\\OpenRTM_aist\\utils\\rtc-template"
00083 else:
00084   conf_path = os.popen("which rtm-config", "r").read().split("\n")
00085   if conf_path[0] != '':
00086     libdir_path = os.popen("rtm-config --libdir", "r").read().split("\n")
00087     pyhelper_path = libdir_path[0] + "/py_helper"
00088   else:
00089     python_path = os.environ['PYTHONPATH'].split(":")
00090     pyhelper_path = python_path[0] + "/OpenRTM_aist/utils/rtc-template"
00091 sys.path.append(pyhelper_path)
00092 
00093 # Option format
00094 opt_args_fmt = ["help",
00095     "module-name=",
00096     "module-type=",
00097     "module-desc=",
00098     "module-version=",
00099     "module-vendor=",
00100     "module-category=",
00101     "module-comp-type=",
00102     "module-act-type=",
00103     "module-max-inst=",
00104     "module-lang=",
00105                 "config=",
00106     "inport=",
00107     "outport=",
00108     "service=",
00109     "service-idl=",
00110     "consumer=",
00111     "consumer-idl=",
00112     "idl-include=",
00113     "backend="]
00114 
00115 
00116 def usage_short():
00117   """
00118   Help message
00119   """
00120   print """
00121 Usage: rtc-template [OPTIONS]
00122 
00123 Options:
00124 
00125     [-h]                                  Print short help.
00126     [--help]                              Print details help.
00127     [--backend[=backend] or -b]           Specify template code generator.
00128     [--module-name[=name]]                Your module name.
00129     [--module-desc[=description]]         Module description.
00130     [--module-version[=version]]          Module version.
00131     [--module-vendor[=vendor]]            Module vendor.
00132     [--module-category[=category]]        Module category.
00133     [--module-comp-type[=component_type]] Component type.
00134     [--module-act-type[=activity_type]]   Component's activity type.
00135     [--module-max-inst[=max_instance]]    Number of maximum instance.
00136     [--module-lang[=language]]            Language.
00137     [--config[=ParamName:Type:Default]]   Configuration variable.
00138     [--inport[=PortName:Type]]            InPort's name and type.
00139     [--outport[=PortName:Type]]           OutPort's name and type
00140     [--service[=PortName:Name:Type]]      Service Provider Port
00141     [--service-idl[=IDL_file]]            IDL file name for service
00142     [--consumer[=PortName:Name:Type]]     Service Consumer Port
00143     [--consumer-idl[=IDL_file]]           IDL file name for consumer
00144     [--idl-include=[path]]                Search path for IDL compile
00145 
00146 """
00147 def usage_long():
00148   """
00149   Help message
00150   """
00151   print """
00152     --output[=output_file]:
00153         Specify base name of output file. If 'XXX' is specified,
00154         C++ source codes XXX.cpp, XXX.h, XXXComp.cpp Makefile.XXX is generated.
00155 
00156     --module-name[=name]:
00157         Your component's base name. This string is used as module's
00158         name and component's base name. A generated new component
00159         class name is also names as this RTC_MODULE_NAME.
00160         Only alphabetical and numerical characters are acceptable.
00161 
00162     --module-desc[=description]:
00163         Short description. If space characters are included, string should be
00164         quoted.
00165 
00166     --module-version[=version]:
00167         Your module version. ex. 1.0.0
00168 
00169     --module-vendor[=vendor]:
00170         Vendor's name of this component.
00171 
00172     --module-category[=category]:
00173         This component module's category. ex. Manipulator MobileRobot, etc...
00174 
00175     --module-comp-type[=component_type]:
00176         Specify component type.
00177       'STATIC', 'UNIQUE', 'COMMUTATIVE' are acceptable.
00178 
00179     --module-act-type[=activity_type]:
00180         Specify component activity's type.
00181         'PERIODIC', 'SPORADIC', 'EVENT_DRIVEN' ace acceptable.
00182 
00183     --module-max-inst[=max_instance]:
00184         Specify maximum number of component instance.
00185 
00186     --config=[ParamName:Type:Default]:
00187         Specify configuration value. The 'ParamName' is used as the
00188         configuration value identifier. This character string is also used as
00189         variable name in the source code. The 'Type' is type of configuration
00190         value. The type that can be converted to character string is allowed.
00191         In C++ language, the type should have operators '<<' and '>>' that
00192         are defined as
00193         'istream& operator<<(Type)'
00194         and
00195         'ostream& operator>>(Type)'.
00196 
00197     --inport=[PortName:Type]:
00198         Specify InPort's name and type. 'PortName' is used as this InPort's
00199         name. This string is also used as variable name in soruce code.
00200         'Type' is InPort's variable type. The acceptable types are,
00201         Timed[ Short | Long | UShort | ULong | Float | Double | Char | Boolean
00202         | Octet | String ] and its sequence types.
00203 
00204     --outport=[PortName:Type]:
00205         Specify OutPort's name and type. 'PortName' is used as this OutPort's
00206         name. This string is also used as variable name in soruce code.
00207         'Type' is OutPort's variable type. The acceptable types are,
00208         Timed[ Short | Long | UShort | ULong | Float | Double | Char | Boolean
00209         | Octet | String ] and its sequence types.
00210     
00211     --service=[PortName:Name:Type]:
00212         Specify service name, type and port name.
00213         PortName: The name of Port to which the interface belongs.
00214               This name is used as CorbaPort's name.
00215         Name: The name of the service interface. This name is used as 
00216               the name of the interface, instance name and variable name.
00217         Type: The type of the serivce interface.
00218               This name is used as type name of the service.
00219 
00220     --service-idl=[IDL filename]:
00221         Specify IDL file of service interface.
00222         For simplicity, please define one interface in one IDL file, although
00223         this IDL file can include two or more interface definition,
00224     
00225     --consumer=[PortName:Name:Type]:
00226         Specify consumer name, type and port name.
00227         PortName: The name of Port to which the consumer belongs.
00228               This name is used as CorbaPort's name.
00229         Name: The name of the consumer. This name is used as 
00230               the name of the consumer, instance name and variable name.
00231         Type: The serivce interface type that is required by the consumer.
00232               This name is used as type name of the consumer.
00233 
00234     --consumer-idl=[IDL filename]:
00235         Specify IDL file of service consumer.
00236         For simplicity, please define one interface in one IDL file, although
00237         this IDL file can include two or more interface definition,
00238   
00239 
00240 Example:
00241     rtc-template -bcxx \\
00242     --module-name=Sample --module-desc='Sample component' \\
00243     --module-version=0.1 --module-vendor=AIST --module-category=Generic \\
00244     --module-comp-type=DataFlowComponent --module-act-type=SPORADIC \\
00245     --module-max-inst=10  \\
00246     --config=int_param0:int:0 --config=int_param1:int:1 \\
00247     --config=double_param0:double:3.14 --config=double_param1:double:9.99 \\
00248     --config="str_param0:std::string:hoge" \\
00249     --config="str_param1:std::string:foo" \\
00250     --inport=Ref:TimedFloat --inport=Sens:TimedFloat \\
00251     --outport=Ctrl:TimedDouble --outport=Monitor:TimedShort \\
00252     --service=MySvcPort:myservice0:MyService \\
00253     --consumer=YourSvcPort:yourservice0:YourService \\
00254     --service-idl=MyService.idl --consumer-idl=YourService.idl
00255 
00256 """
00257   return
00258 
00259 def usage():
00260   usage_short()
00261   usage_long()
00262   return
00263 
00264 class ModuleProfile:
00265   """
00266   ModuleProfile class
00267 
00268   This class create RTM module profile for ezt.
00269   """
00270   
00271   def __init__(self, name="", desc="", type="", version="", vendor="",
00272          category="", comp_type="", act_type="",
00273          max_inst="", lang=""):
00274 
00275     self.name = name
00276     self.desc = desc
00277     self.type = type
00278     self.version = version
00279     self.vendor = vendor
00280     self.category = category
00281     self.comp_type = comp_type
00282     self.act_type = act_type
00283     self.max_inst = max_inst
00284     self.lang = lang
00285     return
00286   
00287 
00288   def setValue(self, member, value):
00289     member = member.replace("-", "_")
00290     if hasattr(self, member):
00291       setattr(self, member, value)
00292     else:
00293       print "Invalid option: --module-" + member + " " + value
00294     return
00295   
00296   def setName(self, name):
00297     self.name = name
00298     return
00299   
00300   def setDesc(self, desc):
00301     self.desc = desc
00302     return
00303   
00304   def setVersion(self, version):
00305     self.version = version
00306     return
00307   
00308   def setVendor(self, vendor):
00309     self.vendor = vendor
00310     return
00311   
00312   def setCategory(self, vategory):
00313     self.category = category
00314     return
00315 
00316   def setCompType(self, comp_type):
00317     self.comp_type = comp_type
00318     return
00319 
00320   def setActType(self, act):
00321     self.act_type = act_type
00322     return
00323 
00324   def setMaxInst(self, max_inst):
00325     self.max_inst = max_inst
00326     return
00327 
00328   def printProfile(self):
00329     print "----- Module Profile -----"
00330     print "Name           ", self.name
00331     print "Description    ", self.desc
00332     print "Version        ", self.version
00333     print "Vendor         ", self.vendor
00334     print "Category       ", self.category
00335     print "Component Type ", self.comp_type
00336     print "Activity Type  ", self.act_type
00337     print "Max Instancese ", self.max_inst
00338     print "Language       ", self.lang
00339     return
00340     
00341     
00342 
00343 def MakeModuleProfile(opts):
00344   """
00345   MakeModuleProfile
00346 
00347   Create ModuleProfile list from command options
00348   """
00349   prof = ModuleProfile()
00350   for opt, arg in opts:
00351     if opt.find("--module-") == 0:
00352       var = opt.replace("--module-","")
00353       prof.setValue(var, arg)
00354   return prof
00355 
00356 
00357 def MakeConfig(opts):
00358   """
00359   MakeConfigurationParameters
00360 
00361   Create Configuration list from command options
00362   """
00363   prof_list = []
00364   cnt = 0
00365   for opt, arg in opts:
00366     if opt == ("--config"):
00367       try:
00368         # For C++ scope resolution operator 
00369         arg = re.sub("::", "@@", arg)
00370         name, type, default = arg.split(":")
00371         name    = re.sub("@@", "::", name)
00372         type    = re.sub("@@", "::", type)
00373         default = re.sub("@@", "::", default)
00374       except:
00375         sys.stderr("Invalid option: " \
00376              + opt \
00377              + "=" \
00378              + arg)
00379       prof = Struct()
00380       prof.name = name
00381       prof.l_name = name.lower()
00382       prof.u_name = name.upper()
00383       prof.type = type
00384       prof.default  = default
00385       prof_list.append(prof)
00386       cnt += 1
00387   return prof_list
00388 
00389 
00390 def MakeDataPort(opts, port_type):
00391   """
00392   MakePortProfile
00393 
00394   Create PortProfile list from command options
00395   """
00396   prof_list = []
00397   cnt = 0
00398   for opt, arg in opts:
00399     if opt == ("--" + port_type):
00400       try:
00401         name, type = arg.split(":")
00402       except:
00403         sys.stderr("Invalid option: " \
00404              + opt \
00405              + "=" \
00406              + arg)
00407       prof = Struct()
00408       prof.name = name
00409       prof.type = type
00410       prof.num  = cnt
00411       prof_list.append(prof)
00412       cnt += 1
00413   return prof_list
00414 
00415 
00416 def MakePortInterface(opts, port_type):
00417   """
00418   MakePortInterface
00419 
00420   Create Port interface profile list from command options
00421   """
00422   prof_list = []
00423   cnt = 0
00424   for opt, arg in opts:
00425     if opt == "--" + port_type:
00426       try:
00427         port, name, type = arg.split(":")
00428       except:
00429         sys.stderr.write("Invalid option: " \
00430              + opt \
00431              + "=" \
00432              + arg)
00433       prof = Struct()
00434       prof.port = port
00435       prof.name = name
00436       prof.type = type
00437       prof.num  = cnt
00438       prof_list.append(prof)
00439       cnt += 1
00440   return prof_list
00441 
00442 def MakeCorbaPort(opts):
00443   """
00444   MakeCorbaPort
00445 
00446   Create Corba Port profile list from command options
00447   """
00448   prof_list = []
00449   cnt = 0
00450   for opt, arg in opts:
00451     if opt == ("--" + "service") or opt == ("--" + "consumer"):
00452       try:
00453         port, name, type = arg.split(":")
00454       except:
00455         sys.stderr.write("Invalid option: " \
00456              + opt \
00457              + "=" \
00458              + arg)
00459       dup = False
00460       for p in prof_list:
00461         if p.name == port:
00462           dup = True
00463       if dup == False:
00464         prof = Struct()
00465         prof.name = port
00466         prof.num  = cnt
00467         prof_list.append(prof)
00468         cnt += 1
00469   return prof_list
00470 
00471 
00472 
00473 def MakeServiceIDL(opts):
00474   """
00475   MakeServiceIDL
00476 
00477   Create ServiceIDL list from command options
00478   """
00479   idl_list = []
00480 
00481   for opt, arg in opts:
00482     if opt.find("--service-idl") == 0:
00483       svc_idl = Struct()
00484       svc_idl.idl_fname = arg
00485       svc_idl.idl_basename, dummy = arg.split(".")
00486       idl_list.append(svc_idl)
00487   return idl_list
00488 
00489 
00490 def MakeConsumerIDL(opts):
00491   idl_list = []
00492   for opt, arg in opts:
00493     if opt == "--consumer-idl":
00494       svc_idl = Struct()
00495       svc_idl.idl_fname = arg
00496       svc_idl.idl_basename, dummy = arg.split(".")
00497       idl_list.append(svc_idl)
00498   return idl_list
00499 
00500 
00501 
00502 def find_opt(opts, value, default):
00503   for opt, arg in opts:
00504     if opt.find(value) == 0:
00505       return arg
00506 
00507   return default
00508 
00509 
00510 def find_opt_list(opts, value, default):
00511   list = []
00512   if len(default) > 0:
00513     list += default
00514   for opt, arg in opts:
00515     if opt == ("--" + value):
00516       list.append(arg)
00517   return list
00518 
00519 
00520 class Backend:
00521   def __init__(self, mod_name, mod):
00522     self.mod = mod
00523     self.obj = getattr(mod, mod_name)
00524     self.mod_name = mod_name
00525 
00526 
00527 class BackendLoader:
00528   def __init__(self):
00529     self.backends = {}
00530     self.opts = []
00531     self.available()
00532     return
00533     
00534 
00535   def available(self):
00536     path_list = [pyhelper_path, "."]
00537     for path in path_list:
00538       for f in os.listdir(path):
00539         if re.compile("_gen.py$").search(f):
00540           mod_name = f.replace(".py", "")
00541           opt_name = f.replace("_gen.py", "")
00542           mod = __import__(mod_name, globals(), locals(), [])
00543           try:
00544             mod.usage()
00545             be = Backend(mod_name, mod)
00546             self.backends[opt_name] = be
00547           except:
00548             print "Invalid backend: ", f
00549             pass
00550 
00551     return self.backends
00552 
00553 
00554   def check_args(self, args):
00555     for opt in args:
00556       if opt.find('-b') == 0:
00557         backend_name = opt.replace("-b", "")
00558         if self.backends.has_key(backend_name):
00559           self.opts.append(backend_name)
00560         else:
00561           print "No such backend: ", backend_name
00562           sys.exit(-1)
00563       elif opt.find('--backend=') == 0:
00564         backend_name = opt.replace("--backend=", "")
00565         if self.backends.has_key(backend_name):
00566           self.opts.append(backend_name)
00567         else:
00568           print "No such backend: ", backend_name
00569           sys.exit(-1)
00570     return self.opts
00571 
00572 
00573   def get_opt_fmts(self):
00574     fmts = []
00575     for be in self.opts:
00576       fmts += self.backends[be].mod.get_opt_fmt()
00577     return fmts
00578 
00579 
00580   def usage_available(self):
00581     print "The following backends are available."
00582     space = 10
00583     for key in self.backends:
00584       desc = self.backends[key].mod.description()     
00585       print "    -b" + key + ("." * (space - len(key))) + desc
00586     print """
00587 Backend [xxx] specific help can be available by the following options.
00588     -bxxx --help|-h or --backend=xxx --help|-h
00589   """
00590     return
00591 
00592 
00593   def usage(self):
00594     for be in self.opts:
00595       print self.backends[be].mod.usage()     
00596       print ""
00597     return
00598 
00599   def usage_short(self):
00600     for be in self.opts:
00601       print self.backends[be].mod.usage_short()
00602       print ""
00603     return
00604 
00605 
00606   def generate_code(self, data, opts):
00607     for be in self.opts:
00608       self.backends[be].obj(data, opts).print_all()
00609     return
00610     
00611 
00612 def fmtd_args(width, args):
00613   arg_fmt = [""]
00614   w = 0
00615   line = 0
00616   for a in args:
00617     w += len(a) + 1
00618     if w > width:
00619       w = len(a) + 1
00620       line += 1
00621       arg_fmt.append("")
00622     arg_fmt[line] += a + " "
00623   return arg_fmt
00624 
00625 
00626 
00627 def main():
00628   global opt_args_fmt
00629   global conf_path
00630 
00631   backends = BackendLoader()
00632   backends.check_args(sys.argv[1:])
00633   opt_args_fmt += backends.get_opt_fmts()
00634 
00635   try:
00636     opts, args = getopt.getopt(sys.argv[1:], "b:ho:v", opt_args_fmt)
00637   except getopt.GetoptError:
00638     print "Error: Invalid option.", getopt.GetoptError
00639     usage_short()
00640     backends.usage_available()
00641     sys.exit(-1)
00642 
00643   if not opts:
00644     usage_short()
00645     backends.usage_available()
00646     sys.exit(-1)
00647 
00648   output = None
00649   verbose = False
00650   output_cxx = False
00651   output_python = False
00652 
00653   for o, a in opts:
00654     if o == "-v":
00655       verbose = True
00656     if o in ("-h"):
00657       usage_short()
00658       backends.usage_available()
00659       backends.usage_short()
00660       sys.exit(0)
00661     if o in ("--help"):
00662       usage()
00663       backends.usage_available()
00664       backends.usage()
00665       sys.exit(0)
00666     if o in ("-o", "--output"):
00667       output = a
00668       # ...
00669 
00670   prefix = [' ']
00671   if conf_path[0] != '':
00672     prefix = os.popen("rtm-config --prefix", "r").read().split("\n")
00673   idl_inc = []
00674   if prefix[0] != '':
00675     idl_inc.append(prefix[0] + "/include/rtm/idl")
00676     idl_inc.append(prefix[0] + "/include/rtm")
00677   idl_inc.append(".")
00678 
00679   # Create dictionary for ezt
00680   data = {
00681     'module':       MakeModuleProfile(opts),
00682                 'config':       MakeConfig(opts),
00683     'inport':       MakeDataPort(opts, "inport"),
00684     'outport':      MakeDataPort(opts, "outport"),
00685     'service':      MakePortInterface(opts, "service"),
00686     'consumer':     MakePortInterface(opts, "consumer"),
00687                 'corbaport':    MakeCorbaPort(opts),
00688     'service_idl':  MakeServiceIDL(opts),
00689     'consumer_idl': MakeConsumerIDL(opts),
00690     'idl_include':  find_opt_list(opts, "--idl-include", idl_inc),
00691     'fname':        output,
00692     'args':         sys.argv,
00693     'fmtd_args':    fmtd_args(70, sys.argv)
00694     }
00695 
00696   if data['fname'] == None:
00697     data['fname'] = data['module'].name
00698 
00699   backends.generate_code(data, opts)
00700 
00701   import README_src
00702   readme_src = README_src.README_src(data)
00703   readme_src.print_all()
00704   return
00705     
00706 
00707 if __name__ == "__main__":
00708   main()


openrtm_aist_python
Author(s): Shinji Kurihara
autogenerated on Thu Aug 27 2015 14:17:28