| Trees | Indices | Help | 
 | 
|---|
|  | 
  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  """defines a class that writes L{code_creators.module_t} to multiple files""" 
  7   
  8  import os 
  9  import writer 
 10  from pyplusplus import messages 
 11  from pyplusplus import _logging_ 
 12  from pygccxml import declarations 
 13  from pyplusplus import decl_wrappers 
 14  from pyplusplus import code_creators 
 15   
 16  #TODO: to add namespace_alias_t classes 
 18      """ 
 19      This class implements classic strategy of deviding classes to files 
 20      one class in one header + source files. 
 21      """ 
 22      HEADER_EXT = '.pypp.hpp' 
 23      SOURCE_EXT = '.pypp.cpp' 
 24   
 25 -    def __init__(self, extmodule, directory_path, write_main=True, files_sum_repository=None, encoding='ascii'): 
 26          """Constructor. 
 27   
 28          @param extmodule: The root of a code creator tree 
 29          @type extmodule: module_t 
 30          @param directory_path: The output directory where the source files are written 
 31          @type directory_path: str 
 32   
 33          @param write_main:  if it is True, the class will write out a main file 
 34              that calls all the registration methods. 
 35          @type write_main: boolean 
 36          """ 
 37          writer.writer_t.__init__( self, extmodule, files_sum_repository, encoding=encoding ) 
 38          self.__directory_path = directory_path 
 39          self.create_dir( directory_path ) 
 40          self.include_creators = []  # List of include_t creators that contain the generated headers 
 41          self.split_header_names = []  # List of include file names for split files 
 42          self.split_method_names = []  # List of methods from the split files 
 43          self.write_main = write_main 
 44          self.written_files = [] 
 45          self.ref_count_creators = ( code_creators.opaque_type_registrator_t, ) 
 46          self.__predefined_include_creators \ 
 47              = filter( lambda creator: isinstance( creator, code_creators.include_t ) 
 48                        , self.extmodule.creators ) 
 49          self.__value_traits = filter( lambda x: isinstance(x, code_creators.value_traits_t) 
 50                                        , self.extmodule.creators ) 
 51   
 52   
 54          if fpath in self.written_files: 
 55              msg = ['Py++ is going to write different content to the same file(%s).' % fpath] 
 56              msg.append('The following is a short list of possible explanations for this behaviour:' ) 
 57              msg.append('* Py++ bug, in this case, please report it' ) 
 58              msg.append('* module_builder_t contains two or more classes with the same alias') 
 59              msg.append('* module_builder_t contains two or more classes with the same wrapper alias') 
 60              msg.append('Please carefully review Py++ warning messages. It should contain an additional information.') 
 61              raise RuntimeError( os.linesep.join(msg) ) 
 62   
 63          self.written_files.append( fpath ) 
 64          writer.writer_t.write_file( fpath, content, self.files_sum_repository, self.encoding ) 
 65   
 67          """Create the output directory if it doesn't already exist. 
 68          """ 
 69          if os.path.exists( directory_path ) and not os.path.isdir(directory_path): 
 70              raise RuntimeError( 'directory_path should contain path to directory.' ) 
 71          if not os.path.exists( directory_path ): 
 72              os.makedirs( directory_path ) 
 73   
 76      directory_path = property( _get_directory_path, 
 77                                 doc="""The name of the output directory. 
 78                                 @type: str 
 79                                 """ ) 
 80   
 82          unique_creators = [] 
 83          unique_creator_ids = set() 
 84          for creator in creators: 
 85              if not id( creator ) in unique_creator_ids: 
 86                  unique_creator_ids.add( id( creator ) ) 
 87                  unique_creators.append( creator ) 
 88          return unique_creators 
 89   
 91          """ references to all class declaration code creators. """ 
 92          if not isinstance( creator, code_creators.registration_based_t ): 
 93              return [] 
 94   
 95          associated_creators = creator.associated_decl_creators[:] 
 96   
 97          internal_creators = [] 
 98          if isinstance( creator, code_creators.compound_t ): 
 99              internal_creators.extend( 
100                  filter( lambda creator: isinstance( creator, code_creators.registration_based_t ) 
101                          , code_creators.make_flatten( creator.creators ) ) ) 
102   
103          map( lambda internal_creator: associated_creators.extend( internal_creator.associated_decl_creators ) 
104               , internal_creators ) 
105          #now associated_creators contains all code creators associated with the creator 
106          #We should leave only creators, defined in the global namespace 
107          associated_creators = filter( lambda associated_creator: associated_creator.parent is self.extmodule 
108                                        , associated_creators ) 
109          return associated_creators 
110   
113   
115          """Return the content of a header file. 
116   
117          @param file_name: A string that uniquely identifies the file name 
118          @type file_name: str 
119          @param function_name: The name of the register_xyz() function 
120          @type function_name: str 
121          @returns: The content for a header file 
122          @rtype: str 
123          """ 
124          tmpl = os.linesep.join([ 
125                      "#ifndef %(file_name)s_hpp__pyplusplus_wrapper" 
126                    , "#define %(file_name)s_hpp__pyplusplus_wrapper" 
127                    , '' 
128                    , "%(code)s" 
129                    , '' 
130                    , "#endif//%(file_name)s_hpp__pyplusplus_wrapper" ]) 
131   
132          content = '' 
133          if self.extmodule.license: 
134              content = self.extmodule.license.create() + os.linesep 
135          content = content + tmpl % { 'file_name' : file_name, 'code' : code } 
136          return content 
137   
139          if not isinstance( code_creator, ( code_creators.class_t, code_creators.class_declaration_t ) ): 
140              return None 
141          if None is code_creator.declaration.indexing_suite: 
142              return None 
143          if not isinstance( code_creator.declaration.indexing_suite, decl_wrappers.indexing_suite2_t ): 
144              return None 
145   
146          #sometimes, for some reason I expose containers as regular classes ( hash_map ) 
147          #and in this case I do generate include to 
148          classes = ( code_creators.indexing_suite1_t, code_creators.indexing_suite2_t ) 
149          for cont_code_creator in code_creator.creators: 
150              if isinstance( cont_code_creator, classes ): 
151                  break 
152          else: 
153              return None 
154   
155          try: 
156              element_type = code_creator.declaration.indexing_suite.element_type 
157              class_traits = declarations.class_traits 
158              if not class_traits.is_my_case( element_type ): 
159                  return None 
160              value_class = class_traits.get_declaration( element_type ) 
161              if value_class.less_than_comparable and value_class.equality_comparable: 
162                  return None #Py++ doesn't create value traits for class that has 
163                              # = and < operators available 
164              return self.create_value_traits_header_name( value_class ) 
165          except RuntimeError, error: 
166              decls_logger = _logging_.loggers.declarations 
167              if not messages.filter_disabled_msgs([messages.W1042], code_creator.declaration.disabled_messages ): 
168                  return #user disabled property warning 
169              decls_logger.warn( "%s;%s" % ( code_creator.declaration, messages.W1042 ) ) 
170   
172          answer = [] 
173          normalize = code_creators.include_directories_t.normalize 
174          unique_headers = code_creators.code_creator_t.unique_headers 
175   
176          if head_headers: 
177              answer.extend( map( lambda header: '#include "%s"' % normalize( header ) 
178                                  , head_headers ) ) 
179   
180          dependend_on_headers = [] 
181          for creator in creators: 
182              dependend_on_headers.extend( creator.get_system_headers( recursive=True ) ) 
183   
184          dependend_on_headers = unique_headers( map( normalize, dependend_on_headers ) ) 
185   
186          for include_cc in self.__predefined_include_creators: 
187              if include_cc.is_system: 
188                  if include_cc.header in dependend_on_headers: 
189                      answer.append( include_cc.create() ) 
190              else:# user header file - always include 
191                  answer.append( include_cc.create() ) 
192   
193          map( lambda user_header: answer.append( '#include "%s"' % user_header ) 
194               , self.get_user_headers( creators ) ) 
195   
196          for creator in creators: 
197              header = self.find_out_value_traits_header( creator ) 
198              if header: 
199                  answer.append( '#include "%s"' % header ) 
200   
201          if tail_headers: 
202              answer.extend( map( lambda header: '#include "%s"' % normalize( header ) 
203                                  , tail_headers ) ) 
204   
205          return os.linesep.join( answer ) 
206   
208          # Write all 'global' namespace_alias_t and namespace_using_t creators first... 
209          ns_types = ( code_creators.namespace_alias_t, code_creators.namespace_using_t ) 
210          ns_creators = filter( lambda x: isinstance( x, ns_types ), self.extmodule.creators ) 
211   
212          ns_creators.extend( filter( lambda x: isinstance( x, ns_types ), self.extmodule.body.creators ) ) 
213          if not ns_creators: 
214              return '' 
215          else: 
216              return os.linesep.join( map( lambda creator: creator.create(), ns_creators ) ) 
217   
219          """Return the content of a cpp file. 
220   
221          @param file_name: The base name of the corresponding include file (without extension) 
222          @type file_name: str 
223          @param function_name: The name of the register_xyz() function 
224          @type function_name: str 
225          @param creators: The code creators that create the register_xyz() function 
226          @type creators: list of code_creator_t 
227          @returns: The content for a cpp file 
228          @rtype: str 
229          """ 
230          declaration_creators = [] 
231          for rc in registration_creators: 
232              declaration_creators.extend( self.associated_decl_creators( rc ) ) 
233          declaration_creators = self.get_unique_creators( declaration_creators ) 
234   
235          creators = registration_creators + declaration_creators 
236   
237          answer = [] 
238          if self.extmodule.license: 
239              answer.append( self.extmodule.license.create() ) 
240   
241          head_headers = [ file_name + self.HEADER_EXT ] 
242          answer.append( self.create_include_code( creators, tail_headers=head_headers ) ) 
243   
244          answer.append( '' ) 
245          answer.append( self.create_namespaces_code( creators ) ) 
246   
247          # Write wrapper classes... 
248          for creator in declaration_creators: 
249              answer.append( '' ) 
250              answer.append( creator.create() ) 
251              if not isinstance( creator, self.ref_count_creators ): 
252                  creator.create = lambda: '' 
253   
254          # Write the register() function... 
255          answer.append( '' ) 
256          answer.append( 'void %s(){' % function_name ) 
257          answer.append( '' ) 
258          for creator in registration_creators: 
259              answer.append( code_creators.code_creator_t.indent( creator.create() ) ) 
260              answer.append( '' ) 
261          answer.append( '}' ) 
262          return os.linesep.join( answer ) 
263   
265          function_name = 'register_%s_class' % class_creator.alias 
266          file_path = os.path.join( self.directory_path, class_creator.alias ) 
267          # Write the .h file... 
268          header_name = file_path + self.HEADER_EXT 
269          self.write_file( header_name 
270                           , self.create_header( class_creator.alias 
271                                                 , self.create_function_code( function_name ) ) ) 
272   
273          # Write the .cpp file... 
274          cpp_code = self.create_source( class_creator.alias, function_name, [class_creator] ) 
275   
276          self.write_file( file_path + self.SOURCE_EXT, cpp_code ) 
277   
278          # Replace the create() method so that only the register() method is called 
279          # (this is called later for the main source file). 
280          class_creator.create = lambda: function_name +'();' 
281          self.include_creators.append( code_creators.include_t( header_name ) ) 
282          self.split_header_names.append(header_name) 
283          self.split_method_names.append(function_name) 
284   
286          """Write the .h/.cpp file for one class. 
287   
288          Writes a .h/.cpp file for the given class. The files use the class name 
289          as base file name. 
290   
291          @param class_creator: The class creator for one particular class 
292          @type class_creator: class_t 
293          """ 
294          try: 
295              if class_creator.declaration.already_exposed: 
296                  return 
297              self.split_class_impl( class_creator ) 
298          except IOError, error: 
299              msg = [ 'Failed to write code for class "%s" into file.;' % class_creator.declaration.name ] 
300              msg.append( "May be the class name is too long?." ) 
301              msg.append( "Error: %s'" % str(error) ) 
302              self.logger.error( os.linesep.join( msg ) ) 
303              raise 
304   
306          # Obtain a list of all class creators... 
307          class_creators = filter( lambda x: isinstance(x, ( code_creators.class_t, code_creators.class_declaration_t ) ) 
308                                   , self.extmodule.body.creators ) 
309          # ...and write a .h/.cpp file for each class 
310          map( self.split_class, class_creators ) 
311   
314   
316          """ 
317          Write the value_traits class to header file, that will be included 
318          from files, that uses indexing suite 2 
319          """ 
320          if value_traits.declaration.already_exposed: 
321              return 
322   
323          header_name = self.create_value_traits_header_name( value_traits.declaration ) 
324          file_path = os.path.join( self.directory_path, header_name ) 
325          self.write_file( file_path 
326                          , self.create_header( header_name.replace( '.', '_' ) 
327                                                , value_traits.create() ) ) 
328          value_traits.create = lambda: '' 
329   
331          map( self.split_value_traits, self.__value_traits ) 
332   
334          """Write non-class creators into a particular .h/.cpp file. 
335   
336          @param creators: The code creators that should be written 
337          @type creators: list of code_creator_t 
338          @param pattern: Name pattern that is used for constructing the final output file name 
339          @type pattern: str 
340          @param function_name: The name of the register_xyz() function 
341          @type function_name: str 
342          @param registrator_pos: The position of the code creator that creates the code to invoke the register_xyz() function. 
343          @type registrator_pos: int 
344          """ 
345          if not creators: 
346              return 
347          file_pattern = self.extmodule.body.name + pattern 
348          file_path = os.path.join( self.directory_path, file_pattern ) 
349          header_name = file_path + self.HEADER_EXT 
350          self.write_file( header_name 
351                           , self.create_header( file_pattern, self.create_function_code( function_name ) ) ) 
352          self.write_file( file_path + self.SOURCE_EXT 
353                           , self.create_source( file_pattern, function_name, creators )) 
354   
355          for creator in creators: 
356              creator.create = lambda: '' 
357          self.extmodule.body.adopt_creator( 
358              code_creators.custom_text_t( function_name + '();' ) 
359              , registrator_pos) 
360          self.include_creators.append( code_creators.include_t( header_name ) ) 
361          self.split_header_names.append(header_name) 
362          self.split_method_names.append(function_name) 
363   
365          """Write all enumerations into a separate .h/.cpp file. 
366          """ 
367          enums_creators = filter( lambda x: isinstance(x, code_creators.enum_t ) 
368                                   , self.extmodule.body.creators ) 
369   
370          self.split_creators( enums_creators, '_enumerations', 'register_enumerations', 0 ) 
371   
373          """Write all global variables into a separate .h/.cpp file. 
374          """ 
375          creators = filter( lambda x: isinstance(x, code_creators.global_variable_t ) 
376                             , self.extmodule.body.creators ) 
377          creators.extend( filter( lambda x: isinstance(x, code_creators.unnamed_enum_t ) 
378                             , self.extmodule.body.creators ) ) 
379          self.split_creators( creators, '_global_variables', 'register_global_variables', -1 ) 
380   
382          """Write all free functions into a separate .h/.cpp file. 
383          """ 
384          free_functions = ( code_creators.free_function_t, code_creators.free_fun_overloads_t ) 
385          creators = filter( lambda x: isinstance(x, free_functions ), self.extmodule.body.creators ) 
386          self.split_creators( creators, '_free_functions', 'register_free_functions', -1 ) 
387   
388      #TODO: move write_main to __init__ 
390          """ Write out the module. 
391              Creates a separate source/header combo for each class and for enums, globals, 
392              and free functions. 
393              If write_main is True it writes out a main file that calls all the registration methods. 
394              After this call split_header_names and split_method_names will contain 
395              all the header files and registration methods used.  This can be used by 
396              user code to create custom registration methods if main is not written. 
397          """ 
398   
399          self.write_code_repository( self.__directory_path ) 
400          self.save_exposed_decls_db( self.__directory_path ) 
401   
402          self.extmodule.do_include_dirs_optimization() 
403   
404          self.split_values_traits() 
405          self.split_classes() 
406          self.split_enums() 
407          self.split_global_variables() 
408          self.split_free_functions() 
409   
410          if self.write_main: 
411              self.include_creators.sort( cmp=lambda ic1, ic2: cmp( ic1.header, ic2.header ) ) 
412              map( lambda creator: self.extmodule.adopt_include( creator ) 
413                   , self.include_creators ) 
414              main_cpp = os.path.join( self.directory_path, self.extmodule.body.name + '.main.cpp' ) 
415              self.write_file( main_cpp, self.extmodule.create() + os.linesep ) 
416          self.files_sum_repository.save_values() 
417   
| Trees | Indices | Help | 
 | 
|---|
| Generated by Epydoc 3.0.1 on Mon Oct 20 08:51:50 2008 | http://epydoc.sourceforge.net |