Salome HOME
Copyright update 2022
[tools/yacsgen.git] / module_generator / mpicompo.py
1 # Copyright (C) 2009-2022  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 module_generator.gener import Component, Invalid
26 from module_generator.cpp_tmpl import initService, cxxService, hxxCompo, cxxCompo
27 from module_generator.cpp_tmpl import exeCPP, cmake_src_compo_cpp
28 from module_generator.yacstypes import corba_rtn_type, corba_in_type
29 from module_generator import mpi_tmpl
30 from module_generator.cppcompo import CPPComponent
31
32 try:
33   from string import Template
34 except:
35   from module_generator.compat import Template,set
36
37 class MPIComponent(CPPComponent):
38   """
39    A :class:`MPIComponent` instance represents a C++ SALOME component with services given as a list of :class:`Service`
40    instances with the parameter *services*.
41
42    :param name: gives the name of the component.
43    :type name: str
44    :param services: the list of services (:class:`Service`) of the component.
45    :param kind: For this type of component, "lib" is the unique valid option. The component is built as a dynamic library.
46    :param libs: list of the additional libraries. see *Library* class.
47       If you want to add "libmylib.so", installed in "/path/to/lib" you should use:
48          libs=[Library(name="mylib", path="/path/to/lib")]
49       For more advanced features, see the documentation of cmake / FIND_LIBRARY
50    :param rlibs: space-separated list specifying the rpath to use in installed targets
51    :param includes: additional include directories, separated by spaces.
52    :param sources: gives all the external source files to add in the compilation step (list of paths).
53    :param exe_path: is only used when kind is "exe" and gives the path to the standalone component.
54    :param compodefs: can be used to add extra definition code in the component for example when using a base class
55       to define the component class by deriving it (see *inheritedclass* parameter)
56    :param inheritedclass: can be used to define a base class for the component. The base class can be defined in external
57       source or with the *compodefs* parameter. The value of the *inheritedclass* parameter is the name of the base class.
58    :param idls: can be used to add extra idl CORBA interfaces to the component. This parameter must gives a list of idl file
59       names that are added into the generated module (idl directory) and compiled with the generated idl of the module.
60    :param interfacedefs: can be used to add idl definitions (or includes of idl files) into the generated idl of the module.
61    :param inheritedinterface: can be used to make the component inherit an extra idl interface that has been included through
62       the *idls* and *interfacedefs* parameters. See the cppgui1 example for how to use these last parameters.
63    :param addedmethods: is a C++ specific parameter that can be used to redefine a component method (DumpPython for example). This
64       parameter is a string that must contain the definition and implementation code of the method. See the cppgui1 example
65       for how to use it.
66
67    For example, the following call defines a standalone component named "mycompo" with one service s1 (it must have been defined before)::
68
69       >>> c1 = module_generator.CPPComponent('mycompo', services=[s1,], kind="exe",
70                                              exe_path="./launch.sh")
71   """
72   def __init__(self, name, services=None, libs=[], rlibs="", includes="", kind="lib",
73                      exe_path=None, sources=None, inheritedclass="", compodefs="",
74                      idls=None,interfacedefs="",inheritedinterface="",addedmethods=""):
75     self.exe_path = exe_path
76     Component.__init__(self, name, services, impl="CPP", libs=libs, rlibs=rlibs,
77                              includes=includes, kind=kind, sources=sources,
78                              inheritedclass=inheritedclass, compodefs=compodefs, idls=idls,
79                              interfacedefs=interfacedefs, inheritedinterface=inheritedinterface,
80                              addedmethods=addedmethods)
81
82   def validate(self):
83     """ validate component definition parameters"""
84     Component.validate(self)
85     kinds = ("lib")
86     if self.kind not in kinds:
87       raise Invalid("kind must be one of %s for component %s" % (kinds,self.name))
88
89   def libraryName(self):
90     """ Name of the target library
91     """
92     ret=""
93     if self.kind == "lib":
94       ret = self.name + "Engine"
95     else:
96       raise Invalid("Invalid kind of component: %s. Supported kinds are 'lib' and 'exe'" % self.name)
97     return ret
98     
99   def makeCompo(self, gen):
100     """generate files for C++ component
101
102        return a dict where key is the file name and value is the file content
103     """
104     (cmake_text, cmake_vars) = self.additionalLibraries()
105     cmake_vars = "${KERNEL_SalomeMPIContainer}\n  " + cmake_vars
106     cxxfile = "%s.cxx" % self.name
107     hxxfile = "%s.hxx" % self.name
108     ret = { cxxfile:self.makecxx(gen),
109             hxxfile:self.makehxx(gen)
110           }
111     sources = " ".join(map(os.path.basename,self.sources))
112     cmakelist_content = cmake_src_compo_cpp.substitute(
113                         module = gen.module.name,
114                         component = self.name,
115                         componentlib = self.libraryName(),
116                         includes = self.includes,
117                         sources = sources,
118                         libs = cmake_vars,
119                         find_libs = cmake_text,
120                         target_properties = self.targetProperties())
121     
122     ret["CMakeLists.txt"] = cmakelist_content
123     
124     return ret
125
126   def makeThServiceDeclaration(self, service, module_name):
127     inputVals = []
128     for port in service.inport:
129       name, typ = service.validatePort(port)
130       inputVals.append("%s %s;" % (corba_in_type(typ, module_name), name ))
131     return mpi_tmpl.hxxThreadService.substitute(service=service.name,
132                                        input_vals="\n".join(inputVals))
133
134   def makehxx(self, gen):
135     """return a string that is the content of .hxx file
136     """
137     services = []
138     compodefs=self.compodefs
139     for serv in self.services:
140       service = "    %s %s(" % (corba_rtn_type(serv.ret,gen.module.name),serv.name)
141       service = service+gen.makeArgs(serv)+");"
142       services.append(service)
143       compodefs = compodefs + self.makeThServiceDeclaration(serv,gen.module.name)
144
145     if self.addedmethods:
146       services.append(self.addedmethods)
147     servicesdef = "\n".join(services)
148
149     inheritedclass=self.inheritedclass
150     if self.inheritedclass:
151       inheritedclass= " public virtual " + self.inheritedclass + ","
152
153     return mpi_tmpl.hxxCompo.substitute(component=self.name, module=gen.module.name,
154                                servicesdef=servicesdef, inheritedclass=inheritedclass,
155                                compodefs=compodefs)
156
157   def makecxx(self, gen):
158     """return a string that is the content of .cxx file
159     """
160     services = []
161     inits = []
162     defs = []
163     for serv in self.services:
164       defs.append(serv.defs)
165       in_vals = []
166       out_vals = []
167       call_params = []
168       for name, typ in serv.inport:
169         in_vals.append("st->%s = %s;" % (name, name ))
170         call_params.append("st->%s" % name)
171         
172       for name, typ in serv.outport:
173         out_vals.append("%s %s;" % (corba_in_type(typ, gen.module.name), name ))
174         call_params.append(name)
175       
176       service_call = "%s(%s)" % (serv.name, ",".join(call_params))
177       
178       service = mpi_tmpl.cxxService.substitute(module=gen.module.name,
179                                       component=self.name, service=serv.name,
180                                       out_vals="\n".join(out_vals),
181                                       service_call=service_call,
182                                       in_vals="\n".join(in_vals),
183                                       parameters=gen.makeArgs(serv),
184                                       body=serv.body)
185       services.append(service)
186
187     return mpi_tmpl.cxxCompo.substitute(component=self.name,
188                                servicesdef="\n".join(defs),
189                                servicesimpl="\n".join(services))
190
191   def getIdlInterfaces(self):
192     services = self.getIdlServices()
193     inheritedinterface=""
194     if self.inheritedinterface:
195       inheritedinterface=self.inheritedinterface+","
196     return mpi_tmpl.interface.substitute(component=self.name,
197                                          services="\n".join(services),
198                                          inheritedinterface=inheritedinterface)
199
200   def getIdlDefs(self):
201     idldefs = """
202 #include "SALOME_MPIObject.idl"
203 """
204     if self.interfacedefs:
205       idldefs = idldefs + self.interfacedefs
206     return idldefs
207   
208   def additionalLibraries(self):
209     cmake_text, cmake_vars = Component.additionalLibraries(self)
210     if "MED" in self.getDependentModules():
211       cmake_vars = cmake_vars + """
212   ${MED_paramedmemcompo}
213   ${MED_paramedcouplingcorba}  
214 """
215     return cmake_text, cmake_vars
216