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
39 import write_ordered_libraries
43 def GetDepConfig(path):
44 if not path in dep_config_cache:
45 dep_config_cache[path] = build_utils.ReadJson(path)['deps_info']
46 return dep_config_cache[path]
49 def DepsOfType(wanted_type, configs):
50 return [c for c in configs if c['type'] == wanted_type]
53 def GetAllDepsConfigsInOrder(deps_config_paths):
55 return set(GetDepConfig(path)['deps_configs'])
56 return build_utils.GetSortedTransitiveDependencies(deps_config_paths, Deps)
60 parser = optparse.OptionParser()
61 build_utils.AddDepfileOption(parser)
62 parser.add_option('--build-config', help='Path to build_config output.')
65 help='Type of this target (e.g. android_library).')
67 '--possible-deps-configs',
68 help='List of paths for dependency\'s build_config files. Some '
69 'dependencies may not write build_config files. Missing build_config '
70 'files are handled differently based on the type of this target.')
72 # android_resources options
73 parser.add_option('--srcjar', help='Path to target\'s resources srcjar.')
74 parser.add_option('--resources-zip', help='Path to target\'s resources zip.')
75 parser.add_option('--package-name',
76 help='Java package name for these resources.')
77 parser.add_option('--android-manifest', help='Path to android manifest.')
79 # android_library/apk options
80 parser.add_option('--jar-path', help='Path to target\'s jar output.')
81 parser.add_option('--dex-path', help='Path to target\'s dex output.')
83 # apk native library options
84 parser.add_option('--native-libs', help='List of top-level native libs.')
85 parser.add_option('--readelf-path', help='Path to toolchain\'s readelf.')
87 options, args = parser.parse_args(argv)
90 parser.error('No positional arguments should be given.')
93 if not options.type in [
94 'android_library', 'android_resources', 'android_apk']:
95 raise Exception('Unknown type: <%s>' % options.type)
98 required_options = ['build_config'] + {
99 'android_library': ['jar_path', 'dex_path'],
100 'android_resources': ['resources_zip'],
101 'android_apk': ['jar_path', 'dex_path', 'resources_zip']
104 if options.native_libs:
105 required_options += ['readelf_path']
107 build_utils.CheckOptions(options, parser, required_options)
109 possible_deps_config_paths = build_utils.ParseGypList(
110 options.possible_deps_configs)
113 allow_unknown_deps = options.type == 'android_apk'
115 c for c in possible_deps_config_paths if not os.path.exists(c)]
116 if unknown_deps and not allow_unknown_deps:
117 raise Exception('Unknown deps: ' + str(unknown_deps))
119 direct_deps_config_paths = [
120 c for c in possible_deps_config_paths if not c in unknown_deps]
121 all_deps_config_paths = GetAllDepsConfigsInOrder(direct_deps_config_paths)
123 direct_deps_configs = [GetDepConfig(p) for p in direct_deps_config_paths]
124 all_deps_configs = [GetDepConfig(p) for p in all_deps_config_paths]
126 direct_library_deps = DepsOfType('android_library', direct_deps_configs)
127 all_library_deps = DepsOfType('android_library', all_deps_configs)
129 direct_resources_deps = DepsOfType('android_resources', direct_deps_configs)
130 all_resources_deps = DepsOfType('android_resources', all_deps_configs)
132 # Initialize some common config.
135 'path': options.build_config,
136 'type': options.type,
137 'deps_configs': direct_deps_config_paths,
140 deps_info = config['deps_info']
142 if options.type in ['android_library', 'android_apk']:
143 javac_classpath = [c['jar_path'] for c in direct_library_deps]
144 deps_info['resources_deps'] = [c['path'] for c in all_resources_deps]
145 deps_info['jar_path'] = options.jar_path
146 deps_info['dex_path'] = options.dex_path
148 'classpath': javac_classpath,
151 if options.type == 'android_library':
152 # Only resources might have srcjars (normal srcjar targets are listed in
153 # srcjar_deps). A resource's srcjar contains the R.java file for those
154 # resources, and (like Android's default build system) we allow a library to
155 # refer to the resources in any of its dependents.
156 config['javac']['srcjars'] = [
157 c['srcjar'] for c in direct_resources_deps if 'srcjar' in c]
159 if options.type == 'android_apk':
160 config['javac']['srcjars'] = []
163 if options.type == 'android_resources':
164 deps_info['resources_zip'] = options.resources_zip
166 deps_info['srcjar'] = options.srcjar
167 if options.package_name:
168 deps_info['package_name'] = options.package_name
170 if options.type == 'android_resources' or options.type == 'android_apk':
171 config['resources'] = {}
172 config['resources']['dependency_zips'] = [
173 c['resources_zip'] for c in all_resources_deps]
174 config['resources']['extra_package_names'] = []
176 if options.type == 'android_apk':
177 config['resources']['extra_package_names'] = [
178 c['package_name'] for c in all_resources_deps if 'package_name' in c]
181 if options.type == 'android_apk':
182 config['apk_dex'] = {}
183 dex_config = config['apk_dex']
184 # TODO(cjhopman): proguard version
185 dex_deps_files = [c['dex_path'] for c in all_library_deps]
186 dex_config['dependency_dex_files'] = dex_deps_files
188 config['dist_jar'] = {
190 c['jar_path'] for c in all_library_deps
195 java_libraries_list = []
196 if options.native_libs:
197 libraries = build_utils.ParseGypList(options.native_libs)
199 libraries_dir = os.path.dirname(libraries[0])
200 write_ordered_libraries.SetReadelfPath(options.readelf_path)
201 write_ordered_libraries.SetLibraryDirs([libraries_dir])
202 all_native_library_deps = (
203 write_ordered_libraries.GetSortedTransitiveDependenciesForBinaries(
205 # Create a java literal array with the "base" library names:
206 # e.g. libfoo.so -> foo
207 java_libraries_list = '{%s}' % ','.join(
208 ['"%s"' % s[3:-3] for s in all_native_library_deps])
210 write_ordered_libraries.FullLibraryPath, all_native_library_deps)
213 'libraries': library_paths,
214 'java_libraries_list': java_libraries_list
217 build_utils.WriteJson(config, options.build_config, only_if_changed=True)
220 build_utils.WriteDepfile(
222 all_deps_config_paths + build_utils.GetPythonDependencies())
225 if __name__ == '__main__':
226 sys.exit(main(sys.argv[1:]))