Skip to content

Commit

Permalink
android: Document .build_config build files.
Browse files Browse the repository at this point in the history
This CL is an attempt to document the rather sophisticated
use and content of .build_config files when building various
Android-specific targets with GN for Chromium.

- Add a new documentation build_config.md under
  android/build/docs/

- Add documentation for the .build_config file format
  itself as a Markdown document inside of
  write_build_config.py to make it easier to update
  the documentation along side the script in the future.

  See build_config.md for extraction + visualization
  instructions.

+ Add missing links to Android Build markdown files
  to docs/README.md

+ Reformat coverage.md a little to make it readable.

R=agrieve@chromium.org,yfriedman@chromium.org,estevenson@chromium.org

Bug: None
Change-Id: Ic9bb61e50d578d69dea4ebc721d41feb9f68a5cb
Reviewed-on: https://chromium-review.googlesource.com/949463
Commit-Queue: David Turner <digit@chromium.org>
Reviewed-by: agrieve <agrieve@chromium.org>
Reviewed-by: Eric Stevenson <estevenson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541395}
  • Loading branch information
digit-android authored and Commit Bot committed Mar 7, 2018
1 parent 902b4c4 commit 40560ef
Show file tree
Hide file tree
Showing 4 changed files with 692 additions and 13 deletions.
170 changes: 170 additions & 0 deletions build/android/docs/build_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Introduction

This document describes the `.build_config` files that are used by the
Chromium build system for Android-specific targets like APK, resources,
and more.

[TOC]

# I. Overview of .build_config files:

The Android build requires performing computations about dependencies in
various targets, which are not possible with the GN build language. To address
this, `.build_config` files are written during the build to store the needed
per-target information as JSON files.

They are always written to `$target_gen_dir/${target_name}.build_config`.

Many scripts under [`build/android/gyp/`](build/android_gyp/), which are used
during the build, can also accept parameter arguments using
`@FileArg references`, which look like:

--some-param=@FileArg(<filename>:<key1>:<key2>:..<keyN>)

This placeholder will ensure that `<filename>` is read as a JSON file, then
return the value at `[key1][key2]...[keyN]` for the `--some-param` option.

Apart from that, the scripts do not need to know anything about the structure
of `.build_config` files (but the GN rules that invoke them do and select
which `@FileArg()` references to use).

For a concrete example, consider the following GN fragment:

```gn
# From //ui/android/BUILD.gn:
android_resources("ui_java_resources") {
custom_package = "org.chromium.ui"
resource_dirs = [ "java/res" ]
deps = [
":ui_strings_grd",
]
}
```

This will end up generating the following JSON file under
`$CHROMIUM_OUTPUT_DIR/gen/ui/android/ui_java_resources.build_config`:

```json
{
"deps_info": {
"deps_configs": [
"gen/ui/android/ui_strings_grd.build_config"
],
"name": "ui_java_resources.build_config",
"package_name": "org.chromium.ui",
"path": "gen/ui/android/ui_java_resources.build_config",
"r_text": "gen/ui/android/ui_java_resources_R.txt",
"resources_dirs": [
"../../ui/android/java/res"
],
"resources_zip": "resource_zips/ui/android/ui_java_resources.resources.zip",
"srcjar": "gen/ui/android/ui_java_resources.srcjar",
"type": "android_resources"
},
"gradle": {},
"resources": {
"dependency_zips": [
"resource_zips/ui/android/ui_strings_grd.resources.zip"
],
"extra_package_names": [],
"extra_r_text_files": []
}
}
```

NOTE: All path values in `.build_config` files are relative to your
`$CHROMIUM_OUTPUT_DIR`.

# II. Generation of .build_config files:

They are generated by the GN [`write_build_config()`](gn_write_build_config)
internal template, which ends up invoking
[`write_build_config.py`](write_build_config_py). For our example above, this
is with the following parameters:

```
python ../../build/android/gyp/write_build_config.py \
--type=android_resources \
--depfile gen/ui/android/ui_java_resources__build_config.d \
--deps-configs=\[\"gen/ui/android/ui_strings_grd.build_config\"\] \
--build-config gen/ui/android/ui_java_resources.build_config \
--resources-zip resource_zips/ui/android/ui_java_resources.resources.zip \
--package-name org.chromium.ui \
--r-text gen/ui/android/ui_java_resources_R.txt \
--resource-dirs=\[\"../../ui/android/java/res\"\] \
--srcjar gen/ui/android/ui_java_resources.srcjar
```

Note that *most* of the content of the JSON file comes from command-line
parameters, but not all of it.

In particular, the `resources['dependency_zips']` entry was computed by
inspecting the content of all dependencies (here, only
`ui_string_grd.build_config`), and collecting their
`deps_configs['resources_zip']` values.

Because a target's `.build_config` file will always be generated after
that of all of its dependencies,
[`write_build_config.py`](write_build_config_py) can traverse the
whole (transitive) set of direct *and* indirect dependencies for a given target
and extract useful information out of it.

