3 # Copyright 2014 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 """Writes a build_config file.
9 The build_config file for a target is a json file containing information about
10 how to build that target based on the target's dependencies. This includes
11 things like: the javac classpath, the list of android resources dependencies,
12 etc. It also includes the information needed to create the build_config for
13 other targets that depend on that one.
15 There are several different types of build_configs:
16 android_library: An android library containing java code.
17 android_resources: A target containing android resources.
19 Android build scripts should not refer to the build_config directly, and the
20 build specification should instead pass information in using the special
21 file-arg syntax (see build_utils.py:ExpandFileArgs). That syntax allows passing
22 of values in a json dict in a file and looks like this:
23 --python-arg=@FileArg(build_config_path:javac:classpath)
25 Note: If paths to input files are passed in this way, it is important that:
26 1. inputs/deps of the action ensure that the files are available the first
29 a. inputs/deps ensure that the action runs whenever one of the files changes
30 b. the files are added to the action's depfile
37 from util import build_utils
40 def GetDepConfig(path):
41 if not path in dep_config_cache:
42 dep_config_cache[path] = build_utils.ReadJson(path)['deps_info']
43 return dep_config_cache[path]
46 def DepsOfType(wanted_type, configs):
47 return [c for c in configs if c['type'] == wanted_type]
50 def GetAllDepsConfigsInOrder(deps_config_paths):
52 return set(GetDepConfig(path)['deps_configs'])
53 return build_utils.GetSortedTransitiveDependencies(deps_config_paths, Deps)
57 parser = optparse.OptionParser()
58 build_utils.AddDepfileOption(parser)
59 parser.add_option('--build-config', help='Path to build_config output.')
62 help='Type of this target (e.g. android_library).')
64 '--possible-deps-configs',
65 help='List of paths for dependency\'s build_config files. Some '
66 'dependencies may not write build_config files. Missing build_config '
67 'files are handled differently based on the type of this target.')
69 # android_resources/apk options
70 parser.add_option('--srcjar', help='Path to target\'s resources srcjar.')
71 parser.add_option('--resources-zip', help='Path to target\'s resources zip.')
73 # android_library/apk options
74 parser.add_option('--jar-path', help='Path to target\'s jar output.')
75 parser.add_option('--dex-path', help='Path to target\'s dex output.')
77 options, args = parser.parse_args(argv)
80 parser.error('No positional arguments should be given.')
83 if not options.type in [
84 'android_library', 'android_resources', 'android_apk']:
85 raise Exception('Unknown type: <%s>' % options.type)
88 required_options = ['build_config'] + {
89 'android_library': ['jar_path', 'dex_path'],
90 'android_resources': ['resources_zip'],
91 'android_apk': ['jar_path', 'dex_path', 'resources_zip']
94 build_utils.CheckOptions(options, parser, required_options)
96 possible_deps_config_paths = build_utils.ParseGypList(
97 options.possible_deps_configs)
102 allow_unknown_deps = options.type == 'android_apk'
104 c for c in possible_deps_config_paths if not os.path.exists(c)]
105 if unknown_deps and not allow_unknown_deps:
106 raise Exception('Unknown deps: ' + unknown_deps)
108 direct_deps_config_paths = [
109 c for c in possible_deps_config_paths if not c in unknown_deps]
110 all_deps_config_paths = GetAllDepsConfigsInOrder(direct_deps_config_paths)
112 direct_deps_configs = [GetDepConfig(p) for p in direct_deps_config_paths]
113 all_deps_configs = [GetDepConfig(p) for p in all_deps_config_paths]
115 direct_library_deps = DepsOfType('android_library', direct_deps_configs)
116 all_resources_deps = DepsOfType('android_resources', all_deps_configs)
117 all_library_deps = DepsOfType('android_library', all_deps_configs)
119 # Initialize some common config.
122 'path': options.build_config,
123 'type': options.type,
124 'deps_configs': direct_deps_config_paths,
127 deps_info = config['deps_info']
129 if options.type in ['android_library', 'android_apk']:
130 javac_classpath = [c['jar_path'] for c in direct_library_deps]
131 deps_info['resources_deps'] = [c['path'] for c in all_resources_deps]
132 deps_info['jar_path'] = options.jar_path
133 deps_info['dex_path'] = options.dex_path
135 'classpath': javac_classpath,
137 # Only resources might have srcjars (normal srcjar targets are listed in
138 # srcjar_deps). A resource's srcjar contains the R.java file for those
139 # resources, and (like Android's default build system) we allow a library to
140 # refer to the resources in any of its dependents.
141 config['javac']['srcjars'] = [
142 c['srcjar'] for c in all_resources_deps if 'srcjar' in c]
144 if options.type == 'android_resources' or options.type == 'android_apk':
145 deps_info['resources_zip'] = options.resources_zip
147 deps_info['srcjar'] = options.srcjar
149 config['resources'] = {}
150 config['resources']['dependency_zips'] = [
151 c['resources_zip'] for c in all_resources_deps]
153 if options.type == 'android_apk':
154 config['apk_dex'] = {}
155 dex_config = config['apk_dex']
156 # TODO(cjhopman): proguard version
157 dex_deps_files = [c['dex_path'] for c in all_library_deps]
158 dex_config['dependency_dex_files'] = dex_deps_files
160 build_utils.WriteJson(config, options.build_config, only_if_changed=True)
163 build_utils.WriteDepfile(
165 all_deps_config_paths + build_utils.GetPythonDependencies())
168 if __name__ == '__main__':
169 sys.exit(main(sys.argv[1:]))