| #!/usr/bin/env python3 |
| # |
| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Writes a build_config file. |
| |
| The build_config file for a target is a json file containing information about |
| how to build that target based on the target's dependencies. This includes |
| things like: the javac classpath, the list of android resources dependencies, |
| etc. It also includes the information needed to create the build_config for |
| other targets that depend on that one. |
| |
| Android build scripts should not refer to the build_config directly, and the |
| build specification should instead pass information in using the special |
| file-arg syntax (see build_utils.py:ExpandFileArgs). That syntax allows passing |
| of values in a json dict in a file and looks like this: |
| --python-arg=@FileArg(build_config_path:javac:classpath) |
| |
| Note: If paths to input files are passed in this way, it is important that: |
| 1. inputs/deps of the action ensure that the files are available the first |
| time the action runs. |
| 2. Either (a) or (b) |
| a. inputs/deps ensure that the action runs whenever one of the files changes |
| b. the files are added to the action's depfile |
| |
| NOTE: All paths within .build_config files are relative to $OUTPUT_CHROMIUM_DIR. |
| |
| This is a technical note describing the format of .build_config files. |
| Please keep it updated when changing this script. For extraction and |
| visualization instructions, see build/android/docs/build_config.md |
| |
| ------------- BEGIN_MARKDOWN --------------------------------------------------- |
| The .build_config file format |
| === |
| |
| # Introduction |
| |
| This document tries to explain the format of `.build_config` generated during |
| the Android build of Chromium. For a higher-level explanation of these files, |
| please read |
| [build/android/docs/build_config.md](build/android/docs/build_config.md). |
| |
| # The `deps_info` top-level dictionary: |
| |
| All `.build_config` files have a required `'deps_info'` key, whose value is a |
| dictionary describing the target and its dependencies. The latter has the |
| following required keys: |
| |
| ## Required keys in `deps_info`: |
| |
| * `deps_info['type']`: The target type as a string. |
| |
| The following types are known by the internal GN build rules and the |
| build scripts altogether: |
| |
| * [java_binary](#target_java_binary) |
| * [java_annotation_processor](#target_java_annotation_processor) |
| * [junit_binary](#target_junit_binary) |
| * [java_library](#target_java_library) |
| * [android_assets](#target_android_assets) |
| * [android_resources](#target_android_resources) |
| * [android_apk](#target_android_apk) |
| * [android_app_bundle_module](#target_android_app_bundle_module) |
| * [android_app_bundle](#target_android_app_bundle) |
| * [dist_jar](#target_dist_jar) |
| * [dist_aar](#target_dist_aar) |
| * [group](#target_group) |
| |
| See later sections for more details of some of these. |
| |
| * `deps_info['path']`: Path to the target's `.build_config` file. |
| |
| * `deps_info['name']`: Nothing more than the basename of `deps_info['path']` |
| at the moment. |
| |
| * `deps_info['deps_configs']`: List of paths to the `.build_config` files of |
| all *direct* dependencies of the current target. |
| |
| NOTE: Because the `.build_config` of a given target is always generated |
| after the `.build_config` of its dependencies, the `write_build_config.py` |
| script can use chains of `deps_configs` to compute transitive dependencies |
| for each target when needed. |
| |
| ## Optional keys in `deps_info`: |
| |
| The following keys will only appear in the `.build_config` files of certain |
| target types: |
| |
| * `deps_info['requires_android']`: True to indicate that the corresponding |
| code uses Android-specific APIs, and thus cannot run on the host within a |
| regular JVM. May only appear in Java-related targets. |
| |
| * `deps_info['supports_android']`: |
| May appear in Java-related targets, and indicates that |
| the corresponding code doesn't use Java APIs that are not available on |
| Android. As such it may run either on the host or on an Android device. |
| |
| * `deps_info['assets']`: |
| Only seen for the [`android_assets`](#target_android_assets) type. See below. |
| |
| * `deps_info['package_name']`: Java package name associated with this target. |
| |
| NOTE: For `android_resources` targets, |
| this is the package name for the corresponding R class. For `android_apk` |
| targets, this is the corresponding package name. This does *not* appear for |
| other target types. |
| |
| * `deps_info['android_manifest']`: |
| Path to an AndroidManifest.xml file related to the current target. |
| |
| * `deps_info['base_module_config']`: |
| Only seen for the [`android_app_bundle`](#target_android_app_bundle) type. |
| Path to the base module for the bundle. |
| |
| * `deps_info['is_base_module']`: |
| Only seen for the |
| [`android_app_bundle_module`](#target_android_app_bundle_module) |
| type. Whether or not this module is the base module for some bundle. |
| |
| * `deps_info['dependency_zips']`: |
| List of `deps_info['resources_zip']` entries for all `android_resources` |
| dependencies for the current target. |
| |
| * `deps_info['extra_package_names']`: |
| Always empty for `android_resources` types. Otherwise, |
| the list of `deps_info['package_name']` entries for all `android_resources` |
| dependencies for the current target. Computed automatically by |
| `write_build_config.py`. |
| |
| * `deps_info['dependency_r_txt_files']`: |
| Exists only on dist_aar. It is the list of deps_info['r_text_path'] from |
| transitive dependencies. Computed automatically. |
| |
| |
| # `.build_config` target types description: |
| |
| ## <a name="target_group">Target type `group`</a>: |
| |
| This type corresponds to a simple target that is only used to group |
| dependencies. It matches the `java_group()` GN template. Its only top-level |
| `deps_info` keys are `supports_android` (always True), and `deps_configs`. |
| |
| |
| ## <a name="target_android_resources">Target type `android_resources`</a>: |
| |
| This type corresponds to targets that are used to group Android resource files. |
| For example, all `android_resources` dependencies of an `android_apk` will |
| end up packaged into the final APK by the build system. |
| |
| It uses the following keys: |
| |
| |
| * `deps_info['res_sources_path']`: |
| Path to file containing a list of resource source files used by the |
| android_resources target. |
| |
| * `deps_info['resources_zip']`: |
| *Required*. Path to the `.resources.zip` file that contains all raw/uncompiled |
| resource files for this target (and also no `R.txt`, `R.java` or `R.class`). |
| |
| If `deps_info['res_sources_path']` is missing, this must point to a prebuilt |
| `.aar` archive containing resources. Otherwise, this will point to a zip |
| archive generated at build time, wrapping the sources listed in |
| `deps_info['res_sources_path']` into a single zip file. |
| |
| * `deps_info['package_name']`: |
| Java package name that the R class for this target belongs to. |
| |
| * `deps_info['android_manifest']`: |
| Optional. Path to the top-level Android manifest file associated with these |
| resources (if not provided, an empty manifest will be used to generate R.txt). |
| |
| * `deps_info['resource_overlay']`: |
| Optional. Whether the resources in resources_zip should override resources with |
| the same name. Does not affect the behaviour of any android_resources() |
| dependencies of this target. If a target with resource_overlay=true depends |
| on another target with resource_overlay=true the target with the dependency |
| overrides the other. |
| |
| * `deps_info['r_text_path']`: |
| Provide the path to the `R.txt` file that describes the resources wrapped by |
| this target. Normally this file is generated from the content of the resource |
| directories or zip file, but some targets can provide their own `R.txt` file |
| if they want. |
| |
| * `deps_info['srcjar_path']`: |
| Path to the `.srcjar` file that contains the auto-generated `R.java` source |
| file corresponding to the content of `deps_info['r_text_path']`. This is |
| *always* generated from the content of `deps_info['r_text_path']` by the |
| `build/android/gyp/process_resources.py` script. |
| |
| * `deps_info['static_library_dependent_classpath_configs']`: |
| Sub dictionary mapping .build_config paths to lists of jar files. For static |
| library APKs, this defines which input jars belong to each |
| static_library_dependent_target. |
| |
| * `deps_info['static_library_proguard_mapping_output_paths']`: |
| Additional paths to copy the ProGuard mapping file to for static library |
| APKs. |
| |
| ## <a name="target_android_assets">Target type `android_assets`</a>: |
| |
| This type corresponds to targets used to group Android assets, i.e. liberal |
| files that will be placed under `//assets/` within the final APK. |
| |
| These use an `deps_info['assets']` key to hold a dictionary of values related |
| to assets covered by this target. |
| |
| * `assets['sources']`: |
| The list of all asset source paths for this target. Each source path can |
| use an optional `:<zipPath>` suffix, where `<zipPath>` is the final location |
| of the assets (relative to `//assets/`) within the APK. |
| |
| * `assets['outputs']`: |
| Optional. Some of the sources might be renamed before being stored in the |
| final //assets/ sub-directory. When this happens, this contains a list of |
| all renamed output file paths |
| |
| NOTE: When not empty, the first items of `assets['sources']` must match |
| every item in this list. Extra sources correspond to non-renamed sources. |
| |
| NOTE: This comes from the `asset_renaming_destinations` parameter for the |
| `android_assets()` GN template. |
| |
| * `assets['disable_compression']`: |
| Optional. Will be True to indicate that these assets should be stored |
| uncompressed in the final APK. For example, this is necessary for locale |
| .pak files used by the System WebView feature. |
| |
| * `assets['treat_as_locale_paks']`: |
| Optional. Will be True to indicate that these assets are locale `.pak` files |
| (containing localized strings for C++). These are later processed to generate |
| a special ``.build_config`.java` source file, listing all supported Locales in |
| the current build. |
| |
| |
| ## <a name="target_java_library">Target type `java_library`</a>: |
| |
| This type is used to describe target that wrap Java bytecode, either created |
| by compiling sources, or providing them with a prebuilt jar. |
| |
| * `deps_info['public_deps_configs']`: List of paths to the `.build_config` files |
| of *direct* dependencies of the current target which are exposed as part of the |
| current target's public API. This should be a subset of |
| deps_info['deps_configs']. |
| |
| * `deps_info['ignore_dependency_public_deps']`: If true, 'public_deps' will not |
| be collected from the current target's direct deps. |
| |
| * `deps_info['unprocessed_jar_path']`: |
| Path to the original .jar file for this target, before any kind of processing |
| through Proguard or other tools. For most targets this is generated |
| from sources, with a name like `$target_name.javac.jar`. However, when using |
| a prebuilt jar, this will point to the source archive directly. |
| |
| * `deps_info['device_jar_path']`: |
| Path to a file that is the result of processing |
| `deps_info['unprocessed_jar_path']` with various tools (ready to be dexed). |
| |
| * `deps_info['host_jar_path']`: |
| Path to a file that is the result of processing |
| `deps_info['unprocessed_jar_path']` with various tools (use by java_binary). |
| |
| * `deps_info['interface_jar_path']: |
| Path to the interface jar generated for this library. This corresponds to |
| a jar file that only contains declarations. Generated by running the `ijar` on |
| `deps_info['unprocessed_jar_path']` or the `turbine` tool on source files. |
| |
| * `deps_info['dex_path']`: |
| Path to the `.dex` file generated for this target, from |
| `deps_info['device_jar_path']` unless this comes from a prebuilt `.aar` archive. |
| |
| * `deps_info['is_prebuilt']`: |
| True to indicate that this target corresponds to a prebuilt `.jar` file. |
| In this case, `deps_info['unprocessed_jar_path']` will point to the source |
| `.jar` file. Otherwise, it will be point to a build-generated file. |
| |
| * `deps_info['java_sources_file']`: |
| Path to a single `.sources` file listing all the Java sources that were used |
| to generate the library (simple text format, one `.jar` path per line). |
| |
| * `deps_info['lint_android_manifest']`: |
| Path to an AndroidManifest.xml file to use for this lint target. |
| |
| * `deps_info['lint_java_sources']`: |
| The list of all `deps_info['java_sources_file']` entries for all library |
| dependencies that are chromium code. Note: this is a list of files, where each |
| file contains a list of Java source files. This is used for lint. |
| |
| * `deps_info['lint_aars']`: |
| List of all aars from transitive java dependencies. This allows lint to collect |
| their custom annotations.zip and run checks like @IntDef on their annotations. |
| |
| * `deps_info['lint_srcjars']`: |
| List of all bundled srcjars of all transitive java library targets. Excludes |
| non-chromium java libraries. |
| |
| * `deps_info['lint_resource_sources']`: |
| List of all resource sources files belonging to all transitive resource |
| dependencies of this target. Excludes resources owned by non-chromium code. |
| |
| * `deps_info['lint_resource_zips']`: |
| List of all resource zip files belonging to all transitive resource dependencies |
| of this target. Excludes resources owned by non-chromium code. |
| |
| * `deps_info['javac']`: |
| A dictionary containing information about the way the sources in this library |
| are compiled. Appears also on other Java-related targets. See the [dedicated |
| section about this](#dict_javac) below for details. |
| |
| * `deps_info['javac_full_classpath']`: |
| The classpath used when performing bytecode processing. Essentially the |
| collection of all `deps_info['unprocessed_jar_path']` entries for the target |
| and all its dependencies. |
| |
| * `deps_info['javac_full_interface_classpath']`: |
| The classpath used when using the errorprone compiler. |
| |
| * `deps_info['proguard_enabled"]`: |
| True to indicate that ProGuard processing is enabled for this target. |
| |
| * `deps_info['proguard_configs"]`: |
| A list of paths to ProGuard configuration files related to this library. |
| |
| * `deps_info['extra_classpath_jars']: |
| For some Java related types, a list of extra `.jar` files to use at build time |
| but not at runtime. |
| |
| ## <a name="target_java_binary">Target type `java_binary`</a>: |
| |
| This type corresponds to a Java binary, which is nothing more than a |
| `java_library` target that also provides a main class name. It thus inherits |
| all entries from the `java_library` type, and adds: |
| |
| * `deps_info['main_class']`: |
| Name of the main Java class that serves as an entry point for the binary. |
| |
| * `deps_info['device_classpath']`: |
| The classpath used when running a Java or Android binary. Essentially the |
| collection of all `deps_info['device_jar_path']` entries for the target and all |
| its dependencies. |
| |
| |
| ## <a name="target_junit_binary">Target type `junit_binary`</a>: |
| |
| A target type for JUnit-specific binaries. Identical to |
| [`java_binary`](#target_java_binary) in the context of `.build_config` files, |
| except the name. |
| |
| |
| ## <a name="target_java_annotation_processor">Target type \ |
| `java_annotation_processor`</a>: |
| |
| A target type for Java annotation processors. Identical to |
| [`java_binary`](#target_java_binary) in the context of `.build_config` files, |
| except the name, except that it requires a `deps_info['main_class']` entry. |
| |
| |
| ## <a name="target_android_apk">Target type `android_apk`</a>: |
| |
| Corresponds to an Android APK. Inherits from the |
| [`java_binary`](#target_java_binary) type and adds: |
| |
| * `deps_info['apk_path']`: |
| Path to the raw, unsigned, APK generated by this target. |
| |
| * `deps_info['incremental_apk_path']`: |
| Path to the raw, unsigned, incremental APK generated by this target. |
| |
| * `deps_info['incremental_install_json_path']`: |
| Path to the JSON file with per-apk details for incremental install. |
| See `build/android/gyp/incremental/write_installer_json.py` for more |
| details about its content. |
| |
| * `deps_info['dist_jar']['all_interface_jars']`: |
| For `android_apk` and `dist_jar` targets, a list of all interface jar files |
| that will be merged into the final `.jar` file for distribution. |
| |
| * `deps_info['final_dex']['path']`: |
| Path to the final classes.dex file (or classes.zip in case of multi-dex) |
| for this APK. |
| |
| * `deps_info['final_dex']['all_dex_files']`: |
| The list of paths to all `deps_info['dex_path']` entries for all libraries |
| that comprise this APK. Valid only for debug builds. |
| |
| * `native['libraries']` |
| List of native libraries for the primary ABI to be embedded in this APK. |
| E.g. [ "libchrome.so" ] (i.e. this doesn't include any ABI sub-directory |
| prefix). |
| |
| * `native['java_libraries_list']` |
| The same list as `native['libraries']` as a string holding a Java source |
| fragment, e.g. `"{\"chrome\"}"`, without any `lib` prefix, and `.so` |
| suffix (as expected by `System.loadLibrary()`). |
| |
| * `native['second_abi_libraries']` |
| List of native libraries for the secondary ABI to be embedded in this APK. |
| Empty if only a single ABI is supported. |
| |
| * `native['uncompress_shared_libraries']` |
| A boolean indicating whether native libraries are stored uncompressed in the |
| APK. |
| |
| * `native['loadable_modules']` |
| A list of native libraries to store within the APK, in addition to those from |
| `native['libraries']`. These correspond to things like the Chromium linker |
| or instrumentation libraries. |
| |
| * `native['secondary_abi_loadable_modules']` |
| Secondary ABI version of loadable_modules |
| |
| * `native['library_always_compress']` |
| A list of library files that we always compress. |
| |
| * `native['library_renames']` |
| A list of library files that we prepend "crazy." to their file names. |
| |
| * `assets` |
| A list of assets stored compressed in the APK. Each entry has the format |
| `<source-path>:<destination-path>`, where `<source-path>` is relative to |
| `$CHROMIUM_OUTPUT_DIR`, and `<destination-path>` is relative to `//assets/` |
| within the APK. |
| |
| NOTE: Not to be confused with the `deps_info['assets']` dictionary that |
| belongs to `android_assets` targets only. |
| |
| * `uncompressed_assets` |
| A list of uncompressed assets stored in the APK. Each entry has the format |
| `<source-path>:<destination-path>` too. |
| |
| * `locales_java_list` |
| A string holding a Java source fragment that gives the list of locales stored |
| uncompressed as android assets. |
| |
| * `extra_android_manifests` |
| A list of `deps_configs['android_manifest]` entries, for all resource |
| dependencies for this target. I.e. a list of paths to manifest files for |
| all the resources in this APK. These will be merged with the root manifest |
| file to generate the final one used to build the APK. |
| |
| * `java_resources_jars` |
| This is a list of `.jar` files whose *Java* resources should be included in |
| the final APK. For example, this is used to copy the `.res` files from the |
| EMMA Coverage tool. The copy will omit any `.class` file and the top-level |
| `//meta-inf/` directory from the input jars. Everything else will be copied |
| into the final APK as-is. |
| |
| NOTE: This has nothing to do with *Android* resources. |
| |
| * `jni['all_source']` |
| The list of all `deps_info['java_sources_file']` entries for all library |
| dependencies for this APK. Note: this is a list of files, where each file |
| contains a list of Java source files. This is used for JNI registration. |
| |
| * `deps_info['proguard_all_configs']`: |
| The collection of all 'deps_info['proguard_configs']` values from this target |
| and all its dependencies. |
| |
| * `deps_info['proguard_classpath_jars']`: |
| The collection of all 'deps_info['extra_classpath_jars']` values from all |
| dependencies. |
| |
| * `deps_info['proguard_under_test_mapping']`: |
| Applicable to apks with proguard enabled that have an apk_under_test. This is |
| the path to the apk_under_test's output proguard .mapping file. |
| |
| ## <a name="target_android_app_bundle_module">Target type \ |
| `android_app_bundle_module`</a>: |
| |
| Corresponds to an Android app bundle module. Very similar to an APK and |
| inherits the same fields, except that this does not generate an installable |
| file (see `android_app_bundle`), and for the following omitted fields: |
| |
| * `deps_info['apk_path']`, `deps_info['incremental_apk_path']` and |
| `deps_info['incremental_install_json_path']` are omitted. |
| |
| * top-level `dist_jar` is omitted as well. |
| |
| In addition to `android_apk` targets though come these new fields: |
| |
| * `deps_info['proto_resources_path']`: |
| The path of an zip archive containing the APK's resources compiled to the |
| protocol buffer format (instead of regular binary xml + resources.arsc). |
| |
| * `deps_info['module_rtxt_path']`: |
| The path of the R.txt file generated when compiling the resources for the bundle |
| module. |
| |
| * `deps_info['module_pathmap_path']`: |
| The path of the pathmap file generated when compiling the resources for the |
| bundle module, if resource path shortening is enabled. |
| |
| * `deps_info['base_allowlist_rtxt_path']`: |
| Optional path to an R.txt file used as a allowlist for base string resources. |
| This means that any string resource listed in this file *and* in |
| `deps_info['module_rtxt_path']` will end up in the base split APK of any |
| `android_app_bundle` target that uses this target as its base module. |
| |
| This ensures that such localized strings are available to all bundle installs, |
| even when language based splits are enabled (e.g. required for WebView strings |
| inside the Monochrome bundle). |
| |
| |
| ## <a name="target_android_app_bundle">Target type `android_app_bundle`</a> |
| |
| This target type corresponds to an Android app bundle, and is built from one |
| or more `android_app_bundle_module` targets listed as dependencies. |
| |
| |
| ## <a name="target_dist_aar">Target type `dist_aar`</a>: |
| |
| This type corresponds to a target used to generate an `.aar` archive for |
| distribution. The archive's content is determined by the target's dependencies. |
| |
| This always has the following entries: |
| |
| * `deps_info['supports_android']` (always True). |
| * `deps_info['requires_android']` (always True). |
| * `deps_info['proguard_configs']` (optional). |
| |
| |
| ## <a name="target_dist_jar">Target type `dist_jar`</a>: |
| |
| This type is similar to [`dist_aar`](#target_dist_aar) but is not |
| Android-specific, and used to create a `.jar` file that can be later |
| redistributed. |
| |
| This always has the following entries: |
| |
| * `deps_info['proguard_enabled']` (False by default). |
| * `deps_info['proguard_configs']` (optional). |
| * `deps_info['supports_android']` (True by default). |
| * `deps_info['requires_android']` (False by default). |
| |
| |
| |
| ## <a name="dict_javac">The `deps_info['javac']` dictionary</a>: |
| |
| This dictionary appears in Java-related targets (e.g. `java_library`, |
| `android_apk` and others), and contains information related to the compilation |
| of Java sources, class files, and jars. |
| |
| * `javac['classpath']` |
| The classpath used to compile this target when annotation processors are |
| present. |
| |
| * `javac['interface_classpath']` |
| The classpath used to compile this target when annotation processors are |
| not present. These are also always used to known when a target needs to be |
| rebuilt. |
| |
| * `javac['processor_classpath']` |
| The classpath listing the jars used for annotation processors. I.e. sent as |
| `-processorpath` when invoking `javac`. |
| |
| * `javac['processor_classes']` |
| The list of annotation processor main classes. I.e. sent as `-processor' when |
| invoking `javac`. |
| |
| ## <a name="android_app_bundle">Target type `android_app_bundle`</a>: |
| |
| This type corresponds to an Android app bundle (`.aab` file). |
| |
| --------------- END_MARKDOWN --------------------------------------------------- |
| """ |
| |
| from __future__ import print_function |
| |
| import collections |
| import itertools |
| import json |
| import optparse |
| import os |
| import sys |
| import xml.dom.minidom |
| |
| from util import build_utils |
| from util import resource_utils |
| |
| # TODO(crbug.com/1174969): Remove this once Python2 is obsoleted. |
| if sys.version_info.major == 2: |
| zip_longest = itertools.izip_longest |
| else: |
| zip_longest = itertools.zip_longest |
| |
| |
| # Types that should never be used as a dependency of another build config. |
| _ROOT_TYPES = ('android_apk', 'java_binary', 'java_annotation_processor', |
| 'junit_binary', 'android_app_bundle') |
| # Types that should not allow code deps to pass through. |
| _RESOURCE_TYPES = ('android_assets', 'android_resources', 'system_java_library') |
| |
| |
| class OrderedSet(collections.OrderedDict): |
| # Value |parameter| is present to avoid presubmit warning due to different |
| # number of parameters from overridden method. |
| @staticmethod |
| def fromkeys(iterable, value=None): |
| out = OrderedSet() |
| out.update(iterable) |
| return out |
| |
| def add(self, key): |
| self[key] = True |
| |
| def update(self, iterable): |
| for v in iterable: |
| self.add(v) |
| |
| |
| def _ExtractMarkdownDocumentation(input_text): |
| """Extract Markdown documentation from a list of input strings lines. |
| |
| This generates a list of strings extracted from |input_text|, by looking |
| for '-- BEGIN_MARKDOWN --' and '-- END_MARKDOWN --' line markers.""" |
| in_markdown = False |
| result = [] |
| for line in input_text.splitlines(): |
| if in_markdown: |
| if '-- END_MARKDOWN --' in line: |
| in_markdown = False |
| else: |
| result.append(line) |
| else: |
| if '-- BEGIN_MARKDOWN --' in line: |
| in_markdown = True |
| |
| return result |
| |
| class AndroidManifest(object): |
| def __init__(self, path): |
| self.path = path |
| dom = xml.dom.minidom.parse(path) |
| manifests = dom.getElementsByTagName('manifest') |
| assert len(manifests) == 1 |
| self.manifest = manifests[0] |
| |
| def GetInstrumentationElements(self): |
| instrumentation_els = self.manifest.getElementsByTagName('instrumentation') |
| if len(instrumentation_els) == 0: |
| return None |
| return instrumentation_els |
| |
| def CheckInstrumentationElements(self, expected_package): |
| instrs = self.GetInstrumentationElements() |
| if not instrs: |
| raise Exception('No <instrumentation> elements found in %s' % self.path) |
| for instr in instrs: |
| instrumented_package = instr.getAttributeNS( |
| 'http://schemas.android.com/apk/res/android', 'targetPackage') |
| if instrumented_package != expected_package: |
| raise Exception( |
| 'Wrong instrumented package. Expected %s, got %s' |
| % (expected_package, instrumented_package)) |
| |
| def GetPackageName(self): |
| return self.manifest.getAttribute('package') |
| |
| |
| dep_config_cache = {} |
| def GetDepConfig(path): |
| if not path in dep_config_cache: |
| with open(path) as jsonfile: |
| dep_config_cache[path] = json.load(jsonfile)['deps_info'] |
| return dep_config_cache[path] |
| |
| |
| def DepsOfType(wanted_type, configs): |
| return [c for c in configs if c['type'] == wanted_type] |
| |
| |
| def DepPathsOfType(wanted_type, config_paths): |
| return [p for p in config_paths if GetDepConfig(p)['type'] == wanted_type] |
| |
| |
| def GetAllDepsConfigsInOrder(deps_config_paths, filter_func=None): |
| def GetDeps(path): |
| config = GetDepConfig(path) |
| if filter_func and not filter_func(config): |
| return [] |
| return config['deps_configs'] |
| |
| return build_utils.GetSortedTransitiveDependencies(deps_config_paths, GetDeps) |
| |
| |
| def GetObjectByPath(obj, key_path): |
| """Given an object, return its nth child based on a key path. |
| """ |
| return GetObjectByPath(obj[key_path[0]], key_path[1:]) if key_path else obj |
| |
| |
| def RemoveObjDups(obj, base, *key_path): |
| """Remove array items from an object[*kep_path] that are also |
| contained in the base[*kep_path] (duplicates). |
| """ |
| base_target = set(GetObjectByPath(base, key_path)) |
| target = GetObjectByPath(obj, key_path) |
| target[:] = [x for x in target if x not in base_target] |
| |
| |
| class Deps(object): |
| def __init__(self, direct_deps_config_paths): |
| self._all_deps_config_paths = GetAllDepsConfigsInOrder( |
| direct_deps_config_paths) |
| self._direct_deps_configs = [ |
| GetDepConfig(p) for p in direct_deps_config_paths |
| ] |
| self._all_deps_configs = [ |
| GetDepConfig(p) for p in self._all_deps_config_paths |
| ] |
| self._direct_deps_config_paths = direct_deps_config_paths |
| |
| def All(self, wanted_type=None): |
| if wanted_type is None: |
| return self._all_deps_configs |
| return DepsOfType(wanted_type, self._all_deps_configs) |
| |
| def Direct(self, wanted_type=None): |
| if wanted_type is None: |
| return self._direct_deps_configs |
| return DepsOfType(wanted_type, self._direct_deps_configs) |
| |
| def DirectAndChildPublicDeps(self, wanted_type=None): |
| """Returns direct dependencies and dependencies exported via public_deps of |
| direct dependencies. |
| """ |
| dep_paths = set(self._direct_deps_config_paths) |
| for direct_dep in self._direct_deps_configs: |
| dep_paths.update(direct_dep.get('public_deps_configs', [])) |
| deps_list = [GetDepConfig(p) for p in dep_paths] |
| if wanted_type is None: |
| return deps_list |
| return DepsOfType(wanted_type, deps_list) |
| |
| def AllConfigPaths(self): |
| return self._all_deps_config_paths |
| |
| def GradlePrebuiltJarPaths(self): |
| ret = [] |
| |
| def helper(cur): |
| for config in cur.Direct('java_library'): |
| if config['is_prebuilt'] or config['gradle_treat_as_prebuilt']: |
| if config['unprocessed_jar_path'] not in ret: |
| ret.append(config['unprocessed_jar_path']) |
| |
| helper(self) |
| return ret |
| |
| def GradleLibraryProjectDeps(self): |
| ret = [] |
| |
| def helper(cur): |
| for config in cur.Direct('java_library'): |
| if config['is_prebuilt']: |
| pass |
| elif config['gradle_treat_as_prebuilt']: |
| helper(Deps(config['deps_configs'])) |
| elif config not in ret: |
| ret.append(config) |
| |
| helper(self) |
| return ret |
| |
| |
| def _MergeAssets(all_assets): |
| """Merges all assets from the given deps. |
| |
| Returns: |
| A tuple of: (compressed, uncompressed, locale_paks) |
| |compressed| and |uncompressed| are lists of "srcPath:zipPath". srcPath is |
| the path of the asset to add, and zipPath is the location within the zip |
| (excluding assets/ prefix). |
| |locale_paks| is a set of all zipPaths that have been marked as |
| treat_as_locale_paks=true. |
| """ |
| compressed = {} |
| uncompressed = {} |
| locale_paks = set() |
| for asset_dep in all_assets: |
| entry = asset_dep['assets'] |
| disable_compression = entry.get('disable_compression') |
| treat_as_locale_paks = entry.get('treat_as_locale_paks') |
| dest_map = uncompressed if disable_compression else compressed |
| other_map = compressed if disable_compression else uncompressed |
| outputs = entry.get('outputs', []) |
| for src, dest in zip_longest(entry['sources'], outputs): |
| if not dest: |
| dest = os.path.basename(src) |
| # Merge so that each path shows up in only one of the lists, and that |
| # deps of the same target override previous ones. |
| other_map.pop(dest, 0) |
| dest_map[dest] = src |
| if treat_as_locale_paks: |
| locale_paks.add(dest) |
| |
| def create_list(asset_map): |
| ret = ['%s:%s' % (src, dest) for dest, src in asset_map.items()] |
| # Sort to ensure deterministic ordering. |
| ret.sort() |
| return ret |
| |
| return create_list(compressed), create_list(uncompressed), locale_paks |
| |
| |
| def _ResolveGroups(config_paths): |
| """Returns a list of configs with all groups inlined.""" |
| ret = list(config_paths) |
| ret_set = set(config_paths) |
| while True: |
| group_paths = DepPathsOfType('group', ret) |
| if not group_paths: |
| return ret |
| for group_path in group_paths: |
| index = ret.index(group_path) |
| expanded_config_paths = [] |
| for deps_config_path in GetDepConfig(group_path)['deps_configs']: |
| if not deps_config_path in ret_set: |
| expanded_config_paths.append(deps_config_path) |
| ret[index:index + 1] = expanded_config_paths |
| ret_set.update(expanded_config_paths) |
| |
| |
| def _DepsFromPaths(dep_paths, |
| target_type, |
| filter_root_targets=True, |
| recursive_resource_deps=False): |
| """Resolves all groups and trims dependency branches that we never want. |
| |
| E.g. When a resource or asset depends on an apk target, the intent is to |
| include the .apk as a resource/asset, not to have the apk's classpath added. |
| |
| This method is meant to be called to get the top nodes (i.e. closest to |
| current target) that we could then use to get a full transitive dependants |
| list (eg using Deps#all). So filtering single elements out of this list, |
| filters whole branches of dependencies. By resolving groups (i.e. expanding |
| them to their constituents), depending on a group is equivalent to directly |
| depending on each element of that group. |
| """ |
| blocklist = [] |
| allowlist = [] |
| |
| # Don't allow root targets to be considered as a dep. |
| if filter_root_targets: |
| blocklist.extend(_ROOT_TYPES) |
| |
| # Don't allow java libraries to cross through assets/resources. |
| if target_type in _RESOURCE_TYPES: |
| allowlist.extend(_RESOURCE_TYPES) |
| # Pretend that this target directly depends on all of its transitive |
| # dependencies. |
| if recursive_resource_deps: |
| dep_paths = GetAllDepsConfigsInOrder(dep_paths) |
| # Exclude assets if recursive_resource_deps is set. The |
| # recursive_resource_deps arg is used to pull resources into the base |
| # module to workaround bugs accessing resources in isolated DFMs, but |
| # assets should be kept in the DFMs. |
| blocklist.append('android_assets') |
| |
| return _DepsFromPathsWithFilters(dep_paths, blocklist, allowlist) |
| |
| |
| def _DepsFromPathsWithFilters(dep_paths, blocklist=None, allowlist=None): |
| """Resolves all groups and trims dependency branches that we never want. |
| |
| See _DepsFromPaths. |
| |
| |blocklist| if passed, are the types of direct dependencies we do not care |
| about (i.e. tips of branches that we wish to prune). |
| |
| |allowlist| if passed, are the only types of direct dependencies we care |
| about (i.e. we wish to prune all other branches that do not start from one of |
| these). |
| """ |
| group_paths = DepPathsOfType('group', dep_paths) |
| config_paths = dep_paths |
| if group_paths: |
| config_paths = _ResolveGroups(dep_paths) + group_paths |
| configs = [GetDepConfig(p) for p in config_paths] |
| if blocklist: |
| configs = [c for c in configs if c['type'] not in blocklist] |
| if allowlist: |
| configs = [c for c in configs if c['type'] in allowlist] |
| |
| return Deps([c['path'] for c in configs]) |
| |
| |
| def _ExtractSharedLibsFromRuntimeDeps(runtime_deps_file): |
| ret = [] |
| with open(runtime_deps_file) as f: |
| for line in f: |
| line = line.rstrip() |
| if not line.endswith('.so'): |
| continue |
| # Only unstripped .so files are listed in runtime deps. |
| # Convert to the stripped .so by going up one directory. |
| ret.append(os.path.normpath(line.replace('lib.unstripped/', ''))) |
| ret.reverse() |
| return ret |
| |
| |
| def _CreateJavaLibrariesList(library_paths): |
| """Returns a java literal array with the "base" library names: |
| e.g. libfoo.so -> foo |
| """ |
| names = ['"%s"' % os.path.basename(s)[3:-3] for s in library_paths] |
| return ('{%s}' % ','.join(sorted(set(names)))) |
| |
| |
| def _CreateJavaLocaleListFromAssets(assets, locale_paks): |
| """Returns a java literal array from a list of locale assets. |
| |
| Args: |
| assets: A list of all APK asset paths in the form 'src:dst' |
| locale_paks: A list of asset paths that correponds to the locale pak |
| files of interest. Each |assets| entry will have its 'dst' part matched |
| against it to determine if they are part of the result. |
| Returns: |
| A string that is a Java source literal array listing the locale names |
| of the corresponding asset files, without directory or .pak suffix. |
| E.g. '{"en-GB", "en-US", "es-ES", "fr", ... }' |
| """ |
| assets_paths = [a.split(':')[1] for a in assets] |
| locales = [os.path.basename(a)[:-4] for a in assets_paths if a in locale_paks] |
| return '{%s}' % ','.join('"%s"' % l for l in sorted(locales)) |
| |
| |
| def _AddJarMapping(jar_to_target, configs): |
| for config in configs: |
| jar = config.get('unprocessed_jar_path') |
| if jar: |
| jar_to_target[jar] = config['gn_target'] |
| for jar in config.get('extra_classpath_jars', []): |
| jar_to_target[jar] = config['gn_target'] |
| |
| |
| def _CompareClasspathPriority(dep): |
| return 1 if dep.get('low_classpath_priority') else 0 |
| |
| |
| def main(argv): |
| parser = optparse.OptionParser() |
| build_utils.AddDepfileOption(parser) |
| parser.add_option('--build-config', help='Path to build_config output.') |
| parser.add_option( |
| '--type', |
| help='Type of this target (e.g. android_library).') |
| parser.add_option('--gn-target', help='GN label for this target') |
| parser.add_option( |
| '--deps-configs', |
| help='GN-list of dependent build_config files.') |
| parser.add_option( |
| '--annotation-processor-configs', |
| help='GN-list of build_config files for annotation processors.') |
| |
| # android_resources options |
| parser.add_option('--srcjar', help='Path to target\'s resources srcjar.') |
| parser.add_option('--resources-zip', help='Path to target\'s resources zip.') |
| parser.add_option('--package-name', |
| help='Java package name for these resources.') |
| parser.add_option('--android-manifest', |
| help='Path to the root android manifest.') |
| parser.add_option('--merged-android-manifest', |
| help='Path to the merged android manifest.') |
| parser.add_option('--resource-dirs', action='append', default=[], |
| help='GYP-list of resource dirs') |
| parser.add_option( |
| '--res-sources-path', |
| help='Path to file containing a list of paths to resources.') |
| parser.add_option( |
| '--resource-overlay', |
| action='store_true', |
| help='Whether resources passed in via --resources-zip should override ' |
| 'resources with the same name') |
| parser.add_option( |
| '--recursive-resource-deps', |
| action='store_true', |
| help='Whether deps should be walked recursively to find resource deps.') |
| |
| # android_assets options |
| parser.add_option('--asset-sources', help='List of asset sources.') |
| parser.add_option('--asset-renaming-sources', |
| help='List of asset sources with custom destinations.') |
| parser.add_option('--asset-renaming-destinations', |
| help='List of asset custom destinations.') |
| parser.add_option('--disable-asset-compression', action='store_true', |
| help='Whether to disable asset compression.') |
| parser.add_option('--treat-as-locale-paks', action='store_true', |
| help='Consider the assets as locale paks in BuildConfig.java') |
| |
| # java library options |
| |
| parser.add_option('--public-deps-configs', |
| help='GN list of config files of deps which are exposed as ' |
| 'part of the target\'s public API.') |
| parser.add_option( |
| '--ignore-dependency-public-deps', |
| action='store_true', |
| help='If true, \'public_deps\' will not be collected from the current ' |
| 'target\'s direct deps.') |
| parser.add_option('--aar-path', help='Path to containing .aar file.') |
| parser.add_option('--device-jar-path', help='Path to .jar for dexing.') |
| parser.add_option('--host-jar-path', help='Path to .jar for java_binary.') |
| parser.add_option('--unprocessed-jar-path', |
| help='Path to the .jar to use for javac classpath purposes.') |
| parser.add_option( |
| '--interface-jar-path', |
| help='Path to the interface .jar to use for javac classpath purposes.') |
| parser.add_option('--is-prebuilt', action='store_true', |
| help='Whether the jar was compiled or pre-compiled.') |
| parser.add_option('--java-sources-file', help='Path to .sources file') |
| parser.add_option('--bundled-srcjars', |
| help='GYP-list of .srcjars that have been included in this java_library.') |
| parser.add_option('--supports-android', action='store_true', |
| help='Whether this library supports running on the Android platform.') |
| parser.add_option('--requires-android', action='store_true', |
| help='Whether this library requires running on the Android platform.') |
| parser.add_option('--bypass-platform-checks', action='store_true', |
| help='Bypass checks for support/require Android platform.') |
| parser.add_option('--extra-classpath-jars', |
| help='GYP-list of .jar files to include on the classpath when compiling, ' |
| 'but not to include in the final binary.') |
| parser.add_option( |
| '--low-classpath-priority', |
| action='store_true', |
| help='Indicates that the library should be placed at the end of the ' |
| 'classpath.') |
| parser.add_option( |
| '--mergeable-android-manifests', |
| help='GN-list of AndroidManifest.xml to include in manifest merging.') |
| parser.add_option('--gradle-treat-as-prebuilt', action='store_true', |
| help='Whether this library should be treated as a prebuilt library by ' |
| 'generate_gradle.py.') |
| parser.add_option('--main-class', |
| help='Main class for java_binary or java_annotation_processor targets.') |
| parser.add_option('--java-resources-jar-path', |
| help='Path to JAR that contains java resources. Everything ' |
| 'from this JAR except meta-inf/ content and .class files ' |
| 'will be added to the final APK.') |
| parser.add_option( |
| '--non-chromium-code', |
| action='store_true', |
| help='True if a java library is not chromium code, used for lint.') |
| |
| # android library options |
| parser.add_option('--dex-path', help='Path to target\'s dex output.') |
| |
| # native library options |
| parser.add_option('--shared-libraries-runtime-deps', |
| help='Path to file containing runtime deps for shared ' |
| 'libraries.') |
| parser.add_option( |
| '--loadable-modules', |
| action='append', |
| help='GN-list of native libraries for primary ' |
| 'android-abi. Can be specified multiple times.', |
| default=[]) |
| parser.add_option('--secondary-abi-shared-libraries-runtime-deps', |
| help='Path to file containing runtime deps for secondary ' |
| 'abi shared libraries.') |
| parser.add_option( |
| '--secondary-abi-loadable-modules', |
| action='append', |
| help='GN-list of native libraries for secondary ' |
| 'android-abi. Can be specified multiple times.', |
| default=[]) |
| parser.add_option( |
| '--native-lib-placeholders', |
| action='append', |
| help='GN-list of native library placeholders to add.', |
| default=[]) |
| parser.add_option( |
| '--secondary-native-lib-placeholders', |
| action='append', |
| help='GN-list of native library placeholders to add ' |
| 'for the secondary android-abi.', |
| default=[]) |
| parser.add_option('--uncompress-shared-libraries', default=False, |
| action='store_true', |
| help='Whether to store native libraries uncompressed') |
| parser.add_option( |
| '--library-always-compress', |
| help='The list of library files that we always compress.') |
| parser.add_option( |
| '--library-renames', |
| default=[], |
| help='The list of library files that we prepend crazy. to their names.') |
| |
| # apk options |
| parser.add_option('--apk-path', help='Path to the target\'s apk output.') |
| parser.add_option('--incremental-apk-path', |
| help="Path to the target's incremental apk output.") |
| parser.add_option('--incremental-install-json-path', |
| help="Path to the target's generated incremental install " |
| "json.") |
| parser.add_option( |
| '--tested-apk-config', |
| help='Path to the build config of the tested apk (for an instrumentation ' |
| 'test apk).') |
| parser.add_option( |
| '--proguard-enabled', |
| action='store_true', |
| help='Whether proguard is enabled for this apk or bundle module.') |
| parser.add_option( |
| '--proguard-configs', |
| help='GN-list of proguard flag files to use in final apk.') |
| parser.add_option( |
| '--proguard-mapping-path', help='Path to jar created by ProGuard step') |
| |
| # apk options that are static library specific |
| parser.add_option( |
| '--static-library-dependent-configs', |
| help='GN list of .build_configs of targets that use this target as a ' |
| 'static library.') |
| |
| # options shared between android_resources and apk targets |
| parser.add_option('--r-text-path', help='Path to target\'s R.txt file.') |
| |
| parser.add_option('--fail', |
| help='GN-list of error message lines to fail with.') |
| |
| parser.add_option('--final-dex-path', |
| help='Path to final input classes.dex (or classes.zip) to ' |
| 'use in final apk.') |
| parser.add_option('--res-size-info', help='Path to .ap_.info') |
| parser.add_option('--apk-proto-resources', |
| help='Path to resources compiled in protocol buffer format ' |
| ' for this apk.') |
| parser.add_option( |
| '--module-pathmap-path', |
| help='Path to pathmap file for resource paths in a bundle module.') |
| parser.add_option( |
| '--base-allowlist-rtxt-path', |
| help='Path to R.txt file for the base resources allowlist.') |
| parser.add_option( |
| '--is-base-module', |
| action='store_true', |
| help='Specifies that this module is a base module for some app bundle.') |
| |
| parser.add_option('--generate-markdown-format-doc', action='store_true', |
| help='Dump the Markdown .build_config format documentation ' |
| 'then exit immediately.') |
| |
| parser.add_option( |
| '--base-module-build-config', |
| help='Path to the base module\'s build config ' |
| 'if this is a feature module.') |
| |
| parser.add_option( |
| '--module-build-configs', |
| help='For bundles, the paths of all non-async module .build_configs ' |
| 'for modules that are part of the bundle.') |
| |
| parser.add_option('--version-name', help='Version name for this APK.') |
| parser.add_option('--version-code', help='Version code for this APK.') |
| |
| options, args = parser.parse_args(argv) |
| |
| if args: |
| parser.error('No positional arguments should be given.') |
| |
| if options.generate_markdown_format_doc: |
| doc_lines = _ExtractMarkdownDocumentation(__doc__) |
| for line in doc_lines: |
| print(line) |
| return 0 |
| |
| if options.fail: |
| parser.error('\n'.join(build_utils.ParseGnList(options.fail))) |
| |
| lib_options = ['unprocessed_jar_path', 'interface_jar_path'] |
| device_lib_options = ['device_jar_path', 'dex_path'] |
| required_options_map = { |
| 'android_apk': ['build_config'] + lib_options + device_lib_options, |
| 'android_app_bundle_module': |
| ['build_config', 'final_dex_path', 'res_size_info'] + lib_options + |
| device_lib_options, |
| 'android_assets': ['build_config'], |
| 'android_resources': ['build_config', 'resources_zip'], |
| 'dist_aar': ['build_config'], |
| 'dist_jar': ['build_config'], |
| 'group': ['build_config'], |
| 'java_annotation_processor': ['build_config', 'main_class'], |
| 'java_binary': ['build_config'], |
| 'java_library': ['build_config', 'host_jar_path'] + lib_options, |
| 'junit_binary': ['build_config'], |
| 'system_java_library': ['build_config', 'unprocessed_jar_path'], |
| 'android_app_bundle': ['build_config', 'module_build_configs'], |
| } |
| required_options = required_options_map.get(options.type) |
| if not required_options: |
| raise Exception('Unknown type: <%s>' % options.type) |
| |
| build_utils.CheckOptions(options, parser, required_options) |
| |
| if options.type != 'android_app_bundle_module': |
| if options.apk_proto_resources: |
| raise Exception('--apk-proto-resources can only be used with ' |
| '--type=android_app_bundle_module') |
| if options.module_pathmap_path: |
| raise Exception('--module-pathmap-path can only be used with ' |
| '--type=android_app_bundle_module') |
| if options.base_allowlist_rtxt_path: |
| raise Exception('--base-allowlist-rtxt-path can only be used with ' |
| '--type=android_app_bundle_module') |
| if options.is_base_module: |
| raise Exception('--is-base-module can only be used with ' |
| '--type=android_app_bundle_module') |
| |
| is_apk_or_module_target = options.type in ('android_apk', |
| 'android_app_bundle_module') |
| |
| if not is_apk_or_module_target: |
| if options.uncompress_shared_libraries: |
| raise Exception('--uncompressed-shared-libraries can only be used ' |
| 'with --type=android_apk or ' |
| '--type=android_app_bundle_module') |
| if options.library_always_compress: |
| raise Exception( |
| '--library-always-compress can only be used with --type=android_apk ' |
| 'or --type=android_app_bundle_module') |
| if options.library_renames: |
| raise Exception( |
| '--library-renames can only be used with --type=android_apk or ' |
| '--type=android_app_bundle_module') |
| |
| if options.device_jar_path and not options.dex_path: |
| raise Exception('java_library that supports Android requires a dex path.') |
| if any(getattr(options, x) for x in lib_options): |
| for attr in lib_options: |
| if not getattr(options, attr): |
| raise('Expected %s to be set.' % attr) |
| |
| if options.requires_android and not options.supports_android: |
| raise Exception( |
| '--supports-android is required when using --requires-android') |
| |
| is_java_target = options.type in ( |
| 'java_binary', 'junit_binary', 'java_annotation_processor', |
| 'java_library', 'android_apk', 'dist_aar', 'dist_jar', |
| 'system_java_library', 'android_app_bundle_module') |
| |
| is_static_library_dex_provider_target = ( |
| options.static_library_dependent_configs and options.proguard_enabled) |
| if is_static_library_dex_provider_target: |
| if options.type != 'android_apk': |
| raise Exception( |
| '--static-library-dependent-configs only supports --type=android_apk') |
| options.static_library_dependent_configs = build_utils.ParseGnList( |
| options.static_library_dependent_configs) |
| static_library_dependent_configs_by_path = { |
| p: GetDepConfig(p) |
| for p in options.static_library_dependent_configs |
| } |
| |
| deps_configs_paths = build_utils.ParseGnList(options.deps_configs) |
| deps = _DepsFromPaths(deps_configs_paths, |
| options.type, |
| recursive_resource_deps=options.recursive_resource_deps) |
| processor_deps = _DepsFromPaths( |
| build_utils.ParseGnList(options.annotation_processor_configs or ''), |
| options.type, filter_root_targets=False) |
| |
| all_inputs = (deps.AllConfigPaths() + processor_deps.AllConfigPaths() + |
| list(static_library_dependent_configs_by_path)) |
| |
| if options.recursive_resource_deps: |
| # Include java_library targets since changes to these targets can remove |
| # resource deps from the build, which would require rebuilding this target's |
| # build config file: crbug.com/1168655. |
| recursive_java_deps = _DepsFromPathsWithFilters( |
| GetAllDepsConfigsInOrder(deps_configs_paths), |
| allowlist=['java_library']) |
| all_inputs.extend(recursive_java_deps.AllConfigPaths()) |
| |
| direct_deps = deps.Direct() |
| system_library_deps = deps.Direct('system_java_library') |
| all_deps = deps.All() |
| all_library_deps = deps.All('java_library') |
| all_resources_deps = deps.All('android_resources') |
| |
| if options.type == 'java_library': |
| java_library_deps = _DepsFromPathsWithFilters( |
| deps_configs_paths, allowlist=['android_resources']) |
| # for java libraries, we only care about resources that are directly |
| # reachable without going through another java_library. |
| all_resources_deps = java_library_deps.All('android_resources') |
| if options.type == 'android_resources' and options.recursive_resource_deps: |
| # android_resources targets that want recursive resource deps also need to |
| # collect package_names from all library deps. This ensures the R.java files |
| # for these libraries will get pulled in along with the resources. |
| android_resources_library_deps = _DepsFromPathsWithFilters( |
| deps_configs_paths, allowlist=['java_library']).All('java_library') |
| if is_apk_or_module_target: |
| # android_resources deps which had recursive_resource_deps set should not |
| # have the manifests from the recursively collected deps added to this |
| # module. This keeps the manifest declarations in the child DFMs, since they |
| # will have the Java implementations. |
| def ExcludeRecursiveResourcesDeps(config): |
| return not config.get('includes_recursive_resources', False) |
| |
| extra_manifest_deps = [ |
| GetDepConfig(p) for p in GetAllDepsConfigsInOrder( |
| deps_configs_paths, filter_func=ExcludeRecursiveResourcesDeps) |
| ] |
| |
| base_module_build_config = None |
| if options.base_module_build_config: |
| with open(options.base_module_build_config, 'r') as f: |
| base_module_build_config = json.load(f) |
| |
| # Initialize some common config. |
| # Any value that needs to be queryable by dependents must go within deps_info. |
| config = { |
| 'deps_info': { |
| 'name': os.path.basename(options.build_config), |
| 'path': options.build_config, |
| 'type': options.type, |
| 'gn_target': options.gn_target, |
| 'deps_configs': [d['path'] for d in direct_deps], |
| 'chromium_code': not options.non_chromium_code, |
| }, |
| # Info needed only by generate_gradle.py. |
| 'gradle': {} |
| } |
| deps_info = config['deps_info'] |
| gradle = config['gradle'] |
| |
| if options.type == 'android_apk' and options.tested_apk_config: |
| tested_apk_deps = Deps([options.tested_apk_config]) |
| tested_apk_config = tested_apk_deps.Direct()[0] |
| gradle['apk_under_test'] = tested_apk_config['name'] |
| |
| if options.type == 'android_app_bundle_module': |
| deps_info['is_base_module'] = bool(options.is_base_module) |
| |
| # Required for generating gradle files. |
| if options.type == 'java_library': |
| deps_info['is_prebuilt'] = bool(options.is_prebuilt) |
| deps_info['gradle_treat_as_prebuilt'] = options.gradle_treat_as_prebuilt |
| |
| if options.android_manifest: |
| deps_info['android_manifest'] = options.android_manifest |
| |
| if options.merged_android_manifest: |
| deps_info['merged_android_manifest'] = options.merged_android_manifest |
| |
| if options.bundled_srcjars: |
| deps_info['bundled_srcjars'] = build_utils.ParseGnList( |
| options.bundled_srcjars) |
| |
| if options.java_sources_file: |
| deps_info['java_sources_file'] = options.java_sources_file |
| |
| if is_java_target: |
| if options.bundled_srcjars: |
| gradle['bundled_srcjars'] = deps_info['bundled_srcjars'] |
| |
| gradle['dependent_android_projects'] = [] |
| gradle['dependent_java_projects'] = [] |
| gradle['dependent_prebuilt_jars'] = deps.GradlePrebuiltJarPaths() |
| |
| if options.main_class: |
| deps_info['main_class'] = options.main_class |
| |
| for c in deps.GradleLibraryProjectDeps(): |
| if c['requires_android']: |
| gradle['dependent_android_projects'].append(c['path']) |
| else: |
| gradle['dependent_java_projects'].append(c['path']) |
| |
| if options.r_text_path: |
| deps_info['r_text_path'] = options.r_text_path |
| |
| # TODO(tiborg): Remove creation of JNI info for type group and java_library |
| # once we can generate the JNI registration based on APK / module targets as |
| # opposed to groups and libraries. |
| if is_apk_or_module_target or options.type in ( |
| 'group', 'java_library', 'junit_binary'): |
| deps_info['jni'] = {} |
| all_java_sources = [c['java_sources_file'] for c in all_library_deps |
| if 'java_sources_file' in c] |
| if options.java_sources_file: |
| all_java_sources.append(options.java_sources_file) |
| |
| if options.apk_proto_resources: |
| deps_info['proto_resources_path'] = options.apk_proto_resources |
| |
| deps_info['version_name'] = options.version_name |
| deps_info['version_code'] = options.version_code |
| if options.module_pathmap_path: |
| deps_info['module_pathmap_path'] = options.module_pathmap_path |
| else: |
| # Ensure there is an entry, even if it is empty, for modules |
| # that have not enabled resource path shortening. Otherwise |
| # build_utils.ExpandFileArgs fails. |
| deps_info['module_pathmap_path'] = '' |
| |
| if options.base_allowlist_rtxt_path: |
| deps_info['base_allowlist_rtxt_path'] = options.base_allowlist_rtxt_path |
| else: |
| # Ensure there is an entry, even if it is empty, for modules |
| # that don't need such a allowlist. |
| deps_info['base_allowlist_rtxt_path'] = '' |
| |
| if is_java_target: |
| deps_info['requires_android'] = bool(options.requires_android) |
| deps_info['supports_android'] = bool(options.supports_android) |
| |
| if not options.bypass_platform_checks: |
| deps_require_android = (all_resources_deps + |
| [d['name'] for d in all_library_deps if d['requires_android']]) |
| deps_not_support_android = ( |
| [d['name'] for d in all_library_deps if not d['supports_android']]) |
| |
| if deps_require_android and not options.requires_android: |
| raise Exception('Some deps require building for the Android platform: ' |
| + str(deps_require_android)) |
| |
| if deps_not_support_android and options.supports_android: |
| raise Exception('Not all deps support the Android platform: ' |
| + str(deps_not_support_android)) |
| |
| if is_apk_or_module_target or options.type == 'dist_jar': |
| all_dex_files = [c['dex_path'] for c in all_library_deps] |
| |
| if is_java_target: |
| # Classpath values filled in below (after applying tested_apk_config). |
| config['javac'] = {} |
| if options.aar_path: |
| deps_info['aar_path'] = options.aar_path |
| if options.unprocessed_jar_path: |
| deps_info['unprocessed_jar_path'] = options.unprocessed_jar_path |
| deps_info['interface_jar_path'] = options.interface_jar_path |
| if options.public_deps_configs: |
| deps_info['public_deps_configs'] = build_utils.ParseGnList( |
| options.public_deps_configs) |
| if options.device_jar_path: |
| deps_info['device_jar_path'] = options.device_jar_path |
| if options.host_jar_path: |
| deps_info['host_jar_path'] = options.host_jar_path |
| if options.dex_path: |
| deps_info['dex_path'] = options.dex_path |
| if is_apk_or_module_target: |
| all_dex_files.append(options.dex_path) |
| if options.low_classpath_priority: |
| deps_info['low_classpath_priority'] = True |
| if options.type == 'android_apk': |
| deps_info['apk_path'] = options.apk_path |
| deps_info['incremental_apk_path'] = options.incremental_apk_path |
| deps_info['incremental_install_json_path'] = ( |
| options.incremental_install_json_path) |
| |
| if options.type == 'android_assets': |
| all_asset_sources = [] |
| if options.asset_renaming_sources: |
| all_asset_sources.extend( |
| build_utils.ParseGnList(options.asset_renaming_sources)) |
| if options.asset_sources: |
| all_asset_sources.extend(build_utils.ParseGnList(options.asset_sources)) |
| |
| deps_info['assets'] = { |
| 'sources': all_asset_sources |
| } |
| if options.asset_renaming_destinations: |
| deps_info['assets']['outputs'] = ( |
| build_utils.ParseGnList(options.asset_renaming_destinations)) |
| if options.disable_asset_compression: |
| deps_info['assets']['disable_compression'] = True |
| if options.treat_as_locale_paks: |
| deps_info['assets']['treat_as_locale_paks'] = True |
| |
| if options.type == 'android_resources': |
| deps_info['resources_zip'] = options.resources_zip |
| if options.resource_overlay: |
| deps_info['resource_overlay'] = True |
| if options.srcjar: |
| deps_info['srcjar'] = options.srcjar |
| if options.android_manifest: |
| manifest = AndroidManifest(options.android_manifest) |
| deps_info['package_name'] = manifest.GetPackageName() |
| if options.package_name: |
| deps_info['package_name'] = options.package_name |
| deps_info['res_sources_path'] = '' |
| if options.res_sources_path: |
| deps_info['res_sources_path'] = options.res_sources_path |
| |
| if options.requires_android and options.type == 'java_library': |
| if options.package_name: |
| deps_info['package_name'] = options.package_name |
| |
| if options.type in ('android_resources', 'android_apk', 'junit_binary', |
| 'dist_aar', 'android_app_bundle_module', 'java_library'): |
| dependency_zips = [] |
| dependency_zip_overlays = [] |
| for c in all_resources_deps: |
| if not c['resources_zip']: |
| continue |
| |
| dependency_zips.append(c['resources_zip']) |
| if c.get('resource_overlay'): |
| dependency_zip_overlays.append(c['resources_zip']) |
| |
| extra_package_names = [] |
| |
| if options.type != 'android_resources': |
| extra_package_names = [ |
| c['package_name'] for c in all_resources_deps if 'package_name' in c |
| ] |
| |
| # android_resources targets which specified recursive_resource_deps may |
| # have extra_package_names. |
| for resources_dep in all_resources_deps: |
| extra_package_names.extend(resources_dep['extra_package_names']) |
| |
| # In final types (i.e. apks and modules) that create real R.java files, |
| # they must collect package names from java_libraries as well. |
| # https://crbug.com/1073476 |
| if options.type != 'java_library': |
| extra_package_names.extend([ |
| c['package_name'] for c in all_library_deps if 'package_name' in c |
| ]) |
| elif options.recursive_resource_deps: |
| # Pull extra_package_names from library deps if recursive resource deps |
| # are required. |
| extra_package_names = [ |
| c['package_name'] for c in android_resources_library_deps |
| if 'package_name' in c |
| ] |
| config['deps_info']['includes_recursive_resources'] = True |
| |
| if options.type in ('dist_aar', 'java_library'): |
| r_text_files = [ |
| c['r_text_path'] for c in all_resources_deps if 'r_text_path' in c |
| ] |
| deps_info['dependency_r_txt_files'] = r_text_files |
| |
| # For feature modules, remove any resources that already exist in the base |
| # module. |
| if base_module_build_config: |
| dependency_zips = [ |
| c for c in dependency_zips |
| if c not in base_module_build_config['deps_info']['dependency_zips'] |
| ] |
| dependency_zip_overlays = [ |
| c for c in dependency_zip_overlays if c not in |
| base_module_build_config['deps_info']['dependency_zip_overlays'] |
| ] |
| extra_package_names = [ |
| c for c in extra_package_names if c not in |
| base_module_build_config['deps_info']['extra_package_names'] |
| ] |
| |
| if options.type == 'android_apk' and options.tested_apk_config: |
| config['deps_info']['arsc_package_name'] = ( |
| tested_apk_config['package_name']) |
| # We should not shadow the actual R.java files of the apk_under_test by |
| # creating new R.java files with the same package names in the tested apk. |
| extra_package_names = [ |
| package for package in extra_package_names |
| if package not in tested_apk_config['extra_package_names'] |
| ] |
| if options.res_size_info: |
| config['deps_info']['res_size_info'] = options.res_size_info |
| |
| config['deps_info']['dependency_zips'] = dependency_zips |
| config['deps_info']['dependency_zip_overlays'] = dependency_zip_overlays |
| config['deps_info']['extra_package_names'] = extra_package_names |
| |
| # These are .jars to add to javac classpath but not to runtime classpath. |
| extra_classpath_jars = build_utils.ParseGnList(options.extra_classpath_jars) |
| if extra_classpath_jars: |
| deps_info['extra_classpath_jars'] = extra_classpath_jars |
| |
| mergeable_android_manifests = build_utils.ParseGnList( |
| options.mergeable_android_manifests) |
| if mergeable_android_manifests: |
| deps_info['mergeable_android_manifests'] = mergeable_android_manifests |
| |
| extra_proguard_classpath_jars = [] |
| proguard_configs = build_utils.ParseGnList(options.proguard_configs) |
| if proguard_configs: |
| # Make a copy of |proguard_configs| since it's mutated below. |
| deps_info['proguard_configs'] = list(proguard_configs) |
| |
| |
| if is_java_target: |
| if options.ignore_dependency_public_deps: |
| classpath_direct_deps = deps.Direct() |
| classpath_direct_library_deps = deps.Direct('java_library') |
| else: |
| classpath_direct_deps = deps.DirectAndChildPublicDeps() |
| classpath_direct_library_deps = deps.DirectAndChildPublicDeps( |
| 'java_library') |
| |
| # The classpath used to compile this target when annotation processors are |
| # present. |
| javac_classpath = set(c['unprocessed_jar_path'] |
| for c in classpath_direct_library_deps) |
| # The classpath used to compile this target when annotation processors are |
| # not present. These are also always used to know when a target needs to be |
| # rebuilt. |
| javac_interface_classpath = set(c['interface_jar_path'] |
| for c in classpath_direct_library_deps) |
| |
| # Preserve order of |all_library_deps|. Move low priority libraries to the |
| # end of the classpath. |
| all_library_deps_sorted_for_classpath = sorted( |
| all_library_deps[::-1], key=_CompareClasspathPriority) |
| |
| # The classpath used for bytecode-rewritting. |
| javac_full_classpath = OrderedSet.fromkeys( |
| c['unprocessed_jar_path'] |
| for c in all_library_deps_sorted_for_classpath) |
| # The classpath used for error prone. |
| javac_full_interface_classpath = OrderedSet.fromkeys( |
| c['interface_jar_path'] for c in all_library_deps_sorted_for_classpath) |
| |
| # Adding base module to classpath to compile against its R.java file |
| if base_module_build_config: |
| javac_full_classpath.add( |
| base_module_build_config['deps_info']['unprocessed_jar_path']) |
| javac_full_interface_classpath.add( |
| base_module_build_config['deps_info']['interface_jar_path']) |
| # Turbine now compiles headers against only the direct classpath, so the |
| # base module's interface jar must be on the direct interface classpath. |
| javac_interface_classpath.add( |
| base_module_build_config['deps_info']['interface_jar_path']) |
| |
| for dep in classpath_direct_deps: |
| if 'extra_classpath_jars' in dep: |
| javac_classpath.update(dep['extra_classpath_jars']) |
| javac_interface_classpath.update(dep['extra_classpath_jars']) |
| for dep in all_deps: |
| if 'extra_classpath_jars' in dep: |
| javac_full_classpath.update(dep['extra_classpath_jars']) |
| javac_full_interface_classpath.update(dep['extra_classpath_jars']) |
| |
| # TODO(agrieve): Might be less confusing to fold these into bootclasspath. |
| # Deps to add to the compile-time classpath (but not the runtime classpath). |
| # These are jars specified by input_jars_paths that almost never change. |
| # Just add them directly to all the classpaths. |
| if options.extra_classpath_jars: |
| javac_classpath.update(extra_classpath_jars) |
| javac_interface_classpath.update(extra_classpath_jars) |
| javac_full_classpath.update(extra_classpath_jars) |
| javac_full_interface_classpath.update(extra_classpath_jars) |
| |
| if is_java_target or options.type == 'android_app_bundle': |
| # The classpath to use to run this target (or as an input to ProGuard). |
| device_classpath = [] |
| if is_java_target and options.device_jar_path: |
| device_classpath.append(options.device_jar_path) |
| device_classpath.extend( |
| c.get('device_jar_path') for c in all_library_deps |
| if c.get('device_jar_path')) |
| if options.type == 'android_app_bundle': |
| for d in deps.Direct('android_app_bundle_module'): |
| device_classpath.extend(c for c in d.get('device_classpath', []) |
| if c not in device_classpath) |
| |
| if options.type in ('dist_jar', 'java_binary', 'junit_binary'): |
| # The classpath to use to run this target. |
| host_classpath = [] |
| if options.host_jar_path: |
| host_classpath.append(options.host_jar_path) |
| host_classpath.extend(c['host_jar_path'] for c in all_library_deps) |
| deps_info['host_classpath'] = host_classpath |
| |
| # We allow lint to be run on android_apk targets, so we collect lint |
| # artifacts for them. |
| # We allow lint to be run on android_app_bundle targets, so we need to |
| # collect lint artifacts for the android_app_bundle_module targets that the |
| # bundle includes. Different android_app_bundle targets may include different |
| # android_app_bundle_module targets, so the bundle needs to be able to |
| # de-duplicate these lint artifacts. |
| if options.type in ('android_app_bundle_module', 'android_apk'): |
| # Collect all sources and resources at the apk/bundle_module level. |
| lint_aars = set() |
| lint_srcjars = set() |
| lint_java_sources = set() |
| lint_resource_sources = set() |
| lint_resource_zips = set() |
| |
| if options.java_sources_file: |
| lint_java_sources.add(options.java_sources_file) |
| if options.bundled_srcjars: |
| lint_srcjars.update(deps_info['bundled_srcjars']) |
| for c in all_library_deps: |
| if c['chromium_code'] and c['requires_android']: |
| if 'java_sources_file' in c: |
| lint_java_sources.add(c['java_sources_file']) |
| lint_srcjars.update(c['bundled_srcjars']) |
| if 'aar_path' in c: |
| lint_aars.add(c['aar_path']) |
| |
| if options.res_sources_path: |
| lint_resource_sources.add(options.res_sources_path) |
| if options.resources_zip: |
| lint_resource_zips.add(options.resources_zip) |
| for c in all_resources_deps: |
| if c['chromium_code']: |
| # Prefer res_sources_path to resources_zips so that lint errors have |
| # real paths and to avoid needing to extract during lint. |
| if c['res_sources_path']: |
| lint_resource_sources.add(c['res_sources_path']) |
| else: |
| lint_resource_zips.add(c['resources_zip']) |
| |
| deps_info['lint_aars'] = sorted(lint_aars) |
| deps_info['lint_srcjars'] = sorted(lint_srcjars) |
| deps_info['lint_java_sources'] = sorted(lint_java_sources) |
| deps_info['lint_resource_sources'] = sorted(lint_resource_sources) |
| deps_info['lint_resource_zips'] = sorted(lint_resource_zips) |
| deps_info['lint_extra_android_manifests'] = [] |
| |
| if options.type == 'android_apk': |
| assert options.android_manifest, 'Android APKs must define a manifest' |
| deps_info['lint_android_manifest'] = options.android_manifest |
| |
| if options.type == 'android_app_bundle': |
| module_configs = [ |
| GetDepConfig(c) |
| for c in build_utils.ParseGnList(options.module_build_configs) |
| ] |
| jni_all_source = set() |
| lint_aars = set() |
| lint_srcjars = set() |
| lint_java_sources = set() |
| lint_resource_sources = set() |
| lint_resource_zips = set() |
| lint_extra_android_manifests = set() |
| for c in module_configs: |
| if c['is_base_module']: |
| assert 'base_module_config' not in deps_info, ( |
| 'Must have exactly 1 base module!') |
| deps_info['base_module_config'] = c['path'] |
| # Use the base module's android manifest for linting. |
| deps_info['lint_android_manifest'] = c['android_manifest'] |
| else: |
| lint_extra_android_manifests.add(c['android_manifest']) |
| jni_all_source.update(c['jni']['all_source']) |
| lint_aars.update(c['lint_aars']) |
| lint_srcjars.update(c['lint_srcjars']) |
| lint_java_sources.update(c['lint_java_sources']) |
| lint_resource_sources.update(c['lint_resource_sources']) |
| lint_resource_zips.update(c['lint_resource_zips']) |
| deps_info['jni'] = {'all_source': sorted(jni_all_source)} |
| deps_info['lint_aars'] = sorted(lint_aars) |
| deps_info['lint_srcjars'] = sorted(lint_srcjars) |
| deps_info['lint_java_sources'] = sorted(lint_java_sources) |
| deps_info['lint_resource_sources'] = sorted(lint_resource_sources) |
| deps_info['lint_resource_zips'] = sorted(lint_resource_zips) |
| deps_info['lint_extra_android_manifests'] = sorted( |
| lint_extra_android_manifests) |
| |
| # Map configs to classpath entries that should be included in their final dex. |
| classpath_entries_by_owning_config = collections.defaultdict(list) |
| extra_main_r_text_files = [] |
| if is_static_library_dex_provider_target: |
| # Map classpath entries to configs that include them in their classpath. |
| configs_by_classpath_entry = collections.defaultdict(list) |
| static_lib_jar_paths = {} |
| for config_path, dep_config in (sorted( |
| static_library_dependent_configs_by_path.items())): |
| # For bundles, only the jar path and jni sources of the base module |
| # are relevant for proguard. Should be updated when bundle feature |
| # modules support JNI. |
| base_config = dep_config |
| if dep_config['type'] == 'android_app_bundle': |
| base_config = GetDepConfig(dep_config['base_module_config']) |
| extra_main_r_text_files.append(base_config['r_text_path']) |
| static_lib_jar_paths[config_path] = base_config['device_jar_path'] |
| proguard_configs.extend(dep_config['proguard_all_configs']) |
| extra_proguard_classpath_jars.extend( |
| dep_config['proguard_classpath_jars']) |
| all_java_sources.extend(base_config['jni']['all_source']) |
| |
| # The srcjars containing the generated R.java files are excluded for APK |
| # targets the use static libraries, so we add them here to ensure the |
| # union of resource IDs are available in the static library APK. |
| for package in base_config['extra_package_names']: |
| if package not in extra_package_names: |
| extra_package_names.append(package) |
| for cp_entry in dep_config['device_classpath']: |
| configs_by_classpath_entry[cp_entry].append(config_path) |
| |
| for cp_entry in device_classpath: |
| configs_by_classpath_entry[cp_entry].append(options.build_config) |
| |
| for cp_entry, candidate_configs in configs_by_classpath_entry.items(): |
| config_path = (candidate_configs[0] |
| if len(candidate_configs) == 1 else options.build_config) |
| classpath_entries_by_owning_config[config_path].append(cp_entry) |
| device_classpath.append(cp_entry) |
| |
| device_classpath = sorted(set(device_classpath)) |
| |
| deps_info['static_library_proguard_mapping_output_paths'] = sorted([ |
| d['proguard_mapping_path'] |
| for d in static_library_dependent_configs_by_path.values() |
| ]) |
| deps_info['static_library_dependent_classpath_configs'] = { |
| path: sorted(set(classpath)) |
| for path, classpath in classpath_entries_by_owning_config.items() |
| } |
| deps_info['extra_main_r_text_files'] = sorted(extra_main_r_text_files) |
| |
| if is_apk_or_module_target or options.type in ('group', 'java_library', |
| 'junit_binary'): |
| deps_info['jni']['all_source'] = sorted(set(all_java_sources)) |
| |
| system_jars = [c['unprocessed_jar_path'] for c in system_library_deps] |
| system_interface_jars = [c['interface_jar_path'] for c in system_library_deps] |
| if system_library_deps: |
| config['android'] = {} |
| config['android']['sdk_interface_jars'] = system_interface_jars |
| config['android']['sdk_jars'] = system_jars |
| |
| if options.type in ('android_apk', 'dist_aar', |
| 'dist_jar', 'android_app_bundle_module', 'android_app_bundle'): |
| for c in all_deps: |
| proguard_configs.extend(c.get('proguard_configs', [])) |
| extra_proguard_classpath_jars.extend(c.get('extra_classpath_jars', [])) |
| if options.type == 'android_app_bundle': |
| for c in deps.Direct('android_app_bundle_module'): |
| proguard_configs.extend(p for p in c.get('proguard_configs', [])) |
| if options.type == 'android_app_bundle': |
| for d in deps.Direct('android_app_bundle_module'): |
| extra_proguard_classpath_jars.extend( |
| c for c in d.get('proguard_classpath_jars', []) |
| if c not in extra_proguard_classpath_jars) |
| |
| if options.type == 'android_app_bundle': |
| deps_proguard_enabled = [] |
| deps_proguard_disabled = [] |
| for d in deps.Direct('android_app_bundle_module'): |
| if not d['device_classpath']: |
| # We don't care about modules that have no Java code for proguarding. |
| continue |
| if d['proguard_enabled']: |
| deps_proguard_enabled.append(d['name']) |
| else: |
| deps_proguard_disabled.append(d['name']) |
| if deps_proguard_enabled and deps_proguard_disabled: |
| raise Exception('Deps %s have proguard enabled while deps %s have ' |
| 'proguard disabled' % (deps_proguard_enabled, |
| deps_proguard_disabled)) |
| deps_info['proguard_enabled'] = bool(options.proguard_enabled) |
| |
| if options.proguard_mapping_path: |
| deps_info['proguard_mapping_path'] = options.proguard_mapping_path |
| |
| # The java code for an instrumentation test apk is assembled differently for |
| # ProGuard vs. non-ProGuard. |
| # |
| # Without ProGuard: Each library's jar is dexed separately and then combined |
| # into a single classes.dex. A test apk will include all dex files not already |
| # present in the apk-under-test. At runtime all test code lives in the test |
| # apk, and the program code lives in the apk-under-test. |
| # |
| # With ProGuard: Each library's .jar file is fed into ProGuard, which outputs |
| # a single .jar, which is then dexed into a classes.dex. A test apk includes |
| # all jar files from the program and the tests because having them separate |
| # doesn't work with ProGuard's whole-program optimizations. Although the |
| # apk-under-test still has all of its code in its classes.dex, none of it is |
| # used at runtime because the copy of it within the test apk takes precidence. |
| |
| if options.type == 'android_apk' and options.tested_apk_config: |
| if tested_apk_config['proguard_enabled']: |
| assert options.proguard_enabled, ('proguard must be enabled for ' |
| 'instrumentation apks if it\'s enabled for the tested apk.') |
| # Mutating lists, so no need to explicitly re-assign to dict. |
| proguard_configs.extend( |
| p for p in tested_apk_config['proguard_all_configs']) |
| extra_proguard_classpath_jars.extend( |
| p for p in tested_apk_config['proguard_classpath_jars']) |
| tested_apk_config = GetDepConfig(options.tested_apk_config) |
| deps_info['proguard_under_test_mapping'] = ( |
| tested_apk_config['proguard_mapping_path']) |
| elif options.proguard_enabled: |
| # Not sure why you'd want to proguard the test apk when the under-test apk |
| # is not proguarded, but it's easy enough to support. |
| deps_info['proguard_under_test_mapping'] = '' |
| |
| # Add all tested classes to the test's classpath to ensure that the test's |
| # java code is a superset of the tested apk's java code |
| device_classpath_extended = list(device_classpath) |
| device_classpath_extended.extend( |
| p for p in tested_apk_config['device_classpath'] |
| if p not in device_classpath) |
| # Include in the classpath classes that are added directly to the apk under |
| # test (those that are not a part of a java_library). |
| javac_classpath.add(tested_apk_config['unprocessed_jar_path']) |
| javac_interface_classpath.add(tested_apk_config['interface_jar_path']) |
| javac_full_classpath.add(tested_apk_config['unprocessed_jar_path']) |
| javac_full_interface_classpath.add(tested_apk_config['interface_jar_path']) |
| javac_full_classpath.update(tested_apk_config['javac_full_classpath']) |
| javac_full_interface_classpath.update( |
| tested_apk_config['javac_full_interface_classpath']) |
| |
| # Exclude .jar files from the test apk that exist within the apk under test. |
| tested_apk_library_deps = tested_apk_deps.All('java_library') |
| tested_apk_dex_files = {c['dex_path'] for c in tested_apk_library_deps} |
| all_dex_files = [p for p in all_dex_files if p not in tested_apk_dex_files] |
| tested_apk_jar_files = set(tested_apk_config['device_classpath']) |
| device_classpath = [ |
| p for p in device_classpath if p not in tested_apk_jar_files |
| ] |
| |
| if options.type in ('android_apk', 'dist_aar', 'dist_jar', |
| 'android_app_bundle_module', 'android_app_bundle'): |
| deps_info['proguard_all_configs'] = sorted(set(proguard_configs)) |
| deps_info['proguard_classpath_jars'] = sorted( |
| set(extra_proguard_classpath_jars)) |
| |
| # Dependencies for the final dex file of an apk. |
| if (is_apk_or_module_target or options.final_dex_path |
| or options.type == 'dist_jar'): |
| config['final_dex'] = {} |
| dex_config = config['final_dex'] |
| dex_config['path'] = options.final_dex_path |
| if is_apk_or_module_target or options.type == 'dist_jar': |
| dex_config['all_dex_files'] = all_dex_files |
| |
| if is_java_target: |
| config['javac']['classpath'] = sorted(javac_classpath) |
| config['javac']['interface_classpath'] = sorted(javac_interface_classpath) |
| # Direct() will be of type 'java_annotation_processor', and so not included |
| # in All('java_library'). |
| # Annotation processors run as part of the build, so need host_jar_path. |
| config['javac']['processor_classpath'] = [ |
| c['host_jar_path'] for c in processor_deps.Direct() |
| if c.get('host_jar_path') |
| ] |
| config['javac']['processor_classpath'] += [ |
| c['host_jar_path'] for c in processor_deps.All('java_library') |
| ] |
| config['javac']['processor_classes'] = [ |
| c['main_class'] for c in processor_deps.Direct()] |
| deps_info['javac_full_classpath'] = list(javac_full_classpath) |
| deps_info['javac_full_interface_classpath'] = list( |
| javac_full_interface_classpath) |
| elif options.type == 'android_app_bundle': |
| # bundles require javac_full_classpath to create .aab.jar.info and require |
| # javac_full_interface_classpath for lint. |
| javac_full_classpath = OrderedSet() |
| javac_full_interface_classpath = OrderedSet() |
| for d in deps.Direct('android_app_bundle_module'): |
| javac_full_classpath.update(d['javac_full_classpath']) |
| javac_full_interface_classpath.update(d['javac_full_interface_classpath']) |
| javac_full_classpath.add(d['unprocessed_jar_path']) |
| javac_full_interface_classpath.add(d['interface_jar_path']) |
| deps_info['javac_full_classpath'] = list(javac_full_classpath) |
| deps_info['javac_full_interface_classpath'] = list( |
| javac_full_interface_classpath) |
| |
| if options.type in ('android_apk', 'dist_jar', 'android_app_bundle_module', |
| 'android_app_bundle'): |
| deps_info['device_classpath'] = device_classpath |
| if options.tested_apk_config: |
| deps_info['device_classpath_extended'] = device_classpath_extended |
| |
| if options.type in ('android_apk', 'dist_jar'): |
| all_interface_jars = [] |
| if options.interface_jar_path: |
| all_interface_jars.append(options.interface_jar_path) |
| all_interface_jars.extend(c['interface_jar_path'] for c in all_library_deps) |
| |
| config['dist_jar'] = { |
| 'all_interface_jars': all_interface_jars, |
| } |
| |
| if is_apk_or_module_target: |
| manifest = AndroidManifest(options.android_manifest) |
| deps_info['package_name'] = manifest.GetPackageName() |
| if not options.tested_apk_config and manifest.GetInstrumentationElements(): |
| # This must then have instrumentation only for itself. |
| manifest.CheckInstrumentationElements(manifest.GetPackageName()) |
| |
| library_paths = [] |
| java_libraries_list = None |
| if options.shared_libraries_runtime_deps: |
| library_paths = _ExtractSharedLibsFromRuntimeDeps( |
| options.shared_libraries_runtime_deps) |
| java_libraries_list = _CreateJavaLibrariesList(library_paths) |
| all_inputs.append(options.shared_libraries_runtime_deps) |
| |
| secondary_abi_library_paths = [] |
| if options.secondary_abi_shared_libraries_runtime_deps: |
| secondary_abi_library_paths = _ExtractSharedLibsFromRuntimeDeps( |
| options.secondary_abi_shared_libraries_runtime_deps) |
| all_inputs.append(options.secondary_abi_shared_libraries_runtime_deps) |
| |
| native_library_placeholder_paths = build_utils.ParseGnList( |
| options.native_lib_placeholders) |
| |
| secondary_native_library_placeholder_paths = build_utils.ParseGnList( |
| options.secondary_native_lib_placeholders) |
| |
| loadable_modules = build_utils.ParseGnList(options.loadable_modules) |
| secondary_abi_loadable_modules = build_utils.ParseGnList( |
| options.secondary_abi_loadable_modules) |
| |
| config['native'] = { |
| 'libraries': |
| library_paths, |
| 'native_library_placeholders': |
| native_library_placeholder_paths, |
| 'secondary_abi_libraries': |
| secondary_abi_library_paths, |
| 'secondary_native_library_placeholders': |
| secondary_native_library_placeholder_paths, |
| 'java_libraries_list': |
| java_libraries_list, |
| 'uncompress_shared_libraries': |
| options.uncompress_shared_libraries, |
| 'library_always_compress': |
| options.library_always_compress, |
| 'library_renames': |
| options.library_renames, |
| 'loadable_modules': |
| loadable_modules, |
| 'secondary_abi_loadable_modules': |
| secondary_abi_loadable_modules, |
| } |
| config['assets'], config['uncompressed_assets'], locale_paks = ( |
| _MergeAssets(deps.All('android_assets'))) |
| |
| deps_info['locales_java_list'] = _CreateJavaLocaleListFromAssets( |
| config['uncompressed_assets'], locale_paks) |
| |
| config['extra_android_manifests'] = [] |
| for c in extra_manifest_deps: |
| config['extra_android_manifests'].extend( |
| c.get('mergeable_android_manifests', [])) |
| |
| # Collect java resources |
| java_resources_jars = [d['java_resources_jar'] for d in all_library_deps |
| if 'java_resources_jar' in d] |
| if options.tested_apk_config: |
| tested_apk_resource_jars = [d['java_resources_jar'] |
| for d in tested_apk_library_deps |
| if 'java_resources_jar' in d] |
| java_resources_jars = [jar for jar in java_resources_jars |
| if jar not in tested_apk_resource_jars] |
| config['java_resources_jars'] = java_resources_jars |
| |
| if options.java_resources_jar_path: |
| deps_info['java_resources_jar'] = options.java_resources_jar_path |
| |
| # DYNAMIC FEATURE MODULES: |
| # Make sure that dependencies that exist on the base module |
| # are not duplicated on the feature module. |
| if base_module_build_config: |
| base = base_module_build_config |
| RemoveObjDups(config, base, 'deps_info', 'device_classpath') |
| RemoveObjDups(config, base, 'deps_info', 'javac_full_classpath') |
| RemoveObjDups(config, base, 'deps_info', 'javac_full_interface_classpath') |
| RemoveObjDups(config, base, 'deps_info', 'jni', 'all_source') |
| RemoveObjDups(config, base, 'final_dex', 'all_dex_files') |
| RemoveObjDups(config, base, 'extra_android_manifests') |
| |
| if is_java_target: |
| jar_to_target = {} |
| _AddJarMapping(jar_to_target, [deps_info]) |
| _AddJarMapping(jar_to_target, all_deps) |
| if base_module_build_config: |
| _AddJarMapping(jar_to_target, [base_module_build_config['deps_info']]) |
| if options.tested_apk_config: |
| _AddJarMapping(jar_to_target, [tested_apk_config]) |
| for jar, target in zip(tested_apk_config['javac_full_classpath'], |
| tested_apk_config['javac_full_classpath_targets']): |
| jar_to_target[jar] = target |
| |
| # Used by bytecode_processor to give better error message when missing |
| # deps are found. |
| config['deps_info']['javac_full_classpath_targets'] = [ |
| jar_to_target[x] for x in deps_info['javac_full_classpath'] |
| ] |
| |
| build_utils.WriteJson(config, options.build_config, only_if_changed=True) |
| |
| if options.depfile: |
| build_utils.WriteDepfile(options.depfile, options.build_config, |
| sorted(set(all_inputs))) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv[1:])) |