GN: Conditional flag values for different build targets

62 views
Skip to first unread message

Thiago Perrotta

unread,
Oct 18, 2023, 2:23:15 PM10/18/23
to gn-dev, Mathias Bynens, Wanda Mora, Peter Kvitek
Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1492079#c6

Use case (go/xyproblem): Given the Chromium codebase we want to build two targets, each one with its own set of configs:

- `chrome`, with `icu_use_data_file = true` and `v8_use_external_startup_data = true`
- `chrome-headless-shell`, with `icu_use_data_file = false` and `v8_use_external_startup_data = false`

Is it possible to have `gn gen` have these flags/switches (`icu_use_data_file` and `v8_use_external_startup_data`) with a different value for each of those individual targets (`chrome` and `chrome-headless-shell`)?

There's one caveat, the following will not work for our use case:

```shell
gn gen --args="cu_use_data_file=true v8_use_external_startup_data=true" out/Default
autoninja -C out/Default chrome
gn gen --args="cu_use_data_file=false v8_use_external_startup_data=false" out/Default
autoninja -C out/Default chrome-headless-shell
```

...because the configs above need to live in a builder/bot, wherein the GN flags config is declared statically.

I know that [CMake supports different configs for different targets](https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#properties-on-targets), even in the same build. Does GN support it too?

Armando Montanez

unread,
Oct 18, 2023, 3:30:20 PM10/18/23
to Thiago Perrotta, gn-dev, Mathias Bynens, Wanda Mora, Peter Kvitek
If I'm understanding correctly, this sounds like something that you'd handle with toolchains that override the default arguments, and then it should be as simple as creating a group (or multiple) that explicitly requests those toolchains.

Your root GN build would look something like this:

group("build_both_targets") {
  deps = [
    ":chrome(//path/to:toolchain_a)",
    ":chrome-headless-shell(//path/to:toolchain_b)",
  ]
}

Then in each toolchain, you'd just have to stamp out the overridden arguments in `toolchain_args`.


--
To unsubscribe from this group and stop receiving emails from it, send an email to gn-dev+un...@chromium.org.

Dirk Pranke

unread,
Oct 18, 2023, 3:32:15 PM10/18/23
to Thiago Perrotta, gn-dev, Mathias Bynens, Wanda Mora, Peter Kvitek
By default, GN does not do what you're trying to do.

The reason is that in order to do this you would need to have the different flags propagate down to the targets that depend on them (e.g., v8 for v8_use_external_startup_data), and then you'd presumably need to compile the target twice, two different ways. That can lead to having to build multiple things twice and that may not be the actual thing you want (but see below). 

In addition, we've generally had the opinion that having flags flow down the graph in that direction makes it much harder to know what is actually affecting what: how v8 is compiled could depend on every single target that uses v8.

And, since flags normally flow up the graph, now you'd be talking about having flags flow in both directions, which seems like it could be even more confusing.

That said, there is a way to do what you want: sometimes you really do want to build the targets twice with two different sets of flags, as you say. You can use two different toolchains, one that has the one set of flags you want, and one that has the other, and declare cross-toolchain dependencies as you need them (though if you can avoid cross-toolchain dependencies, that's probably better, because that's also easier to reason about). The v8 build effectively does this when you're doing cross-compiles: one built using the target toolchain, and one using a version of the host toolchain that has the same bit width as the target. Another example of this is in the Lacros variant of the Chromium, where we build Chrome itself twice, once to be the browser and once to be the window manager (Ash). A third is in some of the multi-bitwidth Android builds (like monochrome and trichrome). And my vague understanding is that Fuchsia uses this pervasively, but I could be wrong about that.

And, as I finish typing this, I see Armando just suggested the same basic thing, more concisely :).

-- Dirk

On Wed, Oct 18, 2023 at 11:23 AM Thiago Perrotta <tper...@chromium.org> wrote:
--

James Robinson

unread,
Oct 18, 2023, 7:27:55 PM10/18/23
to Dirk Pranke, Thiago Perrotta, gn-dev, Mathias Bynens, Wanda Mora, Peter Kvitek
You also may want to consider turning the build crank twice (i.e. running 'gn gen && ninja' twice with different out directories) for the different configurations. With GOMA or RBE or ccache or whatnot redundant build operations can be reused across the two builds. You can also configure build bots to build the separate configurations in isolation from each other and then archive the results together if needed to give the illusion of a single builder producing both configurations. The developer flow is rougher - they have to keep separate out dirs and may waste disk space - but the build configurations can be much simpler.

In the Fuchsia build system we do take advantage of GN's toolchain feature to build different targets with different configurations but this is difficult to scale. In particular any build edges that want to cross the place where the configuration boundary becomes relevant has a difficult time expressing the correct target. In this case since you already need to build v8 for the target architecture and the host architecture it may be difficult to wedge in another axis of configuration for v8. https://gn.googlesource.com/gn/+/main/docs/reference.md#func_toolchain explains the underlying mechanism, I'd personally be wary of using it in this situation.

- James
Reply all
Reply to author
Forward
0 new messages