2216 lines
90 KiB
Python
Executable File
2216 lines
90 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2014 The Chromium Authors
|
|
# 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)
|
|
* [robolectric_binary](#target_robolectric_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['module_name']`:
|
|
Only seen for the
|
|
[`android_app_bundle_module`](#target_android_app_bundle_module)
|
|
type. The name of the feature module.
|
|
|
|
* `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.
|
|
|
|
## <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.
|
|
|
|
* `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['target_sources_file']`:
|
|
Path to a single `.sources` file listing all the Java and Kotlin 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_sources']`:
|
|
The list of all `deps_info['target_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 and Kotlin 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.
|
|
|
|
* `deps_info['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.
|
|
|
|
* `deps_info['preferred_dep']`:
|
|
Whether the target should be the preferred dep. This is usually the case when we
|
|
have a java_group that depends on either the public or internal dep accordingly,
|
|
and it is better to depend on the group rather than the underlying dep. Another
|
|
case is for android_library_factory targets, the factory target should be
|
|
preferred instead of the actual implementation.
|
|
|
|
## <a name="target_robolectric_binary">Target type `robolectric_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 - only used for proguarded 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['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.
|
|
|
|
* `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.
|
|
|
|
* `deps_info['jni_all_source']`
|
|
The list of all `deps_info['target_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 and Kotlin 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 ---------------------------------------------------
|
|
"""
|
|
|
|
import collections
|
|
import itertools
|
|
import json
|
|
import optparse
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import xml.dom.minidom
|
|
|
|
from util import build_utils
|
|
from util import resource_utils
|
|
import action_helpers # build_utils adds //build to sys.path.
|
|
|
|
|
|
# Types that should never be used as a dependency of another build config.
|
|
_ROOT_TYPES = ('android_apk', 'java_binary', 'java_annotation_processor',
|
|
'robolectric_binary', 'android_app_bundle')
|
|
# Types that should not allow code deps to pass through.
|
|
_RESOURCE_TYPES = ('android_assets', 'android_resources', 'system_java_library')
|
|
|
|
# Cache of path -> JSON dict.
|
|
_dep_config_cache = {}
|
|
|
|
|
|
class OrderedSet(collections.OrderedDict):
|
|
@staticmethod
|
|
def fromkeys(iterable):
|
|
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:
|
|
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')
|
|
|
|
|
|
def GetDepConfigRoot(path):
|
|
if not path in _dep_config_cache:
|
|
with open(path) as jsonfile:
|
|
_dep_config_cache[path] = json.load(jsonfile)
|
|
return _dep_config_cache[path]
|
|
|
|
|
|
def GetDepConfig(path):
|
|
return GetDepConfigRoot(path)['deps_info']
|
|
|
|
|
|
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 apply_filter(paths):
|
|
if filter_func:
|
|
return [p for p in paths if filter_func(GetDepConfig(p))]
|
|
return paths
|
|
|
|
def discover(path):
|
|
config = GetDepConfig(path)
|
|
all_deps = config['deps_configs'] + config.get('public_deps_configs', [])
|
|
return apply_filter(all_deps)
|
|
|
|
deps_config_paths = apply_filter(deps_config_paths)
|
|
deps_config_paths = build_utils.GetSortedTransitiveDependencies(
|
|
deps_config_paths, discover)
|
|
return deps_config_paths
|
|
|
|
|
|
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:
|
|
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 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']:
|
|
all_deps = config['deps_configs'] + config.get(
|
|
'public_deps_configs', [])
|
|
helper(Deps(all_deps))
|
|
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 itertools.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):
|
|
# Sort to ensure deterministic ordering.
|
|
items = sorted(asset_map.items())
|
|
return [f'{src}:{dest}' for dest, src in items]
|
|
|
|
return create_list(compressed), create_list(uncompressed), locale_paks
|
|
|
|
|
|
def _ResolveGroupsAndPublicDeps(config_paths):
|
|
"""Returns a list of configs with all groups inlined."""
|
|
|
|
def helper(config_path):
|
|
config = GetDepConfig(config_path)
|
|
if config['type'] == 'group':
|
|
# Groups combine public_deps with deps_configs, so no need to check
|
|
# public_config_paths separately.
|
|
return config['deps_configs']
|
|
if config['type'] == 'android_resources':
|
|
# android_resources targets do not support public_deps, but instead treat
|
|
# all resource deps as public deps.
|
|
return DepPathsOfType('android_resources', config['deps_configs'])
|
|
|
|
return config.get('public_deps_configs', [])
|
|
|
|
return build_utils.GetSortedTransitiveDependencies(config_paths, helper)
|
|
|
|
|
|
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 _FilterConfigPaths(dep_paths, blocklist=None, allowlist=None):
|
|
if not blocklist and not allowlist:
|
|
return dep_paths
|
|
configs = [GetDepConfig(p) for p in dep_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 [c['path'] for c in configs]
|
|
|
|
|
|
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).
|
|
"""
|
|
# Filter both before and after so that public_deps of blocked targets are not
|
|
# added.
|
|
allowlist_with_groups = None
|
|
if allowlist:
|
|
allowlist_with_groups = set(allowlist)
|
|
allowlist_with_groups.add('group')
|
|
dep_paths = _FilterConfigPaths(dep_paths, blocklist, allowlist_with_groups)
|
|
dep_paths = _ResolveGroupsAndPublicDeps(dep_paths)
|
|
dep_paths = _FilterConfigPaths(dep_paths, blocklist, allowlist)
|
|
|
|
return Deps(dep_paths)
|
|
|
|
|
|
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 _DedupFeatureModuleSharedCode(uses_split_arg, modules,
|
|
field_names_to_dedup):
|
|
child_to_ancestors = collections.defaultdict(list)
|
|
if uses_split_arg:
|
|
for split_pair in uses_split_arg:
|
|
child, parent = split_pair.split(':')
|
|
assert child in modules
|
|
assert parent in modules
|
|
child_to_ancestors[child] = [parent]
|
|
|
|
# Create a full list of ancestors for each module.
|
|
for name in modules:
|
|
if name == 'base':
|
|
continue
|
|
curr_name = name
|
|
while curr_name in child_to_ancestors:
|
|
parent = child_to_ancestors[curr_name][0]
|
|
if parent not in child_to_ancestors[name]:
|
|
child_to_ancestors[name].append(parent)
|
|
curr_name = parent
|
|
|
|
if curr_name != 'base':
|
|
child_to_ancestors[name].append('base')
|
|
|
|
# Strip out duplicates from ancestors.
|
|
for name, module in modules.items():
|
|
if name == 'base':
|
|
continue
|
|
# Make sure we get all ancestors, not just direct parent.
|
|
for ancestor in child_to_ancestors[name]:
|
|
for f in field_names_to_dedup:
|
|
if f in module:
|
|
RemoveObjDups(module, modules[ancestor], f)
|
|
|
|
# Strip out duplicates from siblings/cousins.
|
|
for f in field_names_to_dedup:
|
|
_PromoteToCommonAncestor(modules, child_to_ancestors, f)
|
|
|
|
|
|
def _PromoteToCommonAncestor(modules, child_to_ancestors, field_name):
|
|
module_to_fields_set = {}
|
|
for module_name, module in modules.items():
|
|
if field_name in module:
|
|
module_to_fields_set[module_name] = set(module[field_name])
|
|
|
|
seen = set()
|
|
dupes = set()
|
|
for fields in module_to_fields_set.values():
|
|
new_dupes = seen & fields
|
|
if new_dupes:
|
|
dupes |= new_dupes
|
|
seen |= fields
|
|
|
|
for d in dupes:
|
|
owning_modules = []
|
|
for module_name, fields in module_to_fields_set.items():
|
|
if d in fields:
|
|
owning_modules.append(module_name)
|
|
assert len(owning_modules) >= 2
|
|
# Rely on the fact that ancestors are inserted from closest to
|
|
# farthest, where "base" should always be the last element.
|
|
# Arbitrarily using the first owning module - any would work.
|
|
for ancestor in child_to_ancestors[owning_modules[0]]:
|
|
ancestor_is_shared_with_all = True
|
|
for o in owning_modules[1:]:
|
|
if ancestor not in child_to_ancestors[o]:
|
|
ancestor_is_shared_with_all = False
|
|
break
|
|
if ancestor_is_shared_with_all:
|
|
common_ancestor = ancestor
|
|
break
|
|
for o in owning_modules:
|
|
module_to_fields_set[o].remove(d)
|
|
module_to_fields_set[common_ancestor].add(d)
|
|
|
|
for module_name, module in modules.items():
|
|
if field_name in module:
|
|
module[field_name] = sorted(list(module_to_fields_set[module_name]))
|
|
|
|
|
|
def _CopyBuildConfigsForDebugging(debug_dir):
|
|
shutil.rmtree(debug_dir, ignore_errors=True)
|
|
os.makedirs(debug_dir)
|
|
for src_path in _dep_config_cache:
|
|
dst_path = os.path.join(debug_dir, src_path)
|
|
assert dst_path.startswith(debug_dir), dst_path
|
|
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
|
shutil.copy(src_path, dst_path)
|
|
print(f'Copied {len(_dep_config_cache)} .build_config.json into {debug_dir}')
|
|
|
|
|
|
def main(argv):
|
|
parser = optparse.OptionParser()
|
|
action_helpers.add_depfile_arg(parser)
|
|
parser.add_option('--build-config', help='Path to build_config output.')
|
|
parser.add_option('--store-deps-for-debugging-to',
|
|
help='Path to copy all transitive build config files to.')
|
|
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 and group options
|
|
parser.add_option('--preferred-dep',
|
|
action='store_true',
|
|
help='Whether the target should be preferred as a dep.')
|
|
|
|
# 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('--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('--target-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.')
|
|
|
|
# robolectric_library options
|
|
parser.add_option('--is-robolectric',
|
|
action='store_true',
|
|
help='Whether this is a host side android test library.')
|
|
|
|
# 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.')
|
|
|
|
# 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('--generate-markdown-format-doc', action='store_true',
|
|
help='Dump the Markdown .build_config format documentation '
|
|
'then exit immediately.')
|
|
|
|
parser.add_option('--module-name', help='The name of this feature module.')
|
|
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('--parent-module-build-config',
|
|
help='Path to the parent module\'s build config '
|
|
'when not using base module as parent.')
|
|
|
|
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(
|
|
'--uses-split',
|
|
action='append',
|
|
help='List of name pairs separated by : mapping a feature module to a '
|
|
'dependent feature module.')
|
|
|
|
parser.add_option(
|
|
'--trace-events-jar-dir',
|
|
help='Directory of rewritten .jar files for trace event rewriting.')
|
|
|
|
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(action_helpers.parse_gn_list(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', '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,
|
|
'robolectric_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.module_name:
|
|
raise Exception('--module-name 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.library_always_compress:
|
|
raise Exception(
|
|
'--library-always-compress 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', 'robolectric_binary',
|
|
'java_annotation_processor', 'java_library',
|
|
'android_apk', 'dist_aar', 'dist_jar',
|
|
'system_java_library',
|
|
'android_app_bundle_module')
|
|
|
|
deps_configs_paths = action_helpers.parse_gn_list(options.deps_configs)
|
|
public_deps_configs_paths = action_helpers.parse_gn_list(
|
|
options.public_deps_configs)
|
|
deps_configs_paths += public_deps_configs_paths
|
|
deps = _DepsFromPaths(deps_configs_paths,
|
|
options.type,
|
|
recursive_resource_deps=options.recursive_resource_deps)
|
|
public_deps = _DepsFromPaths(public_deps_configs_paths, options.type)
|
|
processor_deps = _DepsFromPaths(action_helpers.parse_gn_list(
|
|
options.annotation_processor_configs or ''),
|
|
options.type,
|
|
filter_root_targets=False)
|
|
|
|
all_inputs = (deps.AllConfigPaths() + processor_deps.AllConfigPaths())
|
|
|
|
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())
|
|
|
|
system_library_deps = deps.Direct('system_java_library')
|
|
all_deps = deps.All()
|
|
all_library_deps = deps.All('java_library')
|
|
|
|
if options.type == 'java_library':
|
|
# For Java libraries, restrict to resource targets that are direct deps, or
|
|
# are indirect via other resource targets.
|
|
# The indirect-through-other-targets ones are picked up because
|
|
# _ResolveGroupsAndPublicDeps() treats resource deps of resource targets as
|
|
# public_deps.
|
|
all_resources_deps = deps.Direct('android_resources')
|
|
else:
|
|
all_resources_deps = 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')
|
|
|
|
base_module_build_config = None
|
|
if options.base_module_build_config:
|
|
base_module_build_config = GetDepConfigRoot(
|
|
options.base_module_build_config)
|
|
parent_module_build_config = base_module_build_config
|
|
if options.parent_module_build_config:
|
|
parent_module_build_config = GetDepConfigRoot(
|
|
options.parent_module_build_config)
|
|
|
|
# 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,
|
|
'chromium_code': not options.non_chromium_code,
|
|
},
|
|
# Info needed only by generate_gradle.py.
|
|
'gradle': {}
|
|
}
|
|
deps_info = config['deps_info']
|
|
gradle = config['gradle']
|
|
|
|
# The paths we record as deps can differ from deps_config_paths:
|
|
# 1) Paths can be removed when blocked by _ROOT_TYPES / _RESOURCE_TYPES.
|
|
# 2) Paths can be added when promoted from group deps or public_deps of deps.
|
|
# Deps are promoted from groups/public_deps in order to make the filtering
|
|
# of 1) work through group() targets (which themselves are not resource
|
|
# targets, but should be treated as such when depended on by a resource
|
|
# target. A more involved filtering implementation could work to maintain
|
|
# the semantics of 1) without the need to promote deps, but we've avoided
|
|
# such an undertaking so far.
|
|
public_deps_set = set()
|
|
if public_deps_configs_paths:
|
|
deps_info['public_deps_configs'] = [d['path'] for d in public_deps.Direct()]
|
|
public_deps_set = set(deps_info['public_deps_configs'])
|
|
|
|
deps_info['deps_configs'] = [
|
|
d['path'] for d in deps.Direct() if d['path'] not in public_deps_set
|
|
]
|
|
|
|
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['module_name'] = options.module_name
|
|
|
|
# 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.preferred_dep:
|
|
deps_info['preferred_dep'] = bool(options.preferred_dep)
|
|
|
|
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'] = action_helpers.parse_gn_list(
|
|
options.bundled_srcjars)
|
|
|
|
if options.target_sources_file:
|
|
deps_info['target_sources_file'] = options.target_sources_file
|
|
|
|
if is_java_target:
|
|
if options.main_class:
|
|
deps_info['main_class'] = options.main_class
|
|
|
|
dependent_prebuilt_jars = deps.GradlePrebuiltJarPaths()
|
|
dependent_prebuilt_jars.sort()
|
|
if dependent_prebuilt_jars:
|
|
gradle['dependent_prebuilt_jars'] = dependent_prebuilt_jars
|
|
|
|
dependent_android_projects = []
|
|
dependent_java_projects = []
|
|
for c in deps.GradleLibraryProjectDeps():
|
|
if c['requires_android']:
|
|
dependent_android_projects.append(c['path'])
|
|
else:
|
|
dependent_java_projects.append(c['path'])
|
|
|
|
gradle['dependent_android_projects'] = dependent_android_projects
|
|
gradle['dependent_java_projects'] = dependent_java_projects
|
|
|
|
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',
|
|
'robolectric_binary',
|
|
'dist_aar'):
|
|
all_target_sources = [
|
|
c['target_sources_file'] for c in all_library_deps
|
|
if 'target_sources_file' in c
|
|
]
|
|
if options.target_sources_file:
|
|
all_target_sources.append(options.target_sources_file)
|
|
|
|
if is_apk_or_module_target or options.type in ('group', 'java_library',
|
|
'robolectric_binary'):
|
|
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)
|
|
|
|
# robolectric is special in that its an android target that runs on host.
|
|
# You are allowed to depend on both android |deps_require_android| and
|
|
# non-android |deps_not_support_android| targets.
|
|
if not options.bypass_platform_checks and not options.is_robolectric:
|
|
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.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(
|
|
action_helpers.parse_gn_list(options.asset_renaming_sources))
|
|
if options.asset_sources:
|
|
all_asset_sources.extend(
|
|
action_helpers.parse_gn_list(options.asset_sources))
|
|
|
|
deps_info['assets'] = {
|
|
'sources': all_asset_sources
|
|
}
|
|
if options.asset_renaming_destinations:
|
|
deps_info['assets']['outputs'] = (action_helpers.parse_gn_list(
|
|
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') or options.is_robolectric:
|
|
if options.package_name:
|
|
deps_info['package_name'] = options.package_name
|
|
|
|
if options.type in ('android_resources', 'android_apk', 'robolectric_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
|
|
]
|
|
if options.package_name:
|
|
extra_package_names += [options.package_name]
|
|
|
|
# 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
|
|
|
|
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
|
|
|
|
# Safe to sort: Build checks that non-overlay resource have no overlap.
|
|
dependency_zips.sort()
|
|
config['deps_info']['dependency_zips'] = dependency_zips
|
|
config['deps_info']['dependency_zip_overlays'] = dependency_zip_overlays
|
|
# Order doesn't matter, so make stable.
|
|
extra_package_names.sort()
|
|
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 = action_helpers.parse_gn_list(
|
|
options.extra_classpath_jars)
|
|
if extra_classpath_jars:
|
|
extra_classpath_jars.sort()
|
|
deps_info['extra_classpath_jars'] = extra_classpath_jars
|
|
|
|
mergeable_android_manifests = action_helpers.parse_gn_list(
|
|
options.mergeable_android_manifests)
|
|
mergeable_android_manifests.sort()
|
|
if mergeable_android_manifests:
|
|
deps_info['mergeable_android_manifests'] = mergeable_android_manifests
|
|
|
|
extra_proguard_classpath_jars = []
|
|
proguard_configs = action_helpers.parse_gn_list(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:
|
|
classpath_direct_deps = deps.Direct()
|
|
classpath_direct_library_deps = deps.Direct('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', 'robolectric_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_sources = set()
|
|
lint_resource_sources = set()
|
|
lint_resource_zips = set()
|
|
|
|
if options.target_sources_file:
|
|
lint_sources.add(options.target_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 'target_sources_file' in c:
|
|
lint_sources.add(c['target_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_sources'] = sorted(lint_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_config_paths = action_helpers.parse_gn_list(
|
|
options.module_build_configs)
|
|
module_configs = [GetDepConfig(c) for c in module_config_paths]
|
|
module_configs_by_name = {d['module_name']: d for d in module_configs}
|
|
per_module_fields = [
|
|
'device_classpath', 'trace_event_rewritten_device_classpath',
|
|
'all_dex_files'
|
|
]
|
|
jni_all_source = set()
|
|
lint_aars = set()
|
|
lint_srcjars = set()
|
|
lint_sources = set()
|
|
lint_resource_sources = set()
|
|
lint_resource_zips = set()
|
|
lint_extra_android_manifests = set()
|
|
config['modules'] = {}
|
|
modules = config['modules']
|
|
for n, c in module_configs_by_name.items():
|
|
if n == 'base':
|
|
assert 'base_module_config' not in deps_info, (
|
|
'Must have exactly 1 base module!')
|
|
deps_info['package_name'] = c['package_name']
|
|
deps_info['version_code'] = c['version_code']
|
|
deps_info['version_name'] = c['version_name']
|
|
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_sources.update(c['lint_sources'])
|
|
lint_resource_sources.update(c['lint_resource_sources'])
|
|
lint_resource_zips.update(c['lint_resource_zips'])
|
|
module = modules[n] = {}
|
|
for f in per_module_fields:
|
|
if f in c:
|
|
module[f] = c[f]
|
|
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_sources'] = sorted(lint_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)
|
|
|
|
_DedupFeatureModuleSharedCode(options.uses_split, modules,
|
|
per_module_fields)
|
|
|
|
if is_apk_or_module_target or options.type in ('group', 'java_library',
|
|
'robolectric_binary',
|
|
'dist_aar'):
|
|
deps_info['jni_all_source'] = sorted(set(all_target_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))
|
|
|
|
if options.final_dex_path:
|
|
config['final_dex'] = {'path': options.final_dex_path}
|
|
if is_apk_or_module_target or options.type == 'dist_jar':
|
|
# Dependencies for the final dex file of an apk.
|
|
deps_info['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'] = sorted(
|
|
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', 'android_app_bundle',
|
|
'android_app_bundle_module', 'dist_aar', 'dist_jar'):
|
|
deps_info['device_classpath'] = device_classpath
|
|
if options.trace_events_jar_dir:
|
|
trace_event_rewritten_device_classpath = []
|
|
for jar_path in device_classpath:
|
|
file_path = jar_path.replace('../', '')
|
|
file_path = file_path.replace('obj/', '')
|
|
file_path = file_path.replace('gen/', '')
|
|
file_path = file_path.replace('.jar', '.tracing_rewritten.jar')
|
|
rewritten_jar_path = os.path.join(options.trace_events_jar_dir,
|
|
file_path)
|
|
trace_event_rewritten_device_classpath.append(rewritten_jar_path)
|
|
|
|
deps_info['trace_event_rewritten_device_classpath'] = (
|
|
trace_event_rewritten_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)
|
|
secondary_abi_library_paths.sort()
|
|
paths_without_parent_dirs = [
|
|
p for p in secondary_abi_library_paths if os.path.sep not in p
|
|
]
|
|
if paths_without_parent_dirs:
|
|
sys.stderr.write('Found secondary native libraries from primary '
|
|
'toolchain directory. This is a bug!\n')
|
|
sys.stderr.write('\n'.join(paths_without_parent_dirs))
|
|
sys.stderr.write('\n\nIt may be helpful to run: \n')
|
|
sys.stderr.write(' gn path out/Default //chrome/android:'
|
|
'monochrome_secondary_abi_lib //base:base\n')
|
|
sys.exit(1)
|
|
|
|
all_inputs.append(options.secondary_abi_shared_libraries_runtime_deps)
|
|
|
|
native_library_placeholder_paths = action_helpers.parse_gn_list(
|
|
options.native_lib_placeholders)
|
|
native_library_placeholder_paths.sort()
|
|
|
|
secondary_native_library_placeholder_paths = action_helpers.parse_gn_list(
|
|
options.secondary_native_lib_placeholders)
|
|
secondary_native_library_placeholder_paths.sort()
|
|
|
|
loadable_modules = action_helpers.parse_gn_list(options.loadable_modules)
|
|
loadable_modules.sort()
|
|
secondary_abi_loadable_modules = action_helpers.parse_gn_list(
|
|
options.secondary_abi_loadable_modules)
|
|
secondary_abi_loadable_modules.sort()
|
|
|
|
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,
|
|
'library_always_compress':
|
|
options.library_always_compress,
|
|
'loadable_modules':
|
|
loadable_modules,
|
|
'secondary_abi_loadable_modules':
|
|
secondary_abi_loadable_modules,
|
|
}
|
|
|
|
# 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]
|
|
java_resources_jars.sort()
|
|
config['java_resources_jars'] = java_resources_jars
|
|
|
|
if is_apk_or_module_target or options.type == 'robolectric_binary':
|
|
# 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)
|
|
]
|
|
# Manifests are listed from highest priority to lowest priority.
|
|
# Ensure directly manfifests come first, and then sort the rest by name.
|
|
# https://developer.android.com/build/manage-manifests#merge_priorities
|
|
config['extra_android_manifests'] = list(mergeable_android_manifests)
|
|
manifests_from_deps = []
|
|
for c in extra_manifest_deps:
|
|
manifests_from_deps += c.get('mergeable_android_manifests', [])
|
|
manifests_from_deps.sort(key=lambda p: (os.path.basename(p), p))
|
|
config['extra_android_manifests'] += manifests_from_deps
|
|
|
|
config['assets'], config['uncompressed_assets'], locale_paks = (
|
|
_MergeAssets(deps.All('android_assets')))
|
|
deps_info['locales_java_list'] = _CreateJavaLocaleListFromAssets(
|
|
config['uncompressed_assets'], locale_paks)
|
|
|
|
if options.java_resources_jar_path:
|
|
deps_info['java_resources_jar'] = options.java_resources_jar_path
|
|
|
|
# DYNAMIC FEATURE MODULES:
|
|
# There are two approaches to dealing with modules dependencies:
|
|
# 1) Perform steps in android_apk_or_module(), with only the knowledge of
|
|
# ancesstor splits. Our implementation currently allows only for 2 levels:
|
|
# base -> parent -> leaf
|
|
# Bundletool normally fails if two leaf nodes merge the same manifest or
|
|
# resources. The fix is to add the common dep to the chrome or base module
|
|
# so that our deduplication logic will work.
|
|
# RemoveObjDups() implements this approach.
|
|
# 2) Perform steps in android_app_bundle(), with knowledge of full set of
|
|
# modules. This is required for dex because it can handle the case of two
|
|
# leaf nodes having the same dep, and promoting that dep to their common
|
|
# parent.
|
|
# _DedupFeatureModuleSharedCode() implements this approach.
|
|
if base_module_build_config:
|
|
ancestors = [base_module_build_config]
|
|
if parent_module_build_config is not base_module_build_config:
|
|
ancestors += [parent_module_build_config]
|
|
for ancestor in ancestors:
|
|
RemoveObjDups(config, ancestor, 'deps_info', 'dependency_zips')
|
|
RemoveObjDups(config, ancestor, 'deps_info', 'dependency_zip_overlays')
|
|
RemoveObjDups(config, ancestor, 'deps_info', 'extra_package_names')
|
|
RemoveObjDups(config, ancestor, 'deps_info', 'jni_all_source')
|
|
RemoveObjDups(config, ancestor, '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 parent_module_build_config is not base_module_build_config:
|
|
_AddJarMapping(jar_to_target, [parent_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. Both javac_full_classpath_targets and javac_full_classpath
|
|
# must be in identical orders, as they get passed as separate arrays and
|
|
# then paired up based on index.
|
|
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:
|
|
action_helpers.write_depfile(options.depfile, options.build_config,
|
|
sorted(set(all_inputs)))
|
|
|
|
if options.store_deps_for_debugging_to:
|
|
GetDepConfig(options.build_config) # Add it to cache.
|
|
_CopyBuildConfigsForDebugging(options.store_deps_for_debugging_to)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv[1:]))
|