blob: 13e0a0c9ee701b56654c75f03138148dc0856737 [file] [view]
# Java Flag Generator
Generates a Java class with typed accessors for the features and params that a
C++ feature list exposes to Java through `kFeaturesExposedToJava` and
`k<Type>ParamsExposedToJava`.
## Features
For each `&namespace::kFooFeature` in `kFeaturesExposedToJava`, the generated
class contains:
```java
/** {@code namespace::kFooFeature} */
public static final class FooFeature {
public static final String NAME = "FooFeatureName";
public static boolean isEnabled() {
return isFeatureEnabled(NAME);
}
}
```
`NAME` is the feature name string from the feature's definition
(`BASE_FEATURE(kFooFeature, "FooFeatureName", ...)`), not a name derived from
the identifier.
## Params
Params are exposed to Java by listing them in one array per param type:
`kBooleanParamsExposedToJava`, `kIntParamsExposedToJava`,
`kDoubleParamsExposedToJava` and `kStringParamsExposedToJava`. These arrays are
optional. For each `&namespace::kFooParam` in them, the generated class
contains:
```java
/** {@code namespace::kFooParam} */
public static final class FooParam {
public static final String NAME = "foo_param";
public static int getValue() {
return getParamValueAsInt(FooFeature.NAME, NAME);
}
}
```
`NAME` is the param name string from the param's definition
(`BASE_FEATURE_PARAM(int, kFooParam, &kFooFeature, "foo_param", 0)`).
`FooFeature.NAME` is the feature name of the param's feature (`kFooFeature`),
which is usually referenced through the feature's nested class. The type
returned by `getValue()` (`boolean`, `int`, `double` or `String`) depends on the
array listing the param.
## Usage
```gn
import("//base/android/java_flag_generator/java_flag_generator.gni")
java_flag_generator("java_flags") {
sources = [ "android/chrome_feature_list.cc" ]
class_name = "org.chromium.chrome.browser.flags.ChromeFeatures"
}
android_library("java") {
srcjar_deps = [ ":java_flags" ]
...
}
```
List the target in the `srcjar_deps` of exactly one `android_library()`;
others should depend on that library.
### Variables
* `sources`: C++ files that define `kFeaturesExposedToJava`, and optionally
`k<Type>ParamsExposedToJava`.
* `class_name`: Fully-qualified name of the generated class.
* `feature_map_class_name` (optional): `FeatureMap` subclass used by all
sources. By default, each source's map is derived from its
`JNI_<Name>_GetNativeMap` function and assumed to be in the package of
`class_name`.
* `deps` (optional): Must include the targets that generate any generated
`FEATURE_DEFINITION_FILE`s.
## Finding feature and param definitions
For each feature in `kFeaturesExposedToJava` and each param in the
`k<Type>ParamsExposedToJava` arrays, the generator looks for definitions in:
1. The source itself.
2. For each quoted `#include "path/foo.h"`, the file `path/foo.cc`. The path is
tried relative to the source root, then relative to the including file.
3. Files listed in `FEATURE_DEFINITION_FILE` directives.
The feature of each param (`&kFooFeature` in
`BASE_FEATURE_PARAM(int, kFooParam, &kFooFeature, 0)`) is looked up in the same
files, relative to the namespace of the param's definition.
If a definition can't be found, the build fails. Fix it by adding a directive
to the source naming the file that defines the feature or param:
```c++
// FEATURE_DEFINITION_FILE: //third_party/blink/common/features.cc
```
Directive paths are looked up in the source tree first, then in
`$root_gen_dir`. For a generated file, add the target that generates it to
`deps`.
Directives that are not needed (the file is already found automatically, or no
feature or param uses it) are errors, so the list stays accurate.
### What counts as a definition
For features: any ALL_CAPS macro call whose name contains `FEATURE` (but not
`DECLARE` or `PARAM`) and whose first argument is a `kCamelCase` identifier,
e.g. `BASE_FEATURE(...)` or `BASE_FEATURE_WITH_COUNTRY_RESTRICTIONS(...)`.
For `BASE_FEATURE` and `BASE_RUNTIME_MUTABLE_FEATURE`, the feature name is the
second argument when it is a string literal; otherwise the feature name is
derived from the identifier (`kFooFeature` -> `"FooFeature"`).
For params: any `BASE_FEATURE_PARAM(T, kFooParam, &kFooFeature, ...)` call.
With 5 arguments, the param name is the fourth argument, which must be a string
literal. With 4 arguments, the param name is derived from the identifier
(`kFooParam` -> `"FooParam"`). Declarations (`BASE_DECLARE_FEATURE_PARAM`) are
not definitions.
## Changing the generator
* Golden tests that run the generator end to end live in
`test/integration_tests.py`. To update the expected output in `test/golden/`,
run:
```sh
REBASELINE=1 base/android/java_flag_generator/test/integration_tests.py
```
* The inputs of each of these tests live in `test/data/<test name>/`, which
becomes the source root (`//`) of the test. Files generated in
`$root_gen_dir` go under `out/Test/gen/` in that directory. Input files end
with an extra `.in` (e.g. `foo_features.cc.in`) so that presubmit checks and
formatters for C++ ignore them.
* Unit tests for the C++ lexer and parser live in `test/parse_test.py`.
* Both run as part of the presubmit checks of this directory (see
`PRESUBMIT.py`).