fixed: compile issue
[opensg.git] / Bindings / Python / osgGenBindings.py.in
blobfff00f321488ef1aedde24ce9cfc1f8edabfe639
1 #!/usr/bin/env python
3 # PyOpenSG is (C) Copyright 2005-2009 by Allen Bierbaum
5 # This file is part of PyOpenSG.
7 # PyOpenSG is free software; you can redistribute it and/or modify it under
8 # the terms of the GNU Lesser General Public License as published by the Free
9 # Software Foundation; either version 2 of the License, or (at your option)
10 # any later version.
12 # PyOpenSG is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 # more details.
17 # You should have received a copy of the GNU Lesser General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 # This script is derived from gen_bindings.py, all class specific tasks were
22 # moved to per lib scripts for the integration with the OpenSG CMake system
23 # (GV)
26 import sys
27 import os
28 import logging
30 try:
31 import xml.etree.ElementTree as et
32 except:
33 import elementtree.ElementTree as et
35 import xml.parsers.expat
37 if ${OSG_HAS_PYOSG_PYPLUSPLUS_DIR}:
38 sys.path.insert(0, "${PYOSG_PYPLUSPLUS_DIR}")
40 if ${OSG_HAS_PYOSG_PYPLUSPLUS_GOODIES_DIR}:
41 sys.path.insert(0, "${PYOSG_PYPLUSPLUS_GOODIES_DIR}")
43 sys.path.insert(0, "../Helper")
44 sys.path.insert(0, "../../../Python/Helper")
47 import osggen
49 from goodies import *
50 from pyplusplus import messages
51 import pygccxml.declarations as pd
53 import osgSetupBindings_${PROJECT_NAME} as ${PROJECT_NAME}Gen
55 pj = os.path.join
57 use_profiler = False
58 use_query_opt = True
60 # Setup global settings
61 set_recursive_default(False)
62 # Need a little more room for bindings
63 sys.setrecursionlimit( sys.getrecursionlimit() * 10)
65 set_logger_level(logging.INFO)
66 #set_logger_level(logging.DEBUG)
67 messages.disable(*messages.all_warning_msgs)
69 import pyplusplus.code_creators.calldef
70 pyplusplus.code_creators.calldef.use_enum_workaround = True
72 def findFcdFileInSubdirectories(fcdFilename, subdirectories=[]):
74 for subdir in subdirectories:
75 for root, dirs, names in os.walk(subdir):
76 if fcdFilename in names:
77 return os.path.join(root, fcdFilename)
79 return None
81 def parseFCDFiles(fcdFullFilename, fcInfoDict, headerList, fc_ignore_list, skip_fcds):
83 if fcdFullFilename == None:
84 return
86 fcdName = os.path.basename(fcdFullFilename).replace('.fcd', '')
87 clsName = fcdName.replace("OSG", "")
89 # print "xbar ", fcdFullFilename
90 # print "xfoo ", fcdName
91 # print "xfb ", fc_ignore_list
92 # print "xbb ", skip_fcds
94 if clsName in fc_ignore_list or fcdFullFilename in skip_fcds:
95 print "IGNORE", clsName
96 return
98 headerList.append(fcdName+".h")
100 try:
101 tree = et.parse(fcdFullFilename)
102 fc_elt = tree.getroot()
103 assert fc_elt.tag == "FieldContainer"
104 attribs = fc_elt.attrib.copy()
105 parent = attribs["parent"]
106 name = attribs["name"]
107 doc = fc_elt.text.strip()
108 except xml.parsers.expat.ExpatError, ex:
109 #print "Error parsing file: %s"%f
110 #print str(ex)
111 #print "Trying re method instead. "
113 file_text = file(f).read()
114 name = re.search('name=\"(.*?)\"', file_text).group(1)
115 parent = re.search('parent=\"(.*?)\"', file_text).group(1)
116 library = re.search('library=\"(.*?)\"', file_text).group(1)
117 doc = ""
119 # Build up the class info
120 #print " name: %s parent: %s" % (name, parent)
121 if not fcInfoDict.has_key(name):
122 fcInfoDict[name] = osggen.FCInfo(name, parent, documentation = doc)
124 def findAndParseFCDFiles(fcInfoDict, headerList, fc_ignore_list, skip_fcds):
126 for fcdName in ${PROJECT_NAME}Gen.moduleFCs:
128 # print "foo ", fcdName
129 fcdFilename = "OSG"+fcdName+".fcd"
130 # print "bar ", fcdFilename
131 fcdFullFilename = findFcdFileInSubdirectories(fcdFilename,
132 ${PROJECT_NAME}Gen.moduleIncludes)
133 # print "foobar ", fcdFullFilename
135 parseFCDFiles(fcdFullFilename, fcInfoDict, headerList, fc_ignore_list, skip_fcds)
137 def parseFCDFileList(fcdInfoDict, headerList, fc_ignore_list, skip_fcds):
139 for fcdFilename in ${PROJECT_NAME}Gen.moduleFCDFiles:
140 parseFCDFiles(fcdFilename, fcdInfoDict, headerList, fc_ignore_list, skip_fcds)
144 gen_classes = []
145 fc_infos = {}
146 core_mods = {}
147 free_funcs = []
149 free_func_mods = {}
151 fc_ignore_list = []
152 skip_fcds = []
154 exc_types = []
155 adddition_exp = []
157 non_fc_template_instances = []
159 modules = [${PROJECT_NAME}Gen]
161 for mod in modules:
162 mod.preScanSetup(gen_classes, fc_infos, core_mods, free_funcs, free_func_mods, exc_types)
164 opensg_src_dir = "${CMAKE_SOURCE_DIR}/Source"
165 output_dir = "${OSG_PYTHON_${PROJECT_NAME}_MODULE_DIR}"
167 def main():
169 main_header_filename = os.path.join(output_dir,
170 '${PROJECT_NAME}_mainheader.h')
171 main_header_filename_in = os.path.join(output_dir,
172 '${PROJECT_NAME}_mainheader.h.in')
173 exported_filename = os.path.join(output_dir,
174 'generated', 'osg_exported.txt')
176 all_headers = ${PROJECT_NAME}Gen.moduleHeaders
178 for mod in modules:
179 mod.excludeFCDSetup(opensg_src_dir, fc_ignore_list, skip_fcds)
181 if ${PROJECT_NAME}Gen.moduleFCs != None:
182 findAndParseFCDFiles(fc_infos, all_headers, fc_ignore_list, skip_fcds)
184 if ${PROJECT_NAME}Gen.moduleFCDFiles != None:
185 parseFCDFileList(fc_infos, all_headers, fc_ignore_list, skip_fcds)
187 template_builder = osggen.LocalTemplateBuilder()
188 tbuilder = TemplateBuilder()
190 for mod in modules:
191 mod.genTemplatesSetup(template_builder, tbuilder, non_fc_template_instances)
193 # Member template instantiations
194 template_instance_text = "\n\n// Member template instantiations\n"
195 template_instance_text += "#if defined(__GCCXML__)\n"
197 for c in fc_infos.itervalues():
198 for t in c.templateInstances:
199 inst_text = "%s;\n"%t
200 template_instance_text = template_instance_text + inst_text
202 for t in non_fc_template_instances:
203 inst_text = "%s;\n" % t
204 template_instance_text = template_instance_text + inst_text
206 template_instance_text += "#endif\n"
208 tbuilder_tfc_txt = template_builder.buildTemplateFileContents();
209 tbuilder_bac_txt = tbuilder.buildAutogenContents();
211 header_extra_txt = "";
213 if tbuilder_tfc_txt != None:
214 header_extra_txt = header_extra_txt + tbuilder_tfc_txt
216 if tbuilder_bac_txt != None:
217 header_extra_txt = header_extra_txt + tbuilder_bac_txt
219 main_header_filename_in = osggen.buildContainerHeader(
220 all_headers,
221 header_extra_txt + template_instance_text,
222 filename = main_header_filename_in)
224 cp_command = "${CMAKE_COMMAND} -E copy_if_different "
225 cp_command += main_header_filename_in + " "
226 cp_command += main_header_filename
228 os.system(cp_command)
230 cache_file = "pypp.pyopensg.cache"
232 gcc_xml = "${GCCXML}"
234 inc_path = ${PROJECT_NAME}Gen.moduleIncludes
236 if ${PROJECT_NAME}Gen.moduleDepIncludes != None:
237 inc_path.extend(${PROJECT_NAME}Gen.moduleDepIncludes)
239 defines = []
240 opensg_cflags = ""
241 boost_cflags = "-DBOOST_PYTHON_MAX_ARITY=21"
243 cflags = opensg_cflags + " " + boost_cflags
246 mb = ModuleBuilder([main_header_filename],
247 working_directory = ".",
248 include_paths = inc_path,
249 cache = cache_file + ".module",
250 define_symbols = defines,
251 ignore_gccxml_output = True,
252 optimize_queries = use_query_opt,
253 #start_with_declarations = ["OSG"],
254 cflags = cflags,
255 gccxml_path=gcc_xml)
256 #dependent_headers = all_headers_full_paths)
258 tbuilder.processTemplates(mb)
259 mb.BOOST_PYTHON_MAX_ARITY = 21
260 mb.global_ns.exclude()
262 osg = mb.global_ns.namespace("OSG", recursive=False)
264 osggen.OSG_MODULE = osg
266 if ${PROJECT_NAME}Gen.moduleDepencies != None:
267 std = mb.global_ns.namespace("std", recursive=False)
268 for moddep in ${PROJECT_NAME}Gen.moduleDepencies:
269 f = open(os.path.join(moddep, 'osg_exported.txt'), "r")
271 for line in f:
272 sline = line.rstrip()
273 try:
274 cls = osg.class_(sline)
275 cls.already_exposed = True
277 except Exception, ex:
278 try:
279 cls = std.class_(sline)
280 cls.already_exposed = True
282 except Exception, ex:
283 #print "class [%s] unknown" % sline
284 pass
286 f.close()
287 # mb.register_module_dependency(moddep)
289 if ${OSG_DO_DUMP_PYTHON_DECLS}:
290 decl_file = file("afterscan_decl_out_final.txt",'w', 1024000)
291 print "Writing out decls to file... ",
292 mb.print_declarations(osg, writer=decl_file.write)
293 #mb.print_declarations(my_class)
294 decl_file.close()
295 print "done."
297 # take the pure virtual functions out immediately otherwise they show
298 # up in random places.
299 cls = osg["FieldContainer"]
301 for pvf in ["createAspectCopy", "shallowCopy",
302 "shallowCopyDependent", "shallowCopyLocal",
303 "execSyncV"]:
304 cls[pvf].ignore = True
305 cls[pvf].set_virtuality(pd.VIRTUALITY_TYPES.NOT_VIRTUAL)
307 # Map from template alias name to real decl wrapper type
308 template_alias_db = {}
309 osg_typedef_db = {}
311 global_typedefs = mb.global_ns.typedefs()
313 for td in global_typedefs:
314 template_alias_db[td.name] = td.type
316 osg_typedefs = osg.typedefs()
318 for mod in modules:
319 mod.postScanSetup(osg, template_alias_db)
321 if "OSGBase" == "${PROJECT_NAME}":
322 ${PROJECT_NAME}Gen.tempLookatPostScanSetup(osg)
325 # Standard classes
326 for class_info in gen_classes:
327 # print "Class: %s"%class_info.name
329 c = osg.class_(class_info.name)
330 c.include()
331 #base_c.finalize()
332 osggen.handleClassDefaults(c, class_info.finalize)
333 for x in class_info.excludes:
334 c[x].exclude()
335 for (n,p) in class_info.policies:
336 c[n].call_policies = p
337 if class_info.use_shared_ptr:
338 c.held_type = "boost::shared_ptr<OSG::%s>"%class_info.name
339 for d in class_info.declarations:
340 c.add_declaration_code(d)
341 for r in class_info.registrations:
342 c.add_registration_code(r)
343 if class_info.modCallable: # Call any customizations needed
344 class_info.modCallable(c)
345 if class_info.finalize:
346 finalize(c)
348 for mod in modules:
349 mod.postGenClassesSetup(osg, mb)
352 # Free functions.
353 for m in free_funcs:
354 #print "m: %s"%m
355 funcs = osg.decls(m)
356 funcs.include()
357 for f in funcs:
358 f.call_policies = osggen.FC_POLICY_RESOLVER(f)
359 for mod_callable in free_func_mods.get(m, []):
360 mod_callable(f)
363 # --- Exception Translation --- #
365 for t in exc_types:
366 class_hierarchy = t[0].split('::')
367 ex_type_name = class_hierarchy.pop()
368 ns = osg
369 for c in class_hierarchy:
370 ns = ns.class_(c)
371 ex_type = ns.class_(ex_type_name)
372 ex_type.translate_exception_to_string('PyExc_%s' % t[1], 'exc.what()')
373 ex_type.include()
374 finalize(ex_type)
378 # For each field container class we have information about, do the following:
379 # - Generate code for class and classBase
380 for key, cinfo in fc_infos.iteritems():
381 base_name = None
382 # print "Field container: %s" % cinfo.name
384 # If requested, expose the base
385 #if has_base:
386 if cinfo.hasBase:
387 try:
388 base_name = cinfo.name + "Base"
389 base_c = osg.class_(base_name)
390 base_c.include()
391 finalize(base_c)
392 osggen.handleClassDefaults(base_c, True)
393 finalize(base_c, True)
394 except Exception, ex:
395 print "Exception when exposing base class [%s]. Skipping" % base_name
396 print " details: ", ex
398 #osggen.removePureVirtuals(base_c)
399 #for x in base_excludes:
400 # base_c[x].exclude()
401 #for (n,p) in base_policies:
402 # base_c[n].call_policies = p
403 # print "Done with %s" % base_name
405 # Expose the core class
406 c = osg.class_(cinfo.name)
407 if cinfo.alias:
408 c.alias = cinfo.alias
409 c.include()
410 osggen.handleClassDefaults(c, True)
411 finalize(c, True)
412 #c.documentation = cinfo.documentation
413 #osggen.removePureVirtuals(c)
415 for x in cinfo.excludes:
416 #print " exclude:", x
417 try:
418 c[x].exclude()
419 except Exception, ex:
420 pass
421 #print "Exception excluding: %s\n%s"%(x,str(ex))
422 for (n,p) in cinfo.policies:
423 #print " set policy for:", n
424 try:
425 c[n].call_policies = p
426 except Exception, ex:
427 pass
428 #print "Exception setting policies on: %s\n%s"%(n,str(ex))
430 for method_info in cinfo.addMethods:
431 add_member_function(c, method_info[0],method_info[1])
433 # Handle template naming.
434 # XXX: This is a hack for the one specific case where it is used right now.
435 # It should be refactored to use some hints from cinfo to choose naming method.
436 for mname in cinfo.templateMethods:
437 # print " member:", mname
438 for f in c.member_functions(mname):
439 ret_type = f.return_type
440 # print " ret type:", ret_type
441 # print " dict:", ret_type.__dict__
442 if not is_void(ret_type):
443 if hasattr(ret_type, "declaration"):
444 ret_alias = ret_type.declaration.alias
445 else:
446 ret_alias = ret_type.CPPNAME.replace(" ", "_")
447 f.alias = "%s_%s" % (f.alias, ret_alias)
448 # print " aliases: %s %s" % (f.alias, ret_alias)
449 else:
450 f.alias = f.name
451 f.name = f.demangled_name
452 f.create_with_signature = True
454 # Register all the pointer conversions that we need and sets held type
455 osggen.addFCPtrCode(c, mb, cinfo.name, cinfo.parent)
457 # Apply mods (modification methods)
458 if core_mods.has_key(key):
459 #print "Apply mods for: ", key
460 for class_mod in core_mods[key][0]:
461 class_mod(c)
462 for base_mod in core_mods[key][1]:
463 base_mod(base_c)
465 for mod in modules:
466 mod.postFCDInfoSetup(osg, mb, adddition_exp)
468 # ------ Standard ------------- #
469 # - Remove all op=
470 # - Always expose with scope method
471 all_classes = osg.classes()
472 for c in all_classes:
473 c.operators(symbol="=", allow_empty=True).exclude()
474 c.always_expose_using_scope = True
478 mb.build_code_creator(module_name='${PROJECT_NAME}Py')
479 mb.code_creator.add_namespace_usage("std")
481 extra_includes = ["OsgPtrHelpers.h",
482 "boost/python/suite/indexing/map_indexing_suite.hpp",
483 "boost/python/suite/indexing/vector_indexing_suite.hpp"]
485 mb.code_creator.replace_included_headers(
486 [main_header_filename] + extra_includes)
488 mb.code_creator.license = """
489 // PyOpenSG is (C) Copyright 2005-2009 by Allen Bierbaum
491 // This file is part of PyOpenSG.
493 // PyOpenSG is free software; you can redistribute it and/or modify it under
494 // the terms of the GNU Lesser General Public License as published by the Free
495 // Software Foundation; either version 2 of the License, or (at your option)
496 // any later version.
498 // PyOpenSG is distributed in the hope that it will be useful, but WITHOUT ANY
499 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
500 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
501 // more details.
503 // You should have received a copy of the GNU Lesser General Public License
504 // along with this program. If not, see <http://www.gnu.org/licenses/>.
506 #if __GNUC__ >= 4 || __GNUC_MINOR__ >=3
507 #pragma GCC diagnostic warning "-Wold-style-cast"
508 #pragma GCC diagnostic warning "-Wunused-local-typedefs"
509 #pragma GCC diagnostic warning "-Wnon-virtual-dtor"
510 #pragma GCC diagnostic warning "-Wshadow"
511 #endif
512 #if WIN32
513 #pragma warning(disable : 4267)
514 #pragma warning(disable : 4344)
515 #endif
518 if ${OSG_DO_DUMP_PYTHON_DECLS}:
519 decl_file = file("new_decl_out_final.txt",'w', 1024000)
520 print "Writing out decls to file... ",
521 mb.print_declarations(osg, writer=decl_file.write)
522 #mb.print_declarations(my_class)
523 decl_file.close()
524 print "done."
526 mb.code_creator.user_defined_directories.append(output_dir)
528 mb.split_module(pj(output_dir,'generated'))
531 f = open(exported_filename, "w")
533 for cls in osg.classes():
534 if cls.ignore == False:
535 f.write(cls.alias + "\n")
536 for exp in adddition_exp:
537 f.write(exp + "\n")
539 f.close()
541 if ${PROJECT_NAME}Gen.nativeWinDependends != None:
542 for nativeWinDep in ${PROJECT_NAME}Gen.nativeWinDependends:
544 nativeWinDepIn = pj(output_dir, "generated", nativeWinDep + "Base.pypp.cpp")
545 nativeWinDepPatched = pj(output_dir, "generated", nativeWinDep + "Base.pypp.cpp.patched")
546 nativeWinDepOut = pj(output_dir, "generated", nativeWinDep + "Base.pypp.patched.cpp")
548 _inFileContent = open(nativeWinDepIn, "r").read();
549 _patchedFileContent = ""
550 _outFileContent = ""
552 try:
553 _patchedFileContent = open(nativeWinDepPatched, "r").read()
554 except Exception, ex:
555 _patchedFileContent = "p"
557 try:
558 _outFileContent = open(nativeWinDepOut, "r").read()
559 except Exception, ex:
560 _outFileContent = "o"
562 _inFileContent = _inFileContent.replace(${PROJECT_NAME}Gen.nativeWin, "NativeWindow")
564 if _patchedFileContent != _outFileContent:
565 print "out file outdated"
566 open(nativeWinDepPatched, "w").write(_inFileContent)
567 open(nativeWinDepOut, "w").write(_inFileContent)
569 main()