| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright 2014 Google Inc. | 3 # Copyright 2014 Google Inc. |
| 4 # | 4 # |
| 5 # Use of this source code is governed by a BSD-style license that can be | 5 # Use of this source code is governed by a BSD-style license that can be |
| 6 # found in the LICENSE file. | 6 # found in the LICENSE file. |
| 7 | 7 |
| 8 """ | 8 import os |
| 9 Functions for parsing the gypd output from gyp. | 9 """Functions for parsing the gypd output from gyp. |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 def parse_dictionary(var_dict, d, current_target_name): | 12 def parse_dictionary(var_dict, d, current_target_name, dest_dir): |
| 13 """ | 13 """Helper function to get the meaningful entries in a dictionary. |
| 14 Helper function to get the meaningful entries in a dictionary. | 14 |
| 15 @param var_dict VarsDict object for storing the results of the parsing. | 15 Parse dictionary d, and store unique relevant entries in var_dict. |
| 16 @param d Dictionary object to parse. | 16 Recursively parses internal dictionaries and files that are referenced. |
| 17 @param current_target_name The current target being parsed. If this | 17 |
| 18 dictionary is a target, this will be its entry | 18 Args: |
| 19 'target_name'. Otherwise, this will be the name of | 19 var_dict: VarsDict object for storing the results of the parsing. |
| 20 the target which contains this dictionary. | 20 d: Dictionary object to parse. |
| 21 current_target_name: The current target being parsed. If this dictionary |
| 22 is a target, this will be its entry 'target_name'. Otherwise, this will |
| 23 be the name of the target which contains this dictionary. |
| 24 dest_dir: Destination for the eventual Android.mk that will be created from |
| 25 this parse, relative to Skia trunk. Used to determine path for source |
| 26 files. |
| 21 """ | 27 """ |
| 22 for source in d.get('sources', []): | 28 for source in d.get('sources', []): |
| 23 # Compare against a lowercase version, in case files are named .H or .GYPI | 29 # Compare against a lowercase version, in case files are named .H or .GYPI |
| 24 lowercase_source = source.lower() | 30 lowercase_source = source.lower() |
| 25 if lowercase_source.endswith('.h'): | 31 if lowercase_source.endswith('.h'): |
| 26 # Android.mk does not need the header files. | 32 # Android.mk does not need the header files. |
| 27 continue | 33 continue |
| 28 if lowercase_source.endswith('gypi'): | 34 if lowercase_source.endswith('gypi'): |
| 29 # The gypi files are included in sources, but the sources they included | 35 # The gypi files are included in sources, but the sources they included |
| 30 # are also included. No need to parse them again. | 36 # are also included. No need to parse them again. |
| 31 continue | 37 continue |
| 32 # The path is relative to the gyp folder, but Android wants the path | 38 # The path is relative to the gyp folder, but Android wants the path |
| 33 # relative to the root. | 39 # relative to dest_dir. |
| 34 source = source.replace('../src', 'src', 1) | 40 rel_source = os.path.relpath(source, os.pardir) |
| 35 var_dict.LOCAL_SRC_FILES.add(source) | 41 rel_source = os.path.relpath(rel_source, dest_dir) |
| 42 var_dict.LOCAL_SRC_FILES.add(rel_source) |
| 36 | 43 |
| 37 for lib in d.get('libraries', []): | 44 for lib in d.get('libraries', []): |
| 38 if lib.endswith('.a'): | 45 if lib.endswith('.a'): |
| 39 # Remove the '.a' | 46 # Remove the '.a' |
| 40 lib = lib[:-2] | 47 lib = lib[:-2] |
| 41 # Add 'lib', if necessary | 48 # Add 'lib', if necessary |
| 42 if not lib.startswith('lib'): | 49 if not lib.startswith('lib'): |
| 43 lib = 'lib' + lib | 50 lib = 'lib' + lib |
| 44 var_dict.LOCAL_STATIC_LIBRARIES.add(lib) | 51 var_dict.LOCAL_STATIC_LIBRARIES.add(lib) |
| 45 else: | 52 else: |
| 46 # lib will be in the form of '-l<name>'. Change it to 'lib<name>' | 53 # lib will be in the form of '-l<name>'. Change it to 'lib<name>' |
| 47 lib = lib.replace('-l', 'lib', 1) | 54 lib = lib.replace('-l', 'lib', 1) |
| 48 var_dict.LOCAL_SHARED_LIBRARIES.add(lib) | 55 var_dict.LOCAL_SHARED_LIBRARIES.add(lib) |
| 49 | 56 |
| 50 for dependency in d.get('dependencies', []): | 57 for dependency in d.get('dependencies', []): |
| 51 # Each dependency is listed as | 58 # Each dependency is listed as |
| 52 # <path_to_file>:<target>#target | 59 # <path_to_file>:<target>#target |
| 53 li = dependency.split(':') | 60 li = dependency.split(':') |
| 54 assert(len(li) <= 2 and len(li) >= 1) | 61 assert(len(li) <= 2 and len(li) >= 1) |
| 55 sub_targets = [] | 62 sub_targets = [] |
| 56 if len(li) == 2 and li[1] != '*': | 63 if len(li) == 2 and li[1] != '*': |
| 57 sub_targets.append(li[1].split('#')[0]) | 64 sub_targets.append(li[1].split('#')[0]) |
| 58 sub_path = li[0] | 65 sub_path = li[0] |
| 59 assert(sub_path.endswith('.gyp')) | 66 assert(sub_path.endswith('.gyp')) |
| 60 # Although the original reference is to a .gyp, parse the corresponding | 67 # Although the original reference is to a .gyp, parse the corresponding |
| 61 # gypd file, which was constructed by gyp. | 68 # gypd file, which was constructed by gyp. |
| 62 sub_path = sub_path + 'd' | 69 sub_path = sub_path + 'd' |
| 63 parse_gypd(var_dict, sub_path, sub_targets) | 70 parse_gypd(var_dict, sub_path, dest_dir, sub_targets) |
| 64 | 71 |
| 65 if 'default_configuration' in d: | 72 if 'default_configuration' in d: |
| 66 config_name = d['default_configuration'] | 73 config_name = d['default_configuration'] |
| 67 # default_configuration is meaningless without configurations | 74 # default_configuration is meaningless without configurations |
| 68 assert('configurations' in d) | 75 assert('configurations' in d) |
| 69 config = d['configurations'][config_name] | 76 config = d['configurations'][config_name] |
| 70 parse_dictionary(var_dict, config, current_target_name) | 77 parse_dictionary(var_dict, config, current_target_name, dest_dir) |
| 71 | 78 |
| 72 for flag in d.get('cflags', []): | 79 for flag in d.get('cflags', []): |
| 73 var_dict.LOCAL_CFLAGS.add(flag) | 80 var_dict.LOCAL_CFLAGS.add(flag) |
| 74 for flag in d.get('cflags_cc', []): | 81 for flag in d.get('cflags_cc', []): |
| 75 var_dict.LOCAL_CPPFLAGS.add(flag) | 82 var_dict.LOCAL_CPPFLAGS.add(flag) |
| 76 | 83 |
| 77 for include in d.get('include_dirs', []): | 84 for include in d.get('include_dirs', []): |
| 78 # The input path will be relative to gyp/, but Android wants relative to | 85 if include.startswith('external'): |
| 79 # LOCAL_PATH | 86 # This path is relative to the Android root. Leave it alone. |
| 80 include = include.replace('..', '$(LOCAL_PATH)', 1) | 87 rel_include = include |
| 88 else: |
| 89 # As with source, the input path will be relative to gyp/, but Android |
| 90 # wants relative to dest_dir. |
| 91 rel_include = os.path.relpath(include, os.pardir) |
| 92 rel_include = os.path.relpath(rel_include, dest_dir) |
| 93 rel_include = os.path.join('$(LOCAL_PATH)', rel_include) |
| 94 |
| 81 # Remove a trailing slash, if present. | 95 # Remove a trailing slash, if present. |
| 82 if include.endswith('/'): | 96 if rel_include.endswith('/'): |
| 83 include = include[:-1] | 97 rel_include = rel_include[:-1] |
| 84 var_dict.LOCAL_C_INCLUDES.add(include) | 98 var_dict.LOCAL_C_INCLUDES.add(rel_include) |
| 85 # For the top level, libskia, include directories should be exported. | 99 # For the top level, libskia, include directories should be exported. |
| 100 # FIXME (scroggo): Do not hard code this. |
| 86 if current_target_name == 'libskia': | 101 if current_target_name == 'libskia': |
| 87 var_dict.LOCAL_EXPORT_C_INCLUDE_DIRS.add(include) | 102 var_dict.LOCAL_EXPORT_C_INCLUDE_DIRS.add(rel_include) |
| 88 | 103 |
| 89 for define in d.get('defines', []): | 104 for define in d.get('defines', []): |
| 90 var_dict.DEFINES.add(define) | 105 var_dict.DEFINES.add(define) |
| 91 | 106 |
| 92 | 107 |
| 93 def parse_gypd(var_dict, path, desired_targets=None): | 108 def parse_gypd(var_dict, path, dest_dir, desired_targets=None): |
| 94 """ | 109 """Parse a gypd file. |
| 95 Parse a gypd file. | 110 |
| 96 @param var_dict VarsDict object for storing the result of the parse. | 111 Open a file that consists of python dictionaries representing build targets. |
| 97 @param path Path to gypd file. | 112 Parse those dictionaries using parse_dictionary. Recursively parses |
| 98 @param desired_targets List of targets to be parsed from this file. If empty, | 113 referenced files. |
| 99 parse all targets. | 114 |
| 115 Args: |
| 116 var_dict: VarsDict object for storing the result of the parse. |
| 117 path: Path to gypd file. |
| 118 dest_dir: Destination for the eventual Android.mk that will be created from |
| 119 this parse, relative to Skia trunk. Used to determine path for source |
| 120 files and include directories. |
| 121 desired_targets: List of targets to be parsed from this file. If empty, |
| 122 parse all targets. |
| 100 """ | 123 """ |
| 101 d = {} | 124 d = {} |
| 102 with open(path, 'r') as f: | 125 with open(path, 'r') as f: |
| 103 # Read the entire file as a dictionary | 126 # Read the entire file as a dictionary |
| 104 d = eval(f.read()) | 127 d = eval(f.read()) |
| 105 | 128 |
| 106 # The gypd file is structured such that the top level dictionary has an entry | 129 # The gypd file is structured such that the top level dictionary has an entry |
| 107 # named 'targets' | 130 # named 'targets' |
| 108 for target in d['targets']: | 131 for target in d['targets']: |
| 109 target_name = target['target_name'] | 132 target_name = target['target_name'] |
| 110 if target_name in var_dict.KNOWN_TARGETS: | 133 if target_name in var_dict.KNOWN_TARGETS: |
| 111 # Avoid circular dependencies | 134 # Avoid circular dependencies |
| 112 continue | 135 continue |
| 113 if desired_targets and target_name not in desired_targets: | 136 if desired_targets and target_name not in desired_targets: |
| 114 # Our caller does not depend on this one | 137 # Our caller does not depend on this one |
| 115 continue | 138 continue |
| 116 # Add it to our known targets so we don't parse it again | 139 # Add it to our known targets so we don't parse it again |
| 117 var_dict.KNOWN_TARGETS.add(target_name) | 140 var_dict.KNOWN_TARGETS.add(target_name) |
| 118 | 141 |
| 119 parse_dictionary(var_dict, target, target_name) | 142 parse_dictionary(var_dict, target, target_name, dest_dir) |
| 120 | 143 |
| OLD | NEW |