[pygccxml-commit] SF.net SVN: pygccxml: [1111] pyplusplus_dev
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2007-08-19 19:42:35
|
Revision: 1111 http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1111&view=rev Author: roman_yakovenko Date: 2007-08-19 12:42:34 -0700 (Sun, 19 Aug 2007) Log Message: ----------- adding better support for mutli-module development - initial implementation Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/code_creator.py pyplusplus_dev/pyplusplus/code_creators/compound.py pyplusplus_dev/pyplusplus/code_creators/declaration_based.py pyplusplus_dev/pyplusplus/code_creators/scoped.py pyplusplus_dev/pyplusplus/file_writers/multiple_files.py pyplusplus_dev/pyplusplus/file_writers/single_file.py pyplusplus_dev/pyplusplus/file_writers/writer.py pyplusplus_dev/pyplusplus/module_builder/builder.py pyplusplus_dev/pyplusplus/module_creator/creator.py pyplusplus_dev/pyplusplus/module_creator/dependencies_manager.py pyplusplus_dev/pyplusplus/utils/__init__.py pyplusplus_dev/unittests/exposed_decls_db_tester.py pyplusplus_dev/unittests/test_all.py Added Paths: ----------- pyplusplus_dev/unittests/already_exposed_tester.py pyplusplus_dev/unittests/data/already_exposed_to_be_exported.hpp Modified: pyplusplus_dev/pyplusplus/code_creators/code_creator.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/code_creator.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/code_creators/code_creator.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -178,3 +178,12 @@ assert isinstance( line, types.StringTypes ) l = line.lstrip() return l.startswith( '//' ) or l.startswith( '/*' ) + + def register_exposed( self, exposed_db ): + """Register exposed declaration in L{exposed data base<utils.exposed_decls_db_t>} + + The default implementation of the function does nothing. + """ + pass + + \ No newline at end of file Modified: pyplusplus_dev/pyplusplus/code_creators/compound.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/compound.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/code_creators/compound.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -86,4 +86,11 @@ if unique: files = self.unique_headers( files ) return files - \ No newline at end of file + + def register_exposed( self, exposed_db ): + """Register exposed declaration in L{exposed data base<utils.exposed_decls_db_t>} + + The default implementation of the function does nothing. + """ + map( lambda creator: creator.register_exposed( exposed_db ) + , self._creators ) Modified: pyplusplus_dev/pyplusplus/code_creators/declaration_based.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/declaration_based.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/code_creators/declaration_based.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -54,3 +54,7 @@ def get_user_headers( self, recursive=False, unique=False ): """return list of user header files to be included from the generated file""" return self.declaration.include_files + + def register_exposed( self, exposed_db ): + """Register exposed declaration in L{exposed data base<utils.exposed_decls_db_t>}""" + exposed_db.expose( self.declaration ) Modified: pyplusplus_dev/pyplusplus/code_creators/scoped.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/scoped.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/code_creators/scoped.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -14,4 +14,11 @@ def _create_impl(self): #template method pattern should be used. - raise NotImplementedError() \ No newline at end of file + raise NotImplementedError() + + def register_exposed( self, exposed_db ): + """Register exposed declaration in L{exposed data base<utils.exposed_decls_db_t>}""" + exposed_db.expose( self.declaration ) + map( lambda creator: creator.register_exposed( exposed_db ) + , self._creators ) + Modified: pyplusplus_dev/pyplusplus/file_writers/multiple_files.py =================================================================== --- pyplusplus_dev/pyplusplus/file_writers/multiple_files.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/file_writers/multiple_files.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -375,7 +375,8 @@ """ self.write_code_repository( self.__directory_path ) - + self.save_exposed_decls_db( self.__directory_path ) + self.extmodule.do_include_dirs_optimization() map( self.split_value_traits, self.__value_traits ) Modified: pyplusplus_dev/pyplusplus/file_writers/single_file.py =================================================================== --- pyplusplus_dev/pyplusplus/file_writers/single_file.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/file_writers/single_file.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -20,9 +20,10 @@ return self.__fname def write(self): + target_dir = os.path.split( self.file_name )[0] headers = self.get_user_headers( [self.extmodule] ) map( lambda header: self.extmodule.add_include( header ) , headers ) - self.write_code_repository( os.path.split( self.file_name )[0] ) + self.write_code_repository( target_dir ) self.write_file( self.file_name, self.extmodule.create(), encoding=self.encoding ) - + self.save_exposed_decls_db( target_dir ) \ No newline at end of file Modified: pyplusplus_dev/pyplusplus/file_writers/writer.py =================================================================== --- pyplusplus_dev/pyplusplus/file_writers/writer.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/file_writers/writer.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -8,10 +8,11 @@ import os import time import codecs +import md5sum_repository +from pyplusplus import utils from pyplusplus import _logging_ from pyplusplus import code_creators from pyplusplus import code_repository -import md5sum_repository class writer_t(object): """Base class for all module/code writers. @@ -30,6 +31,8 @@ self.__encoding=encoding if None is files_sum_repository: self.__files_sum_repository = md5sum_repository.dummy_repository_t() + self.__exposed_decls_db = utils.exposed_decls_db_t() + self.__extmodule.register_exposed( self.__exposed_decls_db ) @property def encoding( self ): @@ -136,3 +139,8 @@ map( lambda creator: headers.extend( creator.get_user_headers() ) , creators ) return code_creators.code_creator_t.unique_headers( headers ) + + def save_exposed_decls_db( self, file_path ): + self.__exposed_decls_db.save( file_path ) + + \ No newline at end of file Modified: pyplusplus_dev/pyplusplus/module_builder/builder.py =================================================================== --- pyplusplus_dev/pyplusplus/module_builder/builder.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/module_builder/builder.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -12,6 +12,7 @@ from pygccxml import parser from pygccxml import declarations as decls_package +from pyplusplus import utils from pyplusplus import _logging_ from pyplusplus import decl_wrappers from pyplusplus import file_writers @@ -96,7 +97,8 @@ self.__registrations_code_head = [] self.__registrations_code_tail = [] - + self.__already_exposed_modules = [] + @property def global_ns( self ): """reference to global namespace""" @@ -106,6 +108,9 @@ def encoding( self ): return self.__encoding + def register_module_dependency( self, other_module_generate_code_dir ): + self.__already_exposed_modules.append( other_module_generate_code_dir ) + def run_query_optimizer(self): """ It is possible to optimze time that takes to execute queries. In most cases @@ -250,7 +255,8 @@ , types_db , target_configuration , enable_indexing_suite - , doc_extractor) + , doc_extractor + , self.__already_exposed_modules) self.__code_creator = creator.create() self.__code_creator.replace_included_headers(self.__parsed_files) #I think I should ask users, what they expect Modified: pyplusplus_dev/pyplusplus/module_creator/creator.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/creator.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/module_creator/creator.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -52,7 +52,8 @@ , types_db=None , target_configuration=None , enable_indexing_suite=True - , doc_extractor=None): + , doc_extractor=None + , already_exposed_dbs=None): """Constructor. @param decls: Declarations that should be exposed in the final module. @@ -62,6 +63,7 @@ @param types_db: ...todo... @param target_configuration: A target configuration object can be used to customize the generated source code to a particular compiler or a particular version of Boost.Python. @param doc_extractor: callable, that takes as argument declaration reference and returns documentation string + @param already_exposed_dbs: list of files/directories other modules, this module depends on, generated their code too @type decls: list of declaration_t @type module_name: str @type boost_python_ns_name: str @@ -69,6 +71,7 @@ @type types_db: L{types_database_t<types_database.types_database_t>} @type target_configuration: L{target_configuration_t<code_creators.target_configuration_t>} @type doc_extractor: callable + @type already_exposed_dbs: list of strings """ declarations.decl_visitor_t.__init__(self) self.logger = _logging_.loggers.module_builder @@ -95,8 +98,12 @@ self.__extmodule.adopt_creator( bp_ns_alias ) self.__module_body = code_creators.module_body_t( name=module_name ) + self.__extmodule.adopt_creator( self.__module_body ) - + + self.__opaque_types_manager = opaque_types_manager.manager_t( self.__extmodule ) + self.__dependencies_manager = dependencies_manager.manager_t(self.decl_logger, already_exposed_dbs) + prepared_decls = self._prepare_decls( decls, doc_extractor ) self.__decls = sort_algorithms.sort( prepared_decls ) @@ -105,19 +112,43 @@ self.__array_1_registered = set() #(type.decl_string,size) self.__free_operators = [] self.__exposed_free_fun_overloads = set() - self.__opaque_types_manager = opaque_types_manager.manager_t( self.__extmodule ) - self.__dependencies_manager = dependencies_manager.manager_t(self.decl_logger) + + + def __print_readme( self, decl ): + readme = decl.readme() + if not readme: + return + if not decl.exportable: + reason = readme[0] + readme = readme[1:] + self.decl_logger.warn( "%s;%s" % ( decl, reason ) ) + + for msg in readme: + self.decl_logger.warn( "%s;%s" % ( decl, msg ) ) + def _prepare_decls( self, decls, doc_extractor ): - decls = declarations.make_flatten( decls ) - - for decl in decls: + to_be_exposed = [] + for decl in declarations.make_flatten( decls ): if decl.ignore: continue + + if isinstance( decl, declarations.namespace_t ): + continue - if decl.already_exposed: + if not decl.exportable: + #leave only decls that user wants to export and that could be exported + self.__print_readme( decl ) continue + if self.__dependencies_manager.is_already_exposed( decl ): + #check wether this is already exposed in other module + continue + + if isinstance( decl.parent, declarations.namespace_t ): + #leave only declarations defined under namespace, but remove namespaces + to_be_exposed.append( decl ) + #Right now this functionality introduce a bug: declarations that should #not be exported for some reason are not marked as such. I will need to #find out. @@ -128,30 +159,14 @@ #if isinstance( decl, declarations.variable_t ): #self.__types_db.update( decl ) - if doc_extractor and decl.exportable: + + if doc_extractor: decl.documentation = doc_extractor( decl ) - readme = decl.readme() - if not readme: - continue + self.__print_readme( decl ) - if not decl.exportable: - reason = readme[0] - readme = readme[1:] - self.decl_logger.warn( "%s;%s" % ( decl, reason ) ) + return to_be_exposed - for msg in readme: - self.decl_logger.warn( "%s;%s" % ( decl, msg ) ) - - #leave only declarations defined under namespace, but remove namespaces - decls = filter( lambda x: not isinstance( x, declarations.namespace_t ) \ - and isinstance( x.parent, declarations.namespace_t ) - , decls ) - #leave only decls that user wants to export and that could be exported - decls = filter( lambda x: x.ignore == False and x.exportable == True, decls ) - - return decls - def _adopt_free_operator( self, operator ): def adopt_operator_impl( operator, found_creators ): creator = filter( lambda creator: isinstance( creator, code_creators.class_t ) Modified: pyplusplus_dev/pyplusplus/module_creator/dependencies_manager.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/dependencies_manager.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/module_creator/dependencies_manager.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -6,19 +6,27 @@ """defines class, which informs user about used, but unexposed declarations""" import os +from pyplusplus import utils from pyplusplus import messages from pygccxml import declarations from pyplusplus import decl_wrappers + class manager_t( object ): - def __init__( self, logger ): + def __init__( self, logger, already_exposed=None ): object.__init__( self ) self.__exported_decls = [] self.__logger = logger - + self.__already_exposed_db = utils.exposed_decls_db_t() + if already_exposed: + map( self.__already_exposed_db.load, already_exposed ) + def add_exported( self, decl ): self.__exported_decls.append( decl ) + def is_already_exposed( self, decl ): + return decl.already_exposed or self.__already_exposed_db.is_exposed( decl ) + def __select_duplicate_aliases( self, decls ): duplicated = {} for decl in decls: @@ -71,7 +79,7 @@ if self.__is_std_decl( decl ): #TODO add element_type to the list of dependencies return [] #std declarations should be exported by Py++! - if decl.already_exposed: + if self.is_already_exposed( decl ): return [] dependencies = decl.i_depend_on_them(recursive=False) if isinstance( decl, declarations.class_t ): Modified: pyplusplus_dev/pyplusplus/utils/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/utils/__init__.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/pyplusplus/utils/__init__.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -54,6 +54,7 @@ class exposed_decls_db_t( object ): + DEFAULT_FILE_NAME = 'exposed_decl.pypp.txt' class row_creator_t( declarations.decl_visitor_t ): def __init__( self, field_delimiter ): self.__decl = None @@ -64,8 +65,6 @@ return declarations.full_name( self.__decl ) def __call__( self, decl ): - if not isinstance( decl.parent, declarations.namespace_t ): - return None #we don't want to dump class internal declarations self.__decl = decl self.__formatted = None try: @@ -91,32 +90,15 @@ def visit_variable(self ): self.__formatted = self.get_full_name() - def __init__( self, activated=False ): - self.__activated = activated + def __init__( self ): self.__exposed = {} self.__row_creator = self.row_creator_t(field_delimiter='@') self.__key_delimiter = '?' self.__row_delimiter = os.linesep - def __create_key( self, decl ): - return decl.__class__.__name__ - - @property - def activated( self ): - return self.__activated - - def expose( self, decl ): - if not self.__activated: - return None - row = self.__row_creator( decl ) - if row is None: - return None - key = self.__create_key( decl ) - if not self.__exposed.has_key( key ): - self.__exposed[ key ] = set() - self.__exposed[ key ].add( row ) - def save( self, fpath ): + if os.path.isdir( fpath ): + fpath = os.path.join( fpath, self.DEFAULT_FILE_NAME ) f = file( fpath, 'w+b' ) for key, items in self.__exposed.iteritems(): for item in items: @@ -124,18 +106,43 @@ f.close() def load( self, fpath ): - self.__exposed = {} + if os.path.isdir( fpath ): + fpath = os.path.join( fpath, self.DEFAULT_FILE_NAME ) f = file( fpath, 'r+b' ) for line in f: key, row = line.split( self.__key_delimiter) + row = row.replace( self.__row_delimiter, '' ) if not self.__exposed.has_key( key ): self.__exposed[ key ] = set() - self.__exposed[ key ].add( row[:len(self.__row_delimiter)] ) + self.__exposed[ key ].add( row ) - def is_exposed( self, decl ): - assert self.activated + def __create_key( self, decl ): + return decl.__class__.__name__ + + def expose( self, decl ): + if not isinstance( decl.parent, declarations.namespace_t ): + return None #we don't want to dump class internal declarations + row = self.__row_creator( decl ) + if row is None: + return None key = self.__create_key( decl ) if not self.__exposed.has_key( key ): + self.__exposed[ key ] = set() + self.__exposed[ key ].add( row ) + + def __get_under_ns_decl( self, decl ): + while True: + if isinstance( decl.parent, declarations.namespace_t ): + return decl + else: + decl = decl.parent + + def is_exposed( self, decl_ ): + if isinstance( decl_, declarations.namespace_t ): + return False#namespaces are always exposed + decl = self.__get_under_ns_decl( decl_ ) + key = self.__create_key( decl ) + if not self.__exposed.has_key( key ): return False row = self.__row_creator( decl ) return row in self.__exposed[ key ] Added: pyplusplus_dev/unittests/already_exposed_tester.py =================================================================== --- pyplusplus_dev/unittests/already_exposed_tester.py (rev 0) +++ pyplusplus_dev/unittests/already_exposed_tester.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -0,0 +1,43 @@ +# Copyright 2004 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import sys +import unittest +import autoconfig +from pyplusplus import utils +import fundamental_tester_base + +class tester_t(fundamental_tester_base.fundamental_tester_base_t): + EXTENSION_NAME = 'already_exposed' + + def __init__( self, *args ): + fundamental_tester_base.fundamental_tester_base_t.__init__( + self + , tester_t.EXTENSION_NAME + , *args ) + + def customize(self, mb ): + exposed_db = utils.exposed_decls_db_t() + map( exposed_db.expose, mb.decls(recursive=True) ) + exposed_db.save( autoconfig.build_dir ) + mb.register_module_dependency( autoconfig.build_dir ) + mb.decls().exclude() + mb.namespace( 'already_exposed' ).include() + + def run_tests(self, module): + self.failUnless( 'ae_t' not in dir( module ) ) + self.failUnless( 'ae_e' not in dir( module ) ) + +def create_suite(): + suite = unittest.TestSuite() + suite.addTest( unittest.makeSuite(tester_t)) + return suite + +def run_suite(): + unittest.TextTestRunner(verbosity=2).run( create_suite() ) + +if __name__ == "__main__": + run_suite() Added: pyplusplus_dev/unittests/data/already_exposed_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/already_exposed_to_be_exported.hpp (rev 0) +++ pyplusplus_dev/unittests/data/already_exposed_to_be_exported.hpp 2007-08-19 19:42:34 UTC (rev 1111) @@ -0,0 +1,17 @@ +// Copyright 2004 Roman Yakovenko. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef __already_exposed_to_be_exported_hpp__ +#define __already_exposed_to_be_exported_hpp__ + +namespace already_exposed{ + +struct ae_t{}; + +enum ae_e { x1, x2 }; + +} + +#endif//__already_exposed_to_be_exported_hpp__ Modified: pyplusplus_dev/unittests/exposed_decls_db_tester.py =================================================================== --- pyplusplus_dev/unittests/exposed_decls_db_tester.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/unittests/exposed_decls_db_tester.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -28,32 +28,45 @@ int VVV; void FFF( int ); } + namespace ns_skip{ + enum a123{ a1=1 }; + struct b123{ + struct c123{}; + }; + int fff(); + int i; + } """ def __init__(self, *args ): unittest.TestCase.__init__(self, *args) def test(self): - db = pypp_utils.exposed_decls_db_t(activated=True) + db = pypp_utils.exposed_decls_db_t() config = parser.config_t( gccxml_path=autoconfig.gccxml.executable ) global_ns = declarations.get_global_namespace( parser.parse_string( self.CODE, config ) ) ns = global_ns.namespace( 'ns' ) for d in ns.decls(recursive=True): db.expose( d ) - - select_exposed = lambda decl: decl.name == decl.name.upper() \ - and not isinstance( decl, declarations.member_calldef_t ) - - for x in ns.decls( select_exposed ): + + for x in ns.decls(recursive=True): self.failUnless( db.is_exposed( x ) == True ) - + + ns_skip = global_ns.namespace( 'ns_skip' ) + for x in ns_skip.decls(recursive=True): + self.failUnless( db.is_exposed( x ) == False ) + db.save( os.path.join( autoconfig.build_dir, 'exposed.db.pypp' ) ) - - db2 = pypp_utils.exposed_decls_db_t(activated=True) + + db2 = pypp_utils.exposed_decls_db_t() db2.load( os.path.join( autoconfig.build_dir, 'exposed.db.pypp' ) ) - for x in ns.decls( select_exposed ): + for x in ns.decls(recursive=True): self.failUnless( db.is_exposed( x ) == True ) - + ns_skip = global_ns.namespace( 'ns_skip' ) + for x in ns_skip.decls(recursive=True): + self.failUnless( db.is_exposed( x ) == False ) + + def create_suite(): suite = unittest.TestSuite() suite.addTest( unittest.makeSuite(tester_t)) Modified: pyplusplus_dev/unittests/test_all.py =================================================================== --- pyplusplus_dev/unittests/test_all.py 2007-08-18 05:54:28 UTC (rev 1110) +++ pyplusplus_dev/unittests/test_all.py 2007-08-19 19:42:34 UTC (rev 1111) @@ -72,6 +72,7 @@ import duplicate_aliases_tester import non_overridable_tester import exposed_decls_db_tester +import already_exposed_tester def create_suite(times): testers = [ @@ -140,6 +141,7 @@ , duplicate_aliases_tester , non_overridable_tester , exposed_decls_db_tester + , already_exposed_tester ] main_suite = unittest.TestSuite() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |