2600 Commits
Author SHA1 Message Date
aphrody-dev 3f99f58c25 fix(build): serialize Ninja dependency prefixes as UTF-8 2026-10-11 11:37:15 +02:00
aphrody-dev 1f0ab182b0 fix(build): separate MSVC dependency prefix from Ninja rules 2026-10-11 11:35:42 +02:00
aphrody-dev 6492eb6833 fix(build): detect localized MSVC include prefixes for Ninja 2026-10-11 11:34:57 +02:00
aphrody-dev 86d4bba9f6 fix(build): preserve pinned GN version in vendored sources 2026-10-11 11:27:47 +02:00
Ryosuke Miyake 0035961837 Fix "Ouput" typos
Rename HeaderChecker::IsFileInOuputDir to IsFileInOutputDir, and the
TargetTest.RuntimeOuputs and TargetTest.RustRuntimeOuputs tests to
*RuntimeOutputs. No behavior change.

Change-Id: I13ea5fe4a3ecc8e322ba9132855b9b616405bab1
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27320
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-10-08 16:18:01 -07:00
Ryosuke Miyake f82afe9241 Add no_check_generated_targets .gn variable
A "gn check --check-generated" failure in a generated source can only be
suppressed with no_check_targets or check_includes = false, both of
which also skip the target's handwritten files.

no_check_generated_targets is a list of label patterns in .gn, in the
same format as no_check_targets. With --check-generated, gn check skips
the generated files (files in the output directory) of matching targets
and still checks their other files. Like check_targets and
no_check_targets, the list is not used when a label pattern is given on
the command line. gn check results are unchanged if the list is unset.

Bug: 559888973
Change-Id: I500cb396ca271daa69a407ea333e56438a28d6f4
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27220
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Matt Stark <msta@google.com>
Commit-Queue: Ryosuke Miyake <rysk@google.com>
2026-10-07 23:01:36 -07:00
Matt Stark b58dfa80d4 Improve the suggestion heuristic for depending on targets.
Previously, if you had a target //skia:headers, which is part of the
group //skia:skia, which is in turn part of the group //:gn_all, and
you tried to include it from //foo:bar, it would see that // is a
prefix of //foo, and thus assume //:gn_all was a local alias.

Change-Id: Ib3fe2edce0d15d5228eb53f97964e2c66a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27300
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-10-07 22:42:18 -07:00
Matt Stark f21094fa9b Do not generate last_commit_position.h in debug builds.
Whenever a commit is created or squashed in git/jj, the commit hash of
HEAD changes, which previously updated last_commit_position.h during
gen.py and forced a rebuild of gn_main.cc and relinking of gn.

In debug mode, generate a dummy last_commit_position.h instead so that
squashes do not invalidate the build cache. Real commit positions
continue to be generated for release builds.

Change-Id: Ib9e2fac8c1ec74f04fb66f382629e1dc6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27280
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-10-07 21:54:10 -07:00
Matt Stark 526295467b Enable check_includes_strict by default.
Note that this change is backwards-incompatible and will require
downstream projects to explicitly disable check_includes_strict in their
BUILDCONFIG.gn.

Bug: 555455099
Change-Id: Ie05cd7f182053355cba533a3c18ea0d06a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27240
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-10-07 19:46:55 -07:00
Matt Stark f9eca75ae5 Disable rust formatter on main branch.
I'm getting errors locally because the code isn't formatted correctly
because we don't lock a cargo version.

Change-Id: I22d73f433e5d2bc949fd0b8cbf17b6b56a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27241
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-10-06 19:29:13 -07:00
Takuto Ikuta 3fef1f0003 Add include sorting configuration to .clang-format and reformat
Configure include sorting options in .clang-format based on
Chromium's settings to adhere to Google C++ Style Guide:
- IncludeBlocks: Regroup
- IncludeCategories (with special priorities for Windows headers)
- IncludeIsMainRegex (for recognizing main headers in tests and platform files)

This ensures that tools/run_formatter.sh automatically sorts headers
and groups them appropriately (e.g. separating main headers, C system headers,
and C++ standard library headers with blank lines).

Also reformat existing files with tools/run_formatter.sh.

Change-Id: I1a82e23a7e1ac117a5f13d43a611a13c475fe2d1
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27200
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
2026-10-02 05:45:37 -07:00
David 'Digit' Turner c4019b9a52 Delayed generated_file() writes if they collect validations metadata
When a generated_file() target is written to the Ninja build
plan, delay its output file write if `collect_validations_metadata`
is true. Instead, the writes will be performed after all targets
have been resolved to ensure there are no runtime crashes when
performing the metadata walk.

Note that the flag can be set directly in the target
definition, or inherited from the .gn default value set
through experimental_collect_validations_metadata.

- builder_record.h: Add a comment explaining why metadata
  walks that include validations must be delayed.

- ninja_generated_file_target_writer.cc: If a target
  has collect_validations_metadata enabled, do not write
  its output file yet, instead set a boolean flag
  to indicate the delay.

- ninja_target_writer.cc: Take an optional pointer to
  a boolean flag to receive notification of delayed
  writes for generated_file() targets. Pass the pointer
  to NinjaGeneratedFileWriter properly.

- setup.cc: Add SetPostResolutionCallback() to register
  a callback to invoke after all items have been resolved
  in the graph (i.e. after the first scheduler.Run() call).

- setup_unittest.cc: Add new unit-test that verify that
  metadata walks with validations do not crash and return
  the correct values (or errors in case of missing deps).

- command_gen.cc: Record delayed generated_file() target
  pointers during graph resolution, then use a post-resolution
  callback to write all delayed generated_file() outputs
  in parallel.

Benchmarking shows that:

- For a medium Fuchsia project (which currently relies on
  validations metadata walks), using
  `gn gen --experimental-collect-validations-metadata` is
  about 15% slower with this patch applied (18.55s to
  20.3s)

- For a default Android/arm64 Chromium build,
  `gn gen --experimental-collect-validations-metadata`
  there is no statical difference (around 3s each).

Bug: 566346002
Change-Id: I58ad0c3bcec71ceec80cf5a617ef00e86415734d
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27086
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Matt Stark <msta@google.com>
Commit-Queue: David Turner <digit@google.com>
2026-10-02 05:19:50 -07:00
Takuto Ikuta 9fe99e2621 Stop forwarding private hard_deps on check_includes_strict targets
Previously, ResolvedTargetData::ComputeHardDeps() and
NinjaTargetWriter::WriteHardDepsStampOrPhony() forwarded hard_deps from
both public_deps and private deps of a target T (unless T was a binary
target with public = []), because standard 'gn check' allows T's
public headers to #include headers from T's private deps.

However, when T sets check_includes_strict = true, 'gn check' enforces
that T's public headers cannot #include headers from T's private deps.
Therefore, targets depending on T cannot transitively reach generated
headers from T's private dependencies.

This change restricts ComputeHardDeps() and WriteHardDepsStampOrPhony()
to only traverse public_deps when check_includes_strict = true (for
non-hard targets), while still including hard_deps of private_deps in
T's own input dependencies in WriteInputDepsStampOrPhonyAndGetDep().

Suggested in:
https://chromium-review.googlesource.com/c/chromium/src/+/8497030/comment/9c2d1aca_83609b40/

Bug: 563098656
Change-Id: If9d5ef1e18475f0bcae1a65553256ff84543d871
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27100
Reviewed-by: Matt Stark <msta@google.com>
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
2026-10-01 23:32:50 -07:00
David 'Digit' Turner 0e7d98e041 Add collect_validations_metadata boolean flag to generated_file() targets.
The default is false, unless the .gn flag
experimental_collect_validations_metadata is set to true.

When this flag is true, metadata walks will visit validation
dependencies. This may result in runtime crashes due to the
data race described in the associated bug.

A future CL will ensure that walks that include validations
are always performed after all targets have been resolved
to fix the issue.

Bug: 566346002
Change-Id: I12a8d913aa3895de8ec991b3a491c45e41b0cbfa
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27085
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
2026-10-01 06:16:15 -07:00
David 'Digit' Turner 0c19d708df Add new experimental_collect_validations_metadata .gn variable
And associated --experimental-collect-validations-metadata
switch.

This is not connected to anything right now.

Bug: 566346002
Change-Id: Id374c42d29cca4d6cd62367596dc81f14fa5198e
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27084
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
2026-10-01 05:44:27 -07:00
David 'Digit' Turner 31dd2c2b8e Move generated_file() writes to dedicated function.
This simply moves NinjaGeneratedFileTargetWriter::GenerateFile()
to its own helper function in a new source file. The new
implementation simply returns false on error instead of
calling g_scheduler->FailWithError().

This is a preparation CL for a fix for the associated bug
that will delay the writing of generate_file() targets that
have `collect_validations_metadata = true`.

Bug: 566346002
Change-Id: I588a3cce0ba6252c65e650a04cb813d885f7295a
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27083
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
2026-10-01 05:41:05 -07:00
David 'Digit' Turner b309775a6f Avoid canonicalization + string comparisons during metadata collection.
Avoid dynamic string allocations + comparisons when comparing
labels during metadata collection.

Replace the GetUserVisibleValue(true) calls and associated
string comparisons with calls to a new Label::Matches() method
which can do the same comparison more quickly by performing
four pointer comparisons.

Change-Id: I51e1f81c49cc9d0a79f3f1310a0ba3113f52d406
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27082
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
2026-10-01 05:31:15 -07:00
David 'Digit' Turner d54a840fa1 Use internal state struct for Target::GetMetadata().
Define a struct holding the common state during recursive
metadata collection. The new MetadataWalker::Walk() method
makes recursive calls easier to see and use less parameters.

This doesn't change the logic, just moves the
implementation and perform a few renames:

+ Rename GetMetadata() first two parameters to data_keys
  and walk_keys to match their GN argument names.

+ Rename next_walk_keys to next_walk_labels because
  this list contains list of labels, not walk/data key
  names.

Bug: 566346002
Change-Id: I33ea582da566d14d91ea6123c8541cf0906bb5a5
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27081
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
2026-10-01 05:29:27 -07:00
David 'Digit' Turner 841e072bef Fix minor Scheduler data races.
Ensure that Scheduler::{is_failed_,has_been_shutdown_}
are properly guarded by a lock since they are accessed
from multiple threads concurrently.

In Scheduler::FailWithError(), ensure the PostTask()
call happens under the lock.

In particular, this can happen when several background worker
threads are posting tasks to the queue, and one of them calls
Scheduler::FailWithError() which will implicitly call PostQuit().

Change-Id: Ie0b70be0838b9fdcf4f41c3ae53bc5bd8e6d71d3
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27080
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-10-01 01:30:18 -07:00
Takuto Ikuta 054c9865a0 rust: Don't make rlibs depend on non-Rust link inputs
rustc does not invoke a linker when building an rlib, so non-Rust native
dependencies (object files of source_sets, static libraries and shared
libraries) are not used when compiling it. Since RUST_LIBRARY is not
final, these dependencies are already propagated as inherited libraries
to the final target that links the rlib.

However, NinjaRustBinaryTargetWriter added them to the rlib's rustc
command line (as -Clink-arg=...) and to its implicit ninja dependencies.
This made compiling an rlib wait for C/C++ code to be compiled, archived
and linked. For example, in a Chromium component build, compiling an
rlib depending on a C++ component waited for its shared library (and
those of its dependencies) to be linked, which put rlib compilation
after long chains of shared library links on the critical path.

Stop adding non-Rust link inputs to rlibs. Final targets still get them
through inherited libraries, as tested in NonRustDeps.

Bug: 563098656
Change-Id: Id5a80c39a44a4e347e8ad64505efe1e686171517
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27000
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-09-30 00:20:18 -07:00
Claudio DeSouza dc685a2b72 gn edit: keep build files alive for warnings
Using `gn edit` with something like `remove testonly` results in a
non-fatal warning if the target does not have such attribute, and that
warning is collected in the `EditState` that `RunEditImpl` returns. This
run in UaF as every warning is an `Err` whose `Location` points into the
`InputFile` owned by the `BuildFile` it came from, however with the
that list being scoped to `RunEditImpl`, we end up with `RunEdit`
formatting those warnings using freed memory.

This CL fixes that by hoisting `build_files_` as a sibling field to
`edit_state_`.

Change-Id: I12acd0c02f3196c5f122642fadf6be2184769256
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26700
Reviewed-by: Matt Stark <msta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-28 17:38:47 -07:00
msta 510ec7992c Add instructions for agent to build GN and run code / tests
Change-Id: If582245cef421ec88150ac1c6d2c0fd96a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/24720
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-27 21:53:26 -07:00
Nico Weber 2dfb8cbd3b Write phony rules for harddeps
Write a rule for each target with at least two hard deps,
similar to what WritePublicInputsStampOrPhony() does for public_inputs:

    build phony/foo/bar.harddeps: $
        phony phony/foo/action phony/foo/dep.harddeps

It lists the target's direct hard deps. This mirrors
ResolvedTargetData::ComputeHardDeps(), so it depends on the same set
of hard deps, but its size is proportional to the number of direct deps.
A target's input deps then just refer to its own .harddeps rule.

Results for a Chromium build (mac, arm64, is_debug=false):

                                      before         after
  size of all loaded .ninja files     1025 MB        427 MB
  gn gen (hyperfine, 6 runs)          2.065s ± .048  1.947s ± .050
    user / sys                        12.0s / 4.3s   10.1s / 4.5s

Chromium no-op builds of base_unittests (target already built, hyperfine, M-series Mac):

                                               before           after
  siso v1.6.0 (autoninja), -offline            735.5 ms ± 13.7  648.3 ms ± 22.8
    user / sys                                 3.7s / 1.9s      2.3s / 2.2s
  depot_tools ninja (1.12.1)                   4.37s ± .02      2.25s ± .02
  ninja v1.13.2                                2.755s ± .009    1.532s ± .007
  ninja with some local changes to tweak perf  535.8 ms ± 2.7   408.4 ms ± 8.1
  (`siso -n` and `ninja -n` are within 2% of the no-op times.)

No intended behavior change.

