Index: build/android/gyp/process_resources.py |
diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py |
index f8971aa9d2a3da428846b907aa90ec4a55df6e4e..f19754b16032e1e44a0443557921d443b527871c 100755 |
--- a/build/android/gyp/process_resources.py |
+++ b/build/android/gyp/process_resources.py |
@@ -17,6 +17,7 @@ import os |
import re |
import shutil |
import sys |
+import xml.etree.ElementTree |
import generate_v14_compatible_resources |
@@ -143,64 +144,42 @@ def _ParseArgs(args): |
return options |
-def CreateExtraRJavaFiles( |
- r_dir, extra_packages, extra_r_text_files, shared_resources, include_all): |
- if include_all: |
- java_files = build_utils.FindInDirectory(r_dir, "R.java") |
- if len(java_files) != 1: |
- return |
- r_java_file = java_files[0] |
- r_java_contents = codecs.open(r_java_file, encoding='utf-8').read() |
- |
- for package in extra_packages: |
- package_r_java_dir = os.path.join(r_dir, *package.split('.')) |
- build_utils.MakeDirectory(package_r_java_dir) |
- package_r_java_path = os.path.join(package_r_java_dir, 'R.java') |
- new_r_java = re.sub(r'package [.\w]*;', u'package %s;' % package, |
- r_java_contents) |
- codecs.open(package_r_java_path, 'w', encoding='utf-8').write(new_r_java) |
- else: |
- if len(extra_packages) != len(extra_r_text_files): |
- raise Exception('Need one R.txt file per extra package') |
- |
- r_txt_file = os.path.join(r_dir, 'R.txt') |
- if not os.path.exists(r_txt_file): |
- return |
- |
- # Map of (resource_type, name) -> Entry. |
- # Contains the correct values for resources. |
- all_resources = {} |
+def CreateRJavaFiles(srcjar_dir, main_r_txt_file, packages, r_txt_files, |
+ shared_resources): |
+ assert len(packages) == len(r_txt_files), 'Need one R.txt file per package' |
+ |
+ # Map of (resource_type, name) -> Entry. |
+ # Contains the correct values for resources. |
+ all_resources = {} |
+ for entry in _ParseTextSymbolsFile(main_r_txt_file): |
+ all_resources[(entry.resource_type, entry.name)] = entry |
+ |
+ # Map of package_name->resource_type->entry |
+ resources_by_package = ( |
+ collections.defaultdict(lambda: collections.defaultdict(list))) |
+ # Build the R.java files using each package's R.txt file, but replacing |
+ # each entry's placeholder value with correct values from all_resources. |
+ for package, r_txt_file in zip(packages, r_txt_files): |
+ if package in resources_by_package: |
+ raise Exception(('Package name "%s" appeared twice. All ' |
+ 'android_resources() targets must use unique package ' |
+ 'names, or no package name at all.') % package) |
+ resources_by_type = resources_by_package[package] |
+ # The sub-R.txt files have the wrong values at this point. Read them to |
+ # figure out which entries belong to them, but use the values from the |
+ # main R.txt file. |
for entry in _ParseTextSymbolsFile(r_txt_file): |
- all_resources[(entry.resource_type, entry.name)] = entry |
- |
- # Map of package_name->resource_type->entry |
- resources_by_package = ( |
- collections.defaultdict(lambda: collections.defaultdict(list))) |
- # Build the R.java files using each package's R.txt file, but replacing |
- # each entry's placeholder value with correct values from all_resources. |
- for package, r_text_file in zip(extra_packages, extra_r_text_files): |
- if not os.path.exists(r_text_file): |
- continue |
- if package in resources_by_package: |
- raise Exception(('Package name "%s" appeared twice. All ' |
- 'android_resources() targets must use unique package ' |
- 'names, or no package name at all.') % package) |
- resources_by_type = resources_by_package[package] |
- # The sub-R.txt files have the wrong values at this point. Read them to |
- # figure out which entries belong to them, but use the values from the |
- # main R.txt file. |
- for entry in _ParseTextSymbolsFile(r_text_file): |
- entry = all_resources[(entry.resource_type, entry.name)] |
- resources_by_type[entry.resource_type].append(entry) |
- |
- for package, resources_by_type in resources_by_package.iteritems(): |
- package_r_java_dir = os.path.join(r_dir, *package.split('.')) |
- build_utils.MakeDirectory(package_r_java_dir) |
- package_r_java_path = os.path.join(package_r_java_dir, 'R.java') |
- java_file_contents = _CreateExtraRJavaFile( |
- package, resources_by_type, shared_resources) |
- with open(package_r_java_path, 'w') as f: |
- f.write(java_file_contents) |
+ entry = all_resources[(entry.resource_type, entry.name)] |
+ resources_by_type[entry.resource_type].append(entry) |
+ |
+ for package, resources_by_type in resources_by_package.iteritems(): |
+ package_r_java_dir = os.path.join(srcjar_dir, *package.split('.')) |
+ build_utils.MakeDirectory(package_r_java_dir) |
+ package_r_java_path = os.path.join(package_r_java_dir, 'R.java') |
+ java_file_contents = _CreateExtraRJavaFile( |
+ package, resources_by_type, shared_resources) |
+ with open(package_r_java_path, 'w') as f: |
+ f.write(java_file_contents) |
def _ParseTextSymbolsFile(path): |
@@ -341,6 +320,11 @@ def CombineZips(zip_files, output_path): |
build_utils.MergeZips(output_path, zip_files, path_transform=path_transform) |
+def _ExtractPackageFromManifest(manifest_path): |
+ doc = xml.etree.ElementTree.parse(manifest_path) |
+ return doc.getroot().get('package') |
+ |
+ |
def _OnStaleMd5(options): |
aapt = options.aapt_path |
with build_utils.TempDir() as temp_dir: |
@@ -351,6 +335,8 @@ def _OnStaleMd5(options): |
gen_dir = os.path.join(temp_dir, 'gen') |
build_utils.MakeDirectory(gen_dir) |
+ r_txt_path = os.path.join(gen_dir, 'R.txt') |
+ srcjar_dir = os.path.join(temp_dir, 'java') |
input_resource_dirs = options.resource_dirs |
@@ -382,34 +368,72 @@ def _OnStaleMd5(options): |
'--no-version-vectors', |
'-I', options.android_sdk_jar, |
'--output-text-symbols', gen_dir, |
- '-J', gen_dir, |
+ '-J', gen_dir, # Required for R.txt generation. |
'--ignore-assets', build_utils.AAPT_IGNORE_PATTERN] |
+ # aapt supports only the "--include-all-resources" mode, where each R.java |
+ # file ends up with all symbols, rather than only those that it had at the |
+ # time it was originally generated. This subtle difference makes no |
+ # difference when compiling, but can lead to increased unused symbols in the |
+ # resulting R.class files. |
+ # TODO(agrieve): See if proguard makes this difference actually translate |
+ # into a size difference. If not, we can delete all of our custom R.java |
+ # template code above (and make include_all_resources the default). |
+ if options.include_all_resources: |
+ srcjar_dir = gen_dir |
+ if options.extra_res_packages: |
+ colon_separated = ':'.join(options.extra_res_packages) |
+ package_command += ['--extra-packages', colon_separated] |
+ if options.non_constant_id: |
+ package_command.append('--non-constant-id') |
+ if options.custom_package: |
+ package_command += ['--custom-package', options.custom_package] |
+ if options.shared_resources: |
+ package_command.append('--shared-lib') |
+ if options.app_as_shared_lib: |
+ package_command.append('--app-as-shared-lib') |
+ |
for d in input_resource_dirs: |
package_command += ['-S', d] |
+ # Adding all dependencies as sources is necessary for @type/foo references |
+ # to symbols within dependencies to resolve. However, it has the side-effect |
+ # that all Java symbols from dependencies are copied into the new R.java. |
+ # E.g.: It enables an arguably incorrect usage of |
+ # "mypackage.R.id.lib_symbol" where "libpackage.R.id.lib_symbol" would be |
+ # more correct. This is just how Android works. |
for d in dep_subdirs: |
package_command += ['-S', d] |
- if options.non_constant_id: |
- package_command.append('--non-constant-id') |
- if options.custom_package: |
- package_command += ['--custom-package', options.custom_package] |
if options.proguard_file: |
package_command += ['-G', options.proguard_file] |
- if options.shared_resources: |
- package_command.append('--shared-lib') |
- if options.app_as_shared_lib: |
- package_command.append('--app-as-shared-lib') |
build_utils.CheckOutput(package_command, print_stderr=False) |
- if options.extra_res_packages: |
- CreateExtraRJavaFiles( |
- gen_dir, |
- options.extra_res_packages, |
- options.extra_r_text_files, |
- options.shared_resources or options.app_as_shared_lib, |
- options.include_all_resources) |
+ # When an empty res/ directory is passed, aapt does not write an R.txt. |
+ if not os.path.exists(r_txt_path): |
+ build_utils.Touch(r_txt_path) |
+ |
+ if not options.include_all_resources: |
+ packages = list(options.extra_res_packages) |
+ r_txt_files = list(options.extra_r_text_files) |
+ |
+ cur_package = options.custom_package |
+ if not options.custom_package: |
+ cur_package = _ExtractPackageFromManifest(options.android_manifest) |
+ |
+ # Don't create a .java file for the current resource target when: |
+ # - no package name was provided (either by manifest or build rules), |
+ # - there was already a dependent android_resources() with the same |
+ # package (occurs mostly when an apk target and resources target share |
+ # an AndroidManifest.xml) |
+ if cur_package != 'dummy.package' and cur_package not in packages: |
+ packages.append(cur_package) |
+ r_txt_files.append(r_txt_path) |
+ |
+ if packages: |
+ shared_resources = options.shared_resources or options.app_as_shared_lib |
+ CreateRJavaFiles(srcjar_dir, r_txt_path, packages, r_txt_files, |
+ shared_resources) |
# This is the list of directories with resources to put in the final .zip |
# file. The order of these is important so that crunched/v14 resources |
@@ -435,16 +459,12 @@ def _OnStaleMd5(options): |
if options.R_dir: |
build_utils.DeleteDirectory(options.R_dir) |
- shutil.copytree(gen_dir, options.R_dir) |
+ shutil.copytree(srcjar_dir, options.R_dir) |
else: |
- build_utils.ZipDir(options.srcjar_out, gen_dir) |
+ build_utils.ZipDir(options.srcjar_out, srcjar_dir) |
if options.r_text_out: |
- r_text_path = os.path.join(gen_dir, 'R.txt') |
- if os.path.exists(r_text_path): |
- shutil.copyfile(r_text_path, options.r_text_out) |
- else: |
- open(options.r_text_out, 'w').close() |
+ shutil.copyfile(r_txt_path, options.r_text_out) |
def main(args): |
@@ -477,7 +497,7 @@ def main(args): |
options.android_sdk_jar, |
] |
input_paths.extend(options.dependencies_res_zips) |
- input_paths.extend(p for p in options.extra_r_text_files if os.path.exists(p)) |
+ input_paths.extend(options.extra_r_text_files) |
resource_names = [] |
for resource_dir in options.resource_dirs: |