1 # Copyright (C) 2009-2013 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.
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 resMakefile, makecommon, configure, paco_configure
35 from mod_tmpl import mainMakefile, autogen, application
36 from mod_tmpl import check_sphinx
37 from cata_tmpl import catalog, interface, idl, idlMakefile, parallel_interface
38 from cata_tmpl import xml, xml_interface, xml_service
39 from cata_tmpl import idlMakefilePaCO_BUILT_SOURCES, idlMakefilePaCO_nodist_salomeinclude_HEADERS
40 from cata_tmpl import idlMakefilePACO_salomepython_DATA, idlMakefilePACO_salomeidl_DATA
41 from cata_tmpl import idlMakefilePACO_INCLUDES
42 from cata_tmpl import cataOutStream, cataInStream, cataOutparam, cataInparam
43 from cata_tmpl import cataOutParallelStream, cataInParallelStream
44 from cata_tmpl import cataService, cataCompo
45 from aster_tmpl import check_aster
46 from salomemodules import salome_modules
47 from yacstypes import corbaTypes, corbaOutTypes, moduleTypes, idlTypes, corba_in_type, corba_out_type
48 from yacstypes import ValidTypes, PyValidTypes, calciumTypes, DatastreamParallelTypes
49 from yacstypes import ValidImpl, ValidImplTypes, ValidStreamTypes, ValidParallelStreamTypes, ValidDependencies
50 from gui_tmpl import pyguimakefile, pysalomeapp, cppguimakefile, cppsalomeapp
51 from doc_tmpl import docmakefile, docconf, docsalomeapp
53 def makedirs(namedir):
54 """Create a new directory named namedir. If a directory already exists copy it to namedir.bak"""
55 if os.path.exists(namedir):
56 dirbak = namedir+".bak"
57 if os.path.exists(dirbak):
59 os.rename(namedir, dirbak)
60 os.listdir(dirbak) #needed to update filesystem on special machines (cluster with NFS, for example)
65 A :class:`Module` instance represents a SALOME module that contains components given as a list of
66 component instances (:class:`CPPComponent` or :class:`PYComponent` or :class:`F77Component` or :class:`ASTERComponent`)
67 with the parameter *components*.
69 :param name: gives the name of the module. The SALOME source module
70 will be located in the <name_SRC> directory.
72 :param components: gives the list of components of the module.
73 :param prefix: is the path of the installation directory.
74 :param layout: If given and has the value "monodir", all components
75 will be generated in a single directory. The default is to generate each component in its
77 :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
78 used to build a sphinx documentation (see http://sphinx.pocoo.org, for more information). If not given, the Makefile.am
79 and the conf.py (sphinx configuration) files are generated. In this case, the file name extension of source files must be .rst.
80 See small examples in Examples/pygui1 and Examples/cppgui1.
81 :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, ...).
82 If not given, the Makefile.am and SalomeApp.xml are generated. All image files are put in the resources directory of the module.
83 The GUI can be implemented in C++ (file name extension '.cxx') or in Python (file name extension '.py').
84 See small examples in Examples/pygui1 and Examples/cppgui1.
86 For example, the following call defines a module named "mymodule" with 2 components c1 and c2 (they must have been
87 defined before) that will be installed in the "install" directory::
89 >>> m = module_generator.Module('mymodule', components=[c1,c2],
93 def __init__(self, name, components=None, prefix="",layout="multidir", doc=None, gui=None):
95 self.components = components or []
96 self.prefix = prefix or "%s_INSTALL" % name
104 traceback.print_exc()
105 print "Error in module %s: %s" % (name,e)
109 # Test Module name, canot have a "-" in the name
110 if self.name.find("-") != -1:
111 raise Invalid("Module name %s is not valid, remove character - in the module name" % self.name)
113 for compo in self.components:
114 if compo.name in lcompo:
115 raise Invalid("%s is already defined as a component of the module" % compo.name)
116 lcompo.add(compo.name)
118 if self.gui and self.layout != "multidir":
119 raise Invalid("A module with GUI can not be generated if layout is not multidir")
121 class Component(object):
122 def __init__(self, name, services=None, impl="PY", libs="", rlibs="",
123 includes="", kind="lib", sources=None,
124 inheritedclass="",compodefs="",
125 idls=None,interfacedefs="",inheritedinterface="",addedmethods=""):
129 self.services = services or []
132 self.includes = includes
133 self.sources = sources or []
134 self.inheritedclass=inheritedclass
135 self.compodefs=compodefs
137 self.interfacedefs=interfacedefs
138 self.inheritedinterface=inheritedinterface
139 self.addedmethods=addedmethods
142 if self.impl not in ValidImpl:
143 raise Invalid("%s is not a valid implementation. It should be one of %s" % (self.impl, ValidImpl))
146 for serv in self.services:
147 serv.impl = self.impl
148 if serv.name in lnames:
149 raise Invalid("%s is already defined as a service of the module" % serv.name)
150 lnames.add(serv.name)
153 for src in self.sources:
154 if not os.path.exists(src):
155 raise Invalid("Source file %s does not exist" % src)
160 def getMakefileItems(self,gen):
163 def setPrerequisites(self, prerequisites_file):
164 self.prerequisites = prerequisites_file
166 class Service(object):
168 A :class:`Service` instance represents a component service with dataflow and datastream ports.
170 :param name: gives the name of the service.
172 :param inport: gives the list of input dataflow ports.
173 :param outport: gives the list of output dataflow ports. An input or output dataflow port is defined
174 by a 2-tuple (port name, data type name). The list of supported basic data types is: "double", "long", "string",
175 "dblevec", "stringvec", "intvec", "file" and "pyobj" only for Python services. Depending on the implementation
176 language, it is also possible to use some types from SALOME modules (see :ref:`yacstypes`).
177 :param ret: gives the type of the return parameter
178 :param instream: gives the list of input datastream ports.
179 :param outstream: gives the list of output datastream ports. An input or output datastream port is defined
180 by a 3-tuple (port name, data type name, mode name). The list of possible data types is: "CALCIUM_double", "CALCIUM_integer",
181 "CALCIUM_real", "CALCIUM_string", "CALCIUM_complex", "CALCIUM_logical", "CALCIUM_long". The mode can be "I" (iterative mode)
182 or "T" (temporal mode).
183 :param defs: gives the source code to insert in the definition section of the component. It can be C++ includes
186 :param body: gives the source code to insert in the service call. It can be any C++
187 or Python code that fits well in the body of the service method.
190 For example, the following call defines a minimal Python service with one input dataflow port (name "a", type double)
191 and one input datastream port::
193 >>> s1 = module_generator.Service('myservice', inport=[("a","double"),],
194 instream=[("aa","CALCIUM_double","I")],
199 def __init__(self, name, inport=None, outport=None, ret="void", instream=None, outstream=None,
200 parallel_instream=None, parallel_outstream=None, defs="", body="", impl_type="sequential"):
202 self.inport = inport or []
203 self.outport = outport or []
205 self.instream = instream or []
206 self.outstream = outstream or []
207 self.parallel_instream = parallel_instream or []
208 self.parallel_outstream = parallel_outstream or []
212 self.impl_type = impl_type
216 for port in self.inport:
217 name, typ = self.validatePort(port)
219 raise Invalid("%s is already defined as a service parameter" % name)
222 for port in self.outport:
223 name, typ = self.validatePort(port)
225 raise Invalid("%s is already defined as a service parameter" % name)
229 for port in self.instream:
230 name, typ, dep = self.validateStream(port)
232 raise Invalid("%s is already defined as a stream port" % name)
235 for port in self.outstream:
236 name, typ, dep = self.validateStream(port)
238 raise Invalid("%s is already defined as a stream port" % name)
241 for port in self.parallel_instream:
242 name, typ = self.validateParallelStream(port)
244 raise Invalid("%s is already defined as a stream port" % name)
247 for port in self.parallel_outstream:
248 name, typ = self.validateParallelStream(port)
250 raise Invalid("%s is already defined as a stream port" % name)
253 self.validateImplType()
255 def validatePort(self, port):
259 raise Invalid("%s is not a valid definition of an data port (name,type)" % (port,))
261 if self.impl in ("PY", "ASTER"):
262 validtypes = PyValidTypes
264 validtypes = ValidTypes
266 if typ not in validtypes:
267 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, validtypes))
270 def validateImplType(self):
271 if self.impl_type not in ValidImplTypes:
272 raise Invalid("%s is not a valid impl type. It should be one of %s" % (self.impl_type, ValidImplTypes))
274 def validateStream(self, port):
276 name, typ, dep = port
278 raise Invalid("%s is not a valid definition of a stream port (name,type,dependency)" % (port,))
279 if typ not in ValidStreamTypes:
280 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidStreamTypes))
281 if dep not in ValidDependencies:
282 raise Invalid("%s is not a valid dependency. It should be one of %s" % (dep, ValidDependencies))
283 return name, typ, dep
285 def validateParallelStream(self, port):
289 raise Invalid("%s is not a valid definition of a parallel stream port (name,type)" % (port,))
290 if typ not in ValidParallelStreamTypes:
291 raise Invalid("%s is not a valid type. It should be one of %s" % (typ, ValidParallelStreamTypes))
294 class Generator(object):
296 A :class:`Generator` instance take a :class:`Module` instance as its first parameter and can be used to generate the
297 SALOME source module, builds it, installs it and includes it in a SALOME application.
299 :param module: gives the :class:`Module` instance that will be used for the generation.
300 :param context: If given , its content is used to specify the prerequisites
301 environment file (key *"prerequisites"*) and the SALOME KERNEL installation directory (key *"kernel"*).
304 For example, the following call creates a generator for the module m::
306 >>> g = module_generator.Generator(m,context)
308 def __init__(self, module, context=None):
310 self.context = context or {}
311 self.kernel = self.context["kernel"]
312 self.gui = self.context.get("gui")
313 self.makeflags = self.context.get("makeflags")
315 if self.module.gui and not self.gui:
316 raise Invalid("To generate a module with GUI, you need to set the 'gui' parameter in the context dictionnary")
317 for component in self.module.components:
318 component.setPrerequisites(self.context.get("prerequisites"))
321 """Generate a SALOME source module"""
323 namedir = module.name+"_SRC"
324 force = self.context.get("force")
325 update = self.context.get("update")
326 paco = self.context.get("paco")
327 if os.path.exists(namedir):
329 shutil.rmtree(namedir)
331 raise Invalid("The directory %s already exists" % namedir)
338 makefile = "SUBDIRS="
339 makefileItems={"header":"""
340 include $(top_srcdir)/adm_local/make_common_starter.am
341 AM_CFLAGS=$(SALOME_INCLUDES) -fexceptions
343 "salomepython_PYTHON":[],
344 "dist_salomescript_SCRIPTS":[],
346 "lib_LTLIBRARIES":[],
347 "salomeinclude_HEADERS":[],
351 #get the list of SALOME modules used and put it in used_modules attribute
352 def get_dependent_modules(mod,modules):
354 if not salome_modules[mod].has_key("depends"):return
355 for m in salome_modules[mod]["depends"]:
356 if modules.has_key(m):continue
357 get_dependent_modules(m,modules)
360 for compo in module.components:
361 for serv in compo.services:
362 for name, typ in serv.inport + serv.outport + [ ("return",serv.ret) ] :
363 mod = moduleTypes[typ]
365 get_dependent_modules(mod,modules)
367 self.used_modules = modules.keys()
369 for compo in module.components:
370 #for components files
371 fdict=compo.makeCompo(self)
372 if self.module.layout=="multidir":
373 srcs[compo.name] = fdict
375 makefile = makefile + " " + compo.name
379 mdict=compo.getMakefileItems(self)
380 makefileItems["salomepython_PYTHON"]=makefileItems["salomepython_PYTHON"]+mdict.get("salomepython_PYTHON",[])
381 makefileItems["dist_salomescript_SCRIPTS"]=makefileItems["dist_salomescript_SCRIPTS"]+mdict.get("dist_salomescript_SCRIPTS",[])
382 makefileItems["salomeres_DATA"]=makefileItems["salomeres_DATA"]+mdict.get("salomeres_DATA",[])
383 makefileItems["lib_LTLIBRARIES"]=makefileItems["lib_LTLIBRARIES"]+mdict.get("lib_LTLIBRARIES",[])
384 makefileItems["salomeinclude_HEADERS"]=makefileItems["salomeinclude_HEADERS"]+mdict.get("salomeinclude_HEADERS",[])
385 makefileItems["body"]=makefileItems["body"]+mdict.get("body","")+'\n'
388 GUIname=module.name+"GUI"
389 fdict=self.makeGui(namedir)
390 srcs[GUIname] = fdict
392 makefile = makefile + " " + GUIname
394 if self.module.layout == "multidir":
395 srcs["Makefile.am"] = makefile+'\n'
397 srcs["Makefile.am"] = self.makeMakefile(makefileItems)
404 catalogfile = "%sCatalog.xml" % module.name
409 for compo in module.components:
410 if hasattr(compo,"calciumextendedinterface") and compo.calciumextendedinterface:
414 #add makefile definitions to make_common_starter.am
416 common_starter = makecommon.substitute(other_includes=other_includes)
417 for mod in self.used_modules:
418 common_starter = common_starter + salome_modules[mod]["makefiledefs"] + '\n'
420 adm_local={"make_common_starter.am": common_starter, "check_aster.m4":check_aster}
422 adm_local["check_sphinx.m4"]=check_sphinx
424 self.makeFiles({"autogen.sh":autogen,
425 "Makefile.am":mainMakefile.substitute(docsubdir=docsubdir),
426 "README":"", "NEWS":"", "AUTHORS":"", "ChangeLog":"",
428 "resources":{"Makefile.am":resMakefile.substitute(module=module.name), catalogfile:self.makeCatalog()},
429 "adm_local":adm_local,
432 #add checks for modules in configure.ac
434 for mod in self.used_modules:
435 configure_modules = configure_modules + salome_modules[mod]["configdefs"] + '\n'
438 configure_makefiles = []
439 if self.module.layout=="multidir":
440 for compo in module.components:
441 configure_makefiles.append(" src/"+compo.name+"/Makefile")
444 configure_makefiles.append(" src/%sGUI/Makefile" % module.name)
446 configure_makefiles.append(" doc/Makefile")
453 other_check=other_check+"""CHECK_BOOST
455 other_summary=other_summary+"""echo " Boost ................. : $boost_ok"
459 other_check=other_check + """CHECK_SALOME_GUI
462 other_summary=other_summary+'''echo " SALOME GUI ............. : $SalomeGUI_ok"
463 echo " Qt ..................... : $qt_ok"
465 other_require=other_require + """
466 if test "x$SalomeGUI_ok" = "xno"; then
467 AC_MSG_ERROR([SALOME GUI is required],1)
469 if test "x$qt_ok" = "xno"; then
470 AC_MSG_ERROR([Qt library is required],1)
474 other_check=other_check+"CHECK_SPHINX\n"
475 other_summary=other_summary+'''echo " Sphinx ................. : $sphinx_ok"\n'''
476 other_require=other_require + """
477 if test "x$sphinx_ok" = "xno"; then
478 AC_MSG_ERROR([Sphinx documentation generator is required],1)
484 idlfile = "%s.idl" % module.name
486 PACO_BUILT_SOURCES=""
487 PACO_SALOMEINCLUDE_HEADERS=""
489 PACO_salomepython_DATA=""
490 PACO_salomeidl_DATA=""
493 PACO_BUILT_SOURCES = idlMakefilePaCO_BUILT_SOURCES.substitute(module=module.name)
494 PACO_SALOMEINCLUDE_HEADERS = idlMakefilePaCO_nodist_salomeinclude_HEADERS.substitute(module=module.name)
495 PACO_salomepython_DATA = idlMakefilePACO_salomepython_DATA.substitute(module=module.name)
496 PACO_salomeidl_DATA = idlMakefilePACO_salomeidl_DATA.substitute(module=module.name)
497 PACO_INCLUDES = idlMakefilePACO_INCLUDES
498 paco_config=paco_configure
500 files["configure.ac"]=configure.substitute(module=module.name.lower(),
501 makefiles='\n'.join(configure_makefiles),
502 paco_configure=paco_config,
503 modules=configure_modules,
504 other_check=other_check,
505 other_summary=other_summary,
506 other_require=other_require,
509 #if components have other idls
512 for compo in module.components:
514 for idl in compo.idls:
515 for fidl in glob.glob(idl):
516 other_idls=other_idls+os.path.basename(fidl) +" "
517 other_sks=other_sks+os.path.splitext(os.path.basename(fidl))[0]+"SK.cc "
519 idlfiles={"Makefile.am": idlMakefile.substitute(module=module.name,
520 PACO_BUILT_SOURCES=PACO_BUILT_SOURCES,
521 PACO_SALOMEINCLUDE_HEADERS=PACO_SALOMEINCLUDE_HEADERS,
522 PACO_INCLUDES=PACO_INCLUDES,
523 PACO_salomepython_DATA=PACO_salomepython_DATA,
524 PACO_salomeidl_DATA=PACO_salomeidl_DATA,
525 other_idls=other_idls,other_sks=other_sks,
527 idlfile : self.makeidl(),
530 idlfiles["%s.xml" % module.name]=self.makexml()
532 files["idl"]=idlfiles
534 self.makeFiles(files,namedir)
536 os.chmod(os.path.join(namedir, "autogen.sh"), 0777)
537 #copy source files if any in created tree
538 for compo in module.components:
539 for src in compo.sources:
540 if self.module.layout=="multidir":
541 shutil.copyfile(src, os.path.join(namedir, "src", compo.name, os.path.basename(src)))
543 shutil.copyfile(src, os.path.join(namedir, "src", os.path.basename(src)))
546 #copy provided idl files in idl directory
547 for idl in compo.idls:
548 for fidl in glob.glob(idl):
549 shutil.copyfile(fidl, os.path.join(namedir, "idl", os.path.basename(fidl)))
551 checks= ("check_Kernel.m4", "check_omniorb.m4", "ac_linker_options.m4", "ac_cxx_option.m4",
552 "python.m4", "enable_pthreads.m4", "check_f77.m4", "acx_pthread.m4", "check_paco++.m4",
553 "check_mpi.m4", "check_lam.m4", "check_openmpi.m4", "check_mpich.m4")
555 checks=checks+("check_boost.m4",)
556 for m4file in checks:
557 shutil.copyfile(os.path.join(self.kernel, "salome_adm", "unix", "config_files", m4file),
558 os.path.join(namedir, "adm_local", m4file))
561 for m4file in ("check_GUI.m4", "check_qt.m4", "check_opengl.m4"):
562 shutil.copyfile(os.path.join(self.gui, "adm_local", "unix", "config_files", m4file),
563 os.path.join(namedir, "adm_local", m4file))
565 self.makeDoc(namedir)
568 def makeDoc(self,namedir):
569 if not self.module.doc:
571 rep=os.path.join(namedir,"doc")
573 for docs in self.module.doc:
574 for doc in glob.glob(docs):
575 name = os.path.basename(doc)
576 shutil.copyfile(doc, os.path.join(rep, name))
581 if not self.module.gui:
582 #without gui but with doc: create a small SalomeApp.xml in doc directory
583 if not os.path.exists(os.path.join(namedir, "doc", "SalomeApp.xml")):
584 #create a minimal SalomeApp.xml
585 salomeapp=docsalomeapp.substitute(module=self.module.name,lmodule=self.module.name.lower())
586 d["SalomeApp.xml"]=salomeapp
587 others="SalomeApp.xml"
589 if not os.path.exists(os.path.join(namedir, "doc", "Makefile.am")):
590 #create a minimal makefile.am
591 d["Makefile.am"]=docmakefile.substitute(others=others)
593 if not os.path.exists(os.path.join(namedir, "doc", "conf.py")):
594 #create a minimal conf.py
595 d["conf.py"]=docconf.substitute(module=self.module.name)
597 self.makeFiles(d,os.path.join(namedir,"doc"))
599 def makeGui(self,namedir):
600 if not self.module.gui:
604 #Force creation of intermediate directories
605 os.makedirs(os.path.join(namedir, "src", self.module.name+"GUI"))
607 for srcs in self.module.gui:
608 for src in glob.glob(srcs):
609 shutil.copyfile(src, os.path.join(namedir, "src", self.module.name+"GUI", os.path.basename(src)))
610 if src[-3:]==".py":ispython=True
611 if src[-4:]==".cxx":iscpp=True
612 if ispython and iscpp:
613 raise Invalid("Module GUI must be pure python or pure C++ but not mixed")
615 return self.makePyGUI(namedir)
617 return self.makeCPPGUI(namedir)
618 raise Invalid("Module GUI must be in python or C++ but it is none of them")
620 def makePyGUI(self,namedir):
622 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "Makefile.am")):
623 #create a minimal makefile.am
626 for srcs in self.module.gui:
627 for src in glob.glob(srcs):
629 sources.append(os.path.basename(src))
631 other.append(os.path.basename(src))
632 makefile=pyguimakefile.substitute(sources=" ".join(sources),other_sources=" ".join(other))
633 d["Makefile.am"]=makefile
635 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "SalomeApp.xml")):
636 #create a minimal SalomeApp.xml
637 salomeapp=pysalomeapp.substitute(module=self.module.name,lmodule=self.module.name.lower())
638 d["SalomeApp.xml"]=salomeapp
642 def makeCPPGUI(self,namedir):
644 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "Makefile.am")):
645 #create a minimal makefile.am
649 for srcs in self.module.gui:
650 for src in glob.glob(srcs):
652 sources.append(os.path.basename(src))
654 sources.append(os.path.basename(src)[:-2]+"_moc.cxx")
655 elif src[-3:]==".ui":
656 ui_files.append("ui_"+os.path.basename(src)[:-3]+".h")
657 elif src[-3:]==".ts":
658 other.append(os.path.basename(src)[:-3]+".qm")
660 other.append(os.path.basename(src))
662 makefile=cppguimakefile.substitute(sources=" ".join(sources),other_sources=" ".join(other),
663 module=self.module.name, uisources= " ".join(ui_files))
664 d["Makefile.am"]=makefile
666 if not os.path.exists(os.path.join(namedir, "src", self.module.name+"GUI", "SalomeApp.xml")):
667 #create a minimal SalomeApp.xml
668 salomeapp=cppsalomeapp.substitute(module=self.module.name,lmodule=self.module.name.lower())
669 d["SalomeApp.xml"]=salomeapp
673 def makeMakefile(self,makefileItems):
675 if makefileItems.has_key("header"):
676 makefile=makefile + makefileItems["header"]+'\n'
677 if makefileItems.has_key("lib_LTLIBRARIES"):
678 makefile=makefile+"lib_LTLIBRARIES= "+" ".join(makefileItems["lib_LTLIBRARIES"])+'\n'
679 if makefileItems.has_key("salomepython_PYTHON"):
680 makefile=makefile+"salomepython_PYTHON= "+" ".join(makefileItems["salomepython_PYTHON"])+'\n'
681 if makefileItems.has_key("dist_salomescript_SCRIPTS"):
682 makefile=makefile+"dist_salomescript_SCRIPTS= "+" ".join(makefileItems["dist_salomescript_SCRIPTS"])+'\n'
683 if makefileItems.has_key("salomeres_DATA"):
684 makefile=makefile+"salomeres_DATA= "+" ".join(makefileItems["salomeres_DATA"])+'\n'
685 if makefileItems.has_key("salomeinclude_HEADERS"):
686 makefile=makefile+"salomeinclude_HEADERS= "+" ".join(makefileItems["salomeinclude_HEADERS"])+'\n'
687 if makefileItems.has_key("body"):
688 makefile=makefile+makefileItems["body"]+'\n'
691 def makeArgs(self, service):
692 """generate source service for arguments"""
694 for name, typ in service.inport:
695 if typ=="file":continue #files are not passed through service interface
696 params.append("%s %s" % (corba_in_type(typ, self.module.name), name))
697 for name, typ in service.outport:
698 if typ=="file":continue #files are not passed through service interface
699 params.append("%s %s" % (corba_out_type(typ, self.module.name), name))
700 return ",".join(params)
702 def makeCatalog(self):
703 """generate SALOME components catalog source"""
705 for compo in self.module.components:
707 for serv in compo.services:
709 for name, typ in serv.inport:
710 params.append(cataInparam.substitute(name=name, type=typ))
711 inparams = "\n".join(params)
713 for name, typ in serv.outport:
714 params.append(cataOutparam.substitute(name=name, type=typ))
715 if serv.ret != "void" :
716 params.append(cataOutparam.substitute(name="return", type=serv.ret))
717 outparams = "\n".join(params)
719 for name, typ, dep in serv.instream:
720 streams.append(cataInStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
721 for name, typ, dep in serv.outstream:
722 streams.append(cataOutStream.substitute(name=name, type=calciumTypes[typ], dep=dep))
723 for name, typ in serv.parallel_instream:
724 streams.append(cataInParallelStream.substitute(name=name, type=DatastreamParallelTypes[typ]))
725 for name, typ in serv.parallel_outstream:
726 streams.append(cataOutParallelStream.substitute(name=name, type=DatastreamParallelTypes[typ]))
727 datastreams = "\n".join(streams)
728 services.append(cataService.substitute(service=serv.name, author="EDF-RD",
729 inparams=inparams, outparams=outparams, datastreams=datastreams))
730 impltype, implname = compo.getImpl()
731 components.append(cataCompo.substitute(component=compo.name, author="EDF-RD", impltype=impltype, implname=implname,
732 services='\n'.join(services)))
733 return catalog.substitute(components='\n'.join(components))
736 """generate module IDL file source (CORBA interface)"""
737 from pacocompo import PACOComponent
740 for compo in self.module.components:
741 if isinstance(compo, PACOComponent):
743 for serv in compo.services:
745 for name, typ in serv.inport:
746 if typ == "file":continue #files are not passed through IDL interface
747 params.append("in %s %s" % (idlTypes[typ], name))
748 for name, typ in serv.outport:
749 if typ == "file":continue #files are not passed through IDL interface
750 params.append("out %s %s" % (idlTypes[typ], name))
751 service = " void %s(" % serv.name
752 service = service+",".join(params)+");"
753 services.append(service)
755 interfaces.append(parallel_interface.substitute(component=compo.name, services="\n".join(services)))
759 for serv in compo.services:
761 for name, typ in serv.inport:
762 if typ == "file":continue #files are not passed through IDL interface
763 if compo.impl in ("PY", "ASTER") and typ == "pyobj":
764 typ = "Engines::fileBlock"
767 params.append("in %s %s" % (typ, name))
768 for name, typ in serv.outport:
769 if typ == "file":continue #files are not passed through IDL interface
770 if compo.impl in ("PY", "ASTER") and typ == "pyobj":
771 typ = "Engines::fileBlock"
774 params.append("out %s %s" % (typ, name))
775 service = " %s %s(" % (idlTypes[serv.ret],serv.name)
776 service = service+",".join(params)+") raises (SALOME::SALOME_Exception);"
777 services.append(service)
779 from hxxcompo import HXX2SALOMEComponent
780 from hxxparacompo import HXX2SALOMEParaComponent
781 if isinstance(compo,HXX2SALOMEComponent) or isinstance(compo,HXX2SALOMEParaComponent):
782 from hxx_tmpl import interfaceidlhxx
784 if isinstance(compo,HXX2SALOMEParaComponent):
785 Inherited="SALOME_MED::ParaMEDMEMComponent"
786 idldefs="""#include "ParaMEDMEMComponent.idl"\n"""
788 if compo.use_medmem==True:
789 Inherited="Engines::EngineComponent,SALOME::MultiCommClass,SALOME_MED::MED_Gen_Driver"
791 Inherited="Engines::EngineComponent"
792 interfaces.append(interfaceidlhxx.substitute(component=compo.name,inherited=Inherited, services="\n".join(services)))
794 inheritedinterface=""
795 if compo.inheritedinterface:
796 inheritedinterface=compo.inheritedinterface+","
797 interfaces.append(interface.substitute(component=compo.name, services="\n".join(services),inheritedinterface=inheritedinterface))
799 #build idl includes for SALOME modules
800 for mod in self.used_modules:
801 idldefs = idldefs + salome_modules[mod]["idldefs"]
803 for compo in self.module.components:
804 if compo.interfacedefs:
805 idldefs = idldefs + compo.interfacedefs
807 return idl.substitute(module=self.module.name, interfaces='\n'.join(interfaces),idldefs=idldefs)
811 from pacocompo import PACOComponent
813 for compo in self.module.components:
814 if isinstance(compo, PACOComponent):
816 for serv in compo.services:
817 if serv.impl_type == "parallel":
818 service = xml_service.substitute(service_name=serv.name)
819 services.append(service)
820 interfaces.append(xml_interface.substitute(component=compo.name, xml_services="\n".join(services)))
821 return xml.substitute(module=self.module.name, interfaces='\n'.join(interfaces))
823 def makeFiles(self, dic, basedir):
824 """create files and directories defined in dictionary dic in basedir directory
825 dic key = file name to create
826 dic value = file content or dictionary defining the content of a sub directory
828 for name, content in dic.items():
829 filename = os.path.join(basedir, name)
830 if isinstance(content, str):
831 fil = open(filename, 'w')
835 if not os.path.exists(filename):
836 os.makedirs(filename)
837 self.makeFiles(content, filename)
840 """Execute the first build step (bootstrap autotools with autogen.sh script) : execution of libtool, autoconf, automake"""
841 ier = os.system("cd %s_SRC;sh autogen.sh" % self.module.name)
843 raise Invalid("bootstrap has ended in error")
846 """Execute the second build step (configure) with installation prefix as given by the prefix attribute of module"""
847 prefix = self.module.prefix
848 paco = self.context.get("paco")
849 mpi = self.context.get("mpi")
850 args = (self.module.name, self.kernel, self.aster)
851 cmd = "cd %s_SRC;./configure --with-kernel=%s --with-aster=%s" % args
853 cmd = cmd + " --with-gui=%s" % self.gui
855 prefix = os.path.abspath(prefix)
856 cmd = cmd + " --prefix=%s" % prefix
858 cmd += " --with-paco=%s" % paco
860 cmd += " --with-mpi=%s" % mpi
864 raise Invalid("configure has ended in error")
867 """Execute the third build step (compile and link) : make"""
868 make_command = "make "
870 make_command += self.makeflags
871 ier = os.system("cd %s_SRC;%s" % (self.module.name, make_command))
873 raise Invalid("make has ended in error")
876 """Execute the installation step : make install """
877 makedirs(self.module.prefix)
878 ier = os.system("cd %s_SRC;make install" % self.module.name)
880 raise Invalid("install has ended in error")
882 def make_appli(self, appliname, restrict=None, altmodules=None, resources=""):
884 Create a SALOME application containing the module and preexisting SALOME modules.
886 :param appliname: is a string that gives the name of the application (directory path where the application
889 :param restrict: If given (a list of module names), only those SALOME modules will be included in the
890 application. The default is to include all modules that are located in the same directory as the KERNEL module and have
891 the same suffix (for example, if KERNEL directory is KERNEL_V5 and GEOM directory is GEOM_V5, GEOM module is automatically
892 included, except if restrict is used).
893 :param altmodules: can be used to add SALOME modules that cannot be managed with the precedent rule. This parameter
894 is a dict with a module name as the key and the installation path as the value.
895 :param resources: can be used to define an alternative resources catalog (path of the file).
897 For example, the following calls create a SALOME application with external modules and resources catalog in "appli" directory::
899 >>> g=Generator(m,context)
905 >>> g.make_appli("appli", restrict=["KERNEL"], altmodules={"GUI":GUI_ROOT_DIR, "YACS":YACS_ROOT_DIR},
906 resources="myresources.xml")
911 rootdir, kerdir = os.path.split(self.kernel)
913 #collect modules besides KERNEL module with the same suffix if any
915 if kerdir[:6] == "KERNEL":
917 for mod in os.listdir(rootdir):
918 if mod[-len(suffix):] == suffix:
919 module = mod[:-len(suffix)]
920 path = os.path.join(rootdir, mod)
921 #try to find catalog files
922 lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*", "*Catalog.xml"))
924 #catalogs have not been found : try the upper level
925 lcata = glob.glob(os.path.join(path, "share", "salome", "resources", "*Catalog.xml"))
927 #catalogs have been found : add the corresponding entries in the application
929 catadir, catafile = os.path.split(cata)
930 name = catafile[:-11]
931 modules_dict[name] = ' <module name="%s" path="%s"/>' % (name, path)
933 modules_dict[module] = ' <module name="%s" path="%s"/>' % (module, path)
935 modules_dict["KERNEL"] = ' <module name="KERNEL" path="%s"/>' % self.kernel
937 #keep only the modules which names are in restrict if given
941 if modules_dict.has_key(mod):
942 modules.append(modules_dict[mod])
944 modules = modules_dict.values()
946 #add the alternate modules if given
948 for module, path in altmodules.items():
949 modules.append(' <module name="%s" path="%s"/>' % (module, path))
951 #add the generated module
952 modules.append(' <module name="%s" path="%s"/>' % (self.module.name, os.path.abspath(self.module.prefix)))
955 #try to find a prerequisites file
956 prerequisites = self.context.get("prerequisites")
957 if not prerequisites:
958 #try to find one in rootdir
959 prerequisites = os.path.join(rootdir, "profile%s.sh" % suffix)
960 if not os.path.exists(prerequisites):
961 raise Invalid("Can not create an application : prerequisites file not defined or does not exist")
963 #add resources catalog if it exists
965 if os.path.isfile(resources):
966 resources_spec='<resources path="%s" />' % os.path.abspath(resources)
968 #create config_appli.xml file
969 appli = application.substitute(prerequisites=prerequisites,
970 modules="\n".join(modules),
971 resources=resources_spec)
972 fil = open(os.path.join(appliname, "config_appli.xml"), 'w')
976 #execute appli_gen.py script
977 appligen = os.path.join(self.kernel, "bin", "salome", "appli_gen.py")
978 ier = os.system("cd %s;%s" % (appliname, appligen))
980 raise Invalid("make_appli has ended in error")
982 #add CatalogResources.xml if not created by appli_gen.py
983 if not os.path.exists(os.path.join(appliname, "CatalogResources.xml")):
984 #CatalogResources.xml does not exist create a minimal one
985 fil = open(os.path.join(appliname, 'CatalogResources.xml'), 'w')
986 command = """<!DOCTYPE ResourcesCatalog>
988 <machine hostname="%s" protocol="ssh" mode="interactive" />
991 host = socket.gethostname().split('.')[0]
992 fil.write(command % host)