1 # Copyright (C) 2009-2016 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
50 import yacsgen_version
52 def makedirs(namedir):
53 """Create a new directory named namedir. If a directory already exists copy it to namedir.bak"""
54 if os.path.exists(namedir):
55 dirbak = namedir+".bak"
56 if os.path.exists(dirbak):
58 os.rename(namedir, dirbak)
59 os.listdir(dirbak) #needed to update filesystem on special machines (cluster with NFS, for example)
64 A :class:`Module` instance represents a SALOME module that contains components given as a list of
65 component instances (:class:`CPPComponent` or :class:`PYComponent` or :class:`F77Component` or :class:`ASTERComponent`)
66 with the parameter *components*.
68 :param name: gives the name of the module. The SALOME source module
69 will be located in the <name_SRC> directory.
71 :param components: gives the list of components of the module.
72 :param prefix: is the path of the installation directory.
73 :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
74 used to build a sphinx documentation (see http://sphinx.pocoo.org, for more information). If not given, the Makefile.am
75 and the conf.py (sphinx configuration) files are generated. In this case, the file name extension of source files must be .rst.
76 See small examples in Examples/pygui1 and Examples/cppgui1.
77 :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, ...).
78 If not given, the CMakeLists.txt and SalomeApp.xml are generated. All image files are put in the resources directory of the module.
79 The GUI can be implemented in C++ (file name extension '.cxx') or in Python (file name extension '.py').
80 See small examples in Examples/pygui1 and Examples/cppgui1.
82 For example, the following call defines a module named "mymodule" with 2 components c1 and c2 (they must have been
83 defined before) that will be installed in the "install" directory::
85 >>> m = module_generator.Module('mymodule', components=[c1,c2],
89 def __init__(self, name, components=None, prefix="", doc=None, gui=None):
91 self.components = components or []
92 self.prefix = prefix or "%s_INSTALL" % name
100 print "Error in module %s: %s" % (name,e)
104 # Test Module name, canot have a "-" in the name
105 if self.name.find("-") != -1:
106 raise Invalid("Module name %s is not valid, remove character - in the module name" % self.name)
108 for compo in self.components:
109 if compo.name in lcompo:
110 raise Invalid("%s is already defined as a component of the module" % compo.name)
111 lcompo.add(compo.name)
114 class Library(object):
116 A :class:'Library' instance contains the informations of a user library.
118 :param name: name of the library (exemple: "cppunit", "calcul")
119 :param path: path where to find the library (exemple: "/home/user/libs")
122 def __init__(self, name, path):
126 def findLibrary(self):
128 return : text for the FIND_LIBRARY command for cmake.
129 Feel free to overload this function for your own needs.
131 return "FIND_LIBRARY( "+self.cmakeVarName()+" "+self.name+" PATH "+self.path + ")\n"
133 def cmakeVarName(self):
135 return : name of the cmake variable used by FIND_LIBRARY
137 return "_userlib_" + self.name.split()[0]
139 class Component(object):
140 def __init__(self, name, services=None, impl="PY", libs=[], rlibs="",
141 includes="", kind="lib", sources=None,
142 inheritedclass="",compodefs="",
143 idls=None,interfacedefs="",inheritedinterface="",addedmethods=""):
147 self.services = services or []
150 self.includes = includes
151 self.sources = sources or []
152 self.inheritedclass=inheritedclass
153 self.compodefs=compodefs
155 self.interfacedefs=interfacedefs
156 self.inheritedinterface=inheritedinterface
157 self.addedmethods=addedmethods
159 def additionalLibraries(self):
160 """ generate the cmake code for finding the additional libraries
162 string containing a list of "find_library"
163 string containing a list of cmake variables defined
168 for lib in self.libs:
169 cmake_text = cmake_text + lib.findLibrary()
170 cmake_vars = cmake_vars + "${" + lib.cmakeVarName() + "}\n "
172 var_template = Template("$${${name}_SalomeIDL${name}}")
173 for mod in self.depend_modules:
174 if salome_modules[mod]["linklibs"]:
175 cmake_vars = cmake_vars + salome_modules[mod]["linklibs"]
177 default_lib = var_template.substitute(name=mod)
178 print "Unknown libraries for module " + mod
179 print "Using default library name " + default_lib
180 cmake_vars = cmake_vars + default_lib + "\n "
182 return cmake_text, cmake_vars
185 if self.impl not in ValidImpl:
186 raise Invalid("%s is not a valid implementation. It should be one of %s" % (self.impl, ValidImpl))
189 for serv in self.services:
190 serv.impl = self.impl
191 if serv.name in lnames:
192 raise Invalid("%s is already defined as a service of the module" % serv.name)
193 lnames.add(serv.name)
196 for src in self.sources:
197 if not os.path.exists(src):
198 raise Invalid("Source file %s does not exist" % src)
203 def getMakefileItems(self,gen):
206 def setPrerequisites(self, prerequisites_file):
207 self.prerequisites = prerequisites_file
209 class Service(object):
211 A :class:`Service` instance represents a component service with dataflow and datastream ports.
213 :param name: gives the name of the service.
215 :param inport: gives the list of input dataflow ports.
216 :param outport: gives the list of output dataflow ports. An input or output dataflow port is defined
217 by a 2-tuple (port name, data type name). The list of supported basic data types is: "double", "long", "string",
218 "dblevec", "stringvec", "intvec", "file" and "pyobj" only for Python services. Depending on the implementation
219 language, it is also possible to use some types from SALOME modules (see :ref:`yacstypes`).
220 :param ret: gives the type of the return parameter
221 :param instream: gives the list of input datastream ports.
222 :param outstream: gives the list of output datastream ports. An input or output datastream port is defined
223 by a 3-tuple (port name, data type name, mode name). The list of possible data types is: "CALCIUM_double", "CALCIUM_integer",
224 "CALCIUM_real", "CALCIUM_string", "CALCIUM_complex", "CALCIUM_logical", "CALCIUM_long". The mode can be "I" (iterative mode)
225 or "T" (temporal mode).
226 :param defs: gives the source code to insert in the definition section of the component. It can be C++ includes
229 :param body: gives the source code to insert in the service call. It can be any C++
230 or Python code that fits well in the body of the service method.
233 For example, the following call defines a minimal Python service with one input dataflow port (name "a", type double)
234 and one input datastream port::
236 >>> s1 = module_generator.Service('myservice', inport=[("a","double"),],
237 instream=[("aa","CALCIUM_double","I")],
242 def __init__(self, name, inport=None, outport=None, ret="void", instream=None, outstream=None,
243 parallel_instream=None, parallel_outstream=None, defs="", body="", impl_type="sequential"):
245 self.inport = inport or []
246 self.outport = outport or []
248 self.instream = instream or []
249 self.outstream = outstream or []
250 self.parallel_instream = parallel_instream or []
251 self.parallel_outstream = parallel_outstream or []
255 self.impl_type = impl_type
259 for port in self.inport:
260 name, typ = self.validatePort(port)
262 raise Invalid("%s is already defined as a service parameter" % name)
265 for port in self.outport:
266 name, typ = self.validatePort(port)
268 raise Invalid("%s is already defined as a service parameter" % name)
272 for port in self.instream:
273 name, typ, dep = self.validateStream(port)
275 raise Invalid("%s is already defined as a stream port" % name)
278 for port in self.outstream:
279 name, typ, dep = self.validateStream(port)
281 raise Invalid("%s is already defined as a stream port" % name)
284 for port in self.parallel_instream:
285 name, typ = self.validateParallelStream(port)
287 raise Invalid("%s is already defined as a stream port" % name)
290 for port in self.parallel_outstream:
291 name, typ = self.validateParallelStream(port)
293 raise Invalid("%s is already defined as a stream port" % name)
296 self.validateImplType()
298 def validatePort(self, port):
302 raise Invalid("%s is not a valid definition of an data port (name,type)" % (port,))
304 if self.impl in ("PY", "ASTER"):
305 validtypes = PyValidTypes
307 validtypes = ValidTypes
309 if typ not in validtypes:
310 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, validtypes))
313 def validateImplType(self):
314 if self.impl_type not in ValidImplTypes:
315 raise Invalid("%s is not a valid impl type. It should be one of %s" % (self.impl_type, ValidImplTypes))
317 def validateStream(self, port):
319 name, typ, dep = port
321 raise Invalid("%s is not a valid definition of a stream port (name,type,dependency)" % (port,))
322 if typ not in ValidStreamTypes:
323 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidStreamTypes))
324 if dep not in ValidDependencies:
325 raise Invalid("%s is not a valid dependency. It should be one of %s" % (dep, ValidDependencies))
326 return name, typ, dep
328 def validateParallelStream(self, port):
332 raise Invalid("%s is not a valid definition of a parallel stream port (name,type)" % (port,))
333 if typ not in ValidParallelStreamTypes:
334 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidParallelStreamTypes))
337 class Generator(object):
339 A :class:`Generator` instance take a :class:`Module` instance as its first parameter and can be used to generate the
340 SALOME source module, builds it, installs it and includes it in a SALOME application.
342 :param module: gives the :class:`Module` instance that will be used for the generation.
343 :param context: If given , its content is used to specify the prerequisites
344 environment file (key *"prerequisites"*) and the SALOME KERNEL installation directory (key *"kernel"*).
347 For example, the following call creates a generator for the module m::
349 >>> g = module_generator.Generator(m,context)
351 def __init__(self, module, context=None):
353 self.context = context or {}
354 self.kernel = self.context["kernel"]
355 self.gui = self.context.get("gui")
356 self.makeflags = self.context.get("makeflags")
358 if self.module.gui and not self.gui:
359 raise Invalid("To generate a module with GUI, you need to set the 'gui' parameter in the context dictionnary")
360 for component in self.module.components:
361 component.setPrerequisites(self.context.get("prerequisites"))
364 """ get the name of the source directory"""
365 return self.module.name+"_SRC"
368 """Generate a SALOME source module"""
370 namedir = self.sourceDir()
371 force = self.context.get("force")
372 update = self.context.get("update")
373 paco = self.context.get("paco")
374 if os.path.exists(namedir):
376 shutil.rmtree(namedir)
378 raise Invalid("The directory %s already exists" % namedir)
386 #get the list of SALOME modules used and put it in used_modules attribute
387 def get_dependent_modules(mod,modules):
389 if not salome_modules[mod].has_key("depends"):return
390 for m in salome_modules[mod]["depends"]:
391 if modules.has_key(m):continue
392 get_dependent_modules(m,modules)
395 for compo in module.components:
396 compo.depend_modules = set()
397 for serv in compo.services:
398 for name, typ in serv.inport + serv.outport + [ ("return",serv.ret) ] :
399 mod = moduleTypes[typ]
401 get_dependent_modules(mod,modules)
402 compo.depend_modules.add(mod)
404 self.used_modules = modules.keys()
406 for compo in module.components:
407 #for components files
408 fdict=compo.makeCompo(self)
409 srcs[compo.name] = fdict
412 components_string = "".join(map(lambda x: x.name+" ", module.components))
415 GUIname=module.name+"GUI"
416 fdict=self.makeGui(namedir)
417 srcs[GUIname] = fdict
418 components_string = components_string + "\n " + GUIname
420 cmakecontent = cmake_src.substitute(components=components_string)
421 srcs["CMakeLists.txt"] = cmakecontent
431 catalogfile = "%sCatalog.xml" % module.name
438 prefix = os.path.abspath(self.module.prefix)
439 component_libs = "".join(map(lambda x: x.libraryName()+" ",
441 add_modules = "".join(map(lambda x:cmake_find_module.substitute(module=x),
443 self.makeFiles({"CMakeLists.txt":cmake_root_cpp.substitute(
444 module=self.module.name,
445 module_min=self.module.name.lower(),
446 compolibs=component_libs,
449 add_modules=add_modules,
450 major_version=yacsgen_version.major_version,
451 minor_version=yacsgen_version.minor_version,
452 patch_version=yacsgen_version.patch_version),
453 "README":"", "NEWS":"", "AUTHORS":"", "ChangeLog":"",
455 "resources":{"CMakeLists.txt":cmake_ressources.substitute(
456 module=self.module.name),
457 catalogfile:self.makeCatalog()},
462 idlfile = "%s.idl" % module.name
464 #if components have other idls
467 for compo in module.components:
469 for idl in compo.idls:
470 for fidl in glob.glob(idl):
471 other_idls=other_idls+os.path.basename(fidl) +" "
472 # other_sks=other_sks+os.path.splitext(os.path.basename(fidl))[0]+"SK.cc "
474 include_template=Template("$${${module}_ROOT_DIR}/idl/salome")
475 opt_inc="".join(map(lambda x:include_template.substitute(module=x)+"\n ",
477 link_template=Template("$${${module}_SalomeIDL${module}}")
478 opt_link="".join(map(lambda x:link_template.substitute(module=x)+"\n ",
481 idlfiles={"CMakeLists.txt":cmake_idl.substitute(module=module.name,
482 extra_idl=other_idls,
483 extra_include=opt_inc,
484 extra_link=opt_link),
485 idlfile :self.makeidl(),
488 files["idl"]=idlfiles
490 self.makeFiles(files,namedir)
492 #copy source files if any in created tree
493 for compo in module.components:
494 for src in compo.sources:
495 shutil.copyfile(src, os.path.join(namedir, "src", compo.name, os.path.basename(src)))
498 #copy provided idl files in idl directory
499 for idl in compo.idls:
500 for fidl in glob.glob(idl):
501 shutil.copyfile(fidl, os.path.join(namedir, "idl", os.path.basename(fidl)))
503 self.makeDoc(namedir)
506 def makeDoc(self,namedir):
507 if not self.module.doc:
509 rep=os.path.join(namedir,"doc")
512 for docs in self.module.doc:
513 for doc in glob.glob(docs):
514 name = os.path.basename(doc)
515 doc_files = doc_files + name + "\n "
516 shutil.copyfile(doc, os.path.join(rep, name))
520 if not self.module.gui:
521 #without gui but with doc: create a small SalomeApp.xml in doc directory
522 if not os.path.exists(os.path.join(namedir, "doc", "SalomeApp.xml")):
523 #create a minimal SalomeApp.xml
524 salomeapp=docsalomeapp.substitute(module=self.module.name,
525 lmodule=self.module.name.lower(),
526 version=yacsgen_version.complete_version)
527 d["SalomeApp.xml"]=salomeapp
529 if not os.path.exists(os.path.join(namedir, "doc", "CMakeLists.txt")):
530 #create a minimal CMakeLists.txt
531 makefile_txt=docmakefile.substitute(module=self.module.name,
533 if not self.module.gui:
534 txt = 'INSTALL(FILES SalomeApp.xml DESTINATION \
535 "${SALOME_%s_INSTALL_RES_DATA}")\n' % self.module.name
536 makefile_txt = makefile_txt + txt
539 d["CMakeLists.txt"]=makefile_txt
542 if not os.path.exists(os.path.join(namedir, "doc", "conf.py")):
543 #create a minimal conf.py
544 d["conf.py"]=docconf.substitute(module=self.module.name)
546 self.makeFiles(d,os.path.join(namedir,"doc"))
548 def makeGui(self,namedir):
549 if not self.module.gui:
553 #Force creation of intermediate directories
554 os.makedirs(os.path.join(namedir, "src", self.module.name+"GUI"))
556 for srcs in self.module.gui:
557 for src in glob.glob(srcs):
558 shutil.copyfile(src, os.path.join(namedir, "src", self.module.name+"GUI", os.path.basename(src)))
559 if src[-3:]==".py":ispython=True
560 if src[-4:]==".cxx":iscpp=True
561 if ispython and iscpp:
562 raise Invalid("Module GUI must be pure python or pure C++ but not mixed")
564 return self.makePyGUI(namedir)
566 return self.makeCPPGUI(namedir)
567 raise Invalid("Module GUI must be in python or C++ but it is none of them")
569 def makePyGUI(self,namedir):
571 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "CMakeLists.txt")):
572 #create a minimal CMakeLists.txt
577 for srcs in self.module.gui:
578 for src in glob.glob(srcs):
580 sources=sources+os.path.basename(src)+"\n "
581 elif src[-3:]==".ts":
582 ts_files=ts_files+os.path.basename(src)+"\n "
584 other=other+os.path.basename(src)+"\n "
585 makefile=cmake_py_gui.substitute(module=self.module.name,
587 ts_resources=ts_files,
589 d["CMakeLists.txt"]=makefile
591 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "SalomeApp.xml")):
592 #create a minimal SalomeApp.xml
593 salomeapp=pysalomeapp.substitute(module=self.module.name,
594 lmodule=self.module.name.lower(),
595 version=yacsgen_version.complete_version)
596 d["SalomeApp.xml"]=salomeapp
600 def makeCPPGUI(self,namedir):
602 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "CMakeLists.txt")):
603 #create a minimal CMakeLists.txt
609 for srcs in self.module.gui:
610 for src in glob.glob(srcs):
611 if src[-4:]==".cxx" or src[-4:]==".cpp":
612 sources=sources+os.path.basename(src)+"\n "
613 elif src[-2:]==".h" or src[-4:]==".hxx":
614 headers=headers+os.path.basename(src)+"\n "
615 elif src[-3:]==".ui":
616 ui_files=ui_files+os.path.basename(src)+"\n "
617 elif src[-3:]==".ts":
618 ts_files=ts_files+os.path.basename(src)+"\n "
620 other=other+os.path.basename(src)+"\n "
622 compo_dirs = "".join(map(lambda x:
623 "${PROJECT_SOURCE_DIR}/src/"+x.name+"\n ",
624 self.module.components))
625 compo_dirs = compo_dirs + "${PROJECT_BINARY_DIR}/src/" + self.module.name + "GUI\n"
626 component_libs = "".join(map(lambda x:
627 x.libraryName()+" ", self.module.components))
628 makefile=cmake_cpp_gui.substitute(module=self.module.name,
629 include_dirs=compo_dirs,
635 ts_resources=ts_files)
636 d["CMakeLists.txt"]=makefile
638 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "SalomeApp.xml")):
639 #create a minimal SalomeApp.xml
640 salomeapp=cppsalomeapp.substitute(module=self.module.name,
641 lmodule=self.module.name.lower(),
642 version=yacsgen_version.complete_version)
643 d["SalomeApp.xml"]=salomeapp
647 def makeMakefile(self,makefileItems):
649 if makefileItems.has_key("header"):
650 makefile=makefile + makefileItems["header"]+'\n'
651 if makefileItems.has_key("lib_LTLIBRARIES"):
652 makefile=makefile+"lib_LTLIBRARIES= "+" ".join(makefileItems["lib_LTLIBRARIES"])+'\n'
653 if makefileItems.has_key("salomepython_PYTHON"):
654 makefile=makefile+"salomepython_PYTHON= "+" ".join(makefileItems["salomepython_PYTHON"])+'\n'
655 if makefileItems.has_key("dist_salomescript_SCRIPTS"):
656 makefile=makefile+"dist_salomescript_SCRIPTS= "+" ".join(makefileItems["dist_salomescript_SCRIPTS"])+'\n'
657 if makefileItems.has_key("salomeres_DATA"):
658 makefile=makefile+"salomeres_DATA= "+" ".join(makefileItems["salomeres_DATA"])+'\n'
659 if makefileItems.has_key("salomeinclude_HEADERS"):
660 makefile=makefile+"salomeinclude_HEADERS= "+" ".join(makefileItems["salomeinclude_HEADERS"])+'\n'
661 if makefileItems.has_key("body"):
662 makefile=makefile+makefileItems["body"]+'\n'
665 def makeArgs(self, service):
666 """generate source service for arguments"""
668 for name, typ in service.inport:
669 if typ=="file":continue #files are not passed through service interface
670 params.append("%s %s" % (corba_in_type(typ, self.module.name), name))
671 for name, typ in service.outport:
672 if typ=="file":continue #files are not passed through service interface
673 params.append("%s %s" % (corba_out_type(typ, self.module.name), name))
674 return ",".join(params)
676 def makeCatalog(self):
677 """generate SALOME components catalog source"""
679 for compo in self.module.components:
681 for serv in compo.services:
683 for name, typ in serv.inport:
684 params.append(cataInparam.substitute(name=name, type=typ))
685 inparams = "\n".join(params)
687 for name, typ in serv.outport:
688 params.append(cataOutparam.substitute(name=name, type=typ))
689 if serv.ret != "void" :
690 params.append(cataOutparam.substitute(name="return", type=serv.ret))
691 outparams = "\n".join(params)
693 for name, typ, dep in serv.instream:
694 streams.append(cataInStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
695 for name, typ, dep in serv.outstream:
696 streams.append(cataOutStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
697 for name, typ in serv.parallel_instream:
698 streams.append(cataInParallelStream.substitute(name=name, type=DatastreamParallelTypes[typ]))
699 for name, typ in serv.parallel_outstream:
700 streams.append(cataOutParallelStream.substitute(name=name, type=DatastreamParallelTypes[typ]))
701 datastreams = "\n".join(streams)
702 services.append(cataService.substitute(service=serv.name, author="EDF-RD",
703 inparams=inparams, outparams=outparams, datastreams=datastreams))
704 impltype, implname = compo.getImpl()
705 components.append(cataCompo.substitute(component=compo.name, author="EDF-RD", impltype=impltype, implname=implname,
706 services='\n'.join(services)))
707 return catalog.substitute(components='\n'.join(components))
710 """generate module IDL file source (CORBA interface)"""
711 from pacocompo import PACOComponent
714 for compo in self.module.components:
715 if isinstance(compo, PACOComponent):
717 for serv in compo.services:
719 for name, typ in serv.inport:
720 if typ == "file":continue #files are not passed through IDL interface
721 params.append("in %s %s" % (idlTypes[typ], name))
722 for name, typ in serv.outport:
723 if typ == "file":continue #files are not passed through IDL interface
724 params.append("out %s %s" % (idlTypes[typ], name))
725 service = " void %s(" % serv.name
726 service = service+",".join(params)+");"
727 services.append(service)
729 interfaces.append(parallel_interface.substitute(component=compo.name, services="\n".join(services)))
733 for serv in compo.services:
735 for name, typ in serv.inport:
736 if typ == "file":continue #files are not passed through IDL interface
737 if compo.impl in ("PY", "ASTER") and typ == "pyobj":
738 typ = "Engines::fileBlock"
741 params.append("in %s %s" % (typ, name))
742 for name, typ in serv.outport:
743 if typ == "file":continue #files are not passed through IDL interface
744 if compo.impl in ("PY", "ASTER") and typ == "pyobj":
745 typ = "Engines::fileBlock"
748 params.append("out %s %s" % (typ, name))
749 service = " %s %s(" % (idlTypes[serv.ret],serv.name)
750 service = service+",".join(params)+") raises (SALOME::SALOME_Exception);"
751 services.append(service)
753 from hxxcompo import HXX2SALOMEComponent
754 from hxxparacompo import HXX2SALOMEParaComponent
755 if isinstance(compo,HXX2SALOMEComponent) or isinstance(compo,HXX2SALOMEParaComponent):
756 from hxx_tmpl import interfaceidlhxx
758 if isinstance(compo,HXX2SALOMEParaComponent):
759 Inherited="SALOME_MED::ParaMEDMEMComponent"
760 idldefs="""#include "ParaMEDMEMComponent.idl"\n"""
762 if compo.use_medmem==True:
763 Inherited="Engines::EngineComponent,SALOME::MultiCommClass,SALOME_MED::MED_Gen_Driver"
765 Inherited="Engines::EngineComponent"
766 interfaces.append(interfaceidlhxx.substitute(component=compo.name,inherited=Inherited, services="\n".join(services)))
768 inheritedinterface=""
769 if compo.inheritedinterface:
770 inheritedinterface=compo.inheritedinterface+","
771 interfaces.append(interface.substitute(component=compo.name, services="\n".join(services),inheritedinterface=inheritedinterface))
773 #build idl includes for SALOME modules
774 for mod in self.used_modules:
775 idldefs = idldefs + salome_modules[mod]["idldefs"]
777 for compo in self.module.components:
778 if compo.interfacedefs:
779 idldefs = idldefs + compo.interfacedefs
781 return idl.substitute(module=self.module.name, interfaces='\n'.join(interfaces),idldefs=idldefs)
785 from pacocompo import PACOComponent
787 for compo in self.module.components:
788 if isinstance(compo, PACOComponent):
790 for serv in compo.services:
791 if serv.impl_type == "parallel":
792 service = xml_service.substitute(service_name=serv.name)
793 services.append(service)
794 interfaces.append(xml_interface.substitute(component=compo.name, xml_services="\n".join(services)))
795 return xml.substitute(module=self.module.name, interfaces='\n'.join(interfaces))
797 def makeFiles(self, dic, basedir):
798 """create files and directories defined in dictionary dic in basedir directory
799 dic key = file name to create
800 dic value = file content or dictionary defining the content of a sub directory
802 for name, content in dic.items():
803 filename = os.path.join(basedir, name)
804 if isinstance(content, str):
805 fil = open(filename, 'w')
809 if not os.path.exists(filename):
810 os.makedirs(filename)
811 self.makeFiles(content, filename)
814 """Execute the second build step (configure) with installation prefix as given by the prefix attribute of module"""
815 prefix = os.path.abspath(self.module.prefix)
817 self.build_dir = "%s_build" % self.module.name
818 makedirs(self.build_dir)
820 build_sh = "cd %s; cmake ../%s -DCMAKE_INSTALL_PREFIX:PATH=%s"%(self.build_dir, self.sourceDir(), prefix)
821 ier = os.system(build_sh)
823 raise Invalid("configure has ended in error")
826 """Execute the third build step (compile and link) : make"""
827 make_command = "cd %s; make " % self.build_dir
829 make_command += self.makeflags
830 ier = os.system(make_command)
832 raise Invalid("make has ended in error")
835 """Execute the installation step : make install """
836 make_command = "cd %s; make install" % self.build_dir
837 ier = os.system(make_command)
839 raise Invalid("install has ended in error")
841 def make_appli(self, appliname, restrict=None, altmodules=None, resources=""):
843 Create a SALOME application containing the module and preexisting SALOME modules.
845 :param appliname: is a string that gives the name of the application (directory path where the application
848 :param restrict: If given (a list of module names), only those SALOME modules will be included in the
849 application. The default is to include all modules that are located in the same directory as the KERNEL module and have
850 the same suffix (for example, if KERNEL directory is KERNEL_V5 and GEOM directory is GEOM_V5, GEOM module is automatically
851 included, except if restrict is used).
852 :param altmodules: can be used to add SALOME modules that cannot be managed with the precedent rule. This parameter
853 is a dict with a module name as the key and the installation path as the value.
854 :param resources: can be used to define an alternative resources catalog (path of the file).
856 For example, the following calls create a SALOME application with external modules and resources catalog in "appli" directory::
858 >>> g=Generator(m,context)
863 >>> g.make_appli("appli", restrict=["KERNEL"], altmodules={"GUI":GUI_ROOT_DIR, "YACS":YACS_ROOT_DIR},
864 resources="myresources.xml")
869 rootdir, kerdir = os.path.split(self.kernel)
871 #collect modules besides KERNEL module with the same suffix if any
873 if kerdir[:6] == "KERNEL":
875 for mod in os.listdir(rootdir):
876 if mod[-len(suffix):] == suffix:
877 module = mod[:-len(suffix)]
878 path = os.path.join(rootdir, mod)
879 #try to find catalog files
880 lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*", "*Catalog.xml"))
882 #catalogs have not been found : try the upper level
883 lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*Catalog.xml"))
885 #catalogs have been found : add the corresponding entries in the application
887 catadir, catafile = os.path.split(cata)
888 name = catafile[:-11]
889 modules_dict[name] = ' <module name="%s" path="%s"/>' % (name, path)
891 modules_dict[module] = ' <module name="%s" path="%s"/>' % (module, path)
893 modules_dict["KERNEL"] = ' <module name="KERNEL" path="%s"/>' % self.kernel
895 #keep only the modules which names are in restrict if given
899 if modules_dict.has_key(mod):
900 modules.append(modules_dict[mod])
902 modules = modules_dict.values()
904 #add the alternate modules if given
906 for module, path in altmodules.items():
907 modules.append(' <module name="%s" path="%s"/>' % (module, path))
909 #add the generated module
910 modules.append(' <module name="%s" path="%s"/>' % (self.module.name, os.path.abspath(self.module.prefix)))
913 #try to find a prerequisites file
914 prerequisites = self.context.get("prerequisites")
915 if not prerequisites:
916 #try to find one in rootdir
917 prerequisites = os.path.join(rootdir, "profile%s.sh" % suffix)
918 if not os.path.exists(prerequisites):
919 raise Invalid("Can not create an application : prerequisites file not defined or does not exist")
921 #add resources catalog if it exists
923 if os.path.isfile(resources):
924 resources_spec='<resources path="%s" />' % os.path.abspath(resources)
926 #create config_appli.xml file
927 appli = application.substitute(prerequisites=prerequisites,
928 modules="\n".join(modules),
929 resources=resources_spec)
930 fil = open(os.path.join(appliname, "config_appli.xml"), 'w')
934 #execute appli_gen.py script
935 appligen = os.path.join(self.kernel, "bin", "salome", "appli_gen.py")
936 ier = os.system("cd %s;%s" % (appliname, appligen))
938 raise Invalid("make_appli has ended in error")
940 #add CatalogResources.xml if not created by appli_gen.py
941 if not os.path.exists(os.path.join(appliname, "CatalogResources.xml")):
942 #CatalogResources.xml does not exist create a minimal one
943 fil = open(os.path.join(appliname, 'CatalogResources.xml'), 'w')
944 command = """<!DOCTYPE ResourcesCatalog>
946 <machine hostname="%s" protocol="ssh" mode="interactive" />
949 host = socket.gethostname().split('.')[0]
950 fil.write(command % host)