]> SALOME platform Git repositories - tools/yacsgen.git/blob - module_generator/gener.py
Salome HOME
CCAR: add definition parameter "sources" to C++, F77, Python components.
[tools/yacsgen.git] / module_generator / gener.py
1 import os, shutil, glob, socket
2
3 try:
4   from string import Template
5 except:
6   from compat import Template, set
7
8 class Invalid(Exception):
9   pass
10
11 from mod_tmpl import resMakefile, makecommon, configure
12 from mod_tmpl import mainMakefile, autogen, application
13 from cata_tmpl import catalog, interface, idl, idlMakefile
14 from cata_tmpl import cataOutStream, cataInStream, cataOutparam, cataInparam
15 from cata_tmpl import cataService, cataCompo
16 from aster_tmpl import check_aster
17
18 corbaTypes = {"double":"CORBA::Double", "long":"CORBA::Long",
19               "string":"const char*", "dblevec":"const %s::dblevec&",
20               "stringvec":"const %s::stringvec&", "intvec":"const %s::intvec&"}
21 corbaOutTypes = {"double":"CORBA::Double&", "long":"CORBA::Long&",
22                 "string":"CORBA::String_out", "dblevec":"%s::dblevec_out",
23                 "stringvec":"%s::stringvec_out", "intvec":"%s::intvec_out"}
24
25 def corba_in_type(typ, module):
26   if typ in ("dblevec", "intvec", "stringvec"):
27     return corbaTypes[typ] % module
28   else:
29     return corbaTypes[typ]
30
31 def corba_out_type(typ, module):
32   if typ in ("dblevec", "intvec", "stringvec"):
33     return corbaOutTypes[typ] % module
34   else:
35     return corbaOutTypes[typ]
36
37 calciumTypes = {"CALCIUM_double":"CALCIUM_double", 
38                 "CALCIUM_integer":"CALCIUM_integer", 
39                 "CALCIUM_real":"CALCIUM_real",
40                 "CALCIUM_string":"CALCIUM_string", 
41                 "CALCIUM_complex":"CALCIUM_complex", 
42                 "CALCIUM_logical":"CALCIUM_logical",
43                } 
44
45 ValidImpl = ("CPP", "PY", "F77", "ASTER")
46 ValidTypes = corbaTypes.keys()
47 ValidStreamTypes = calciumTypes.keys()
48 ValidDependencies = ("I", "T")
49 PyValidTypes = ValidTypes+["pyobj"]
50
51 def makedirs(namedir):
52   if os.path.exists(namedir):
53     dirbak = namedir+".bak"
54     if os.path.exists(dirbak):
55       shutil.rmtree(dirbak)
56     os.rename(namedir, dirbak)
57     os.listdir(dirbak) #sert seulement a mettre a jour le systeme de fichier sur certaines machines
58   os.makedirs(namedir)
59
60 class Module(object):
61   def __init__(self, name, components=None, prefix=""):
62     self.name = name
63     self.components = components or []
64     self.prefix = prefix or "%s_INSTALL" % name
65     self.validate()
66
67   def validate(self):
68     lcompo = set()
69     for compo in self.components:
70       if compo.name in lcompo:
71         raise Invalid("%s is already defined as a component of the module" % compo.name)
72       lcompo.add(compo.name)
73       compo.validate()
74
75 class Component(object):
76   def __init__(self, name, services=None, impl="PY", libs="", rlibs="", 
77                      includes="", kind="lib", sources=None):
78     self.name = name
79     self.impl = impl
80     self.kind = kind
81     self.services = services or []
82     self.libs = libs
83     self.rlibs = rlibs
84     self.includes = includes
85     self.sources = sources or []
86
87   def validate(self):
88     if self.impl not in ValidImpl:
89       raise Invalid("%s is not a valid implementation. It should be one of %s" % (self.impl, ValidImpl))
90
91     lnames = set()
92     for serv in self.services:
93       serv.impl = self.impl
94       if serv.name in lnames:
95         raise Invalid("%s is already defined as a service of the module" % serv.name)
96       lnames.add(serv.name)
97       serv.validate()
98
99     for src in self.sources:
100       if not os.path.exists(src):
101         raise Invalid("Source file %s does not exist" % src)
102
103   def getImpl(self):
104     return "SO", ""
105
106 class Service(object):
107   def __init__(self, name, inport=None, outport=None, instream=None, 
108                      outstream=None, body="", defs=""):
109     self.name = name
110     self.inport = inport or []
111     self.outport = outport or []
112     self.instream = instream or []
113     self.outstream = outstream or []
114     self.defs = defs
115     self.body = body
116     self.impl = ""
117
118   def validate(self):
119     lports = set()
120     for port in self.inport:
121       name, typ = self.validatePort(port)
122       if name in lports:
123         raise Invalid("%s is already defined as a service parameter" % name)
124       lports.add(name)
125
126     for port in self.outport:
127       name, typ = self.validatePort(port)
128       if name in lports:
129         raise Invalid("%s is already defined as a service parameter" % name)
130       lports.add(name)
131
132     lports = set()
133     for port in self.instream:
134       name, typ, dep = self.validateStream(port)
135       if name in lports:
136         raise Invalid("%s is already defined as a stream port" % name)
137       lports.add(name)
138
139     for port in self.outstream:
140       name, typ, dep = self.validateStream(port)
141       if name in lports:
142         raise Invalid("%s is already defined as a stream port" % name)
143       lports.add(name)
144
145   def validatePort(self, port):
146     try:
147       name, typ = port
148     except:
149       raise Invalid("%s is not a valid definition of an data port (name,type)" % (port,))
150
151     if self.impl in ("PY", "ASTER"):
152       validtypes = PyValidTypes
153     else:
154       validtypes = ValidTypes
155
156     if typ not in validtypes:
157       raise Invalid("%s is not a valid type. It should be one of %s" % (typ, validtypes))
158     return name, typ
159
160   def validateStream(self, port):
161     try:
162       name, typ, dep = port
163     except:
164       raise Invalid("%s is not a valid definition of a stream port (name,type,dependency)" % (port,))
165     if typ not in ValidStreamTypes:
166       raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidStreamTypes))
167     if dep not in ValidDependencies:
168       raise Invalid("%s is not a valid dependency. It should be one of %s" % (dep, ValidDependencies))
169     return name, typ, dep
170
171 class Generator(object):
172   def __init__(self, module, context=None):
173     self.module = module
174     self.context = context or {}
175     self.kernel = self.context["kernel"]
176     self.aster = ""
177
178   def generate(self):
179     module = self.module
180     namedir = module.name+"_SRC"
181     force = self.context.get("force")
182     update = self.context.get("update")
183     if os.path.exists(namedir):
184       if force:
185         shutil.rmtree(namedir)
186       elif not update:
187         raise Invalid("The directory %s already exists" % namedir)
188     if update:
189       makedirs(namedir)
190     else:
191       os.makedirs(namedir)
192
193     srcs = {}
194     makefile = "SUBDIRS="
195     makefiles = []
196     for compo in module.components:
197       makefile = makefile+" "+compo.name
198       srcs[compo.name] = compo.makeCompo(self)
199       makefiles.append("     src/"+compo.name+"/Makefile")
200
201     srcs["Makefile.am"] = makefile+'\n'
202     idlfile = "%s.idl" % module.name
203     catalogfile = "%sCatalog.xml" % module.name
204
205     self.makeFiles({"autogen.sh":autogen,
206                     "Makefile.am":mainMakefile,
207                     "README":"", "NEWS":"", "AUTHORS":"", "ChangeLog":"",
208                     "configure.ac":configure.substitute(module=module.name.lower(), makefiles='\n'.join(makefiles)),
209                     "idl":{"Makefile.am":idlMakefile.substitute(module=module.name), idlfile:self.makeidl()},
210                     "src":srcs,
211                     "resources":{"Makefile.am":resMakefile.substitute(module=module.name), catalogfile:self.makeCatalog()},
212                     "adm_local":{"make_common_starter.am":makecommon, "check_aster.m4":check_aster},
213                     }, namedir)
214     os.chmod(os.path.join(namedir, "autogen.sh"), 0777)
215     #copy source files if any in creates tree
216     for compo in module.components:
217       for src in compo.sources:
218         shutil.copyfile(src, os.path.join(namedir, "src", compo.name, src))
219
220     for m4file in ("check_Kernel.m4", "check_omniorb.m4", 
221                    "ac_linker_options.m4", "ac_cxx_option.m4",
222                    "python.m4", "enable_pthreads.m4", "check_f77.m4", 
223                    "acx_pthread.m4", "check_boost.m4"):
224       shutil.copyfile(os.path.join(self.kernel, "salome_adm", "unix", "config_files", m4file), 
225                       os.path.join(namedir, "adm_local", m4file))
226
227     return
228
229   def makeArgs(self, service):
230     params = []
231     for name, typ in service.inport:
232       params.append("%s %s" % (corba_in_type(typ, self.module.name), name))
233     for name, typ in service.outport:
234       params.append("%s %s" % (corba_out_type(typ, self.module.name), name))
235     return ",".join(params)
236
237   def makeCatalog(self):
238     components = []
239     for compo in self.module.components:
240       services = []
241       for serv in compo.services:
242         params = []
243         for name, typ in serv.inport:
244           params.append(cataInparam.substitute(name=name, type=typ))
245         inparams = "\n".join(params)
246         params = []
247         for name, typ in serv.outport:
248           params.append(cataOutparam.substitute(name=name, type=typ))
249         outparams = "\n".join(params)
250         streams = []
251         for name, typ, dep in serv.instream:
252           streams.append(cataInStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
253         for name, typ, dep in serv.outstream:
254           streams.append(cataOutStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
255         datastreams = "\n".join(streams)
256         services.append(cataService.substitute(service=serv.name, author="EDF-RD",
257                                                inparams=inparams, outparams=outparams, datastreams=datastreams))
258       impltype, implname = compo.getImpl()
259       components.append(cataCompo.substitute(component=compo.name, author="EDF-RD", impltype=impltype, implname=implname,
260                                              services='\n'.join(services)))
261     return catalog.substitute(components='\n'.join(components))
262
263   def makeidl(self):
264     interfaces = []
265     for compo in self.module.components:
266       services = []
267       for serv in compo.services:
268         params = []
269         for name, typ in serv.inport:
270           if compo.impl in ("PY", "ASTER") and typ == "pyobj":
271             typ = "Engines::fileBlock"
272           params.append("in %s %s" % (typ, name))
273         for name, typ in serv.outport:
274           if compo.impl in ("PY", "ASTER") and typ == "pyobj":
275             typ = "Engines::fileBlock"
276           params.append("out %s %s" % (typ, name))
277         service = "    void %s(" % serv.name
278         service = service+",".join(params)+") raises (SALOME::SALOME_Exception);"
279         services.append(service)
280       interfaces.append(interface.substitute(component=compo.name, services="\n".join(services)))
281     return idl.substitute(module=self.module.name, interfaces='\n'.join(interfaces))
282
283   def makeFiles(self, dic, basedir):
284     for name, content in dic.items():
285       filename = os.path.join(basedir, name)
286       if isinstance(content, str):
287         fil =  open(filename, 'w')
288         fil.write(content)
289         fil.close()
290       else:
291         if not os.path.exists(filename):
292           os.makedirs(filename)
293         self.makeFiles(content, filename)
294
295   def bootstrap(self):
296     ier = os.system("cd %s_SRC;sh autogen.sh" % self.module.name)
297     if ier != 0:
298       raise Invalid("bootstrap has ended in error")
299
300   def configure(self):
301     prefix = self.module.prefix
302     if prefix:
303       prefix = os.path.abspath(prefix)
304       cmd = "cd %s_SRC;./configure --with-kernel=%s --with-aster=%s --prefix=%s"
305       ier = os.system(cmd % (self.module.name, self.kernel, self.aster, prefix))
306     else:
307       cmd = "cd %s_SRC;./configure --with-kernel=%s --with-aster=%s"
308       ier = os.system(cmd % (self.module.name, self.kernel, self.aster))
309     if ier != 0:
310       raise Invalid("configure has ended in error")
311
312   def make(self):
313     ier = os.system("cd %s_SRC;make" % self.module.name)
314     if ier != 0:
315       raise Invalid("make has ended in error")
316
317   def install(self):
318     ier = os.system("cd %s_SRC;make install" % self.module.name)
319     if ier != 0:
320       raise Invalid("install has ended in error")
321
322   def make_appli(self, appliname, restrict=None, altmodules=None):
323     makedirs(appliname)
324
325     rootdir, kerdir = os.path.split(self.kernel)
326
327     #collect modules besides KERNEL module with the same suffix if any
328     modules_dict = {}
329     if kerdir[:6] == "KERNEL":
330       suffix = kerdir[6:]
331       for mod in os.listdir(rootdir):
332         if mod[-len(suffix):] == suffix:
333           module = mod[:-len(suffix)]
334           path = os.path.join(rootdir, mod)
335           #try to find catalog files
336           lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*", "*Catalog.xml"))
337           if not lcata:
338             #catalogs have not been found : try the upper level
339             lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*Catalog.xml"))
340           if lcata:
341             #catalogs have been found : add the corresponding entries in the application
342             for cata in lcata:
343               catadir, catafile = os.path.split(cata)
344               name = catafile[:-11]
345               modules_dict[name] = '  <module name="%s" path="%s"/>' % (name, path)
346           else:
347             modules_dict[module] = '  <module name="%s" path="%s"/>' % (module, path)
348
349     modules_dict["KERNEL"] = '  <module name="KERNEL" path="%s"/>' % self.kernel
350
351     #keep only the modules which names are in restrict if given
352     modules = []
353     if restrict:
354       for mod in restrict:
355         if modules_dict.has_key(mod):
356           modules.append(modules_dict[mod])
357     else:
358       modules = modules_dict.values()
359
360     #add the alternate modules if given
361     if altmodules:
362       for module, path in altmodules.items():
363         modules.append('  <module name="%s" path="%s"/>' % (module, path))
364
365     #add the generated module
366     modules.append('  <module name="%s" path="%s"/>' % (self.module.name, os.path.abspath(self.module.prefix)))
367
368     #try to find a prerequisites file
369     prerequisites = self.context.get("prerequisites")
370     if not prerequisites:
371       #try to find one in rootdir
372       prerequisites = os.path.join(rootdir, "profile%s.sh" % suffix)
373     if not os.path.exists(prerequisites):
374       raise Invalid("Can not create an application : prerequisites file not defined or does not exist")
375
376     #create config_appli.xml file
377     appli = application.substitute(prerequisites=prerequisites, modules="\n".join(modules))
378     fil = open(os.path.join(appliname, "config_appli.xml"), 'w')
379     fil.write(appli)
380     fil.close()
381
382     #execute appli_gen.py script
383     appligen = os.path.join(self.kernel, "bin", "salome", "appli_gen.py")
384     ier = os.system("cd %s;%s" % (appliname, appligen))
385     if ier != 0:
386       raise Invalid("make_appli has ended in error")
387
388     #add CatalogResources.xml if not created by appli_gen.py
389     if not os.path.exists(os.path.join(appliname, "CatalogResources.xml")):
390       #CatalogResources.xml does not exist create a minimal one
391       fil  = open(os.path.join(appliname, 'CatalogResources.xml'), 'w')
392       command = """<!DOCTYPE ResourcesCatalog>
393 <resources>
394     <machine hostname="%s" protocol="ssh" mode="interactive" />
395 </resources>
396 """
397       host = socket.gethostname().split('.')[0]
398       fil.write(command % host)
399       fil.close()
400