summaryrefslogtreecommitdiffstats
path: root/chromium/build/android/gyp/dex.py
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 10:22:43 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:36:28 +0000
commit271a6c3487a14599023a9106329505597638d793 (patch)
treee040d58ffc86c1480b79ca8528020ca9ec919bf8 /chromium/build/android/gyp/dex.py
parent7b2ffa587235a47d4094787d72f38102089f402a (diff)
BASELINE: Update Chromium to 77.0.3865.59
Change-Id: I1e89a5f3b009a9519a6705102ad65c92fe736f21 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/build/android/gyp/dex.py')
-rwxr-xr-xchromium/build/android/gyp/dex.py300
1 files changed, 106 insertions, 194 deletions
diff --git a/chromium/build/android/gyp/dex.py b/chromium/build/android/gyp/dex.py
index 9c551b9e78c..a2e17b4e282 100755
--- a/chromium/build/android/gyp/dex.py
+++ b/chromium/build/android/gyp/dex.py
@@ -4,9 +4,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import json
+import argparse
import logging
-import optparse
import os
import re
import shutil
@@ -15,82 +14,59 @@ import tempfile
import zipfile
from util import build_utils
+from util import zipalign
sys.path.insert(1, os.path.join(os.path.dirname(__file__), os.path.pardir))
import convert_dex_profile
-def _CheckFilePathEndsWithJar(parser, file_path):
- if not file_path.endswith(".jar"):
- parser.error("%s does not end in .jar" % file_path)
-
-
-def _CheckFilePathsEndWithJar(parser, file_paths):
- for file_path in file_paths:
- _CheckFilePathEndsWithJar(parser, file_path)
-
-
def _ParseArgs(args):
args = build_utils.ExpandFileArgs(args)
+ parser = argparse.ArgumentParser()
- parser = optparse.OptionParser()
build_utils.AddDepfileOption(parser)
-
- parser.add_option('--output-directory',
- default=os.getcwd(),
- help='Path to the output build directory.')
- parser.add_option('--dex-path', help='Dex output path.')
- parser.add_option('--configuration-name',
- help='The build CONFIGURATION_NAME.')
- parser.add_option('--proguard-enabled',
- help='"true" if proguard is enabled.')
- parser.add_option('--debug-build-proguard-enabled',
- help='"true" if proguard is enabled for debug build.')
- parser.add_option('--proguard-enabled-input-path',
- help=('Path to dex in Release mode when proguard '
- 'is enabled.'))
- parser.add_option('--inputs', help='A list of additional input paths.')
- parser.add_option('--excluded-paths',
- help='A list of paths to exclude from the dex file.')
- parser.add_option('--main-dex-list-path',
- help='A file containing a list of the classes to '
- 'include in the main dex.')
- parser.add_option('--multidex-configuration-path',
- help='A JSON file containing multidex build configuration.')
- parser.add_option('--multi-dex', default=False, action='store_true',
- help='Generate multiple dex files.')
- parser.add_option('--d8-jar-path', help='Path to D8 jar.')
- parser.add_option('--release', action='store_true', default=False,
- help='Run D8 in release mode. Release mode maximises main '
- 'dex and deletes non-essential line number information '
- '(vs debug which minimizes main dex and keeps all line '
- 'number information, and then some.')
- parser.add_option('--min-api',
- help='Minimum Android API level compatibility.')
-
- parser.add_option('--dexlayout-profile',
- help=('Text profile for dexlayout. If present, a dexlayout '
- 'pass will happen'))
- parser.add_option('--profman-path',
- help=('Path to ART profman binary. There should be a '
- 'lib/ directory at the same path containing shared '
- 'libraries (shared with dexlayout).'))
- parser.add_option('--dexlayout-path',
- help=('Path to ART dexlayout binary. There should be a '
- 'lib/ directory at the same path containing shared '
- 'libraries (shared with dexlayout).'))
- parser.add_option('--dexdump-path', help='Path to dexdump binary.')
- parser.add_option(
+ parser.add_argument('--output', required=True, help='Dex output path.')
+ parser.add_argument('--input-list', help='GN-list of additional input paths.')
+ parser.add_argument(
+ '--main-dex-list-path',
+ help='File containing a list of the classes to include in the main dex.')
+ parser.add_argument(
+ '--multi-dex',
+ action='store_true',
+ help='Allow multiple dex files within output.')
+ parser.add_argument('--d8-jar-path', required=True, help='Path to D8 jar.')
+ parser.add_argument(
+ '--release',
+ action='store_true',
+ help='Run D8 in release mode. Release mode maximises main dex and '
+ 'deletes non-essential line number information (vs debug which minimizes '
+ 'main dex and keeps all line number information, and then some.')
+ parser.add_argument(
+ '--min-api', help='Minimum Android API level compatibility.')
+ parser.add_argument('inputs', nargs='*', help='Input .jar files.')
+
+ group = parser.add_argument_group('Dexlayout')
+ group.add_argument(
+ '--dexlayout-profile',
+ help=('Text profile for dexlayout. If present, a dexlayout '
+ 'pass will happen'))
+ group.add_argument(
+ '--profman-path',
+ help=('Path to ART profman binary. There should be a lib/ directory at '
+ 'the same path with shared libraries (shared with dexlayout).'))
+ group.add_argument(
+ '--dexlayout-path',
+ help=('Path to ART dexlayout binary. There should be a lib/ directory at '
+ 'the same path with shared libraries (shared with dexlayout).'))
+ group.add_argument('--dexdump-path', help='Path to dexdump binary.')
+ group.add_argument(
'--proguard-mapping-path',
help=('Path to proguard map from obfuscated symbols in the jar to '
- 'unobfuscated symbols present in the code. If not '
- 'present, the jar is assumed not to be obfuscated.'))
+ 'unobfuscated symbols present in the code. If not present, the jar '
+ 'is assumed not to be obfuscated.'))
- options, paths = parser.parse_args(args)
-
- required_options = ('d8_jar_path',)
- build_utils.CheckOptions(options, parser, required=required_options)
+ options = parser.parse_args(args)
if options.dexlayout_profile:
build_utils.CheckOptions(
@@ -98,67 +74,19 @@ def _ParseArgs(args):
parser,
required=('profman_path', 'dexlayout_path', 'dexdump_path'))
elif options.proguard_mapping_path is not None:
- raise Exception('Unexpected proguard mapping without dexlayout')
-
- if options.multidex_configuration_path:
- with open(options.multidex_configuration_path) as multidex_config_file:
- multidex_config = json.loads(multidex_config_file.read())
- options.multi_dex = multidex_config.get('enabled', False)
+ parser.error('Unexpected proguard mapping without dexlayout')
if options.main_dex_list_path and not options.multi_dex:
- logging.warning('--main-dex-list-path is unused if multidex is not enabled')
-
- if options.inputs:
- options.inputs = build_utils.ParseGnList(options.inputs)
- _CheckFilePathsEndWithJar(parser, options.inputs)
- if options.excluded_paths:
- options.excluded_paths = build_utils.ParseGnList(options.excluded_paths)
-
- if options.proguard_enabled_input_path:
- _CheckFilePathEndsWithJar(parser, options.proguard_enabled_input_path)
- _CheckFilePathsEndWithJar(parser, paths)
-
- return options, paths
-
-
-def _MoveTempDexFile(tmp_dex_dir, dex_path):
- """Move the temp dex file out of |tmp_dex_dir|.
-
- Args:
- tmp_dex_dir: Path to temporary directory created with tempfile.mkdtemp().
- The directory should have just a single file.
- dex_path: Target path to move dex file to.
-
- Raises:
- Exception if there are multiple files in |tmp_dex_dir|.
- """
- tempfiles = os.listdir(tmp_dex_dir)
- if len(tempfiles) > 1:
- raise Exception('%d files created, expected 1' % len(tempfiles))
-
- tmp_dex_path = os.path.join(tmp_dex_dir, tempfiles[0])
- shutil.move(tmp_dex_path, dex_path)
-
-
-def _NoClassFiles(jar_paths):
- """Returns True if there are no .class files in the given JARs.
+ parser.error('--main-dex-list-path is unused if multidex is not enabled')
- Args:
- jar_paths: list of strings representing JAR file paths.
+ if options.input_list:
+ options.inputs += build_utils.ParseGnList(options.input_list)
- Returns:
- (bool) True if no .class files are found.
- """
- for jar_path in jar_paths:
- with zipfile.ZipFile(jar_path) as jar:
- if any(name.endswith('.class') for name in jar.namelist()):
- return False
- return True
+ return options
def _RunD8(dex_cmd, input_paths, output_path):
- dex_cmd += ['--output', output_path]
- dex_cmd += input_paths
+ dex_cmd = dex_cmd + ['--output', output_path] + input_paths
build_utils.CheckOutput(dex_cmd, print_stderr=False)
@@ -242,7 +170,7 @@ def _LayoutDex(binary_profile, input_dex, dexlayout_path, temp_dir):
output_files = os.listdir(dexlayout_output_dir)
if not output_files:
raise Exception('dexlayout unexpectedly produced no output')
- return [os.path.join(dexlayout_output_dir, f) for f in output_files]
+ return sorted([os.path.join(dexlayout_output_dir, f) for f in output_files])
def _ZipMultidex(file_dir, dex_files):
@@ -284,37 +212,44 @@ def _ZipMultidex(file_dir, dex_files):
return zip_name
-def _ZipSingleDex(dex_file, zip_name):
- """Zip up a single dex file.
+def _ZipAligned(dex_files, output_path):
+ """Creates a .dex.jar with 4-byte aligned files.
Args:
- dex_file: A dexfile whose name is ignored.
- zip_name: The output file in which to write the zip.
+ dex_files: List of dex files.
+ output_path: The output file in which to write the zip.
"""
- build_utils.DoZip([('classes.dex', dex_file)], zip_name)
-
-
-def main(args):
- options, paths = _ParseArgs(args)
- if ((options.proguard_enabled == 'true'
- and options.configuration_name == 'Release')
- or (options.debug_build_proguard_enabled == 'true'
- and options.configuration_name == 'Debug')):
- paths = [options.proguard_enabled_input_path]
-
- if options.inputs:
- paths += options.inputs
-
- if options.excluded_paths:
- # Excluded paths are relative to the output directory.
- exclude_paths = options.excluded_paths
- paths = [p for p in paths if not
- os.path.relpath(p, options.output_directory) in exclude_paths]
-
- input_paths = list(paths)
- if options.multi_dex and options.main_dex_list_path:
- input_paths.append(options.main_dex_list_path)
-
+ with zipfile.ZipFile(output_path, 'w') as z:
+ for i, dex_file in enumerate(dex_files):
+ name = 'classes{}.dex'.format(i + 1 if i > 0 else '')
+ zipalign.AddToZipHermetic(z, name, src_path=dex_file, alignment=4)
+
+
+def _PerformDexlayout(tmp_dir, tmp_dex_output, options):
+ if options.proguard_mapping_path is not None:
+ matching_profile = os.path.join(tmp_dir, 'obfuscated_profile')
+ convert_dex_profile.ObfuscateProfile(
+ options.dexlayout_profile, tmp_dex_output,
+ options.proguard_mapping_path, options.dexdump_path, matching_profile)
+ else:
+ logging.warning('No obfuscation for %s', options.dexlayout_profile)
+ matching_profile = options.dexlayout_profile
+ binary_profile = _CreateBinaryProfile(matching_profile, tmp_dex_output,
+ options.profman_path, tmp_dir)
+ output_files = _LayoutDex(binary_profile, tmp_dex_output,
+ options.dexlayout_path, tmp_dir)
+ if len(output_files) > 1:
+ return _ZipMultidex(tmp_dir, output_files)
+
+ if zipfile.is_zipfile(output_files[0]):
+ return output_files[0]
+
+ final_output = os.path.join(tmp_dir, 'dex_classes.zip')
+ _ZipAligned(output_files, final_output)
+ return final_output
+
+
+def _PerformDexing(options):
dex_cmd = ['java', '-jar', options.d8_jar_path, '--no-desugaring']
if options.multi_dex and options.main_dex_list_path:
dex_cmd += ['--main-dex-list', options.main_dex_list_path]
@@ -323,62 +258,39 @@ def main(args):
if options.min_api:
dex_cmd += ['--min-api', options.min_api]
- is_dex = options.dex_path.endswith('.dex')
- is_jar = options.dex_path.endswith('.jar')
-
with build_utils.TempDir() as tmp_dir:
tmp_dex_dir = os.path.join(tmp_dir, 'tmp_dex_dir')
os.mkdir(tmp_dex_dir)
- if is_jar and _NoClassFiles(paths):
- # Handle case where no classfiles are specified in inputs
- # by creating an empty JAR
- with zipfile.ZipFile(options.dex_path, 'w') as outfile:
- outfile.comment = 'empty'
- else:
- # .dex files can't specify a name for D8. Instead, we output them to a
- # temp directory then move them after the command has finished running
- # (see _MoveTempDexFile). For other files, tmp_dex_dir is None.
- _RunD8(dex_cmd, paths, tmp_dex_dir)
-
- tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output')
- if is_dex:
- _MoveTempDexFile(tmp_dex_dir, tmp_dex_output)
+ _RunD8(dex_cmd, options.inputs, tmp_dex_dir)
+ dex_files = [os.path.join(tmp_dex_dir, f) for f in os.listdir(tmp_dex_dir)]
+
+ if not options.output.endswith('.dex'):
+ tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output.zip')
+ _ZipAligned(sorted(dex_files), tmp_dex_output)
else:
- # d8 supports outputting to a .zip, but does not have deterministic file
- # ordering: https://issuetracker.google.com/issues/119945929
- build_utils.ZipDir(tmp_dex_output, tmp_dex_dir)
+ # Output to a .dex file.
+ if len(dex_files) > 1:
+ raise Exception('%d files created, expected 1' % len(dex_files))
+ tmp_dex_output = dex_files[0]
if options.dexlayout_profile:
- if options.proguard_mapping_path is not None:
- matching_profile = os.path.join(tmp_dir, 'obfuscated_profile')
- convert_dex_profile.ObfuscateProfile(
- options.dexlayout_profile, tmp_dex_output,
- options.proguard_mapping_path, options.dexdump_path,
- matching_profile)
- else:
- logging.warning('No obfuscation for %s', options.dexlayout_profile)
- matching_profile = options.dexlayout_profile
- binary_profile = _CreateBinaryProfile(matching_profile, tmp_dex_output,
- options.profman_path, tmp_dir)
- output_files = _LayoutDex(binary_profile, tmp_dex_output,
- options.dexlayout_path, tmp_dir)
- target = None
- if len(output_files) > 1:
- target = _ZipMultidex(tmp_dir, output_files)
- else:
- output = output_files[0]
- if not zipfile.is_zipfile(output):
- target = os.path.join(tmp_dir, 'dex_classes.zip')
- _ZipSingleDex(output, target)
- else:
- target = output
- shutil.move(os.path.join(tmp_dir, target), tmp_dex_output)
+ tmp_dex_output = _PerformDexlayout(tmp_dir, tmp_dex_output, options)
# The dex file is complete and can be moved out of tmp_dir.
- shutil.move(tmp_dex_output, options.dex_path)
+ shutil.move(tmp_dex_output, options.output)
+
+
+def main(args):
+ options = _ParseArgs(args)
+
+ input_paths = list(options.inputs)
+ if options.multi_dex and options.main_dex_list_path:
+ input_paths.append(options.main_dex_list_path)
+
+ _PerformDexing(options)
build_utils.WriteDepfile(
- options.depfile, options.dex_path, input_paths, add_pydeps=False)
+ options.depfile, options.output, input_paths, add_pydeps=False)
if __name__ == '__main__':