Bug: chromium:40278737
Change-Id: I163e6bea334c2e626bf7c96cd8d942848a6766bf
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26741
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Nico Weber <thakis@google.com>
Commit-Queue: Nico Weber <thakis@chromium.org>
2026-09-24 09:08:32 -07:00
Matt Stark 56c22442ee Support conditional sources for gn check.
Suppose you have foo_linux.cc including bar.h, and:
```
source_set("foo") {
  sources = [ "foo.cc" ]
  if (is_linux) {
    sources += [ "foo_linux.cc" ]
  }
}
```

Previously, we would suggest `gn edit "add deps //:bar"` //:foo`.
Now, we no longer output the gn edit suggestion, and instead suggest
doing so inside an is_linux conditional.

Change-Id: Iac7fb49959fb6437b5ffd2595614bf526a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26680
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-23 23:17:40 -07:00
Nico Weber 8707f1b5c5 Don't write order-only deps reachable through direct deps
The size of the generated ninja files is quadratic: NinjaCBinaryTargetWriter writes an order-only dep for every non-linkable
dep of a target. `source_set("a")` depending on `source_set("b")`
depending on `source_set("c")` produced:

build phony/c.linkdeps: phony c.o
build phony/b.linkdeps: phony b.o || phony/c.linkdeps
build phony/a.linkdeps: phony a.o || phony/b.linkdeps phony/c.linkdeps

a.linkdeps listing c.linkdeps is not needed.

Instead, only write order-only deps for:

1. Direct deps (looking through groups, which have no build statement).
2. Libraries inherited through direct deps whose build statement doesn't
   list them (e.g. Rust libraries, or final targets that forward shared
   libraries).
3. Frameworks (create_bundle targets). ClassifyDependency() doesn't
   treat them as non-linkable deps of non-final targets.

https://issues.chromium.org/issues/40278737#comment7 compares ninja
files before and after this patch and checks that they are equivalent.

Results for a Chromium build (mac, arm64, is_debug=false):

                                      before         after
  size of all loaded .ninja files     2634 MB        1009 MB
    .linkdeps phony edges             1442 MB          15 MB
    `||` on alink edges                181 MB           5 MB
    `||` on link edges                  21 MB         0.3 MB
  gn gen (hyperfine, 6 runs)          2.917s ± .047  2.160s ± .052
    user / sys                        18.5s / 7.2s   12.3s / 4.7s

Chromium no-op builds of base_unittests (target already built, hyperfine,
M-series Mac), for siso and various ninja versions:

                                               before          after
  siso v1.6.0 (autoninja), -offline            1.058s ± .031   735.5 ms ± 13.7
    user / sys                                 7.0s / 2.0s     3.7s / 1.9s
  depot_tools ninja (1.12.1)                   10.09s ± .10    4.37s ± .02
  ninja v1.13.2                                6.388s ± .049   2.755s ± .009
  ninja with some local changes to tweak perf  950.9 ms ± 5.1  535.8 ms ± 2.7

(`siso -n` and `ninja -n` are within 2% of the no-op times.)

No intended behavior change.

Bug: chromium:40278737
Change-Id: I517db1c641001e404d3e02ab0e653c1133076d7f
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26740
Commit-Queue: Nico Weber <thakis@chromium.org>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Nico Weber <thakis@google.com>
2026-09-23 23:15:21 -07:00
Matt Stark 127dd2a6d5 When suggestions have a known includer target, don't complain that they
don't resolve to a single target.

This made a lot of sense when you had :foo1 and :foo2 both contain foo.cc in their sources,
and you ran `gn suggest foo.cc=bar.h`, but makes less sense when gn
check complains that foo1 doesn't depend on bar and foo2 also doesn't
depend on bar.

Change-Id: I1111e7c1b623015047721cf35e23420d6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26660
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-17 19:37:59 -07:00
Marc Jin 59107452bf rust_project_writer: Support aliased_deps in rust-project.json
When generating rust-project.json via `gn gen --export-rust-project`,
RustProjectWriter previously emitted only
`dep->rust_values().crate_name()` for crate dependencies in `"deps"`,
ignoring `target->rust_values().aliased_deps()`.

By contrast, NinjaRustBinaryTargetWriter checks `aliased_deps()` when
passing `--extern <alias>=<rlib>` flags to `rustc`. When a target uses
`aliased_deps` (such as renamed third-party Cargo crates),
`rust-analyzer` and Kythe indexers consuming `rust-project.json` could
not resolve imports using the aliased name.

This change updates `AddTarget` in `rust_project_writer.cc` to check
`target->rust_values().aliased_deps()` and emit the aliased dependency
name alongside `crate_name()`.

Bug:513301934
CONV=1d75e1e8-412c-4982-8ca8-e70282d906f4
Change-Id: I9f90915d1c252aab24c3dcdc7552b115b6ef9779
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26620
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Marc Jin <jmarc@google.com>
2026-09-16 06:37:26 -07:00
Philipp Wollermann 3c5809c35b Header check: validate includes before building diagnostics
A header can belong to several targets. Diagnosing each candidate
during the search can build unrestricted reachability tables and
errors that are discarded when a later candidate permits the include.

