| Index: tools/mb/docs/design_spec.md
|
| diff --git a/tools/mb/docs/design_spec.md b/tools/mb/docs/design_spec.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9d5edf23589c624db295535382971525239292c4
|
| --- /dev/null
|
| +++ b/tools/mb/docs/design_spec.md
|
| @@ -0,0 +1,312 @@
|
| +# The MB (Meta-Build wrapper) design spec
|
| +
|
| +[TOC]
|
| +
|
| +## Summary of Design Requirements
|
| +
|
| +MB is intended to address two major aspects of the GYP -> GN
|
| +transition for Chromium and two minor aspects:
|
| +
|
| +1. "bot toggling" - make it so that we can easily flip a given bot
|
| + back and forth between GN and GYP.
|
| +
|
| +2. "bot configuration" - provide a single source of truth for all of
|
| + the different configurations (os/arch/gyp_define combinations) of
|
| + Chromium that are supported.
|
| +
|
| +3. "multi-build support" - make it easier for developers to build
|
| + multiple different build configs (gyp and gn, or linux and android,
|
| + for example) in a single checkout.
|
| +
|
| +4. "gn configs" - explore ways to manage sets of GN flags more easily
|
| + (i.e., all the flags needed for a ChromeCast build, or the Linux ASAN
|
| + bot). Eventually we may migrate this functionality into GN itself.
|
| +
|
| +MB must handle at least the `gen` and `analyze` steps on the bots, i.e.,
|
| +we need to wrap both the `gyp_chromium` invocation to generate the
|
| +Ninja files, and the `analyze` step that takes a list of modified files
|
| +and a list of targets to build and returns which targets are affected by
|
| +the files.
|
| +
|
| +MB may also provide a `build` wrapper in order to build multiple
|
| +configurations in a single step for developer convenience.
|
| +
|
| +## Design
|
| +
|
| +MB is intended to be as simple as possible, and to defer as much work as
|
| +possible to GN or GYP. It should live as a very simple Python wrapper
|
| +that offers little in the way of surprises.
|
| +
|
| +### Command line
|
| +
|
| +It is structured as a single binary that supports a list of subcommands:
|
| +
|
| +* `mb gen //out/Release chromium_linux_rel`
|
| +* `mb analyze -i input.json -o output.json chromium_linux_rel`
|
| +
|
| +### Configurations
|
| +
|
| +`mb` looks in the `//build/mb_conf.pyl` config file to determine whether
|
| +to use GYP or GN for a particular build directory, and what set of flags
|
| +(`GYP_DEFINES` or `gn args`) to use.
|
| +
|
| +`mb_conf.pyl` is structured as a file containing a single PYthon Literal
|
| +expression, a dictionary with two main keys, `build_configs` and
|
| +`mixins`.
|
| +
|
| +The `build_configs` key points to a dictionary of named build
|
| +configurations. Each name should be either a bot name (e.g.,
|
| +`chromium_linux_rel`) or an obvious developer configuration
|
| +(`gyp_shared_debug`).
|
| +
|
| +There should be an entry in this dict for every supported configuration
|
| +of Chromium, meaning every configuration we have a bot for, and every
|
| +configuration commonly used by develpers but that we may not have a bot
|
| +for.
|
| +
|
| +Each build_config entry then points to a list of "mixins" that will
|
| +define what that build_config does. Each item in the list must be
|
| +an entry in the dictionary value of the `mixins` key.
|
| +
|
| +Each entry is itself a diction that contains one or more of the
|
| +following keys:
|
| +
|
| + * `gyp_configs`: a list of the configurations to build, e.g.,
|
| + ['Release', 'Release_x64']; specifying this in conjunction
|
| + with type=gyp_one_config can reduce the time it takes to run gyp_chromium
|
| + a bit.
|
| + * `gyp_defines`: a string containing a list of GYP_DEFINES.
|
| + * `gn_args`: a string containing a list of values passed to gn --args.
|
| + * `mixins`: a list of other mixins that should be included.
|
| + * `type`: a string with either the value `gyp`, `gyp_one_config`, or `gn`;
|
| + setting this indicates which meta-build tool to use.
|
| +
|
| +When `mb gen` executes, it takes a build_config name, looks it up in the
|
| +'build_configs' dict, and then does a left-to-right expansion of the
|
| +mixins; gyp_defines and gn_args values are concatenated, and type and
|
| +gyp_configs values override each other.
|
| +
|
| +For example, if you had:
|
| +
|
| +```
|
| +{
|
| + 'build_configs`: {
|
| + 'linux_release_trybot': ['gyp_release', 'trybot'],
|
| + 'gn_shared_debug': None,
|
| + }
|
| + 'mixins': {
|
| + 'bot': {
|
| + 'gyp_defines': 'use_goma=1 dcheck_always_on=0',
|
| + 'gn_args': 'use_goma=true dcheck_always_on=false',
|
| + },
|
| + 'debug': {
|
| + 'gn_args': 'is_debug=true',
|
| + },
|
| + 'gn': {'type': 'gn'},
|
| + 'gyp_release': {
|
| + 'gyp_config': 'Release'
|
| + 'mixins': ['release'],
|
| + 'type': 'gyp',
|
| + },
|
| + 'release': {
|
| + 'gn_args': 'is_debug=false',
|
| + }
|
| + 'shared': {
|
| + 'gn_args': 'is_component_build=true',
|
| + 'gyp_defines': 'component=shared_library',
|
| + },
|
| + 'trybot': {
|
| + 'gyp_defines': 'dcheck_always_on=1',
|
| + 'gn_args': 'dcheck_always_on=true',
|
| + }
|
| + }
|
| +}
|
| +
|
| +and you ran `mb gen //out/Release linux_release_trybot`, it would
|
| +translate into a call to `gyp_chromium -G Release` with `GYP_DEFINES` set to
|
| +`"use_goma=true dcheck_always_on=false dcheck_always_on=true"`.
|
| +
|
| +(From that you can see that mb is intentionally dumb and does not
|
| +attempt to de-dup the flags, it lets gyp do that).
|
| +
|
| +### Handling the analyze step
|
| +
|
| +The way a GYP bot runs the "analyze" step is to pass gyp_chromium
|
| +two filename paths.
|
| +
|
| +The first path is to a JSON file used as input; it contains a single
|
| +object with a two fields:
|
| +
|
| + * `files`: an array of the modified filenames to check (as
|
| + paths relative to the checkout root).
|
| + * `targets`: an array of the unqualified target names to check.
|
| +
|
| +The second path is a path where the analyze generator should write the
|
| +result, also as a JSON object. This object may contain the following
|
| +fields:
|
| +
|
| + * `error`: this should only be present if something failed.
|
| + * `targets`: the subset of the input `targets` that depend on the
|
| + input `files`.
|
| + * `build_targets`: the minimal subset of targets needed to build all
|
| + of `targets` that were affected.
|
| + * `status`: one of three strings:
|
| + * `"Found dependency"` (build the `build_targets`)
|
| + * `"No dependency"` (i.e., no build needed)
|
| + * `"Found dependency (all)"` (build everything, in which case
|
| + `targets` and `build_targets` are not returned).
|
| +
|
| +mb replicates this command line interface, through `'mb analyze -i
|
| +input.json -o output.json build_config`.
|
| +
|
| +It implements the equivalent functionality in GN by calling `'gn refs
|
| +[list of files] --type=executable --all --as=output` and filtering the
|
| +output to match the list of targets.
|
| +
|
| +### Multi-build support
|
| +
|
| +Today one can pass options to GYP builds in many different ways:
|
| +
|
| +* specifying args directly to `gyp_chromium` with the `-D` flag.
|
| +* setting the `GYP_DEFINES` environment variable.
|
| +* setting the `GYP_DEFINES` key in a file named `chromium.gyp_env` that
|
| + lives in the directory above `src`.
|
| +* setting variables in a file in `~/.gyp/include.gypi`.
|
| +
|
| +Each of these approaches has advantages and disadvantages; the first two
|
| +are flexible, and allow you to customize each build directory (except
|
| +that you cannot have different flags for debug and release builds unless
|
| +you invoke gyp twice and only build one config each time), but they
|
| +require you to set something every time you run the command line (i.e.,
|
| +extra typing). The third saves typing, but does not allow you to
|
| +generate different build dirs in a single checkout; the fourth applies
|
| +not only to every build dir, but every checkout.
|
| +
|
| +GN, on the other hand, only supports setting flags via the `--args`
|
| +command line argument, or the `args.gn` file in the build directory;
|
| +these are the equivalent of the first two GYP methods.
|
| +
|
| +Ideally we would have a mechanism that offered the best of both worlds:
|
| +we could customize each build directory (including whether to use gyp or
|
| +gn), and we could generate multiple directories at once.
|
| +
|
| +MB supports this by looking for a config file named `builds.pyl` in the
|
| +directory above the checkout. The builds.pyl config file should contain
|
| +a dictionary where each key indicates the path to a desired build
|
| +directory, and each value specifies a particular build config (one of
|
| +the valid `build_config` values in `//build/mb_conf.pyl`).
|
| +
|
| +For example, this:
|
| +
|
| +```
|
| +src% cat ../build.pyl
|
| +{
|
| + "//out/Release": ["linux_release_trybot"],
|
| + "//out/Debug.gn": ["gn_shared_debug"],
|
| +}
|
| +src% mbw gen
|
| +src%
|
| +```
|
| +
|
| +is the equivalent of:
|
| +
|
| +```
|
| +src% GYP_DEFINES="use_goma=1 dcheck_always_on=0 dcheck_always_on=1" build/gyp_chromium -G config=Release -G output_dir=out
|
| +src% gn gen //out/Debug.gn --args='use_goma=true dcheck_always_on=true dcheck_always_on=false'
|
| +```
|
| +
|
| +## Detailed Design Requirements and Rationale
|
| +
|
| +This section is collection of semi-organized notes on why MB is the way
|
| +it is
|
| +
|
| +### in-tree or out-of-tree
|
| +
|
| +The first issue is whether or not this should exist as a script in
|
| +Chromium at all; an alternative would be to simply change the bot
|
| +configurations to know whether to use GYP or GN, and which flags to
|
| +pass.
|
| +
|
| +That would certainly work, but experience over the past two years
|
| +suggests a few things:
|
| +
|
| + * we should push as much logic as we can into the source repositories
|
| + so that they can be versioned and changed atomically with changes to
|
| + the product code; having to coordinate changes between src/ and
|
| + build/ is at best annoying and can lead to weird errors.
|
| + * the infra team would really like to move to providing
|
| + product-independent services (i.e., not have to do one thing for
|
| + Chromium, another for NaCl, a third for V8, etc.).
|
| + * we found that during the SVN->GIT migration the ability to flip bot
|
| + configurations between the two via changes to a file in chromium
|
| + was very useful.
|
| +
|
| +All of this suggests that the interface between bots and Chromium should
|
| +be a simple one, hiding as much of the chromium logic as possible.
|
| +
|
| +### Do we need multi-build support?
|
| +
|
| +Strictly speaking, no. MB could be useful just as a bot->chromium
|
| +interface. However, we do know that managing multiple build directories
|
| +is often awkward for many Chromium devs, at least until they write their
|
| +own wrappers. Many devs often also use multiple checkouts here, which
|
| +has higher overhead and can lead to confusion.
|
| +
|
| +We also know that some people miss the equivalents of setting
|
| +environment variables, chromium.gyp_env, etc., and would like an easier
|
| +way to make sure that multiple build dirs can share settings (like
|
| +use_goma and goma_dir, for example).
|
| +
|
| +### Why not have MB be smarter about de-duping flags?
|
| +
|
| +This just adds complexity to the MB implementation, and duplicates logic
|
| +that GYP and GN already have to support anyway; in particular, it might
|
| +require MB to know how to parse GYP and GN values. The belief is that
|
| +if MB does *not* do this, it will lead to fewer surprises.
|
| +
|
| +It will not be hard to change this if need be.
|
| +
|
| +### Non-goals
|
| +
|
| +* MB is not intended to replace the
|
| + [CR tool](https://code.google.com/p/chromium/wiki/CRUserManual). It
|
| + is only intended to replace the gyp_chromium part of `'gclient
|
| + runhooks'`. Hopefully the CR tool will learn about and integrate w/ MB
|
| + once MB becomes stable.
|
| +
|
| +* MB is not (yet?) intended to replace direct invocation of GN or GYP for
|
| + complicated build scenarios (aka ChromeOS), where multiple flags need
|
| + to be set to user-defined paths for specific toolchains (e.g., where
|
| + ChromeOS needs to specify specific board types and compilers).
|
| +
|
| +### Open issues
|
| +
|
| +* Some common flags (goma_dir being the obvious one) may need to be
|
| + specified via the user, and it's unclear how to integrate this with
|
| + the concept of build_configs.
|
| +
|
| + Right now, MB has hard-coded support for a few flags (i.e., you can
|
| + pass the --goma-dir flag, and it will know to expand "${goma_dir}" in
|
| + the string before calling out to the tool. We may want to generalize
|
| + this to a common key/value approach (perhaps then meeting the
|
| + ChromeOS non-goal, above), or we may want to keep this very strictly
|
| + limited for simplicity.
|
| +
|
| +* Do we need to add a `'mb build'` command?
|
| +
|
| + Being able to update multiple build dirs after syncing is useful, but
|
| + for GN-based dirs, ninja will do it for us automatically. It's unclear
|
| + if enough people will have a mixture of GYP and GN builds to make this
|
| + worth it to add.
|
| +
|
| +* How do we integrate `mb` with `gclient runhooks`?
|
| +
|
| + On the bots, we will disable gyp_chromium as part of runhooks (using
|
| + GYP_CHROMIUM_NO_ACTION=1), so that mb shows up as a separate step.
|
| +
|
| + However, gyp_chromium is run by default as part of `gclient runhooks`
|
| + and `gclient sync` for normal developers, and we probably don't want
|
| + to make everyone need to use GYP_CHROMIUM_NO_ACTION. Given that
|
| + `mb gen` with no arguments and no builds.pyl file is equivalent to
|
| + `gyp_chromium`, we might want to just update the hook to call mb.
|
| + Are there downsides to doing so?
|
|
|