This is the kind of processing that cannot be done at the GN language level,
and is very powerful for Android builds.


# III. Usage of .build_config files:

In addition to being parsed by `write_build_config.py`, when they are listed
in the `--deps-configs` of a given target, the `.build_config` files are used
by other scripts under [build/android/gyp/] to build stuff.

For example, the GN `android_resources` template uses it to invoke the
[`process_resources.py`] script with the following command, in order to
generate various related files (e.g. `ui_java_resources_R.txt`):

```sh
python ../../build/android/gyp/process_resources.py \
--depfile gen/ui/android/ui_java_resources_1.d \
--android-sdk-jar ../../third_party/android_tools/sdk/platforms/android-27/android.jar \
--aapt-path ../../third_party/android_tools/sdk/build-tools/27.0.3/aapt \
--dependencies-res-zips=@FileArg\(gen/ui/android/ui_java_resources.build_config:resources:dependency_zips\) \
--extra-res-packages=@FileArg\(gen/ui/android/ui_java_resources.build_config:resources:extra_package_names\) \
--extra-r-text-files=@FileArg\(gen/ui/android/ui_java_resources.build_config:resources:extra_r_text_files\) \
--resource-dirs=\[\"../../ui/android/java/res\"\] \
--debuggable \
--resource-zip-out resource_zips/ui/android/ui_java_resources.resources.zip \
--r-text-out gen/ui/android/ui_java_resources_R.txt \
--srcjar-out gen/ui/android/ui_java_resources.srcjar \
--non-constant-id \
--custom-package org.chromium.ui \
--shared-resources
```

Note the use of `@FileArg()` references here, to tell the script where to find
the information it needs.


# IV. Format of .build_config files:

Thanks to `@FileArg()` references, Python build scripts under
[`build/android/gyp/`](build/android/gyp/) do not need to know anything
about the internal format of `.build_config` files.

This format is decided between internal GN build rules and
[`write_build_config.py`][write_build_config_py]. Since these changes rather
often, the format documentation is kept inside the Python script itself, but
can be extracted as a Markdown file and visualized with the following commands:

```sh
# Extract .build_config format documentation
build/android/gyp/write_build_config.py \
--generate-markdown-format-doc > /tmp/format.md

# Launch a browser to visualize the format documentation.
python tools/md_browser/md_browser.py -d /tmp /tmp/format.md
```

[build/android/gyp/]: https://chromium.googlesource.com/chromium/src/build/+/master/android/gyp/
[gn_write_build_config]: https://cs.chromium.org/chromium/src/build/config/android/internal_rules.gni?q=write_build_config&sq=package:chromium
[write_build_config_py]: https://chromium.googlesource.com/chromium/src/build/+/master/android/gyp/write_build_config.py
40 changes: 27 additions & 13 deletions build/android/docs/coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,43 @@ build/android/generate_emma_html.py script.
## How to collect EMMA coverage data

1. Use the following GN build arguments:
```
target_os = "android"
emma_coverage = true
emma_filter = "org.chromium.chrome.browser.ntp.*,-*Test*,-*Fake*,-*Mock*"
```
The filter syntax is as documented for the [EMMA coverage
filters](http://emma.sourceforge.net/reference/ch02s06s02.html).

Now when building, **.em** files will be created in the build directory.

```
target_os = "android"
emma_coverage = true
emma_filter = "org.chromium.chrome.browser.ntp.*,-*Test*,-*Fake*,-*Mock*"
```

The filter syntax is as documented for the [EMMA coverage
filters](http://emma.sourceforge.net/reference/ch02s06s02.html).

Now when building, **.em** files will be created in the build directory.

2. Run tests, with option `--coverage-dir <directory>`, to specify where to save
the .ec file. For example, you can run chrome junit tests:
`out/Debug/bin/run_chrome_junit_tests --coverage-dir /tmp/coverage`.

3. Turn off strict mode when running instrumentation tests by adding
`--strict-mode=off` because the EMMA code causes strict mode violations by
accessing disk.

4. Use a pre-L Android OS (running Dalvik) because code coverage is not
supported in ART.

5. The coverage results of junit and instrumentation tests will be merged
automatically if they are in the same directory.

6. Now we have both .em and .ec files. We can create a html report using
`generate_emma_html.py`, for example:
`build/android/generate_emma_html.py --coverage-dir /tmp/coverage/
--metadata-dir out/Debug/ --output example.html`.

```
build/android/generate_emma_html.py \
--coverage-dir /tmp/coverage/ \
--metadata-dir out/Debug/ \
--output example.html
```
Then an example.html containing coverage info will be created:
`EMMA: writing [html] report to
[<your_current_directory>/example.html] …`

```
EMMA: writing [html] report to [<your_current_directory>/example.html] ...
```
Loading

0 comments on commit 40560ef

Please sign in to comment.