blob: b1a8dbd522fe7ad405524252bf73a0338693f7b7 [file] [log] [blame] [view]
# GYP → GN Conversion Cookbook (Cobalt Edition)
[TOC]
## Foreword
Read the GN docs to familiarize yourself with the GN build system. I recommend
reading at least our [Quick Start][quick-start] guide, and skimming
the [Language document][language] and [Style Guide][style-guide] too.
The [GN and GYP Patterns][gn-gyp-patterns] document has some useful info too,
although not all of it is applicable to Cobalt.
Also read [Chromium's GYP → GN conversion cookbook][chromium-cookbook] if you
haven't already. The guidelines in that cookbook generally apply here. This
document consists of Cobalt-specific addenda to that document.
If you are uncertain how a certain idiom is expressed in GN, I suggest
consulting the Chromium code to see how they did it. Not all of Chromium's GN
idioms are adaptable to Cobalt (primarily because Chromium has no Starboard
concept), but it is a good place to start.
[quick-start]: https://cobalt.googlesource.com/cobalt/+/master/src/cobalt/doc/gn_quick_start.md
[language]: https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/language.md
[style-guide]: https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/style_guide.md
[gn-gyp-patterns]: https://docs.google.com/document/d/1xuInfaOjQQ00mtzaTPfiLH-Hw1wlxfH-60jHoa921Lc/edit
[chromium-cookbook]: https://chromium.googlesource.com/experimental/chromium/src/+/refs/wip/bajones/webvr/tools/gn/docs/cookbook.md
## gyp_to_gn.py
There is a script to partially automate the GYP to GN conversion in
`cobalt/tools/gyp_to_gn.py`. To run it, use:
cobalt/tools/gyp_to_gn.py path/to/module/module.gyp | gn format --stdin > path/to/module/BUILD.gn
This script is able to produce reasonably close GN output for many GYP files.
However, it is not perfect, and some manual inspection and revision of the
output is often necessary. As of this writing, known issues in addition to the
ones the script warns about are:
1. It doesn't translate over comments. This is because the script uses `eval`
to load the GYP file, which naturally cuts out all of the comments.
1. Sometimes the script will output `sources =` when it should have outputted
`sources +=`. This is because the GYP file had `'sources':` in both places,
but one of those places was inside a `conditions` block or similar. This bug
can be fixed, but it will take a little work.
The same problem can happen with other variables besides `sources`, e.g.
`defines`, `deps`, etc.
The script relies on two helper files in its directory, `variable_rewrites.dict`
and `deps_substitutions.txt`. `variable_rewrites.dict` is a Python dictionary
containing variables which were renamed or changed into booleans.
`deps_substitutions.txt` is a tab-delimited file containing a (non-exhaustive)
list of targets which were renamed.
## File Correspondences
`gyp_gn_files.md` in this directory contains a list of GYP -> GN file
correspondences. If you create a new irregular file correspondence, please add
it to this list before you forget!
## Variables vs Build Args
GN distinguishes between variables and build args. Build args are parameters
declared inside a `declare_args` block, that are intended for developers to
specify at the time they run gn. Ordinary variables are specified outside of
`declare_args` blocks, and they are intended to not change from build to build.
An example of a build arg is `use_goma`; if this build arg is turned on,
compilation is done with Goma instead of locally. (As of this writing,
`use_goma` is by default on for stub and linux platforms, and off on the
others.) An example of a variable is `gl_type`; this is something which depends
on the Starboard platform, and it doesn't make sense for individual developers
to change the value of this variable at compile time.
Some build behaviors controlled by environment variables in GYP been refactored
into GN build args. Here is a list of correspondences:
GYP | GN | Defined in
-------------- | ---------------------- | -----------------------------------------
`LB_FASTBUILD` | `cobalt_use_fastbuild` | `//starboard/build/config/fastbuild.gni`
`USE_ASAN` | `use_asan` | `//starboard/build/config/sanitizers.gni`
`USE_TSAN` | `use_tsan` | `//starboard/build/config/sanitizers.gni`
## Feature Flags
Most variables defined in `cobalt/build/config/base.gypi` and
`build/common.gypi` have been moved to `cobalt/build/config/base.gni` or
`starboard/build/config/base.gni`, depending on whether they are Cobalt or
Starboard variables. (A few, like `cobalt_config` and `starboard_path`, have
been moved to `BUILDCONFIG.gn`, and others may have been moved to other places
as well.)
Some variables have not been copied over. Most commonly this is because the
variable in question has been replaced by a config, group or something in GN
more appropriate.
Also, since GN has a true boolean type, variables which took on 0/1 values in
GYP have been converted to take on true/false values in GN.
Variables in Starboard platforms' `gyp_configuration.gypi` file have been moved
to `configuration.gni` under the Starboard platform's directory.
`base.gni` automatically imports the `configuration.gni` file of the
right Starboard platform.
GN doesn't allow defining a build arg twice with different values or changing
the value of a variable/build arg by importing a file. It also has no analog to
GYP's %-variable. Unfortunately for us, this means the code of `base.gni`
must necessarily check whether every variable/build arg it defines has already
been defined by the Starboard platform in `configuration.gni`.
Chromium frowns upon files with too many variables or build arg definitions.
They prefer to keep such definitions close to the files which actually use them.
In contrast, we keep a single `base.gni` file, because it would be inconvenient
for porters to have to browse through dozens of files to find out which variables
they should override.
## Build Args with Platform-Specific Defaults
There are some build args, like `use_goma`, which have different default values
on different Starboard platforms. Here is the generic declaration of `use_goma`,
located in `//starboard/shared/toolchain/goma.gni`:
if (!defined(use_goma)) {
# Set to true to enable distributed compilation using Goma. By default
# we use Goma for stub and linux.
use_goma = false
}
Notice a few things:
1. As with feature flags, `goma.gni` first checks to see if the Starboard
platform configuration has already defined it (with a different default)
in `configuration.gni`.
2. The comment is located right above the variable, inside the if statement.
This looks weird, but it's intentionally done this way so that the comment
will be printed out in `gn args --list`.
3. Starboard platforms which define alternative defaults are encouraged to
copy the comment when making their own definition of `use_goma`. (See the
stub platform configuration for an example.) It's not strictly necessary, but
if it's not done, then `gn args --list` won't print any documentation for
this build arg.
## BUILDCONFIG Variables
Some things which must necessarily be defined in `BUILDCONFIG.gn` may depend on
values from the Starboard platform, like:
* The `target_os` and `target_cpu`
* The `test_target_type`, and `final_executable_type` (which correspond to the
GYP variables `gtest_target_type` and `final_executable_type`)
* The host and target toolchain
These values are obtained from the Starboard platform's `buildconfig.gni`
file.
## Generic Compiler Options
In GYP, we have variables like `sb_pedantic_warnings` and keys like `rtti`,
which, if set for a target, turn on or off additional compiler flags. In GN,
these variables have been refactored into configs.
Consult the following examples:
### Pedantic Warnings
GYP:
'variables': {
'sb_pedantic_warnings': 1
}
GN:
configs -= [ "//starboard/build/config:no_pedantic_warnings" ]
configs += [ "//starboard/build/config:pedantic_warnings" ]
### Optimizations
GYP:
'optimizations': 'debuggable'
GN:
configs -= [ "//starboard/build/config:default_optimizations" ]
configs += [ "//starboard/build/config:debuggable_optimizations" ]
Ditto for `none` and `full`.
### RTTI
GYP:
'rtti': 1
GN:
configs -= [ "//starboard/build/config:default_rtti" ]
configs += [ "//starboard/build/config:rtti" ]
GYP:
'rtti': 0
GN:
configs -= [ "//starboard/build/config:default_rtti" ]
configs += [ "//starboard/build/config:no_rtti" ]
### -Wexit-time-destructors
GYP:
'enable_wexit_time_destructors': 1
GN:
configs += [ "//starboard/build/config:wexit_time_destructors" ]
There is no `//starboard/build/config:no_wexit_time_destructors` config.
### Implementation Details
Each Starboard generic compiler config is implemented by referencing a
platform-dependent implementation as a subconfig. For instance, here is, in
essence, the code for `//starboard/build/config:pedantic_warnings`:
config("pedantic_warnings") {
configs = [ "//$starboard_path/config:pedantic_warnings" ]
}
Each Starboard platform is then expected to define a pedantic warnings config
(and a no-pedantic-warnings config) in its `BUILD.gn` file. For instance, the
stub platform's implementation is:
config("pedantic_warnings") {
cflags = [
"-Wall",
"-Wextra",
"-Wunreachable-code",
]
}
Similarly, each Starboard platform is expected to define configs for turning on
and off RTTI, or what the default RTTI state should be; configs for turning on
and off optimizations, and the like. In reality, Starboard platforms often in
turn delegate to configs implemented by toolchains (which stub does for e.g.
RTTI).
## Variables Renamed
In general, following Chromium's practice, booleans have been renamed to have a
`use_`, `enable_` or `is_` prefix, if they did not already have such a prefix.
These prefixes come after any `cobalt_` or `sb_` prefix.
Here is a partial table of some renames:
GYP | GN
--------------------------- | --------------------------
`cobalt_fastbuild` | `cobalt_use_fastbuild`
`cobalt_version` | `cobalt_build_id`
`sb_allows_memory_tracking` | `sb_allow_memory_tracking`
`target_arch` | `target_cpu`
## Table of Variables Refactored into Configs
Variable | Config
----------------------------------------------------- | --------------------------------------------------------------
`sb_pedantic_warnings` | `//starboard/build/config:{no_}pedantic_warnings`
`compiler_flags`, `linker_flags` | `//$starboard_path:compiler_defaults`
`compiler_flags_debug`, `compiler_flags_c_debug`, ... | `//$starboard_path:compiler_defaults_debug`
`compiler_flags_devel`, `compiler_flags_c_devel`, ... | `//$starboard_path:compiler_defaults_devel`
`compiler_flags_qa`, `compiler_flags_c_qa`, ... | `//$starboard_path:compiler_defaults_qa`
`compiler_flags_gold`, `compiler_flags_c_gold`, ... | `//$starboard_path:compiler_defaults_gold`
`compiler_flags_host`, `compiler_flags_c_host`, ... | `//$starboard_path:compiler_defaults($host_toolchain)`
`platform_libraries` | `//$starboard_path:compiler_defaults` (in the `libs` variable)
## gtest_target_type and friends
The `gtest_target_type` variable has been renamed `test_target_type`. Platforms
wishing to override the default value of this variable (e.g. Android) should
put the override in `buildconfig.gni`. `final_executable_type` is similar.
To use these types in targets, consult the following conversion table:
GYP | GN
---------------------------------------------------- | ---------------------------
`'type': '<(gtest_target_type)', 'name': 'foo',` | `test("foo") {`
`'type': '<(final_executable_type)', 'name': 'foo',` | `final_executable("foo") {`
## Deploy
Replace
{
'target_name': 'target_deploy',
'type': 'none',
'dependencies': [
'target',
],
'variables': {
'executable_name': 'target',
},
'includes': [ '<(DEPTH)/starboard/build/deploy.gypi' ],
},
with
deploy("deploy") {
executable_name = "target"
deps = [
":target",
]
}
and import `//starboard/build/deploy.gni` at the top of the file.
## Runner Script
The GYP build system has a runner script, `gyp_cobalt`, which does a ton of
preprocessing, then runs GYP four times, once for each Cobalt configuration.
GN does not use a runner script. The preprocessing that `gyp_cobalt` does is
being moved into the actual GN build itself, making a runner script mostly
unnecessary. Furthermore, a nontrivial runner script would potentially interfere
with Ninja correctly rerunning GN when GN build files have changed.
## Generic GN Advice for Build Args
If you're adding a flag inside a `declare_args` block, read these tidbits of
advice:
* Use boolean values when possible. If you need a default value that expands
to some complex thing in the default case (like the location of the
compiler which would be computed by a script), use a default value of -1 or
the empty string. Outside of the `declare_args` block, conditionally expand
the default value as necessary.
* Use a name like `use_foo` or `is_foo` (whatever is more appropriate for
your feature) rather than just `foo`.
* Write good comments directly above the declaration with no blank line.
These comments will appear as documentation in `gn args --list`.
* Don't call `exec_script` inside `declare_args`. This will execute the script
even if the value is overridden, which is wasteful. See first bullet.