Salome HOME
Update copyrights 2014.
[tools/yacsgen.git] / module_generator / cppcompo.py
1 # Copyright (C) 2009-2014  EDF R&D
2 #
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
7 #
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # Lesser General Public License for more details.
12 #
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19
20 """
21   Module that defines CPPComponent for SALOME components implemented in C++
22 """
23
24 import os
25 from gener import Component, Invalid
26 from cpp_tmpl import initService, cxxService, hxxCompo, cxxCompo
27 from cpp_tmpl import exeCPP, compoEXEMakefile, compoMakefile
28 from yacstypes import corba_rtn_type
29
30 class CPPComponent(Component):
31   """
32    A :class:`CPPComponent` instance represents a C++ SALOME component with services given as a list of :class:`Service`
33    instances with the parameter *services*.
34
35    :param name: gives the name of the component.
36    :type name: str
37    :param services: the list of services (:class:`Service`) of the component.
38    :param kind: If it is given and has the value "exe", the component will be built as a standalone
39       component (executable or shell script). The default is to build the component as a dynamic library.
40    :param libs: gives all the libraries options to add when linking the generated component (-L...).
41    :param rlibs: gives all the runtime libraries options to add when linking the generated component (-R...).
42    :param includes: gives all the include options to add when compiling the generated component (-I...).
43    :param sources: gives all the external source files to add in the compilation step (list of paths).
44    :param exe_path: is only used when kind is "exe" and gives the path to the standalone component.
45    :param compodefs: can be used to add extra definition code in the component for example when using a base class
46       to define the component class by deriving it (see *inheritedclass* parameter)
47    :param inheritedclass: can be used to define a base class for the component. The base class can be defined in external
48       source or with the *compodefs* parameter. The value of the *inheritedclass* parameter is the name of the base class.
49    :param idls: can be used to add extra idl CORBA interfaces to the component. This parameter must gives a list of idl file
50       names that are added into the generated module (idl directory) and compiled with the generated idl of the module.
51    :param interfacedefs: can be used to add idl definitions (or includes of idl files) into the generated idl of the module.
52    :param inheritedinterface: can be used to make the component inherit an extra idl interface that has been included through
53       the *idls* and *interfacedefs* parameters. See the cppgui1 example for how to use these last parameters.
54    :param addmethods: is a C++ specific parameter that can be used to redefine a component method (DumpPython for example). This
55       parameter is a string that must contain the definition and implementation code of the method. See the cppgui1 example
56       for how to use it.
57    :param calciumextendedinterface: if you want to use the Calcium extended interface for C++ as defined by the header CalciumInterface.hxx
58       set this parameter to 1. By default its value is 0 so to not use extended interface. The extended interface requires boost as a dependency.
59
60    For example, the following call defines a standalone component named "mycompo" with one service s1 (it must have been defined before)::
61
62       >>> c1 = module_generator.CPPComponent('mycompo', services=[s1,], kind="exe",
63                                              exe_path="./launch.sh")
64   """
65   def __init__(self, name, services=None, libs="", rlibs="", includes="", kind="lib",
66                      exe_path=None, sources=None, inheritedclass="", compodefs="",
67                      idls=None,interfacedefs="",inheritedinterface="",addedmethods="",
68                      calciumextendedinterface=0):
69     self.exe_path = exe_path
70     self.calciumextendedinterface=calciumextendedinterface
71     Component.__init__(self, name, services, impl="CPP", libs=libs, rlibs=rlibs,
72                              includes=includes, kind=kind, sources=sources,
73                              inheritedclass=inheritedclass, compodefs=compodefs, idls=idls,
74                              interfacedefs=interfacedefs, inheritedinterface=inheritedinterface,
75                              addedmethods=addedmethods)
76
77   def validate(self):
78     """ validate component definition parameters"""
79     Component.validate(self)
80     kinds = ("lib", "exe")
81     if self.kind not in kinds:
82       raise Invalid("kind must be one of %s for component %s" % (kinds,self.name))
83
84     if self.kind == "exe" :
85       if not self.exe_path:
86         raise Invalid("exe_path must be defined for component %s" % self.name)
87
88   def makeCompo(self, gen):
89     """generate files for C++ component
90
91        return a dict where key is the file name and value is the content of the file
92     """
93     cxxfile = "%s.cxx" % self.name
94     hxxfile = "%s.hxx" % self.name
95     if self.kind == "lib":
96       sources = " ".join(map(os.path.basename,self.sources))
97       return {"Makefile.am":gen.makeMakefile(self.getMakefileItems(gen)),
98               cxxfile:self.makecxx(gen),
99               hxxfile:self.makehxx(gen)
100              }
101     if self.kind == "exe":
102       return {"Makefile.am":gen.makeMakefile(self.getMakefileItems(gen)),
103               self.name+".exe":exeCPP.substitute(compoexe=self.exe_path),
104               cxxfile:self.makecxx(gen, 1),
105               hxxfile:self.makehxx(gen)
106              }
107
108   def getMakefileItems(self,gen):
109     makefileItems={"header":"""
110 include $(top_srcdir)/adm_local/make_common_starter.am
111
112 AM_CFLAGS=$(SALOME_INCLUDES) -fexceptions
113 """}
114     if self.kind == "lib":
115       makefileItems["lib_LTLIBRARIES"]=["lib"+self.name+"Engine.la"]
116       makefileItems["salomeinclude_HEADERS"]=[self.name+".hxx"]
117       makefileItems["body"]=compoMakefile.substitute(module=gen.module.name,
118                                                      component=self.name,
119                                                      libs=self.libs,
120                                                      rlibs=self.rlibs,
121                                                      sources= " ".join(map(os.path.basename,self.sources)),
122                                                      includes=self.includes)
123     elif self.kind == "exe":
124       makefileItems["lib_LTLIBRARIES"]=["lib"+self.name+"Exelib.la"]
125       makefileItems["salomeinclude_HEADERS"]=[self.name+".hxx"]
126       makefileItems["dist_salomescript_SCRIPTS"]=[self.name+".exe"]
127       makefileItems["body"]=compoEXEMakefile.substitute(module=gen.module.name,
128                                                         component=self.name,
129                                                         libs=self.libs,
130                                                         rlibs=self.rlibs,
131                                                         includes=self.includes)
132     return makefileItems
133
134   def makehxx(self, gen):
135     """return a string that is the content of .hxx file
136     """
137     services = []
138     for serv in self.services:
139       service = "    %s %s(" % (corba_rtn_type(serv.ret,gen.module.name),serv.name)
140       service = service+gen.makeArgs(serv)+");"
141       services.append(service)
142
143     if self.addedmethods:
144       services.append(self.addedmethods)
145     servicesdef = "\n".join(services)
146
147     inheritedclass=self.inheritedclass
148     if self.inheritedclass:
149       inheritedclass= " public virtual " + self.inheritedclass + ","
150
151     return hxxCompo.substitute(component=self.name, module=gen.module.name,
152                                servicesdef=servicesdef, inheritedclass=inheritedclass,
153                                compodefs=self.compodefs)
154
155   def makecxx(self, gen, exe=0):
156     """return a string that is the content of .cxx file
157     """
158     services = []
159     inits = []
160     defs = []
161     for serv in self.services:
162       defs.append(serv.defs)
163       service = cxxService.substitute(component=self.name, service=serv.name,
164                                       parameters=gen.makeArgs(serv),
165                                       body=serv.body, exe=exe)
166       streams = []
167       for name, typ, dep in serv.instream:
168         streams.append('          create_calcium_port(this,(char *)"%s",(char *)"%s",(char *)"IN",(char *)"%s");'% (name, typ, dep))
169       instream = "\n".join(streams)
170       streams = []
171       for name, typ, dep in serv.outstream:
172         streams.append('          create_calcium_port(this,(char *)"%s",(char *)"%s",(char *)"OUT",(char *)"%s");'% (name, typ, dep))
173       outstream = "\n".join(streams)
174
175       init = initService.substitute(component=self.name, service=serv.name,
176                                     instream=instream, outstream=outstream)
177       services.append(service)
178       inits.append(init)
179
180     CalciumInterface=""
181     if self.calciumextendedinterface:
182       CalciumInterface="#include <CalciumInterface.hxx>"
183
184     return cxxCompo.substitute(component=self.name, module=gen.module.name,
185                                exe=exe, exe_path=self.exe_path,
186                                servicesdef="\n".join(defs),
187                                servicesimpl="\n".join(services),
188                                initservice='\n'.join(inits),
189                                CalciumInterface=CalciumInterface)
190