1 # Copyright (C) 2009-2014 EDF R&D
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.
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.
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
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 import os, shutil, glob, socket
25 from string import Template
27 from compat import Template, set
29 class Invalid(Exception):
34 from mod_tmpl import *
35 from cata_tmpl import catalog, interface, idl, parallel_interface
36 from cata_tmpl import xml, xml_interface, xml_service
37 from cata_tmpl import idlMakefilePaCO_BUILT_SOURCES, idlMakefilePaCO_nodist_salomeinclude_HEADERS
38 from cata_tmpl import idlMakefilePACO_salomepython_DATA, idlMakefilePACO_salomeidl_DATA
39 from cata_tmpl import idlMakefilePACO_INCLUDES
40 from cata_tmpl import cataOutStream, cataInStream, cataOutparam, cataInparam
41 from cata_tmpl import cataOutParallelStream, cataInParallelStream
42 from cata_tmpl import cataService, cataCompo
43 #from aster_tmpl import check_aster
44 from salomemodules import salome_modules
45 from yacstypes import corbaTypes, corbaOutTypes, moduleTypes, idlTypes, corba_in_type, corba_out_type
46 from yacstypes import ValidTypes, PyValidTypes, calciumTypes, DatastreamParallelTypes
47 from yacstypes import ValidImpl, ValidImplTypes, ValidStreamTypes, ValidParallelStreamTypes, ValidDependencies
48 from gui_tmpl import cmake_py_gui, pysalomeapp, cmake_cpp_gui, cppsalomeapp
49 from doc_tmpl import docmakefile, docconf, docsalomeapp
51 def makedirs(namedir):
52 """Create a new directory named namedir. If a directory already exists copy it to namedir.bak"""
53 if os.path.exists(namedir):
54 dirbak = namedir+".bak"
55 if os.path.exists(dirbak):
57 os.rename(namedir, dirbak)
58 os.listdir(dirbak) #needed to update filesystem on special machines (cluster with NFS, for example)
63 A :class:`Module` instance represents a SALOME module that contains components given as a list of
64 component instances (:class:`CPPComponent` or :class:`PYComponent` or :class:`F77Component` or :class:`ASTERComponent`)
65 with the parameter *components*.
67 :param name: gives the name of the module. The SALOME source module
68 will be located in the <name_SRC> directory.
70 :param components: gives the list of components of the module.
71 :param prefix: is the path of the installation directory.
72 :param doc: can be used to add an online documentation to the module. It must be a list of file names (sources, images, ...) that will be
73 used to build a sphinx documentation (see http://sphinx.pocoo.org, for more information). If not given, the Makefile.am
74 and the conf.py (sphinx configuration) files are generated. In this case, the file name extension of source files must be .rst.
75 See small examples in Examples/pygui1 and Examples/cppgui1.
76 :param gui: can be used to add a GUI to the module. It must be a list of file names (sources, images, qt designer files, ...).
77 If not given, the CMakeLists.txt and SalomeApp.xml are generated. All image files are put in the resources directory of the module.
78 The GUI can be implemented in C++ (file name extension '.cxx') or in Python (file name extension '.py').
79 See small examples in Examples/pygui1 and Examples/cppgui1.
81 For example, the following call defines a module named "mymodule" with 2 components c1 and c2 (they must have been
82 defined before) that will be installed in the "install" directory::
84 >>> m = module_generator.Module('mymodule', components=[c1,c2],
88 def __init__(self, name, components=None, prefix="", doc=None, gui=None):
90 self.components = components or []
91 self.prefix = prefix or "%s_INSTALL" % name
99 print "Error in module %s: %s" % (name,e)
103 # Test Module name, canot have a "-" in the name
104 if self.name.find("-") != -1:
105 raise Invalid("Module name %s is not valid, remove character - in the module name" % self.name)
107 for compo in self.components:
108 if compo.name in lcompo:
109 raise Invalid("%s is already defined as a component of the module" % compo.name)
110 lcompo.add(compo.name)
113 class Library(object):
115 A :class:'Library' instance contains the informations of a user library.
117 :param name: name of the library (exemple: "cppunit", "calcul")
118 :param path: path where to find the library (exemple: "/home/user/libs")
121 def __init__(self, name, path):
125 def findLibrary(self):
127 return : text for the FIND_LIBRARY command for cmake.
128 Feel free to overload this function for your own needs.
130 return "FIND_LIBRARY( "+self.cmakeVarName()+" "+self.name+" PATH "+self.path + ")\n"
132 def cmakeVarName(self):
134 return : name of the cmake variable used by FIND_LIBRARY
136 return "_userlib_" + self.name.split()[0]
138 class Component(object):
139 def __init__(self, name, services=None, impl="PY", libs=[], rlibs="",
140 includes="", kind="lib", sources=None,
141 inheritedclass="",compodefs="",
142 idls=None,interfacedefs="",inheritedinterface="",addedmethods=""):
146 self.services = services or []
149 self.includes = includes
150 self.sources = sources or []
151 self.inheritedclass=inheritedclass
152 self.compodefs=compodefs
154 self.interfacedefs=interfacedefs
155 self.inheritedinterface=inheritedinterface
156 self.addedmethods=addedmethods
158 def additionalLibraries(self):
159 """ generate the cmake code for finding the additional libraries
161 string containing a list of "find_library"
162 string containing a list of cmake variables defined
167 for lib in self.libs:
168 cmake_text = cmake_text + lib.findLibrary()
169 cmake_vars = cmake_vars + "${" + lib.cmakeVarName() + "}\n "
171 var_template = Template("$${${name}_SalomeIDL${name}}")
172 for mod in self.depend_modules:
173 if salome_modules[mod]["linklibs"]:
174 cmake_vars = cmake_vars + salome_modules[mod]["linklibs"]
176 default_lib = var_template.substitute(name=mod)
177 print "Unknown libraries for module " + mod
178 print "Using default library name " + default_lib
179 cmake_vars = cmake_vars + default_lib + "\n "
181 return cmake_text, cmake_vars
184 if self.impl not in ValidImpl:
185 raise Invalid("%s is not a valid implementation. It should be one of %s" % (self.impl, ValidImpl))
188 for serv in self.services:
189 serv.impl = self.impl
190 if serv.name in lnames:
191 raise Invalid("%s is already defined as a service of the module" % serv.name)
192 lnames.add(serv.name)
195 for src in self.sources:
196 if not os.path.exists(src):
197 raise Invalid("Source file %s does not exist" % src)
202 def getMakefileItems(self,gen):
205 def setPrerequisites(self, prerequisites_file):
206 self.prerequisites = prerequisites_file
208 class Service(object):
210 A :class:`Service` instance represents a component service with dataflow and datastream ports.
212 :param name: gives the name of the service.
214 :param inport: gives the list of input dataflow ports.
215 :param outport: gives the list of output dataflow ports. An input or output dataflow port is defined
216 by a 2-tuple (port name, data type name). The list of supported basic data types is: "double", "long", "string",
217 "dblevec", "stringvec", "intvec", "file" and "pyobj" only for Python services. Depending on the implementation
218 language, it is also possible to use some types from SALOME modules (see :ref:`yacstypes`).
219 :param ret: gives the type of the return parameter
220 :param instream: gives the list of input datastream ports.
221 :param outstream: gives the list of output datastream ports. An input or output datastream port is defined
222 by a 3-tuple (port name, data type name, mode name). The list of possible data types is: "CALCIUM_double", "CALCIUM_integer",
223 "CALCIUM_real", "CALCIUM_string", "CALCIUM_complex", "CALCIUM_logical", "CALCIUM_long". The mode can be "I" (iterative mode)
224 or "T" (temporal mode).
225 :param defs: gives the source code to insert in the definition section of the component. It can be C++ includes
228 :param body: gives the source code to insert in the service call. It can be any C++
229 or Python code that fits well in the body of the service method.
232 For example, the following call defines a minimal Python service with one input dataflow port (name "a", type double)
233 and one input datastream port::
235 >>> s1 = module_generator.Service('myservice', inport=[("a","double"),],
236 instream=[("aa","CALCIUM_double","I")],
241 def __init__(self, name, inport=None, outport=None, ret="void", instream=None, outstream=None,
242 parallel_instream=None, parallel_outstream=None, defs="", body="", impl_type="sequential"):
244 self.inport = inport or []
245 self.outport = outport or []
247 self.instream = instream or []
248 self.outstream = outstream or []
249 self.parallel_instream = parallel_instream or []
250 self.parallel_outstream = parallel_outstream or []
254 self.impl_type = impl_type
258 for port in self.inport:
259 name, typ = self.validatePort(port)
261 raise Invalid("%s is already defined as a service parameter" % name)
264 for port in self.outport:
265 name, typ = self.validatePort(port)
267 raise Invalid("%s is already defined as a service parameter" % name)
271 for port in self.instream:
272 name, typ, dep = self.validateStream(port)
274 raise Invalid("%s is already defined as a stream port" % name)
277 for port in self.outstream:
278 name, typ, dep = self.validateStream(port)
280 raise Invalid("%s is already defined as a stream port" % name)
283 for port in self.parallel_instream:
284 name, typ = self.validateParallelStream(port)
286 raise Invalid("%s is already defined as a stream port" % name)
289 for port in self.parallel_outstream:
290 name, typ = self.validateParallelStream(port)
292 raise Invalid("%s is already defined as a stream port" % name)
295 self.validateImplType()
297 def validatePort(self, port):
301 raise Invalid("%s is not a valid definition of an data port (name,type)" % (port,))
303 if self.impl in ("PY", "ASTER"):
304 validtypes = PyValidTypes
306 validtypes = ValidTypes
308 if typ not in validtypes:
309 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, validtypes))
312 def validateImplType(self):
313 if self.impl_type not in ValidImplTypes:
314 raise Invalid("%s is not a valid impl type. It should be one of %s" % (self.impl_type, ValidImplTypes))
316 def validateStream(self, port):
318 name, typ, dep = port
320 raise Invalid("%s is not a valid definition of a stream port (name,type,dependency)" % (port,))
321 if typ not in ValidStreamTypes:
322 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidStreamTypes))
323 if dep not in ValidDependencies:
324 raise Invalid("%s is not a valid dependency. It should be one of %s" % (dep, ValidDependencies))
325 return name, typ, dep
327 def validateParallelStream(self, port):
331 raise Invalid("%s is not a valid definition of a parallel stream port (name,type)" % (port,))
332 if typ not in ValidParallelStreamTypes:
333 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidParallelStreamTypes))
336 class Generator(object):
338 A :class:`Generator` instance take a :class:`Module` instance as its first parameter and can be used to generate the
339 SALOME source module, builds it, installs it and includes it in a SALOME application.
341 :param module: gives the :class:`Module` instance that will be used for the generation.
342 :param context: If given , its content is used to specify the prerequisites
343 environment file (key *"prerequisites"*) and the SALOME KERNEL installation directory (key *"kernel"*).
346 For example, the following call creates a generator for the module m::
348 >>> g = module_generator.Generator(m,context)
350 def __init__(self, module, context=None):
352 self.context = context or {}
353 self.kernel = self.context["kernel"]
354 self.gui = self.context.get("gui")
355 self.makeflags = self.context.get("makeflags")
357 if self.module.gui and not self.gui:
358 raise Invalid("To generate a module with GUI, you need to set the 'gui' parameter in the context dictionnary")
359 for component in self.module.components:
360 component.setPrerequisites(self.context.get("prerequisites"))
363 """ get the name of the source directory"""
364 return self.module.name+"_SRC"
367 """Generate a SALOME source module"""
369 namedir = self.sourceDir()
370 force = self.context.get("force")
371 update = self.context.get("update")
372 paco = self.context.get("paco")
373 if os.path.exists(namedir):
375 shutil.rmtree(namedir)
377 raise Invalid("The directory %s already exists" % namedir)
385 #get the list of SALOME modules used and put it in used_modules attribute
386 def get_dependent_modules(mod,modules):
388 if not salome_modules[mod].has_key("depends"):return
389 for m in salome_modules[mod]["depends"]:
390 if modules.has_key(m):continue
391 get_dependent_modules(m,modules)
394 for compo in module.components:
395 compo.depend_modules = set()
396 for serv in compo.services:
397 for name, typ in serv.inport + serv.outport + [ ("return",serv.ret) ] :
398 mod = moduleTypes[typ]
400 get_dependent_modules(mod,modules)
401 compo.depend_modules.add(mod)
403 self.used_modules = modules.keys()
405 for compo in module.components:
406 #for components files
407 fdict=compo.makeCompo(self)
408 srcs[compo.name] = fdict
411 components_string = "".join(map(lambda x: x.name+" ", module.components))
414 GUIname=module.name+"GUI"
415 fdict=self.makeGui(namedir)
416 srcs[GUIname] = fdict
417 components_string = components_string + "\n " + GUIname
419 cmakecontent = cmake_src.substitute(components=components_string)
420 srcs["CMakeLists.txt"] = cmakecontent
430 catalogfile = "%sCatalog.xml" % module.name
437 prefix = os.path.abspath(self.module.prefix)
438 component_libs = "".join(map(lambda x: x.libraryName()+" ",
440 add_modules = "".join(map(lambda x:cmake_find_module.substitute(module=x),
442 self.makeFiles({"CMakeLists.txt":cmake_root_cpp.substitute(
443 module=self.module.name,
444 module_min=self.module.name.lower(),
445 compolibs=component_libs,
448 add_modules=add_modules),
449 "README":"", "NEWS":"", "AUTHORS":"", "ChangeLog":"",
451 "resources":{"CMakeLists.txt":cmake_ressources.substitute(
452 module=self.module.name),
453 catalogfile:self.makeCatalog()},
458 idlfile = "%s.idl" % module.name
460 #if components have other idls
463 for compo in module.components:
465 for idl in compo.idls:
466 for fidl in glob.glob(idl):
467 other_idls=other_idls+os.path.basename(fidl) +" "
468 # other_sks=other_sks+os.path.splitext(os.path.basename(fidl))[0]+"SK.cc "
470 include_template=Template("$${${module}_ROOT_DIR}/idl/salome")
471 opt_inc="".join(map(lambda x:include_template.substitute(module=x)+"\n ",
473 link_template=Template("$${${module}_SalomeIDL${module}}")
474 opt_link="".join(map(lambda x:link_template.substitute(module=x)+"\n ",
477 idlfiles={"CMakeLists.txt":cmake_idl.substitute(module=module.name,
478 extra_idl=other_idls,
479 extra_include=opt_inc,
480 extra_link=opt_link),
481 idlfile :self.makeidl(),
484 files["idl"]=idlfiles
486 self.makeFiles(files,namedir)
488 #copy source files if any in created tree
489 for compo in module.components:
490 for src in compo.sources:
491 shutil.copyfile(src, os.path.join(namedir, "src", compo.name, os.path.basename(src)))
494 #copy provided idl files in idl directory
495 for idl in compo.idls:
496 for fidl in glob.glob(idl):
497 shutil.copyfile(fidl, os.path.join(namedir, "idl", os.path.basename(fidl)))
499 self.makeDoc(namedir)
502 def makeDoc(self,namedir):
503 if not self.module.doc:
505 rep=os.path.join(namedir,"doc")
508 for docs in self.module.doc:
509 for doc in glob.glob(docs):
510 name = os.path.basename(doc)
511 doc_files = doc_files + name + "\n "
512 shutil.copyfile(doc, os.path.join(rep, name))
516 if not self.module.gui:
517 #without gui but with doc: create a small SalomeApp.xml in doc directory
518 if not os.path.exists(os.path.join(namedir, "doc", "SalomeApp.xml")):
519 #create a minimal SalomeApp.xml
520 salomeapp=docsalomeapp.substitute(module=self.module.name,lmodule=self.module.name.lower())
521 d["SalomeApp.xml"]=salomeapp
523 if not os.path.exists(os.path.join(namedir, "doc", "CMakeLists.txt")):
524 #create a minimal CMakeLists.txt
525 makefile_txt=docmakefile.substitute(module=self.module.name,
527 if not self.module.gui:
528 txt = 'INSTALL(FILES SalomeApp.xml DESTINATION \
529 "${SALOME_%s_INSTALL_RES_DATA}")\n' % self.module.name
530 makefile_txt = makefile_txt + txt
533 d["CMakeLists.txt"]=makefile_txt
536 if not os.path.exists(os.path.join(namedir, "doc", "conf.py")):
537 #create a minimal conf.py
538 d["conf.py"]=docconf.substitute(module=self.module.name)
540 self.makeFiles(d,os.path.join(namedir,"doc"))
542 def makeGui(self,namedir):
543 if not self.module.gui:
547 #Force creation of intermediate directories
548 os.makedirs(os.path.join(namedir, "src", self.module.name+"GUI"))
550 for srcs in self.module.gui:
551 for src in glob.glob(srcs):
552 shutil.copyfile(src, os.path.join(namedir, "src", self.module.name+"GUI", os.path.basename(src)))
553 if src[-3:]==".py":ispython=True
554 if src[-4:]==".cxx":iscpp=True
555 if ispython and iscpp:
556 raise Invalid("Module GUI must be pure python or pure C++ but not mixed")
558 return self.makePyGUI(namedir)
560 return self.makeCPPGUI(namedir)
561 raise Invalid("Module GUI must be in python or C++ but it is none of them")
563 def makePyGUI(self,namedir):
565 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "CMakeLists.txt")):
566 #create a minimal CMakeLists.txt
571 for srcs in self.module.gui:
572 for src in glob.glob(srcs):
574 sources=sources+os.path.basename(src)+"\n "
575 elif src[-3:]==".ts":
576 ts_files=ts_files+os.path.basename(src)+"\n "
578 other=other+os.path.basename(src)+"\n "
579 makefile=cmake_py_gui.substitute(module=self.module.name,
581 ts_resources=ts_files,
583 d["CMakeLists.txt"]=makefile
585 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "SalomeApp.xml")):
586 #create a minimal SalomeApp.xml
587 salomeapp=pysalomeapp.substitute(module=self.module.name,lmodule=self.module.name.lower())
588 d["SalomeApp.xml"]=salomeapp
592 def makeCPPGUI(self,namedir):
594 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "CMakeLists.txt")):
595 #create a minimal CMakeLists.txt
601 for srcs in self.module.gui:
602 for src in glob.glob(srcs):
603 if src[-4:]==".cxx" or src[-4:]==".cpp":
604 sources=sources+os.path.basename(src)+"\n "
605 elif src[-2:]==".h" or src[-4:]==".hxx":
606 headers=headers+os.path.basename(src)+"\n "
607 elif src[-3:]==".ui":
608 ui_files=ui_files+os.path.basename(src)+"\n "
609 elif src[-3:]==".ts":
610 ts_files=ts_files+os.path.basename(src)+"\n "
612 other=other+os.path.basename(src)+"\n "
614 compo_dirs = "".join(map(lambda x:
615 "${PROJECT_SOURCE_DIR}/src/"+x.name+"\n ",
616 self.module.components))
617 compo_dirs = compo_dirs + "${PROJECT_BINARY_DIR}/src/" + self.module.name + "GUI\n"
618 component_libs = "".join(map(lambda x:
619 x.libraryName()+" ", self.module.components))
620 makefile=cmake_cpp_gui.substitute(module=self.module.name,
621 include_dirs=compo_dirs,
627 ts_resources=ts_files)
628 d["CMakeLists.txt"]=makefile
630 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "SalomeApp.xml")):
631 #create a minimal SalomeApp.xml
632 salomeapp=cppsalomeapp.substitute(module=self.module.name,lmodule=self.module.name.lower())
633 d["SalomeApp.xml"]=salomeapp
637 def makeMakefile(self,makefileItems):
639 if makefileItems.has_key("header"):
640 makefile=makefile + makefileItems["header"]+'\n'
641 if makefileItems.has_key("lib_LTLIBRARIES"):
642 makefile=makefile+"lib_LTLIBRARIES= "+" ".join(makefileItems["lib_LTLIBRARIES"])+'\n'
643 if makefileItems.has_key("salomepython_PYTHON"):
644 makefile=makefile+"salomepython_PYTHON= "+" ".join(makefileItems["salomepython_PYTHON"])+'\n'
645 if makefileItems.has_key("dist_salomescript_SCRIPTS"):
646 makefile=makefile+"dist_salomescript_SCRIPTS= "+" ".join(makefileItems["dist_salomescript_SCRIPTS"])+'\n'
647 if makefileItems.has_key("salomeres_DATA"):
648 makefile=makefile+"salomeres_DATA= "+" ".join(makefileItems["salomeres_DATA"])+'\n'
649 if makefileItems.has_key("salomeinclude_HEADERS"):
650 makefile=makefile+"salomeinclude_HEADERS= "+" ".join(makefileItems["salomeinclude_HEADERS"])+'\n'
651 if makefileItems.has_key("body"):
652 makefile=makefile+makefileItems["body"]+'\n'
655 def makeArgs(self, service):
656 """generate source service for arguments"""
658 for name, typ in service.inport:
659 if typ=="file":continue #files are not passed through service interface
660 params.append("%s %s" % (corba_in_type(typ, self.module.name), name))
661 for name, typ in service.outport:
662 if typ=="file":continue #files are not passed through service interface
663 params.append("%s %s" % (corba_out_type(typ, self.module.name), name))
664 return ",".join(params)
666 def makeCatalog(self):
667 """generate SALOME components catalog source"""
669 for compo in self.module.components:
671 for serv in compo.services:
673 for name, typ in serv.inport:
674 params.append(cataInparam.substitute(name=name, type=typ))
675 inparams = "\n".join(params)
677 for name, typ in serv.outport:
678 params.append(cataOutparam.substitute(name=name, type=typ))
679 if serv.ret != "void" :
680 params.append(cataOutparam.substitute(name="return", type=serv.ret))
681 outparams = "\n".join(params)
683 for name, typ, dep in serv.instream:
684 streams.append(cataInStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
685 for name, typ, dep in serv.outstream:
686 streams.append(cataOutStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
687 for name, typ in serv.parallel_instream:
688 streams.append(cataInParallelStream.substitute(name=name, type=DatastreamParallelTypes[typ]))
689 for name, typ in serv.parallel_outstream:
690 streams.append(cataOutParallelStream.substitute(name=name, type=DatastreamParallelTypes[typ]))
691 datastreams = "\n".join(streams)
692 services.append(cataService.substitute(service=serv.name, author="EDF-RD",
693 inparams=inparams, outparams=outparams, datastreams=datastreams))
694 impltype, implname = compo.getImpl()
695 components.append(cataCompo.substitute(component=compo.name, author="EDF-RD", impltype=impltype, implname=implname,
696 services='\n'.join(services)))
697 return catalog.substitute(components='\n'.join(components))
700 """generate module IDL file source (CORBA interface)"""
701 from pacocompo import PACOComponent
704 for compo in self.module.components:
705 if isinstance(compo, PACOComponent):
707 for serv in compo.services:
709 for name, typ in serv.inport:
710 if typ == "file":continue #files are not passed through IDL interface
711 params.append("in %s %s" % (idlTypes[typ], name))
712 for name, typ in serv.outport:
713 if typ == "file":continue #files are not passed through IDL interface
714 params.append("out %s %s" % (idlTypes[typ], name))
715 service = " void %s(" % serv.name
716 service = service+",".join(params)+");"
717 services.append(service)
719 interfaces.append(parallel_interface.substitute(component=compo.name, services="\n".join(services)))
723 for serv in compo.services:
725 for name, typ in serv.inport:
726 if typ == "file":continue #files are not passed through IDL interface
727 if compo.impl in ("PY", "ASTER") and typ == "pyobj":
728 typ = "Engines::fileBlock"
731 params.append("in %s %s" % (typ, name))
732 for name, typ in serv.outport:
733 if typ == "file":continue #files are not passed through IDL interface
734 if compo.impl in ("PY", "ASTER") and typ == "pyobj":
735 typ = "Engines::fileBlock"
738 params.append("out %s %s" % (typ, name))
739 service = " %s %s(" % (idlTypes[serv.ret],serv.name)
740 service = service+",".join(params)+") raises (SALOME::SALOME_Exception);"
741 services.append(service)
743 from hxxcompo import HXX2SALOMEComponent
744 from hxxparacompo import HXX2SALOMEParaComponent
745 if isinstance(compo,HXX2SALOMEComponent) or isinstance(compo,HXX2SALOMEParaComponent):
746 from hxx_tmpl import interfaceidlhxx
748 if isinstance(compo,HXX2SALOMEParaComponent):
749 Inherited="SALOME_MED::ParaMEDMEMComponent"
750 idldefs="""#include "ParaMEDMEMComponent.idl"\n"""
752 if compo.use_medmem==True:
753 Inherited="Engines::EngineComponent,SALOME::MultiCommClass,SALOME_MED::MED_Gen_Driver"
755 Inherited="Engines::EngineComponent"
756 interfaces.append(interfaceidlhxx.substitute(component=compo.name,inherited=Inherited, services="\n".join(services)))
758 inheritedinterface=""
759 if compo.inheritedinterface:
760 inheritedinterface=compo.inheritedinterface+","
761 interfaces.append(interface.substitute(component=compo.name, services="\n".join(services),inheritedinterface=inheritedinterface))
763 #build idl includes for SALOME modules
764 for mod in self.used_modules:
765 idldefs = idldefs + salome_modules[mod]["idldefs"]
767 for compo in self.module.components:
768 if compo.interfacedefs:
769 idldefs = idldefs + compo.interfacedefs
771 return idl.substitute(module=self.module.name, interfaces='\n'.join(interfaces),idldefs=idldefs)
775 from pacocompo import PACOComponent
777 for compo in self.module.components:
778 if isinstance(compo, PACOComponent):
780 for serv in compo.services:
781 if serv.impl_type == "parallel":
782 service = xml_service.substitute(service_name=serv.name)
783 services.append(service)
784 interfaces.append(xml_interface.substitute(component=compo.name, xml_services="\n".join(services)))
785 return xml.substitute(module=self.module.name, interfaces='\n'.join(interfaces))
787 def makeFiles(self, dic, basedir):
788 """create files and directories defined in dictionary dic in basedir directory
789 dic key = file name to create
790 dic value = file content or dictionary defining the content of a sub directory
792 for name, content in dic.items():
793 filename = os.path.join(basedir, name)
794 if isinstance(content, str):
795 fil = open(filename, 'w')
799 if not os.path.exists(filename):
800 os.makedirs(filename)
801 self.makeFiles(content, filename)
804 """Execute the second build step (configure) with installation prefix as given by the prefix attribute of module"""
805 prefix = os.path.abspath(self.module.prefix)
807 self.build_dir = "%s_build" % self.module.name
808 makedirs(self.build_dir)
810 build_sh = "cd %s; cmake ../%s -DCMAKE_INSTALL_PREFIX:PATH=%s"%(self.build_dir, self.sourceDir(), prefix)
811 ier = os.system(build_sh)
813 raise Invalid("configure has ended in error")
816 """Execute the third build step (compile and link) : make"""
817 make_command = "cd %s; make " % self.build_dir
819 make_command += self.makeflags
820 ier = os.system(make_command)
822 raise Invalid("make has ended in error")
825 """Execute the installation step : make install """
826 make_command = "cd %s; make install" % self.build_dir
827 ier = os.system(make_command)
829 raise Invalid("install has ended in error")
831 def make_appli(self, appliname, restrict=None, altmodules=None, resources=""):
833 Create a SALOME application containing the module and preexisting SALOME modules.
835 :param appliname: is a string that gives the name of the application (directory path where the application
838 :param restrict: If given (a list of module names), only those SALOME modules will be included in the
839 application. The default is to include all modules that are located in the same directory as the KERNEL module and have
840 the same suffix (for example, if KERNEL directory is KERNEL_V5 and GEOM directory is GEOM_V5, GEOM module is automatically
841 included, except if restrict is used).
842 :param altmodules: can be used to add SALOME modules that cannot be managed with the precedent rule. This parameter
843 is a dict with a module name as the key and the installation path as the value.
844 :param resources: can be used to define an alternative resources catalog (path of the file).
846 For example, the following calls create a SALOME application with external modules and resources catalog in "appli" directory::
848 >>> g=Generator(m,context)
853 >>> g.make_appli("appli", restrict=["KERNEL"], altmodules={"GUI":GUI_ROOT_DIR, "YACS":YACS_ROOT_DIR},
854 resources="myresources.xml")
859 rootdir, kerdir = os.path.split(self.kernel)
861 #collect modules besides KERNEL module with the same suffix if any
863 if kerdir[:6] == "KERNEL":
865 for mod in os.listdir(rootdir):
866 if mod[-len(suffix):] == suffix:
867 module = mod[:-len(suffix)]
868 path = os.path.join(rootdir, mod)
869 #try to find catalog files
870 lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*", "*Catalog.xml"))
872 #catalogs have not been found : try the upper level
873 lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*Catalog.xml"))
875 #catalogs have been found : add the corresponding entries in the application
877 catadir, catafile = os.path.split(cata)
878 name = catafile[:-11]
879 modules_dict[name] = ' <module name="%s" path="%s"/>' % (name, path)
881 modules_dict[module] = ' <module name="%s" path="%s"/>' % (module, path)
883 modules_dict["KERNEL"] = ' <module name="KERNEL" path="%s"/>' % self.kernel
885 #keep only the modules which names are in restrict if given
889 if modules_dict.has_key(mod):
890 modules.append(modules_dict[mod])
892 modules = modules_dict.values()
894 #add the alternate modules if given
896 for module, path in altmodules.items():
897 modules.append(' <module name="%s" path="%s"/>' % (module, path))
899 #add the generated module
900 modules.append(' <module name="%s" path="%s"/>' % (self.module.name, os.path.abspath(self.module.prefix)))
903 #try to find a prerequisites file
904 prerequisites = self.context.get("prerequisites")
905 if not prerequisites:
906 #try to find one in rootdir
907 prerequisites = os.path.join(rootdir, "profile%s.sh" % suffix)
908 if not os.path.exists(prerequisites):
909 raise Invalid("Can not create an application : prerequisites file not defined or does not exist")
911 #add resources catalog if it exists
913 if os.path.isfile(resources):
914 resources_spec='<resources path="%s" />' % os.path.abspath(resources)
916 #create config_appli.xml file
917 appli = application.substitute(prerequisites=prerequisites,
918 modules="\n".join(modules),
919 resources=resources_spec)
920 fil = open(os.path.join(appliname, "config_appli.xml"), 'w')
924 #execute appli_gen.py script
925 appligen = os.path.join(self.kernel, "bin", "salome", "appli_gen.py")
926 ier = os.system("cd %s;%s" % (appliname, appligen))
928 raise Invalid("make_appli has ended in error")
930 #add CatalogResources.xml if not created by appli_gen.py
931 if not os.path.exists(os.path.join(appliname, "CatalogResources.xml")):
932 #CatalogResources.xml does not exist create a minimal one
933 fil = open(os.path.join(appliname, 'CatalogResources.xml'), 'w')
934 command = """<!DOCTYPE ResourcesCatalog>
936 <machine hostname="%s" protocol="ssh" mode="interactive" />
939 host = socket.gethostname().split('.')[0]
940 fil.write(command % host)