Separate acceptance checks from diagnostics. First search for a target
that permits the include, checking visibility, permitted dependency
chains, include exceptions and strict checking rules. Only enter the
diagnostic pass if the include is rejected.

Chromium `gn gen --check`, medians of five round-robin rounds:
  Mac (M4 Max):    2.70 s -> 2.62 s
  GCE c4d-384:     4.22 s -> 4.08 s
  Intel 13900KS:   2.55 s -> 2.33 s

CPU time (c4d-standard-384):
  User:  31.6 s -> 28.6 s (-9%)
  Sys:   33.9 s -> 34.0 s (0%)

Heap stats:
  Allocs (count):  53.78 M -> 53.51 M (-1%)
  Heap (total):    19.78 GB -> 18.10 GB (-8%)
  Heap (peak):      3.22 GB ->  2.30 GB (-29%)

Change-Id: I8c0118801072da1d37b7da291e5c047f9abfcd29
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26343
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Philipp Wollermann <philwo@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-09-16 05:20:39 -07:00
Philipp Wollermann 3968ba76ca Header check: defer unrestricted dependency walks
Precompute only the dependency reachability needed to permit includes.
Leave the unrestricted walk, which also follows private dependencies
transitively, to the existing lazy lookup when no permitted path is
found. This avoids building large diagnostic tables for every checked
target.

Use a shared lock for reachability cache hits, taking the exclusive
lock only on a miss.

Chromium `gn gen --check`, medians of five round-robin rounds:
  Mac (M4 Max):     3.13 s -> 2.70 s
  GCE c4d-384:      5.15 s -> 4.22 s
  Intel 13900KS:    3.30 s -> 2.55 s

CPU time (c4d-standard-384):
  User:  38.5 s -> 31.6 s (-18%)
  Sys:   50.2 s -> 33.9 s (-32%)

Heap stats:
  Allocs (count):  54.24 M -> 53.78 M (-1%)
  Heap (total):    24.92 GB -> 19.78 GB (-21%)
  Heap (peak):      5.46 GB ->  3.22 GB (-41%)

Change-Id: Idbd45609b60d465f78b240db93a33695af34c131
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26342
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Philipp Wollermann <philwo@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-09-16 05:12:36 -07:00
Philipp Wollermann 9adad59686 Header check: batch reachability and file checking tasks
Post reachability precomputation in groups of 32 targets and file
checking in groups of 64 files. This reduces queue operations and
completion counter updates. Collect violations within each group and
merge them under one lock.

Share the task posting and completion wait between both phases.

Chromium `gn gen --check`, medians of five round-robin rounds:
  Mac (M4 Max):    3.07 s -> 3.13 s (within noise)
  GCE c4d-384:     5.80 s -> 5.15 s
  Intel 13900KS:   3.24 s -> 3.30 s (within noise)

CPU time (c4d-standard-384):
  User:  39.6 s -> 38.5 s (-3%)
  Sys:   45.4 s -> 50.2 s (+11%)

Heap stats:
  Allocs (count):  54.24 M -> 54.24 M (0%)
  Heap (total):    24.93 GB -> 24.92 GB (0%)
  Heap (peak):      5.47 GB ->  5.46 GB (0%)

Change-Id: I8b884c5dd5c1bd58a40aaf151073ce9058326501
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26341
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Matt Stark <msta@google.com>
Commit-Queue: Philipp Wollermann <philwo@google.com>
2026-09-16 05:12:11 -07:00
Philipp Wollermann 81bf84fbeb Header check: select files from the existing file map
Build the list of files to check by filtering the complete file map.
This avoids rebuilding a second map and repeating the work to merge
each target's source, public and generated file metadata.

Derive the targets for reachability precomputation from the selected
files, so targets without eligible files do not get caches. Add a test
for this selection.

Chromium `gn gen --check`, medians of five round-robin rounds:
  Mac (M4 Max):    3.16 s -> 3.07 s
  GCE c4d-384:     5.96 s -> 5.80 s
  Intel 13900KS:   3.42 s -> 3.24 s

CPU time (c4d-standard-384):
  User:  40.0 s -> 39.6 s (-1%)
  Sys:   53.0 s -> 45.4 s (-14%)

Heap stats:
  Allocs (count):  55.16 M -> 54.24 M (-2%)
  Heap (total):    25.58 GB -> 24.93 GB (-3%)
  Heap (peak):      5.74 GB ->  5.47 GB (-5%)

Change-Id: Iaa4971421bf860d9453dc4ebfa5fd65452a1980c
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26340
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Philipp Wollermann <philwo@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-09-16 05:11:47 -07:00
Matt Stark 1b0f22ec57 Add an allowlist for allow_circular_includes_from.
Bug: 556482973

