jamesa/generate_oby.py
changeset 5 842a773e65f2
equal deleted inserted replaced
4:60053dab7e2a 5:842a773e65f2
       
     1 # Copyright (c) 2009 Symbian Foundation Ltd
       
     2 # This component and the accompanying materials are made available
       
     3 # under the terms of the License "Eclipse Public License v1.0"
       
     4 # which accompanies this distribution, and is available
       
     5 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     6 #
       
     7 # Initial Contributors:
       
     8 # Symbian Foundation Ltd - initial contribution.
       
     9 # 
       
    10 # Contributors:
       
    11 #
       
    12 # Description:
       
    13 # Create a barebones OBY file from a dependency report text file.
       
    14 
       
    15 """Take a report generated by get_deps.py and attempt to create an OBY
       
    16 file to build a ROM with the dependency list.
       
    17 """
       
    18 
       
    19 from build_graph import without_comments
       
    20 from optparse import OptionParser
       
    21 
       
    22 import os
       
    23 import re
       
    24 import sys
       
    25 import logging
       
    26 
       
    27 __author__ = 'James Aley'
       
    28 __email__ = 'jamesa@symbian.org'
       
    29 __version__ = '1.0'
       
    30 
       
    31 # Logging config
       
    32 _LOG_FORMAT = '%(levelname)s: %(message)s'
       
    33 logging.basicConfig(format=_LOG_FORMAT, level=logging.WARNING, stream=sys.stdout)
       
    34 
       
    35 # Regexes for bld.inf parsing
       
    36 _RE_EXPORT_SECTION = '\\s*PRJ_EXPORTS\\s*'
       
    37 _RE_OTHER_SECTION = '\\s*PRJ_[a-z]+\\s*'
       
    38 _RE_IBY_OBY = '\\s*([^\\s]+\\.[oi]by)\\s+.*'
       
    39 _p_export_section = re.compile(_RE_EXPORT_SECTION, re.I)
       
    40 _p_other_section = re.compile(_RE_OTHER_SECTION, re.I)
       
    41 _p_iby_oby = re.compile(_RE_IBY_OBY, re.I)
       
    42 
       
    43 # OBY output templates
       
    44 _OBY_HEADER = """// OBY file generated by genereate_oby.py.
       
    45 // The following includes are derived from the dependency report: %s
       
    46 
       
    47 """
       
    48 
       
    49 _OBY_INCLUDE = """
       
    50 // Required for: %s
       
    51 %s
       
    52 """
       
    53 
       
    54 _OBY_UNRESOLVED = """
       
    55 
       
    56 // The following appear to be exported by this component, 
       
    57 // but were not found under the include directory:
       
    58 %s
       
    59 """
       
    60 
       
    61 _OBY_NO_EXPORTS = """
       
    62 
       
    63 // The following components are required in your dependency graph, but
       
    64 // they appear not to export an IBY/OBY file. Your ROM will likely not
       
    65 // build until you locate the correct include files for these.
       
    66 %s
       
    67 """
       
    68 
       
    69 _INCLUDE_TEMPLATE = '#include <%s>'
       
    70 
       
    71 def bld_inf_list(report_path):
       
    72     """Returna list of bld.inf files from the report
       
    73     """
       
    74     bld_list = []
       
    75     report_file = None
       
    76     try:
       
    77         report_file = open(report_path)
       
    78     except IOError, e:
       
    79         logging.critical('Could not open report: %s' % (repr(e), ))
       
    80         exit(1)
       
    81     return filter(lambda x: x and not x.isspace(), [line.strip() for line in without_comments(report_file)])
       
    82 
       
    83 def get_paths(bld_inf_file):
       
    84     """Returns a list of referenced OBY or IBY files from a bld.inf file.
       
    85     bld_inf_file is an open file handle, which will not be closed by this
       
    86     function.
       
    87     """
       
    88     oby_iby = []
       
    89     export_section = False
       
    90     for line in without_comments(bld_inf_file):
       
    91         if export_section:
       
    92             match_iby_oby = _p_iby_oby.search(line)
       
    93             if match_iby_oby:
       
    94                 file_name = match_iby_oby.groups()[0].strip()
       
    95                 oby_iby.append(file_name)
       
    96             else:
       
    97                 match_other_section = _p_other_section.search(line)
       
    98                 if match_other_section:
       
    99                     export_section = False
       
   100         else:
       
   101             match_export_section = _p_export_section.search(line)
       
   102             if match_export_section:
       
   103                 export_section = True
       
   104     obys = filter(lambda x: x.lower().endswith('.oby'), oby_iby)
       
   105     if len(obys) > 0:
       
   106         return obys
       
   107     return oby_iby
       
   108 
       
   109 def rom_file_list(bld_inf_paths):
       
   110     """Iterate through a list of bld.inf file paths and extra the references
       
   111     to OBY or IBY files where appropriate (OBY takes precedence). Return a
       
   112     dictionary of relevant files in the format:
       
   113         { 'component_bld_inf' : [ iby_file_list] }
       
   114     """
       
   115     obys_ibys = {}
       
   116     for path in bld_inf_paths:
       
   117         bld_inf_file = None
       
   118         try:
       
   119             bld_inf_file = open(path)
       
   120         except IOError, e:
       
   121             logging.error('Unable to open bld.inf file: %s' % (repr(e), ))
       
   122             continue
       
   123         rom_file_paths = get_paths(bld_inf_file)
       
   124         obys_ibys[path] = rom_file_paths
       
   125         bld_inf_file.close()
       
   126     return obys_ibys
       
   127 
       
   128 def iby_map(iby_dict, dir_name, file_names):
       
   129      """Searches for the specified IBY/OBY file under the include_root path.
       
   130      Returns the absolute path to the IBY/OBY if it was found, otherwise a blank string.
       
   131      """
       
   132      for component in iby_dict.keys():
       
   133          # Map the file names for each component IBY file to a matching
       
   134          # file name under the export directory, if it exists, otherwise
       
   135          # keep the existing name for now - it might be matched later.
       
   136          file_names = map(lambda x: x.lower(), file_names)
       
   137          component_ibys = map(lambda x: os.path.basename(x).lower() in file_names \
       
   138                                   and os.path.join(dir_name, os.path.basename(x)) \
       
   139                                   or x, \
       
   140                                   iby_dict[component])
       
   141          iby_dict[component] = component_ibys
       
   142 
       
   143 def write_oby(out_path, iby_map, input_path, include_root):
       
   144     """Write an OBY file to include the required IBY and OBY files for this
       
   145     ROM specification, given by iby_map.
       
   146     """
       
   147     out_file = None
       
   148     try:
       
   149         out_file = open(out_path, 'w')
       
   150     except IOError, e:
       
   151         logging.critical('Unable to write OBY file: %s' % repr(e))
       
   152         exit(1)
       
   153 
       
   154     # Write the header with the input file name included
       
   155     out_file.write(_OBY_HEADER % (input_path, ))
       
   156 
       
   157     exports = filter(lambda x: len(iby_map[x]) > 0, iby_map.keys())
       
   158     no_exports = filter(lambda x: len(iby_map[x]) == 0, iby_map.keys())
       
   159 
       
   160     # Write the includes and missing exports
       
   161     for component in exports:
       
   162         iby_list = iby_map[component]
       
   163         exported = filter(lambda x: x.startswith(include_root), iby_list)
       
   164         # Need relative paths for include, but os.path.relpath is added
       
   165         # in Python 2.6, which isn't supported by other Symbian tools
       
   166         # at present :-(
       
   167         exported = map(lambda x: x[len(include_root) + 1:], exported)
       
   168         exported.sort()
       
   169         
       
   170         missing = filter(lambda x: not x.startswith(include_root), iby_list)
       
   171         missing = map(lambda x: os.path.basename(x), missing)
       
   172         missing.sort()
       
   173         
       
   174         # Write the IBY file includes for this component
       
   175         out_file.write(_OBY_INCLUDE % (component, '\n'.join([_INCLUDE_TEMPLATE % (iby, ) for iby in exported]), ))
       
   176         
       
   177         # Write the missing IBY reports
       
   178         if len(missing) > 0:
       
   179             out_file.write(_OBY_UNRESOLVED % ('\n'.join(['// %s' % (missed, ) for missed in missing]), ))
       
   180 
       
   181     # Write report for the IBY that appear not to export any ROM include files
       
   182     out_file.write(_OBY_NO_EXPORTS % ('\n'.join(['// %s' % (path,) for path in no_exports]), ))
       
   183     out_file.close()
       
   184 
       
   185 # Main
       
   186 if __name__ == '__main__':
       
   187     # Options config
       
   188     parser = OptionParser()
       
   189     parser.set_description(__doc__)
       
   190     parser.add_option('-r', '--report', dest='report_path', 
       
   191                       help='File name for the report generated by get_deps.py', 
       
   192                       metavar='INPUT_FILE', default='dependencies.txt')
       
   193     parser.add_option('-o', '--output', dest='output_file',
       
   194                       help='OBY ouput file to write to.',
       
   195                       metavar='OUT_FILE', default='generated.oby')
       
   196     parser.add_option('-i', '--include_root', dest='include_root',
       
   197                       help='Environment ROM inlcude root.',
       
   198                       metavar='INCLUDE_ROOT', 
       
   199                       default=os.path.sep.join(['epoc32', 'rom']))
       
   200     (options, args) = parser.parse_args()
       
   201 
       
   202     # Read the report and get a list of bld.inf files, then convert to
       
   203     # a dictionary of bld_inf -> [IBY file list] mappings.
       
   204     bld_infs = bld_inf_list(options.report_path)
       
   205     bld_iby_map = rom_file_list(bld_infs)
       
   206 
       
   207     # Walk the include tree to find the exported IBYs.
       
   208     os.path.walk(options.include_root, iby_map, bld_iby_map)
       
   209 
       
   210     # Write the OBY file
       
   211     write_oby(options.output_file, bld_iby_map, options.report_path, options.include_root)
       
   212