Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(630)

Unified Diff: tools/gn/docs/reference.md

Issue 1820493002: Add more documentation for GN header checking (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/gn/docs/reference.md
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 6edacfce5c714010a7656ad4c8f18a1454189c1f..f136a97b336024b47e16124c5f22d67bc6f65e93 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -281,6 +281,9 @@
## **gn check <out_dir> [<label_pattern>] [\--force]**
```
+ GN's include header checker validates that the includes for C-like
+ source files match the build dependency graph.
+
"gn check" is the same thing as "gn gen" with the "--check" flag
except that this command does not write out any build files. It's
intended to be an easy way to manually trigger include file checking.
@@ -290,19 +293,102 @@
only those matching targets will be checked. See
"gn help label_pattern" for details.
+```
+
+### **Command-specific switches**
+
+```
+ --force
+ Ignores specifications of "check_includes = false" and checks
+ all target's files that match the target label.
+
+```
+
+### **What gets checked**
+
+```
The .gn file may specify a list of targets to be checked. Only these
targets will be checked if no label_pattern is specified on the
command line. Otherwise, the command-line list is used instead. See
"gn help dotfile".
+ Targets can opt-out from checking with "check_includes = false"
+ (see "gn help check_includes").
+
+ For targets being checked:
+
+ - GN opens all C-like source files in the targets to be checked and
+ scans the top for includes.
+
+ - Includes with a "nogncheck" annotation are skipped (see
+ "gn help nogncheck").
+
+ - Only includes using "quotes" are checked. <brackets> are assumed
+ to be system includes.
+
+ - Include paths are assumed to be relative to either the source root
+ or the "root_gen_dir" and must include all the path components.
+ (It might be nice in the future to incorporate GN's knowledge of
+ the include path to handle other include styles.)
+
+ - GN does not run the preprocessor so will not understand
+ conditional includes.
+
+ - Only includes matching known files in the build are checked:
+ includes matching unknown paths are ignored.
+
+ For an include to be valid:
+
+ - The included file must be in the current target, or there must
+ be a path following only public dependencies to a target with the
+ file in it ("gn path" is a good way to diagnose problems).
+
+ - There can be multiple targets with an included file: only one
+ needs to be valid for the include to be allowed.
+
+ - If there are only "sources" in a target, all are considered to
+ be public and can be included by other targets with a valid public
+ dependency path.
+
+ - If a target lists files as "public", only those files are
+ able to be included by other targets. Anything in the sources
+ will be considered private and will not be includable regardless
+ of dependency paths.
+
+ - Ouptuts from actions are treated like public sources on that
+ target.
+
+ - A target can include headers from a target that depends on it
+ if the other target is annotated accordingly. See
+ "gn help allow_circular_includes_from".
+
```
-### **Command-specific switches**
+### **Advice on fixing problems**
```
- --force
- Ignores specifications of "check_includes = false" and checks
- all target's files that match the target label.
+ If you have a third party project that uses relative includes,
+ it's generally best to exclude that target from checking altogether
+ via "check_includes = false".
+
+ If you have conditional includes, make sure the build conditions
+ and the preprocessor conditions match, and annotate the line with
+ "nogncheck" (see "gn help nogncheck" for an example).
+
+ If two targets are hopelessly intertwined, use the
+ "allow_circular_includes_from" annotation. Ideally each should have
+ identical dependencies so configs inherited from those dependencies
+ are consistent (see "gn help allow_circular_includes_from").
+
+ If you have a standalone header file or files that need to be shared
+ between a few targets, you can consider making a source_set listing
+ only those headers as public sources. With only header files, the
+ source set will be a no-op from a build perspective, but will give a
+ central place to refer to those headers. That source set's files
+ will still need to pass "gn check" in isolation.
+
+ In rare cases it makes sense to list a header in more than one
+ target if it could be considered conceptually a member of both.
```
@@ -494,6 +580,16 @@
```
Formats .gn file to a standard format.
+ The contents of some lists ('sources', 'deps', etc.) will be sorted to
+ a canonical order. To suppress this, you can add a comment of the form
+ "# NOSORT" immediately preceeding the assignment. e.g.
+
+ # NOSORT
+ sources = [
+ "z.cc",
+ "a.cc",
+ ]
+
```
### **Arguments**
@@ -3503,25 +3599,57 @@
These targets will be permitted to include headers from the current
target despite the dependency going in the opposite direction.
+ When you use this, both targets must be included in a final binary
+ for it to link. To keep linker errors from happening, it is good
+ practice to have all external dependencies depend only on one of
+ the two targets, and to set the visibility on the other to enforce
+ this. Thus the targets will always be linked together in any output.
+
```
-### **Tedious exposition**
+### **Details**
```
Normally, for a file in target A to include a file from target B,
A must list B as a dependency. This invariant is enforced by the
- "gn check" command (and the --check flag to "gn gen").
+ "gn check" command (and the --check flag to "gn gen" -- see
+ "gn help check").
Sometimes, two targets might be the same unit for linking purposes
(two source sets or static libraries that would always be linked
- together in a final executable or shared library). In this case,
- you want A to be able to include B's headers, and B to include A's
- headers.
+ together in a final executable or shared library) and they each
+ include headers from the other: you want A to be able to include B's
+ headers, and B to include A's headers. This is not an ideal situation
+ but is sometimes unavoidable.
This list, if specified, lists which of the dependencies of the
current target can include header files from the current target.
That is, if A depends on B, B can only include headers from A if it is
- in A's allow_circular_includes_from list.
+ in A's allow_circular_includes_from list. Normally includes must
+ follow the direction of dependencies, this flag allows them to go
+ in the opposite direction.
+
+```
+
+### **Danger**
+
+```
+ In the above example, A's headers are likely to include headers from
+ A's dependencies. Those dependencies may have public_configs that
+ apply flags, defines, and include paths that make those headers work
+ properly.
+
+ With allow_circular_includes_from, B can include A's headers, and
+ transitively from A's dependencies, without having the dependencies
+ that would bring in the public_configs those headers need. The result
+ may be errors or inconsistent builds.
+
+ So when you use allow_circular_includes_from, make sure that any
+ compiler settings, flags, and include directories are the same between
+ both targets (consider putting such things in a shared config they can
+ both reference). Make sure the dependencies are also the same (you
+ might consider a group to collect such dependencies they both
+ depend on).
```
@@ -3529,11 +3657,21 @@
```
source_set("a") {
- deps = [ ":b", ":c" ]
+ deps = [ ":b", ":a_b_shared_deps" ]
allow_circular_includes_from = [ ":b" ]
...
}
+ source_set("b") {
+ deps = [ ":a_b_shared_deps" ]
+ # Sources here can include headers from a despite lack of deps.
+ ...
+ }
+
+ group("a_b_shared_deps") {
+ public_deps = [ ":c" ]
+ }
+
```
## **args**: Arguments passed to an action.
@@ -3880,29 +4018,12 @@
This does not affect other targets that depend on the current target,
it just skips checking the includes of the current target's files.
-```
-
-### **Controlling includes individually**
-
-```
- If only certain includes are problematic, you can annotate them
- individually rather than disabling header checking on an entire
- target. Add the string "nogncheck" to the include line:
+ If there are a few conditionally included headers that trip up
+ checking, you can exclude headers individually by annotating them with
+ "nogncheck" (see "gn help nogncheck").
- #include "foo/something_weird.h" // nogncheck (bug 12345)
-
- It is good form to include a reference to a bug (if the include is
- improper, or some other comment expressing why the header checker
- doesn't work for this particular case.
-
- The most common reason to need "nogncheck" is conditional includes.
- The header checker does not understand the preprocessor, so may flag
- some includes as improper even if the dependencies and #defines are
- always matched correctly:
-
- #if defined(ENABLE_DOOM_MELON)
- #include "doom_melon/beam_controller.h" // nogncheck
- #endif
+ The topic "gn help check" has general information on how checking
+ works and advice on how to pass a check in problematic cases.
```
@@ -3933,6 +4054,9 @@
for all dependencies in one complete package. Since GN does not unpack
static libraries to forward their contents up the dependency chain,
it is an error for complete static libraries to depend on other static
+
+ In rare cases it makes sense to list a header in more than one
+ target if it could be considered conceptually a member of both.
libraries.
```
@@ -5371,6 +5495,47 @@
```
+## **nogncheck**: Skip an include line from checking.
+
+```
+ GN's header checker helps validate that the includes match the build
+ dependency graph. Sometimes an include might be conditional or
+ otherwise problematic, but you want to specifically allow it. In this
+ case, it can be whitelisted.
+
+ Include lines containing the substring "nogncheck" will be excluded
+ from header checking. The most common case is a conditional include:
+
+ #if defined(ENABLE_DOOM_MELON)
+ #include "tools/doom_melon/doom_melon.h" // nogncheck
+ #endif
+
+ If the build file has a conditional dependency on the corresponding
+ target that matches the conditional include, everything will always
+ link correctly:
+
+ source_set("mytarget") {
+ ...
+ if (enable_doom_melon) {
+ defines = [ "ENABLE_DOOM_MELON" ]
+ deps += [ "//tools/doom_melon" ]
+ }
+
+ But GN's header checker does not understand preprocessor directives,
+ won't know it matches the build dependencies, and will flag this
+ include as incorrect when the condition is false.
+
+```
+
+### **More information**
+
+```
+ The topic "gn help check" has general information on how checking
+ works and advice on fixing problems. Targets can also opt-out of
+ checking, see "gn help check_includes".
+
+
+```
## **Runtime dependencies**
```
« no previous file with comments | « tools/gn/commands.h ('k') | tools/gn/header_checker.cc » ('j') | tools/gn/variables.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698