Change-Id: I6dffad2dfe0844be442cd554dbe12e2c6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/21942
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-16 00:02:21 -07:00
Takuto Ikuta 5649e56e9e [gn] Use std::unordered_map for waiting_map_
Previously, BuilderRecord::waiting_map_ was a base::flat_map. For
heavily depended-upon targets (such as core libraries like //base:base
and popular configs) that have thousands of dependents, inserting a new
dependent in waiting_map_ caused a binary search followed by an O(N)
memmove of all subsequent elements to keep the flat_map sorted.

Once StringAtomSet global lock contention is eliminated, worker threads
parse and submit targets to the Builder at a much higher rate, making
these O(N) memmove insertions a major bottleneck on the main thread.

However, waiting_map_ only requires point lookup by pointer and full
traversals to notify dependents of state changes; it never requires
sorted order (and functions like GetSortedUnresolvedDeps already sort
their output explicitly).

Switching to std::unordered_map eliminates the array shifts on insertion.

Benchmark results (`gn gen out/Default` on Chromium, 5 runs with hyperfine,
official release build configuration with Fuchsia Clang + libc++ +
static libjemalloc.a + LTO):
- Stacked on StringAtomSet sharding (CL 26540):
  2.258s ± 0.035s -> 2.060s ± 0.064s (-198ms / -8.8%, min 2.011s)
- Compared to origin/main:
  2.755s ± 0.029s -> 2.060s ± 0.064s (-695ms / 1.34x faster)

Output ninja files remain bit-for-bit identical across all 14,639 files.

TAG=agy
CONV=4cb5d931-60a8-4f44-8632-3e8d9fb10a8d

Change-Id: I3174ee798a5f6d0c58736fc05ad4ed2684b1d37c
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26560
Reviewed-by: Matt Stark <msta@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
2026-09-15 17:08:31 -07:00
Takuto Ikuta 2ab81981a8 [gn] Shard StringAtomSet to avoid lock contention
Previously, StringAtomSet used a single global std::mutex to protect the
global KeySet and Slab storage. On high-core-count machines, worker
threads frequently miss their thread-local cache for new strings across
thousands of files, causing intense lock contention on this single
mutex.

Profiling Chromium's //out/Default build generation with official GN
release build settings (Fuchsia Clang + libc++ + static libjemalloc.a +
LTO) showed that kernel futex waits on StringAtomSet::find() accounted
for over 70% of the total System CPU time.

This change shards StringAtomSet into 256 independent, cache-aligned
(alignas(64)) partitions indexed by the string hash's upper bits. In
addition, both StringAtomSet and ThreadLocalCache pre-insert
kEmptyString in their constructors so that empty strings hit directly
without slab allocation or extra branches in the lookup hot path.

Benchmark results (`gn gen out/Default` on Chromium, 5 runs with
hyperfine, official release build configuration):
- Wall-clock time: 2.755s ± 0.029s -> 2.262s ± 0.038s (-493ms / 1.22x faster)
- System CPU time: 14.079s -> 4.030s (-10.05s / -71.4% reduction!)
- User CPU time:   23.740s -> 22.889s (-0.85s)

Output ninja files remain bit-for-bit identical across all 14,639 files.

TAG=agy
CONV=4cb5d931-60a8-4f44-8632-3e8d9fb10a8d
Change-Id: I2d09d9f25c6c86482ef420282a41606308b8d8d4
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26540
Commit-Queue: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-09-15 16:55:16 -07:00
Takuto Ikuta 4c122caddf [gn] Use DCHECK in Target::info()
Follow-up to https://gn-review.googlesource.com/c/gn/+/26480.

As pointed out by Matt Stark (msta@), having a lazy
'info_.emplace(this)' fallback inside Target::info() could theoretically
allow concurrent mutation if info() were ever called on an unresolved
target in a multi-threaded context.

In production, Target::OnResolvedWithoutChecks() is always called before
any multi-threaded queries occur. Across the entire unit test suite (845
tests), only a single test (NinjaCBinaryTargetWriterTest.
DupeObjFileError) invoked NinjaCBinaryTargetWriter without calling
OnResolved() first.

By adding 'ASSERT_TRUE(target.OnResolved(&err))' to DupeObjFileError, we
can replace the lazy initialization in Target::info() with
'DCHECK(info_.has_value())', making info() strictly read-only and
branchless in release builds.

Note: 'info_' itself remains 'mutable' because ResolvedTargetData
queries receive 'const Target*' and lazily compute/populate the cache
fields inside TargetInfo (e.g., lib_dirs, inherited_libs). Keeping
'mutable' on 'info_' as a whole avoids scattering 'mutable' across ~20
individual fields inside TargetInfo and modifying all helper signatures.

