]> SALOME platform Git repositories - tools/yacsgen.git/blob - module_generator/astcompo.py
Salome HOME
Autotools replaced by cmake in generated modules.
[tools/yacsgen.git] / module_generator / astcompo.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   This module defines the ASTERComponent class for ASTER component generation
22   An ASTER component comes in 3 flavors :
23    - implemented as a dynamic library (kind='lib')
24    - implemented as a standalone component (kind='exe')
25    - implemented as a specific container (kind='cexe')
26 """
27 import re, os, sys
28
29 from gener import Component, Invalid, makedirs
30
31 from pyth_tmpl import pyinitEXEService, pyinitCEXEService, pyinitService
32 import aster_tmpl
33 from aster_tmpl import asterCEXEService, asterEXEService
34 from aster_tmpl import asterService, asterEXECompo, asterCEXECompo, asterCompo
35 from aster_tmpl import comm, make_etude, cexe, exeaster
36 from aster_tmpl import container, component
37 from aster_tmpl import cmake_src_compo_aster, cmake_src_compo_aster_lib
38
39 class ASTERComponent(Component):
40   """
41    A :class:`ASTERComponent` instance represents an ASTER SALOME component (special component for Code_Aster that is a mix of
42    Fortran and Python code) with services given as a list of :class:`Service` instances with the parameter *services*.
43
44    :param name: gives the name of the component.
45    :type name: str
46    :param services: the list of services (:class:`Service`) of the component.
47    :param kind: If it is given and has the value "exe", the component will be built as a standalone
48       component (executable or shell script). The default is to build the component as a dynamic library.
49    :param libs: gives all the libraries options to add when linking the generated component (-L...).
50    :param rlibs: gives all the runtime libraries options to add when linking the generated component (-R...).
51    :param exe_path: is only used when kind is "exe" and gives the path to the standalone component.
52    :param aster_dir: gives the Code_Aster installation directory.
53    :param python_path: If it is given (as a list of paths), all the paths are added to the python path (sys.path).
54    :param argv: is a list of strings that gives the command line parameters for Code_Aster. This parameter is only useful when
55       kind is "lib".
56
57    For example, the following call defines a Code_Aster component named "mycompo" with one service s1 (it must have been defined before).
58    This standalone component takes some command line arguments::
59
60       >>> c1 = module_generator.ASTERComponent('mycompo', services=[s1,], kind="exe",
61                                                           exe_path="launch.sh",
62                                                           argv=["-memjeveux","4"])
63   """
64   def __init__(self, name, services=None, libs=[], rlibs="", aster_dir="", 
65                      python_path=None, argv=None, kind="lib", exe_path=None):
66     """initialise component attributes"""
67     self.aster_dir = aster_dir
68     self.python_path = python_path or []
69     self.argv = argv or []
70     self.exe_path = exe_path
71     Component.__init__(self, name, services, impl="ASTER", libs=libs, 
72                              rlibs=rlibs, kind=kind)
73
74   def validate(self):
75     """validate the component definition"""
76     Component.validate(self)
77     if not self.aster_dir:
78       raise Invalid("aster_dir must be defined for component %s" % self.name)
79
80     kinds = ("lib", "cexe", "exe")
81     if self.kind not in kinds:
82       raise Invalid("kind must be one of %s for component %s" % (kinds,self.name))
83     if self.kind == "lib" and not self.python_path:
84       raise Invalid("python_path must be defined for component %s" % self.name)
85     if self.kind == "cexe" :
86       if not self.exe_path:
87         raise Invalid("exe_path must be defined for component %s" % self.name)
88     if self.kind == "exe" :
89       if not self.exe_path:
90         raise Invalid("exe_path must be defined for component %s" % self.name)
91
92     #Si un port de nom jdc n'est pas defini dans la liste des inports du service,
93     #on en ajoute un de type string en premiere position
94     for serv in self.services:
95       found=False
96       for port_name,port_type in serv.inport:
97         if port_name == "jdc":
98           found=True
99           break
100       if not found:
101         serv.inport.insert(0, ("jdc", "string"))
102
103   def libraryName(self):
104     """ Name of the target library
105         No library for an aster component
106     """
107     return ""
108     
109   def getAsterPythonPath(self):
110     """Directory of aster python modules
111     """
112     python_version_dir = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
113     aster_python_path = os.path.join(self.aster_dir, "lib", python_version_dir, "site-packages")
114
115     if not os.path.exists(aster_python_path) :
116       aster_python_path = os.path.join(self.aster_dir, "bibpyt")
117       
118     return aster_python_path
119
120   def getConfig(self, gen):
121     """Content of the config.txt file
122     """
123     path_compo=os.path.join(os.path.abspath(gen.module.prefix),'lib',
124                       'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
125                       'site-packages','salome','%s_component.py'%self.name)
126     conf="""ENV_SH         | env     | -     | $ASTER_VERSION_DIR/share/aster/profile.sh
127 BINELE         | bin     | -     | $ASTER_VERSION_DIR/share/aster/elements
128 SRCPY          | src     | -     | %s
129 ARGPYT         | exec    | -     | %s
130 """ % (self.getAsterPythonPath(), path_compo)
131     
132     return conf
133
134   def makeCompo(self, gen):
135     """drive the generation of SALOME module files and code files
136        depending on the choosen component kind
137     """
138     filename = "%s.py" % self.name
139     #on suppose que les composants ASTER sont homogenes (utilisent meme install)
140     gen.aster = self.aster_dir
141
142     #get ASTER version
143     f = os.path.join(self.aster_dir, self.getAsterPythonPath(), 'Accas', 'properties.py')
144     self.version=(0,0,0)
145     if os.path.isfile(f):
146       mydict = {}
147       execfile(f, mydict)
148       v,r,p = mydict['version'].split('.')
149       self.version=(int(v),int(r),int(p))
150
151     if self.kind == "lib":
152       f = self.name+".py"
153       return {"CMakeLists.txt":cmake_src_compo_aster_lib.substitute(sources=f),
154               filename:self.makeaster(gen)}
155     elif self.kind == "cexe":
156       fdict=self.makecexepath(gen)
157       sources = self.name + ".py\n  " + self.name + "_container.py"
158       if self.version < (10,1,2):
159         sources =  sources + "\n  E_SUPERV.py"
160       d= {"CMakeLists.txt":cmake_src_compo_aster.substitute(
161                                             sources=sources,
162                                             module=gen.module.name,
163                                             resources=self.name+"_config.txt",
164                                             scripts=self.name+".exe"),
165            self.name+".exe":cexe.substitute(compoexe=self.exe_path),
166            filename:self.makecexeaster(gen)
167          }
168       d.update(fdict)
169       return d
170     elif self.kind == "exe":
171       fdict=self.makeexepath(gen)
172       sources =  self.name + "_module.py\n  "
173       sources =  sources + self.name + "_component.py"
174       if self.version < (10,1,2):
175         sources =  sources + "\n  E_SUPERV.py"
176       d= {"CMakeLists.txt":cmake_src_compo_aster.substitute(
177                                             sources=sources,
178                                             module=gen.module.name,
179                                             resources=self.name+"_config.txt",
180                                             scripts=self.name+".exe"),
181            self.name+".exe":exeaster.substitute(compoexe=self.exe_path),
182            self.name+"_module.py":self.makeexeaster(gen)
183          }
184       d.update(fdict)
185       return d
186
187   def makeexepath(self, gen):
188     """standalone component: generate files for calculation code"""
189
190     fdict={}
191
192     if self.version < (10,1,2):
193       #patch to E_SUPERV.py
194       fil = open(os.path.join(self.aster_dir, "bibpyt", "Execution", "E_SUPERV.py"))
195       esuperv = fil.read()
196       fil.close()
197       esuperv = re.sub("def Execute\(self\)", "def Execute(self, params)", esuperv)
198       esuperv = re.sub("j=self.JdC", "self.jdc=j=self.JdC", esuperv)
199       esuperv = re.sub("\*\*args", "context_ini=params, **args", esuperv)
200       esuperv = re.sub("def main\(self\)", "def main(self,params={})", esuperv)
201       esuperv = re.sub("return self.Execute\(\)", "return self.Execute(params)", esuperv)
202       fdict["E_SUPERV.py"]=esuperv
203
204     #use a specific main program (modification of config.txt file)
205     config = ""
206     path_config = os.path.join(self.aster_dir, "config.txt")
207     if os.path.exists(path_config) :
208       # old aster version - old mechanism kept for compatibility
209       fil = open(path_config)
210       config = fil.read()
211       fil.close()
212       config = re.sub(" profile.sh", os.path.join(self.aster_dir, "profile.sh"), config)
213       path=os.path.join(os.path.abspath(gen.module.prefix),'lib',
214                       'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
215                       'site-packages','salome','%s_component.py'%self.name)
216       config = re.sub("Execution\/E_SUPERV.py", path, config)
217     else :
218       # getConfig doesn't work with older versions of aster
219       config = self.getConfig(gen)
220
221     fdict["%s_config.txt" % self.name] = config
222     fdict["%s_component.py" % self.name] = component.substitute(component=self.name)
223
224     return fdict
225
226   def makecexepath(self, gen):
227     """specific container: generate files"""
228
229     fdict={}
230
231     if self.version < (10,1,2):
232       #patch to E_SUPERV.py
233       fil = open(os.path.join(self.aster_dir, "bibpyt", "Execution", "E_SUPERV.py"))
234       esuperv = fil.read()
235       fil.close()
236       esuperv = re.sub("def Execute\(self\)", "def Execute(self, params)", esuperv)
237       esuperv = re.sub("j=self.JdC", "self.jdc=j=self.JdC", esuperv)
238       esuperv = re.sub("\*\*args", "context_ini=params, **args", esuperv)
239       esuperv = re.sub("def main\(self\)", "def main(self,params={})", esuperv)
240       esuperv = re.sub("return self.Execute\(\)", "return self.Execute(params)", esuperv)
241       fdict["E_SUPERV.py"]=esuperv
242
243     #use a specific main program
244     config = ""
245     path_config = os.path.join(self.aster_dir, "config.txt")
246     if os.path.exists(path_config) :
247       # old aster version - old mechanism kept for compatibility
248       fil = open(path_config)
249       config = fil.read()
250       fil.close()
251       config = re.sub(" profile.sh", os.path.join(self.aster_dir, "profile.sh"), config)
252       path=os.path.join(os.path.abspath(gen.module.prefix),'lib',
253                       'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
254                       'site-packages','salome','%s_container.py' % self.name)
255       config = re.sub("Execution\/E_SUPERV.py", path, config)
256     else :
257       # getConfig doesn't work with older versions of aster
258       config = self.getConfig(gen)
259
260     fdict["%s_container.py" % self.name] = container
261     fdict["%s_config.txt" % self.name] = config
262
263     return fdict
264
265   def getImportESuperv(self):
266     importesuperv=""
267     if self.version < (10,1,2):
268       importesuperv="from E_SUPERV import SUPERV"
269     else :
270       importesuperv="""sys.path=["%s"]+sys.path
271 from Execution.E_SUPERV import SUPERV
272 """ % self.getAsterPythonPath()
273     return importesuperv
274
275
276   def makeexeaster(self, gen):
277     """standalone component: generate SALOME component source"""
278     services = []
279     inits = []
280     defs = []
281     for serv in self.services:
282       defs.append(serv.defs)
283       params = []
284       datas = []
285       for name, typ in serv.inport:
286         if typ=="file":continue #files are not passed through service interface
287         params.append(name)
288         if typ == "pyobj":
289           datas.append('"%s":cPickle.loads(%s)' % (name, name))
290         else:
291           datas.append('"%s":%s' % (name, name))
292       #ajout de l'adresse du composant
293       datas.append('"component":self.proxy.ptr()')
294       dvars = "{"+','.join(datas)+"}"
295       inparams = ",".join(params)
296
297       params = []
298       datas = []
299       for name, typ in serv.outport:
300         if typ=="file":continue #files are not passed through service interface
301         params.append(name)
302         if typ == "pyobj":
303           datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
304         else:
305           datas.append('j.g_context["%s"]'%name)
306       outparams = ",".join(params)
307       rvars = ",".join(datas)
308
309       service = asterEXEService.substitute(component=self.name,
310                                            service=serv.name,
311                                            inparams=inparams,
312                                            outparams=outparams,
313                                            body=serv.body,
314                                            dvars=dvars, rvars=rvars)
315       streams = []
316       for name, typ, dep in serv.instream:
317         streams.append('       calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
318       instream = "\n".join(streams)
319       streams = []
320       for name, typ, dep in serv.outstream:
321         streams.append('       calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
322       outstream = "\n".join(streams)
323
324       init = pyinitEXEService.substitute(component=self.name, service=serv.name,
325                                          instream=instream, outstream=outstream)
326       services.append(service)
327       inits.append(init)
328
329     importesuperv = self.getImportESuperv()
330
331     return asterEXECompo.substitute(component=self.name, module=gen.module.name,
332                                     servicesdef="\n".join(defs),
333                                     servicesimpl="\n".join(services),
334                                     initservice='\n'.join(inits),
335                                     aster_dir=self.aster_dir,
336                                     importesuperv=importesuperv,
337                                     )
338
339   def makecexeaster(self, gen):
340     """specific container: generate SALOME component source"""
341     services = []
342     inits = []
343     defs = []
344     for serv in self.services:
345       defs.append(serv.defs)
346       params = []
347       datas = []
348       for name, typ in serv.inport:
349         if typ=="file":continue #files are not passed through service interface
350         params.append(name)
351         if typ == "pyobj":
352           datas.append('"%s":cPickle.loads(%s)' % (name, name))
353         else:
354           datas.append('"%s":%s' % (name, name))
355       #ajout de l'adresse du composant
356       datas.append('"component":self.proxy.ptr()')
357       dvars = "{"+','.join(datas)+"}"
358       inparams = ",".join(params)
359
360       params = []
361       datas = []
362       for name, typ in serv.outport:
363         params.append(name)
364         if typ == "pyobj":
365           datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
366         else:
367           datas.append('j.g_context["%s"]'%name)
368       outparams = ",".join(params)
369       rvars = ",".join(datas)
370
371       service = asterCEXEService.substitute(component=self.name,
372                                             service=serv.name,
373                                             inparams=inparams,
374                                             outparams=outparams,
375                                             body=serv.body,
376                                             dvars=dvars, rvars=rvars)
377       streams = []
378       for name, typ, dep in serv.instream:
379         streams.append('       calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
380       instream = "\n".join(streams)
381       streams = []
382       for name, typ, dep in serv.outstream:
383         streams.append('       calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
384       outstream = "\n".join(streams)
385
386       init = pyinitCEXEService.substitute(component=self.name, 
387                                           service=serv.name,
388                                           instream=instream, 
389                                           outstream=outstream)
390       services.append(service)
391       inits.append(init)
392
393     importesuperv = self.getImportESuperv()
394
395     return asterCEXECompo.substitute(component=self.name, 
396                                      module=gen.module.name,
397                                      servicesdef="\n".join(defs), 
398                                      servicesimpl="\n".join(services), 
399                                      initservice='\n'.join(inits),
400                                      aster_dir=self.aster_dir,
401                                      importesuperv=importesuperv,
402                                      )
403
404   def getImpl(self):
405     if self.kind == "cexe":
406       return "CEXE", self.name+".exe"
407     else:
408       return "SO", ""
409
410   def makeaster(self, gen):
411     """library component: generate SALOME component source"""
412     services = []
413     inits = []
414     defs = []
415     for serv in self.services:
416       defs.append(serv.defs)
417       params = []
418       datas = []
419       for name, typ in serv.inport:
420         if typ=="file":continue #files are not passed through service interface
421         params.append(name)
422         if typ == "pyobj":
423           datas.append('"%s":cPickle.loads(%s)' % (name, name))
424         else:
425           datas.append('"%s":%s' % (name, name))
426       #ajout de l'adresse du composant
427       datas.append('"component":self.proxy.ptr()')
428       dvars = "{"+','.join(datas)+"}"
429       inparams = ",".join(params)
430
431       params = []
432       datas = []
433       for name, typ in serv.outport:
434         params.append(name)
435         if typ == "pyobj":
436           datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
437         else:
438           datas.append('j.g_context["%s"]'%name)
439       outparams = ",".join(params)
440       rvars = ",".join(datas)
441
442       service = asterService.substitute(component=self.name, service=serv.name, 
443                                         inparams=inparams, outparams=outparams, 
444                                         body=serv.body, 
445                                         dvars=dvars, rvars=rvars)
446       streams = []
447       for name, typ, dep in serv.instream:
448         streams.append('       calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
449       instream = "\n".join(streams)
450       streams = []
451       for name, typ, dep in serv.outstream:
452         streams.append('       calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
453       outstream = "\n".join(streams)
454
455       init = pyinitService.substitute(component=self.name, service=serv.name,
456                                       instream=instream, outstream=outstream)
457       services.append(service)
458       inits.append(init)
459
460     python_path = ",".join([repr(p) for p in self.python_path])
461     argv = ",".join([repr(p) for p in self.argv])
462     return asterCompo.substitute(component=self.name, module=gen.module.name,
463                                  servicesdef="\n".join(defs), 
464                                  servicesimpl="\n".join(services), 
465                                  initservice='\n'.join(inits),
466                                  aster_dir=self.aster_dir, 
467                                  python_path=python_path, argv=argv)
468