• Facebook
  • Twitter
  • Reddit
  • StumbleUpon
  • Digg
  • email

#!/usr/bin/env python
# -----------------------------------------------------------------------------
# This source file is part of Python-Ogre and is covered by the LGPL
# For the latest info, see http://python-ogre.org/
#
# -----------------------------------------------------------------------------
 
## STARTER TEMPLATE..
## replace ogresdksample with lowercase project name
## set MAIN_NAMESPACE
## rename and configure .h files
 
 
import os, sys, time, shutil
try:
   import psyco
   psyco.full()
except ImportError:
   pass
 
#add environment to the path
sys.path.append( os.path.join( '..', '..' ) )
#add common utils to the pass
sys.path.append( '..' )
sys.path.append( '.' )
 
import environment
import common_utils
import customization_data
import hand_made_wrappers
 
 
import pygccxml
from pygccxml import parser
from pygccxml import declarations
from pyplusplus import messages
from pyplusplus import module_builder
from pyplusplus import decl_wrappers
from pyplusplus.code_creators import include
 
from pyplusplus import function_transformers as ft
from pyplusplus.module_builder import call_policies
try:
  from pyplusplus.creators_factory import sort_algorithms
except ImportError, e:
  from pyplusplus.module_creator import sort_algorithms
 
import common_utils.extract_documentation as exdoc
import common_utils.var_checker as varchecker
import common_utils.ogre_properties as ogre_properties
from common_utils import docit
 
# override standard pretty name function
from pyplusplus.decl_wrappers import algorithm
algorithm.create_valid_name = common_utils.PO_create_valid_name 
 
 
MAIN_NAMESPACE = 'OgreBites'
 
############################################################
##
##  Here is where we manually exclude stuff
##
############################################################
 
def ManualExclude ( mb ):
    global_ns = mb.global_ns
    if MAIN_NAMESPACE:
        main_ns = global_ns.namespace( MAIN_NAMESPACE )
    else:
        main_ns = global_ns    
 
############################################################
##
##  And there are things that manually need to be INCLUDED 
##
############################################################
 
def ManualInclude ( mb ):
    global_ns = mb.global_ns
    if MAIN_NAMESPACE:
        main_ns = global_ns.namespace( MAIN_NAMESPACE )
    else:
        main_ns = global_ns    
    cl = ['Sample', 'SdkSample','SdkCameraMan']
    for c in cl:
        for v in main_ns.class_(c).variables():
            print "Including Var", v
            v.include()
 
#        print v, v.ignore
#    print dir(v)
#    sys.exit()
############################################################
##
##  And things that need manual fixes, but not necessarly hand wrapped
##
############################################################
def ManualFixes ( mb ):    
    global_ns = mb.global_ns
    if MAIN_NAMESPACE:
        main_ns = global_ns.namespace( MAIN_NAMESPACE )
    else:
        main_ns = global_ns
 
############################################################
##
##  And things that need to have their argument and call values fixed.
##  ie functions that pass pointers in the argument list and of course we need
##  to read the updated values - so instead we pass them back 
##  as new values in a tuple (ETC ETC)
##
############################################################
 
def ManualTransformations ( mb ):
    global_ns = mb.global_ns
    if MAIN_NAMESPACE:
        main_ns = global_ns.namespace( MAIN_NAMESPACE )
    else:
        main_ns = global_ns
 
    def create_output( size ):
        return [ ft.output( i ) for i in range( size ) ]
 
 
###############################################################################
##
##  Now for the AUTOMATIC stuff that should just work
##
###############################################################################
 