TAG=agy
CONV=4cb5d931-60a8-4f44-8632-3e8d9fb10a8d
Change-Id: I6a697e0172473d38b80ca04ea0985c6dab8e3d44
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26500
Commit-Queue: Takuto Ikuta <tikuta@google.com>
Reviewed-by: Matt Stark <msta@google.com>
2026-09-14 20:30:02 -07:00
Takuto Ikuta b98227b7c3 [gn] Make ResolvedTargetData stateless
Profiling 'gn gen' on Chromium 'out/Default' (36k targets, 64 cores)
revealed that ResolvedTargetData::GetTargetInfo was a major bottleneck:
- std::__Cr::__shared_mutex_base::lock_shared() consumed 9.01% cycles.
- Hash computation (CityHash/hash_memory) consumed 14.35% cycles.
Together, about 23% of total CPU cycles were spent on every query
acquiring shared_locks and probing shard hash maps, even though targets
are queried repeatedly and their pointers are immutable after
resolution.

As suggested by Matt Stark (msta@), we can simplify this significantly:

1. Move TargetInfo directly into Target as 'std::optional<TargetInfo>'.
2. Initialize 'info_' when Target::OnResolvedWithoutChecks() is called
   (with a fallback lazy initialization in info() for unit tests that
   skip OnResolved).
3. Make ResolvedTargetData completely stateless. GetTargetInfo() simply
   returns '&target->info()' inline with zero locks, zero hashing, and
   zero dynamic heap allocations for TargetInfo map entries.
4. Because Target owns its TargetInfo directly, the lifetime of
   TargetInfo perfectly matches Target, eliminating any possibility of
   use-after-free or address-reuse (ABA) bugs when Targets or
   ResolvedTargetData instances are destroyed in unit tests.

Performance impact on Chromium 'out/Default' (vs origin/main):
- Wall-clock time: 3.281s -> 3.173s (-108ms, -3.3%)
- User CPU time:   30.87s -> 27.32s (-3.55s, -11.5%)
- CPU cycles:     102.91G -> 89.86G (-13.05G cycles, -12.7%)
- Instructions:   110.14G -> 102.72G (-7.42G instrs, -6.7%)

All 845 unit tests passed. Output ninja files are bit-for-bit identical.

TAG=agy
CONV=4cb5d931-60a8-4f44-8632-3e8d9fb10a8d
Change-Id: Ib23f999522044d5b4b46128491d54ef9061ef4b5
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26480
Reviewed-by: Matt Stark <msta@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
2026-09-14 19:39:22 -07:00
Takuto Ikuta 018bad7658 [recipe] Enable THP for jemalloc build in GN recipe
Configure jemalloc with --with-malloc-conf=thp:always to enable
Transparent Huge Pages (THP) by default on Linux.

