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 Android build scripts should not refer to the build_config directly, and the
16 build specification should instead pass information in using the special
17 file-arg syntax (see build_utils.py:ExpandFileArgs). That syntax allows passing
18 of values in a json dict in a file and looks like this:
19 --python-arg=@FileArg(build_config_path:javac:classpath)
21 Note: If paths to input files are passed in this way, it is important that:
22 1. inputs/deps of the action ensure that the files are available the first
25 a. inputs/deps ensure that the action runs whenever one of the files changes
26 b. the files are added to the action's depfile
33 from util
import build_utils
35 import write_ordered_libraries
39 def GetDepConfig(path
):
40 if not path
in dep_config_cache
:
41 dep_config_cache
[path
] = build_utils
.ReadJson(path
)['deps_info']
42 return dep_config_cache
[path
]
45 def DepsOfType(wanted_type
, configs
):
46 return [c
for c
in configs
if c
['type'] == wanted_type
]
49 def GetAllDepsConfigsInOrder(deps_config_paths
):
51 return set(GetDepConfig(path
)['deps_configs'])
52 return build_utils
.GetSortedTransitiveDependencies(deps_config_paths
, Deps
)
56 parser
= optparse
.OptionParser()
57 build_utils
.AddDepfileOption(parser
)
58 parser
.add_option('--build-config', help='Path to build_config output.')
61 help='Type of this target (e.g. android_library).')
63 '--possible-deps-configs',
64 help='List of paths for dependency\'s build_config files. Some '
65 'dependencies may not write build_config files. Missing build_config '
66 'files are handled differently based on the type of this target.')
68 # android_resources options
69 parser
.add_option('--srcjar', help='Path to target\'s resources srcjar.')
70 parser
.add_option('--resources-zip', help='Path to target\'s resources zip.')
71 parser
.add_option('--package-name',
72 help='Java package name for these resources.')
73 parser
.add_option('--android-manifest', help='Path to android manifest.')
75 # java library options
76 parser
.add_option('--jar-path', help='Path to target\'s jar output.')
77 parser
.add_option('--supports-android', action
='store_true',
78 help='Whether this library supports running on the Android platform.')
79 parser
.add_option('--requires-android', action
='store_true',
80 help='Whether this library requires running on the Android platform.')
81 parser
.add_option('--bypass-platform-checks', action
='store_true',
82 help='Bypass checks for support/require Android platform.')
84 # android library options
85 parser
.add_option('--dex-path', help='Path to target\'s dex output.')
87 # native library options
88 parser
.add_option('--native-libs', help='List of top-level native libs.')
89 parser
.add_option('--readelf-path', help='Path to toolchain\'s readelf.')
91 options
, args
= parser
.parse_args(argv
)
94 parser
.error('No positional arguments should be given.')
97 if not options
.type in [
98 'java_library', 'android_resources', 'android_apk', 'deps_dex']:
99 raise Exception('Unknown type: <%s>' % options
.type)
101 required_options
= ['build_config'] + {
102 'java_library': ['jar_path'],
103 'android_resources': ['resources_zip'],
104 'android_apk': ['jar_path', 'dex_path', 'resources_zip'],
105 'deps_dex': ['dex_path']
108 if options
.native_libs
:
109 required_options
.append('readelf_path')
111 build_utils
.CheckOptions(options
, parser
, required_options
)
113 if options
.type == 'java_library':
114 if options
.supports_android
and not options
.dex_path
:
115 raise Exception('java_library that supports Android requires a dex path.')
117 if options
.requires_android
and not options
.supports_android
:
119 '--supports-android is required when using --requires-android')
121 possible_deps_config_paths
= build_utils
.ParseGypList(
122 options
.possible_deps_configs
)
124 allow_unknown_deps
= options
.type == 'android_apk'
126 c
for c
in possible_deps_config_paths
if not os
.path
.exists(c
)]
127 if unknown_deps
and not allow_unknown_deps
:
128 raise Exception('Unknown deps: ' + str(unknown_deps
))
130 direct_deps_config_paths
= [
131 c
for c
in possible_deps_config_paths
if not c
in unknown_deps
]
132 all_deps_config_paths
= GetAllDepsConfigsInOrder(direct_deps_config_paths
)
134 direct_deps_configs
= [GetDepConfig(p
) for p
in direct_deps_config_paths
]
135 all_deps_configs
= [GetDepConfig(p
) for p
in all_deps_config_paths
]
137 direct_library_deps
= DepsOfType('java_library', direct_deps_configs
)
138 all_library_deps
= DepsOfType('java_library', all_deps_configs
)
140 direct_resources_deps
= DepsOfType('android_resources', direct_deps_configs
)
141 all_resources_deps
= DepsOfType('android_resources', all_deps_configs
)
142 # Resources should be ordered with the highest-level dependency first so that
143 # overrides are done correctly.
144 all_resources_deps
.reverse()
146 # Initialize some common config.
149 'name': os
.path
.basename(options
.build_config
),
150 'path': options
.build_config
,
151 'type': options
.type,
152 'deps_configs': direct_deps_config_paths
,
155 deps_info
= config
['deps_info']
158 if options
.type == 'java_library' and not options
.bypass_platform_checks
:
159 deps_info
['requires_android'] = options
.requires_android
160 deps_info
['supports_android'] = options
.supports_android
162 deps_require_android
= (all_resources_deps
+
163 [d
['name'] for d
in all_library_deps
if d
['requires_android']])
164 deps_not_support_android
= (
165 [d
['name'] for d
in all_library_deps
if not d
['supports_android']])
167 if deps_require_android
and not options
.requires_android
:
168 raise Exception('Some deps require building for the Android platform: ' +
169 str(deps_require_android
))
171 if deps_not_support_android
and options
.supports_android
:
172 raise Exception('Not all deps support the Android platform: ' +
173 str(deps_not_support_android
))
176 if options
.type in ['java_library', 'android_apk']:
177 javac_classpath
= [c
['jar_path'] for c
in direct_library_deps
]
178 java_full_classpath
= [c
['jar_path'] for c
in all_library_deps
]
179 deps_info
['resources_deps'] = [c
['path'] for c
in all_resources_deps
]
180 deps_info
['jar_path'] = options
.jar_path
181 if options
.type == 'android_apk' or options
.supports_android
:
182 deps_info
['dex_path'] = options
.dex_path
184 'classpath': javac_classpath
,
187 'full_classpath': java_full_classpath
190 if options
.type == 'java_library':
191 # Only resources might have srcjars (normal srcjar targets are listed in
192 # srcjar_deps). A resource's srcjar contains the R.java file for those
193 # resources, and (like Android's default build system) we allow a library to
194 # refer to the resources in any of its dependents.
195 config
['javac']['srcjars'] = [
196 c
['srcjar'] for c
in direct_resources_deps
if 'srcjar' in c
]
198 if options
.type == 'android_apk':
199 # Apks will get their resources srcjar explicitly passed to the java step.
200 config
['javac']['srcjars'] = []
202 if options
.type == 'android_resources':
203 deps_info
['resources_zip'] = options
.resources_zip
205 deps_info
['srcjar'] = options
.srcjar
206 if options
.package_name
:
207 deps_info
['package_name'] = options
.package_name
209 if options
.type == 'android_resources' or options
.type == 'android_apk':
210 config
['resources'] = {}
211 config
['resources']['dependency_zips'] = [
212 c
['resources_zip'] for c
in all_resources_deps
]
213 config
['resources']['extra_package_names'] = []
215 if options
.type == 'android_apk':
216 config
['resources']['extra_package_names'] = [
217 c
['package_name'] for c
in all_resources_deps
if 'package_name' in c
]
220 # Dependencies for the final dex file of an apk or a 'deps_dex'.
221 if options
.type in ['android_apk', 'deps_dex']:
222 config
['final_dex'] = {}
223 dex_config
= config
['final_dex']
224 # TODO(cjhopman): proguard version
225 dex_deps_files
= [c
['dex_path'] for c
in all_library_deps
]
226 dex_config
['dependency_dex_files'] = dex_deps_files
228 if options
.type == 'android_apk':
229 config
['dist_jar'] = {
231 c
['jar_path'] for c
in all_library_deps
236 java_libraries_list
= []
237 if options
.native_libs
:
238 libraries
= build_utils
.ParseGypList(options
.native_libs
)
240 libraries_dir
= os
.path
.dirname(libraries
[0])
241 write_ordered_libraries
.SetReadelfPath(options
.readelf_path
)
242 write_ordered_libraries
.SetLibraryDirs([libraries_dir
])
243 all_native_library_deps
= (
244 write_ordered_libraries
.GetSortedTransitiveDependenciesForBinaries(
246 # Create a java literal array with the "base" library names:
247 # e.g. libfoo.so -> foo
248 java_libraries_list
= '{%s}' % ','.join(
249 ['"%s"' % s
[3:-3] for s
in all_native_library_deps
])
251 write_ordered_libraries
.FullLibraryPath
, all_native_library_deps
)
254 'libraries': library_paths
,
255 'java_libraries_list': java_libraries_list
258 build_utils
.WriteJson(config
, options
.build_config
, only_if_changed
=True)
261 build_utils
.WriteDepfile(
263 all_deps_config_paths
+ build_utils
.GetPythonDependencies())
266 if __name__
== '__main__':
267 sys
.exit(main(sys
.argv
[1:]))