def AutoFixes ( mb, MAIN_NAMESPACE ): 
    """ now we fix a range of things automatically - typically by going through 
    the entire name space trying to guess stuff and fix it:)
    """    
    global_ns = mb.global_ns
    if MAIN_NAMESPACE:
        main_ns = global_ns.namespace( MAIN_NAMESPACE )
    else:
        main_ns = global_ns
 
    # Functions that have void pointers in their argument list need to change to unsigned int's  
    pointee_types=[]
    ignore_names=[]
 
    # and change functions that return a variety of pointers to instead return unsigned int's
    pointee_types=[]
    ignore_names=[]  # these are function names we know it's cool to exclude
    common_utils.Fix_Pointer_Returns ( main_ns ) # , pointee_types, ignore_names )   
 
    # functions that need to have implicit conversions turned off
    ImplicitClasses=[] 
    common_utils.Fix_Implicit_Conversions ( main_ns, ImplicitClasses )
 
    if os.name =='nt':
        Fix_NT( mb )
    elif os.name =='posix':
        Fix_Posix( mb )
 
 
 
###############################################################################
##
## here are the helper functions that do much of the work
##
###############################################################################     
def Fix_Posix ( mb ):
    """ fixup for posix specific stuff -- note only expect to be called on a posix machine
    """
    ## we could do more here if need be...
    if sys.platform == 'darwin':
        pass
    elif sys.platform.startswith ('linux'):
        pass
 
 
def Fix_NT ( mb ):
    """ fixup for NT systems
    """
 
def FindProtectedVars ( mb ):
    global_ns = mb.global_ns
    main_ns = global_ns.namespace( MAIN_NAMESPACE )
    for v in main_ns.variables():
        if v.access_type == 'protected':
            v.set_exportable(True)
            v._exportable_reason = "Forced"
            print "Protected Variable Exposed:", v, v.access_type
        else:
            print "VAR:",v, v.access_type
    for c in main_ns.classes():
        print "Class: ", c
 
#
# the 'main'function
#            
def generate_code():  
    if 0:
        messages.disable( 
    #           Warnings 1020 - 1031 are all about why Py++ generates wrapper for class X
              messages.W1020
            , messages.W1021
            , messages.W1022
            , messages.W1023
            , messages.W1024
            , messages.W1025
            , messages.W1026
            , messages.W1027
            , messages.W1028
            , messages.W1029
            , messages.W1030
            , messages.W1031
            , messages.W1035
            , messages.W1040 
            , messages.W1038        
            , messages.W1041
            , messages.W1036 # pointer to Python immutable member
            , messages.W1033 # unnamed variables
            , messages.W1018 # expose unnamed classes
            , messages.W1049 # returns reference to local variable
            , messages.W1014 # unsupported '=' operator
             )
    #
    # Use GCCXML to create the controlling XML file.
    # If the cache file (../cache/*.xml) doesn't exist it gets created, otherwise it just gets loaded
    # NOTE: If you update the source library code you need to manually delete the cache .XML file   
    #
    xml_cached_fc = parser.create_cached_source_fc(
                        os.path.join( environment.ogresdksample.root_dir, "python_ogresdksample.h" )
                        , environment.ogresdksample.cache_file )
 
    defined_symbols = environment.defined_symbols 
    defined_symbols.append( 'VERSION_' + environment.ogresdksample.version )  
    print environment.ogresdksample.include_dirs
    #
    # build the core Py++ system from the GCCXML created source
    #    
    mb = module_builder.module_builder_t( [ xml_cached_fc ]
                                          , gccxml_path=environment.gccxml_bin
                                          , working_directory=environment.root_dir
                                          , include_paths=environment.ogresdksample.include_dirs
                                          , define_symbols=defined_symbols
                                          , indexing_suite_version=2
                                          , cflags=environment.ogresdksample.cflags
                                           )
 
    # if this module depends on another set it here                                           
    mb.register_module_dependency ( environment.ogre.generated_dir )
 
    # normally implicit conversions work OK, however they can cause strange things to happen so safer to leave off
    mb.constructors().allow_implicit_conversion = False                                           
 
    mb.BOOST_PYTHON_MAX_ARITY = 25
    mb.classes().always_expose_using_scope = True
 
    #
    # We filter (both include and exclude) specific classes and functions that we want to wrap
    # 
    global_ns = mb.global_ns
    global_ns.exclude()
    main_ns = global_ns.namespace( MAIN_NAMESPACE )
    main_ns.include()
 
    common_utils.AutoExclude ( mb, MAIN_NAMESPACE )
    ManualExclude ( mb )
    common_utils.AutoInclude ( mb, MAIN_NAMESPACE )
    ManualInclude ( mb )
    # here we fixup functions that expect to modifiy their 'passed' variables    
    ManualTransformations ( mb )
    AutoFixes ( mb, MAIN_NAMESPACE )
    ManualFixes ( mb )
 
    common_utils.Auto_Functional_Transformation ( main_ns ) #, special_vars=[]  )
 
    FindProtectedVars ( mb )
 
    #
    # We need to tell boost how to handle calling (and returning from) certain functions
    #
    common_utils.Set_DefaultCall_Policies ( mb.global_ns.namespace ( MAIN_NAMESPACE ) )
 
    #
    # the manual stuff all done here !!!
    #
    hand_made_wrappers.apply( mb )
 
    NoPropClasses = [""]
    for cls in main_ns.classes():
        if cls.name not in NoPropClasses:
            cls.add_properties( recognizer=ogre_properties.ogre_property_recognizer_t() )
 
    # THIS MUST BE AFTER Auto_Functional_Transformation
    common_utils.Auto_Document( mb, MAIN_NAMESPACE )
 
    ## add additional version information to the module to help identify it correctly 
    common_utils.addDetailVersion ( mb, environment, environment.ogresdksample )
 
    ##########################################################################################
    #
    # Creating the code. After this step you should not modify/customize declarations.
    #
    ##########################################################################################
    extractor = exdoc.doc_extractor() # I'm excluding the UTFstring docs as lots about nothing 
    mb.build_code_creator (module_name='_ogresdksample_' , doc_extractor= extractor )
 
    for inc in environment.ogresdksample.include_dirs:
        mb.code_creator.user_defined_directories.append(inc )
    mb.code_creator.user_defined_directories.append( environment.ogresdksample.generated_dir )
    mb.code_creator.replace_included_headers( customization_data.header_files( environment.ogresdksample.version ) )
 
    huge_classes = map( mb.class_, customization_data.huge_classes( environment.ogresdksample.version ) )
 
    mb.split_module(environment.ogresdksample.generated_dir, huge_classes, use_files_sum_repository=False)
 
    ## now we need to ensure a series of headers and additional source files are
    ## copied to the generated directory..
