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 Module that generates SALOME c++ Component from a non SALOME c++ component
21 (its header and its shares library)
28 from tempfile import mkstemp
29 from gener import Component, Invalid
30 from hxx_tmpl import cxxService, hxxCompo, cxxCompo, compoMakefile
31 from module_generator import Service
32 from yacstypes import corba_rtn_type,moduleTypes
33 from hxx_awk import parse01,parse1,parse2,parse3
34 from hxx_awk import cpp2idl_mapping
35 # these tables contain the part of code which depends upon c++ types
36 from hxx_awk import cpp_impl_a,cpp_impl_b,cpp_impl_c
37 from hxx_awk import cpp2yacs_mapping
38 from tempfile import mkdtemp
39 from hxx_tmpl_gui import hxxgui_cxx, hxxgui_h, hxxgui_icon_ts
40 from hxx_tmpl_gui import hxxgui_message_en, hxxgui_message_fr
41 from hxx_tmpl_gui import hxxgui_config, hxxgui_xml_fr, hxxgui_xml_en
43 # ------------------------------------------------------------------------------
45 class HXX2SALOMEComponent(Component):
46 def __init__(self, hxxfile , cpplib , cpp_path ):
47 # search a file within a directory tree
48 def search_file(pattern, root):
50 for path, dirs, files in os.walk(os.path.abspath(root)):
51 for filename in fnmatch.filter(files, pattern):
52 matches.append(os.path.join(path, filename))
55 hxxfileful = search_file(hxxfile,cpp_path)
56 cpplibful = search_file(cpplib,cpp_path)
57 format_error = 'Error in HXX2SALOMEComponent : file %s ot found in %s'
58 assert len(hxxfileful) > 0, format_error % (hxxfile, cpp_path)
59 assert len(cpplibful) > 0, format_error % (cpplib, cpp_path)
60 hxxfile = hxxfileful[0]
63 # grab name of c++ component
64 cmd1="""awk '$1 == "class" && $0 !~ /;/ {print $2}' """ + hxxfile +\
65 """|awk -F: '{printf "%s",$1}' """
67 class_name=f.readlines()[0]
69 print "classname=",class_name
72 # create temporary awk files for the parsing
74 f01=os.fdopen(fd01,"w")
93 # awk parsing of hxx files -
94 # result written in file parse_type_result
98 "sed 's/virtual //g'",
99 "sed 's/MEDMEM_EXPORT//g'",
100 "sed 's/throw.*;/;/g'",
103 "awk -v class_name=%s -f %s" % (class_name, p3n) ]
104 cmd2 = ' | '.join(cmd2)
107 import subprocess, sys
108 subprocess.call(cmd2, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT)
114 # Retrieve the information which was generated in
115 # the file parse_type_result.
116 # The structure of the file is :
118 # Function return_type function_name
119 # [arg1_type arg1_name]
120 # [arg2_type arg2_name]
122 # The service names are stored in list_of_services
123 # The information relative to a service (called service_name) is stored in
124 # the dictionnary service_definition[service_name]
126 service_definition={}
127 result_parsing=open("parse_type_result","r")
128 for line in result_parsing.readlines():
129 line=line[0:-1] # get rid of trailing \n
130 words = string.split(line,';')
132 if len(words) >=3 and words[0] == "Function": # detect a new service
133 function_name=words[2]
134 # store the name of new service
135 list_of_services.append(function_name)
136 # create a dict to store informations relative to this service
137 service_definition[function_name]={}
138 service_definition[function_name]["ret"]=words[1] # return type
139 service_definition[function_name]["inports"]=[]
140 service_definition[function_name]["outports"]=[]
141 service_definition[function_name]["ports"]=[]
142 service_definition[function_name]["impl"]=[]
144 # an argument type and argument name of the current service
146 current_service=list_of_services[-1]
147 current_service_dict=service_definition[current_service]
150 # store in c++ order the arg names
151 current_service_dict["ports"].append( (argname,typename) )
153 # separate in from out parameters
154 inout=cpp2idl_mapping[typename][0:2]
155 assert inout=="in" or inout=="ou",'Error in table cpp2idl_mapping'
157 current_service_dict["inports"].append((argname, typename) )
159 current_service_dict["outports"].append((argname, typename) )
162 # - generate implementation of c++ servant
163 # - store it in service_definition[serv]["impl"]
164 for serv in list_of_services:
166 print "service : ",serv
167 print " inports -> ",service_definition[serv]["inports"]
168 print " outports -> ",service_definition[serv]["outports"]
169 print " return -> ",service_definition[serv]["ret"]
172 # Part 1 : Argument pre-processing
173 s_argument_processing="//\tArguments processing\n"
174 for (argname,argtype) in service_definition[serv]["inports"] + \
175 service_definition[serv]["outports"]:
176 format=cpp_impl_a[argtype]
177 s_argument_processing += format % {"arg" : argname }
179 # if there was no args
180 if s_argument_processing=="//\tArguments processing\n":
181 s_argument_processing=""
184 # Part 2 : Call to the underlying c++ function
185 s_call_cpp_function="//\tCall cpp component\n\t"
186 rtn_type=service_definition[serv]["ret"]
188 # if return type is void, the call syntax is different
189 if rtn_type == "void" :
190 s_call_cpp_function += "cppCompo_->%s(" % serv
192 s_call_cpp_function +=\
193 "%s _rtn_cpp = cppCompo_->%s(" % (rtn_type ,serv )
195 for (argname,argtype) in service_definition[serv]["ports"]:
196 # special treatment for some arguments
200 if string.find(cpp_impl_a[argtype],"auto_ptr" ) != -1 :
201 # for auto_ptr argument, retrieve the raw pointer behind
203 if argtype == "const MEDMEM::MESH&" or \
204 argtype == "const MEDMEM::SUPPORT&" :
205 # we cannot create MESHClient on the stack
206 # (private constructor!),
207 # so we create it on the heap and dereference it
210 post+="," # separator between arguments
211 s_call_cpp_function += " %s_%s%s" % ( pre,argname,post)
212 if s_call_cpp_function[-1]==',':
213 # get rid of trailing comma
214 s_call_cpp_function=s_call_cpp_function[0:-1]
216 s_call_cpp_function=s_call_cpp_function+');\n'
218 # Part 3.a : Out Argument Post-processing
219 s_argument_postprocessing="//\tPost-processing & return\n"
220 for (argname,argtype) in service_definition[serv]["outports"]:
221 format=cpp_impl_c[argtype]
222 # the treatment of %(module) is postponed in makecxx()
223 # because we don't know here the module name
224 s_argument_postprocessing += \
225 format % {"arg" : argname, "module" : "%(module)s" }
227 # Part 3.b : In Argument Post-processing
228 for (argname,argtype) in service_definition[serv]["inports"]:
229 # not all in types require a treatment
230 if cpp_impl_c.has_key(argtype):
231 format=cpp_impl_c[argtype]
232 # id : treatment of %(module) is postponed in makecxx
233 s_argument_postprocessing += \
234 format % {"arg" : argname, "module" : "%(module)s" }
236 # Part 3.c : return processing
237 s_rtn_processing=cpp_impl_b[rtn_type]
239 format_end_serv = "\tendService(\"%(class_name)s_i::%(serv_name)s\");"
240 format_end_serv += "\n\tEND_OF(\"%(class_name)s_i::%(serv_name)s\");\n"
241 s_rtn_processing += format_end_serv %\
242 { "serv_name" : serv, "class_name" : class_name }
244 if rtn_type != "void":
245 s_rtn_processing += "\treturn _rtn_ior;"
247 service_definition[serv]["impl"] = s_argument_processing + \
248 s_call_cpp_function + \
249 s_argument_postprocessing + \
252 print "implementation :\n",service_definition[serv]["impl"]
255 # Create a list of Service objects (called services),
256 # and give it to Component constructor
259 self.use_medmem=False
260 self.use_medcoupling=False
261 for serv in list_of_services:
262 # for inports and outports, Service class expects a list of tuples,
263 # each tuple containing the name and the yacs type of the port
264 # thus we need to convert c++ types to yacs types
265 # (we use for that the cpp2yacs_mapping table)
267 for op in service_definition[serv]["inports"]:
268 inports.append([op[0], cpp2yacs_mapping[op[1]] ] )
271 for op in service_definition[serv]["outports"]:
272 outports.append([op[0], cpp2yacs_mapping[op[1]] ] )
275 if service_definition[serv]["ret"] != "void":
276 Return=cpp2yacs_mapping[service_definition[serv]["ret"]]
278 # find out if component uses medmem types and/or medcoupling types
279 for (argname,argtype) in inports + outports + [("return",Return)]:
280 if moduleTypes[argtype]=="MED":
281 if argtype.count("Coupling")>0:
282 self.use_medcoupling=True
287 code=service_definition[serv]["impl"]
289 print "service : ",serv
290 print " inports -> ",service_definition[serv]["inports"]
291 print " converted inports -> ",inports
292 print " outports -> ",service_definition[serv]["outports"]
293 print " converted outports -> ",outports
294 print " Return -> ",service_definition[serv]["ret"]
295 print " converted Return -> ",Return
297 services.append(Service(serv,
305 Includes="-I${"+name+"CPP_ROOT_DIR}/include"
306 Libs="-L${"+name+"CPP_ROOT_DIR}/lib -l"+name+"CXX"
309 self.inheritedconstructor=""
312 #include CORBA_CLIENT_HEADER(MED)
313 #include CORBA_CLIENT_HEADER(MED_Gen)
314 #include "FIELDClient.hxx"
315 #include "MESHClient.hxx"
316 #include "MEDMEM_Support_i.hxx"
317 #include "MEDMEM_Mesh_i.hxx"
318 #include "MEDMEM_FieldTemplate_i.hxx"
319 #include "Med_Gen_Driver_i.hxx"
321 Inheritedclass="Med_Gen_Driver_i, public SALOMEMultiComm"
322 self.inheritedconstructor="Med_Gen_Driver_i(orb),"
324 if self.use_medcoupling:
326 #include CORBA_CLIENT_HEADER(MEDCouplingCorbaServant)
327 #include "MEDCouplingFieldDoubleServant.hxx"
328 #include "MEDCouplingUMeshServant.hxx"
329 #include "MEDCouplingFieldDouble.hxx"
330 #include "MEDCouplingUMesh.hxx"
331 #include "MEDCouplingUMeshClient.hxx"
332 #include "MEDCouplingFieldDouble.hxx"
333 #include "MEDCouplingFieldDoubleClient.hxx"
336 Component.__init__(self, name, services, impl="CPP", libs=Libs,
337 rlibs="", includes=Includes, kind="lib",
338 sources=None,inheritedclass=Inheritedclass,
341 # ------------------------------------------------------------------------------
342 def makeCompo(self, gen):
343 """generate files for C++ component
344 return a dict where key is the file name and
345 value is the content of the file
347 cxxfile = "%s_i.cxx" % self.name
348 hxxfile = "%s_i.hxx" % self.name
349 return {"Makefile.am":gen.makeMakefile(self.getMakefileItems(gen)),
350 cxxfile:self.makecxx(gen),
351 hxxfile:self.makehxx(gen)
354 # ------------------------------------------------------------------------------
355 def getMakefileItems(self,gen):
356 makefileItems={"header":"""
357 include $(top_srcdir)/adm_local/make_common_starter.am
360 makefileItems["lib_LTLIBRARIES"]=["lib"+self.name+"Engine.la"]
361 makefileItems["salomeinclude_HEADERS"]=["%s_i.hxx" % self.name]
362 makefileItems["body"]=compoMakefile.substitute(module=gen.module.name,
365 includes=self.includes)
368 # ------------------------------------------------------------------------------
369 def makehxx(self, gen):
370 """return a string that is the content of .hxx file
373 for serv in self.services:
374 service = " %s %s(" % (corba_rtn_type(serv.ret,gen.module.name),
376 service = service+gen.makeArgs(serv)+") throw (SALOME::SALOME_Exception);"
377 services.append(service)
378 servicesdef = "\n".join(services)
380 inheritedclass=self.inheritedclass
381 if self.inheritedclass:
382 inheritedclass= " public virtual " + self.inheritedclass + ","
384 return hxxCompo.substitute(component=self.name,
385 module=gen.module.name,
386 servicesdef=servicesdef,
387 inheritedclass=inheritedclass,
388 compodefs=self.compodefs)
390 # ------------------------------------------------------------------------------
391 def makecxx(self, gen, exe=0):
392 """return a string that is the content of .cxx file
397 for serv in self.services:
398 defs.append(serv.defs)
399 print "CNC bug : ",serv.body
400 service = cxxService.substitute(
403 ret=corba_rtn_type(serv.ret,gen.module.name),
404 parameters=gen.makeArgs(serv),
405 body=serv.body % {"module":gen.module.name+"_ORB"} )
406 services.append(service)
407 return cxxCompo.substitute(component=self.name,
408 inheritedconstructor=self.inheritedconstructor,
409 servicesdef="\n".join(defs),
410 servicesimpl="\n".join(services))
412 # ------------------------------------------------------------------------------
413 def getGUIfilesTemplate(self):
414 """generate in a temporary directory files for a generic GUI,
415 and return a list with file names.
416 it is the responsability of the user to get rid
417 of the temporary directory when finished
419 gui_cxx=hxxgui_cxx.substitute(component_name=self.name)
420 gui_h=hxxgui_h.substitute(component_name=self.name)
421 gui_icon_ts=hxxgui_icon_ts.substitute(component_name=self.name)
422 gui_message_en=hxxgui_message_en.substitute(component_name=self.name)
423 gui_message_fr=hxxgui_message_fr.substitute(component_name=self.name)
424 gui_config=hxxgui_config.substitute(component_name=self.name)
425 gui_xml_fr=hxxgui_xml_fr.substitute(component_name=self.name)
426 gui_xml_en=hxxgui_xml_en.substitute(component_name=self.name)
428 gui_cxx_file_name=os.path.join(temp_dir,self.name+"GUI.cxx")
429 gui_h_file_name=os.path.join(temp_dir,self.name+"GUI.h")
430 gui_icon_ts_file_name=os.path.join(temp_dir,self.name+"_icons.ts")
431 gui_message_en_file_name=os.path.join(temp_dir,self.name+"_msg_en.ts")
432 gui_message_fr_file_name=os.path.join(temp_dir,self.name+"_msg_fr.ts")
433 gui_config_file_name=os.path.join(temp_dir,"config")
434 gui_xml_fr_file_name=os.path.join(temp_dir,self.name+"_en.xml")
435 gui_xml_en_file_name=os.path.join(temp_dir,self.name+"_fr.xml")
439 gui_cxx_file=open(gui_cxx_file_name,"w")
440 gui_cxx_file.write(gui_cxx)
442 list_of_gui_names.append(gui_cxx_file_name)
444 gui_h_file=open(gui_h_file_name,"w")
445 gui_h_file.write(gui_h)
447 list_of_gui_names.append(gui_h_file_name)
449 gui_icon_ts_file=open(gui_icon_ts_file_name,"w")
450 gui_icon_ts_file.write(gui_icon_ts)
451 gui_icon_ts_file.close()
452 list_of_gui_names.append(gui_icon_ts_file_name)
454 gui_message_en_file=open(gui_message_en_file_name,"w")
455 gui_message_en_file.write(gui_message_en)
456 gui_message_en_file.close()
457 list_of_gui_names.append(gui_message_en_file_name)
459 gui_message_fr_file=open(gui_message_fr_file_name,"w")
460 gui_message_fr_file.write(gui_message_fr)
461 gui_message_fr_file.close()
462 list_of_gui_names.append(gui_message_fr_file_name)
464 gui_config_file=open(gui_config_file_name,"w")
465 gui_config_file.write(gui_config)
466 gui_config_file.close()
467 list_of_gui_names.append(gui_config_file_name)
469 gui_xml_fr_file=open(gui_xml_fr_file_name,"w")
470 gui_xml_fr_file.write(gui_xml_fr)
471 gui_xml_fr_file.close()
472 list_of_gui_names.append(gui_xml_fr_file_name)
474 gui_xml_en_file=open(gui_xml_en_file_name,"w")
475 gui_xml_en_file.write(gui_xml_en)
476 gui_xml_en_file.close()
477 list_of_gui_names.append(gui_xml_en_file_name)
480 return list_of_gui_names