When running large GN generation tasks (such as Chromium's gn gen),
jemalloc allocates extensive virtual memory ranges. Without THP enabled
by default, allocations rely heavily on 4KB pages, leading to
significant kernel overhead in page fault handling and page table walks
(minor page faults: ~467k).

By enabling thp:always, jemalloc proactively uses 2MB huge pages via
madvise(MADV_HUGEPAGE), reducing minor page faults by 54% and improving
wall clock time by ~218ms (~6.7%).

Benchmark (`hyperfine --warmup 2 --runs 10` on Chromium `gn gen`):
- jemalloc (default):       3.236 s ± 0.028 s
- jemalloc (thp:always):    3.018 s ± 0.052 s  (-218 ms, 1.07x faster)

perf stat comparison:
- Minor faults:  467,490 -> 215,229 (-54.0%)
- CPU cycles:    104.9G  -> 98.2G   (-6.7B cycles)
- User CPU time: 26.54s  -> 23.92s  (-2.62s)
- Sys CPU time:  17.51s  -> 15.62s  (-1.89s)

TAG=agy
CONV=4cb5d931-60a8-4f44-8632-3e8d9fb10a8d
Change-Id: I134509479c0cf74c397cea8c8227d911e2734963
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26460
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: David Turner <digit@google.com>
2026-09-14 01:09:34 -07:00
Philipp Wollermann cfcd774b98 Header check: avoid interning paths during include lookup
Resolving each include against each include directory constructs a
SourceFile, which interns the candidate path even when lookup fails.
This adds allocations and contention on the shared interning lock.

Use a hash map keyed by path string views. Normalize candidate paths
in a reusable buffer, look them up directly, and return the SourceFile
stored in the matching entry.

Chromium `gn gen --check`, medians of five round-robin rounds:
  Mac (M4 Max):    3.91 s -> 3.16 s
  GCE c4d-384:     7.71 s -> 5.96 s
  Intel 13900KS:   4.11 s -> 3.42 s

CPU time (c4d-standard-384):
  User:  43.8 s -> 40.0 s (-9%)
  Sys:  121.1 s -> 53.0 s (-56%)

Heap stats:
  Allocs (count):  64.84 M -> 55.16 M (-15%)
  Heap (total):    26.27 GB -> 25.58 GB (-3%)
  Heap (peak):      5.95 GB ->  5.74 GB (-4%)

Change-Id: Iefb962d72efcba69361bccce430e41d10a63c2a9
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26320
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Philipp Wollermann <philwo@google.com>
2026-09-11 03:30:22 -07:00
Matt Stark 0625da07ec Improve heuristic to disambiguate recommended dependency to add.
If it still is ambiguous after applying visibility rules, we
disambiguate by label.

Change-Id: I1a36609a24091cc4780e166532f211f26a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26420
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-10 00:47:00 -07:00
Matt Stark f999721186 No longer automatically add files to public.
It is more preferred to split into a source set if you have public
depending on a private header.

Conveniently, this also means that `gn check --fix` will never succeed
and then break if you run it immediately after (which it would
previously do because the header that was made public may require
something to be moved from deps to public_deps)

Change-Id: I762a529c279232c6d7edb94bf99eecbc6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26400
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-09 01:46:55 -07:00
Matt Stark e095a1af96 Deduplicate deps/public_deps and sources/public in gn edit
When running `gn check --fix`, if you added a #include to both the .cc
and the .h file, you will get the following suggestions:
* "add deps //dep"
* "add public_deps //dep"

This ensures that it will only get added to public_deps.

Additionally, change gn suggest to recommend adding to public_deps
instead of moving from deps to public_deps.

Change-Id: I59074724bb5ed61a3499f1a81d2f3b356a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26380
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-09 01:12:05 -07:00
Matt Stark c0e4aae6d8 Preserve toolchain when generating suggestions in gn check
Record the source target on HeaderChecker::Violation so that CheckPublicHeaders
passes the actual toolchain of the violating target to OutputSuggestions,
preventing incorrect cross-toolchain suggestions.

Change-Id: I7625f30ced367c2f8680e673fc5a5d0b6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26360
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-08 20:13:30 -07:00
Matt Stark 5df47e556e Use ReachabilityCache to improve performance of loop detection
Together with the previous optimizations, this changes the time
complexity of suggestions be no longer proportional to the number of targets in the build graph.

To benchmark this, I changed the allowlist for `check_includes_strict`
to //*, then ran `gn check`.

Before: Outputs a few errors per second. Left it running for a few
minutes and I had no way to tell how long it was going to take, but
probably hours.
After: Outputs 295,000 errors in 22 seconds.

Change-Id: I4658aa7f612400eec44870c7dc962f176a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26242
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-07 23:04:29 -07:00
Matt Stark 28fc44708c Support target(target_type, name) in gn edit
Change-Id: Ic0b136bb5ddebb969411bc9ff56161bd6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26300
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-07 22:51:48 -07:00
Matt Stark 3163718ce7 Cache reverse dependencies for dependency exposure.
This is part of a larger process to improve the performance of
suggestions, but does not have change the time complexity until gn-review.googlesource.com/c/gn/+/26242 is submitted (benchmarks in that commit)

Change-Id: Ic0bd366f7b2639f16a9e633dde527cec6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26281
Commit-Queue: Matt Stark <msta@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
2026-09-07 17:38:02 -07:00
Matt Stark 8288110acd Skip attempting to resolve known files as module names.
This is part of a larger process to improve the performance of
suggestions, but does not have change the time complexity until gn-review.googlesource.com/c/gn/+/26242 is submitted (benchmarks in that commit)

Change-Id: I6e0067ca86f1e1afc6c8a828004011fd6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26260
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-07 17:27:53 -07:00
Matt Stark 5b0f883062 Cache file path -> target lookup in gn suggest.
This is part of a larger process to improve the performance of
suggestions, but does not have change the time complexity until gn-review.googlesource.com/c/gn/+/26242 is submitted (benchmarks in that commit)

Change-Id: Ia47be0e501d26be321ad2fdc8681750b6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26240
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-07 17:26:15 -07:00
Matt Stark 4f6a76b64b Make gn edit move idempotent.
`gn check --fix` currently outputs errors when it tries to apply the
same move twice. This fixes move to be a no-op when it's already
applied, similar to other commands.

Change-Id: Id0b8182d3fc8e9f9d6d308951f387f766a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26220
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-03 19:59:16 -07:00
Matt Stark 356ee8a865 When re-running build/gen.py from ninja, preserve environment variables.
This ensures that when you run:
```
CXX=PATH_TO_CXX build/gen.py ...
ninja -C out
```

PATH_TO_CXX is actually used when building

Change-Id: Ie9b7fb149bd37181e7e1ba76024a9a806a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26180
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-02 20:22:59 -07:00
Matt Stark 7e0a9f67f1 Implement pretty for several more types
Change-Id: I47ca96f5d8183de90cbd26e1386001536a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26201
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Matt Stark <msta@google.com>
2026-09-02 20:09:30 -07:00