#     files =  os.listdir( environment.Config.PATH_INCLUDE_sdksample )
#     files_filtered = []
#     for f in files:
#         if f.startswith ("Sample") or f.startswith ("FileSystem"):
#             files_filtered.append (f)
#     print files_filtered
    common_utils.copyTree ( sourcePath = environment.Config.PATH_INCLUDE_sdksample,
                            destPath = environment.ogresdksample.generated_dir,
                            recursive=False,
                             )
    if environment.ogre.version.startswith("1.7"):
        ## have a code generation issue that needs resolving...
        filesToFix=['SdkTrayManager.pypp.cpp']
        for filename in filesToFix:
            fname = os.path.join( environment.ogresdksample.generated_dir, filename)
            try:
                f = open(fname, 'r')
                buf = f.read()
                f.close()
                if (" MEMCATEGORY_GENERAL" in buf) or ("<MEMCATEGORY_GENERAL" in buf):
                    buf = buf.replace ( " MEMCATEGORY_GENERAL", " Ogre::MEMCATEGORY_GENERAL")
                    buf = buf.replace ( "<MEMCATEGORY_GENERAL", "<Ogre::MEMCATEGORY_GENERAL")
                    f = open ( fname, 'w+')
                    f.write ( buf )
                    f.close()
                    print "UGLY FIX OK:", fname
            except:
                print "ERROR: Unable to fix:", fname
 
if __name__ == '__main__':
    start_time = time.clock()
    generate_code()
    print 'Source code was updated( %f minutes ).' % (  ( time.clock() - start_time )/60 )