{"size": 21475, "ext": "js", "max_stars_repo_path": "assets/js/page-GNStyleGuide.a561b37b.js", "max_stars_repo_name": "weharmony/weharmony.github.io", "max_stars_repo_stars_event_min_datetime": "2021-06-03T07:21:09.000Z", "max_stars_repo_stars_event_max_datetime": "2021-08-25T02:52:07.000Z", "max_issues_repo_path": "assets/js/page-GNStyleGuide.a561b37b.js", "max_issues_repo_name": "weharmony/weharmony.github.io", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "assets/js/page-GNStyleGuide.a561b37b.js", "max_forks_repo_name": "weharmony/weharmony.github.io", "max_forks_repo_forks_event_min_datetime": "2021-06-07T03:03:27.000Z", "max_forks_repo_forks_event_max_datetime": "2021-07-20T06:03:20.000Z"}
{"max_stars_count": 6, "max_issues_count": null, "max_forks_count": 2, "avg_line_length": 21475.0, "max_line_length": 21475, "alphanum_fraction": 0.6643538999}
(window.webpackJsonp=window.webpackJsonp||[]).push([[176],{1630:function(e,t,s){"use strict";s.r(t);var n=s(1),a=Object(n.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h1",{attrs:{id:"gn-style-guide"}},[e._v("GN Style Guide")]),e._v(" "),s("nav",{staticClass:"table-of-contents"},[s("ol",[s("li",[s("a",{attrs:{href:"#gn-style-guide"}},[e._v("GN Style Guide")]),s("ol",[s("li",[s("a",{attrs:{href:"#naming-and-ordering-within-the-file"}},[e._v("Naming and ordering within the file")]),s("ol",[s("li",[s("a",{attrs:{href:"#location-of-build-files"}},[e._v("Location of build files")])]),s("li",[s("a",{attrs:{href:"#targets"}},[e._v("Targets")])]),s("li",[s("a",{attrs:{href:"#configs"}},[e._v("Configs")])]),s("li",[s("a",{attrs:{href:"#example"}},[e._v("Example")])])])]),s("li",[s("a",{attrs:{href:"#ordering-within-a-target"}},[e._v("Ordering within a target")]),s("ol",[s("li",[s("a",{attrs:{href:"#conditions"}},[e._v("Conditions")])])])]),s("li",[s("a",{attrs:{href:"#formatting-and-indenting"}},[e._v("Formatting and indenting")]),s("ol",[s("li",[s("a",{attrs:{href:"#sources"}},[e._v("Sources")])]),s("li",[s("a",{attrs:{href:"#deps"}},[e._v("Deps")])]),s("li",[s("a",{attrs:{href:"#import"}},[e._v("Import")])])])]),s("li",[s("a",{attrs:{href:"#usage"}},[e._v("Usage")]),s("ol",[s("li",[s("a",{attrs:{href:"#source-sets-versus-static-libraries"}},[e._v("Source sets versus static libraries")])]),s("li",[s("a",{attrs:{href:"#components-versus-shared-libraries-versus-source-sets"}},[e._v("Components versus shared libraries versus source sets")])]),s("li",[s("a",{attrs:{href:"#loadable-modules-versus-shared-libraries"}},[e._v("Loadable modules versus shared libraries")])])])]),s("li",[s("a",{attrs:{href:"#build-arguments"}},[e._v("Build arguments")]),s("ol",[s("li",[s("a",{attrs:{href:"#scope"}},[e._v("Scope")])]),s("li",[s("a",{attrs:{href:"#type"}},[e._v("Type")])]),s("li",[s("a",{attrs:{href:"#naming-conventions"}},[e._v("Naming conventions")]),s("ol",[s("li",[s("a",{attrs:{href:"#variables"}},[e._v("Variables")])])])])])])])])])]),s("h2",{attrs:{id:"naming-and-ordering-within-the-file"}},[e._v("Naming and ordering within the file")]),e._v(" "),s("h3",{attrs:{id:"location-of-build-files"}},[e._v("Location of build files")]),e._v(" "),s("p",[e._v("It usually makes sense to have more build files closer to the code than\nfewer ones at the top level; this is in contrast with what we did with\nGYP. This makes things easier to find, and also makes the set of owners\nrequired for reviews smaller since changes are more focused to particular\nsubdirectories.")]),e._v(" "),s("h3",{attrs:{id:"targets"}},[e._v("Targets")]),e._v(" "),s("ul",[s("li",[e._v("Most BUILD files should have a target with the same name as the\ndirectory. This target should be the first target.")]),e._v(" "),s("li",[e._v("Other targets should be in some logical order -- usually\nmore important targets will be first, and unit tests will follow the\ncorresponding target. If there's no clear ordering, consider\nalphabetical order.")]),e._v(" "),s("li",[e._v('Test support libraries should be static libraries named "test_support".\nFor example, "//ui/compositor:test_support". Test support libraries should\ninclude as public deps the non-test-support version of the library\nso tests need only depend on the test_support target (rather than\nboth).')])]),e._v(" "),s("p",[e._v("Naming advice")]),e._v(" "),s("ul",[s("li",[e._v("Targets and configs should be named using lowercase with underscores\nseparating words, unless there is a strong reason to do otherwise.")]),e._v(" "),s("li",[e._v("Source sets, groups, and static libraries do not need globally unique names.\nPrefer to give such targets short, non-redundant names without worrying\nabout global uniqueness. For example, it looks much better to write a\ndependency as "),s("code",[e._v('"//mojo/public/bindings"')]),e._v(" rather than\n"),s("code",[e._v('"//mojo/public/bindings:mojo_bindings"')])]),e._v(" "),s("li",[e._v("Shared libraries (and by extension, components) must have globally unique\noutput names. Give such targets short non-unique names above, and then\nprovide a globally unique "),s("code",[e._v("output_name")]),e._v(" for that target.")]),e._v(" "),s("li",[e._v("Executables and tests should be given a globally unique name. Technically\nonly the output names must be unique, but since only the output names\nappear in the shell and on bots, it's much less confusing if the name\nmatches the other places the executable appears.")])]),e._v(" "),s("h3",{attrs:{id:"configs"}},[e._v("Configs")]),e._v(" "),s("ul",[s("li",[e._v("A config associated with a single target should be named the same as\nthe target with "),s("code",[e._v("_config")]),e._v(" following it.")]),e._v(" "),s("li",[e._v("A config should appear immediately before the corresponding target\nthat uses it.")])]),e._v(" "),s("h3",{attrs:{id:"example"}},[e._v("Example")]),e._v(" "),s("p",[e._v("Example for the "),s("code",[e._v("src/foo/BUILD.gn")]),e._v(" file:")]),e._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('# Copyright 2016 The Chromium Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license that can be\n# found in the LICENSE file.\n\n# Config for foo is named foo_config and immediately precedes it in the file.\nconfig("foo_config") {\n}\n\n# Target matching path name is the first target.\nexecutable("foo") {\n}\n\n# Test for foo follows it.\ntest("foo_unittests") {\n}\n\nconfig("bar_config") {\n}\n\nsource_set("bar") {\n}\n')])]),e._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[e._v("1")]),s("br"),s("span",{staticClass:"line-number"},[e._v("2")]),s("br"),s("span",{staticClass:"line-number"},[e._v("3")]),s("br"),s("span",{staticClass:"line-number"},[e._v("4")]),s("br"),s("span",{staticClass:"line-number"},[e._v("5")]),s("br"),s("span",{staticClass:"line-number"},[e._v("6")]),s("br"),s("span",{staticClass:"line-number"},[e._v("7")]),s("br"),s("span",{staticClass:"line-number"},[e._v("8")]),s("br"),s("span",{staticClass:"line-number"},[e._v("9")]),s("br"),s("span",{staticClass:"line-number"},[e._v("10")]),s("br"),s("span",{staticClass:"line-number"},[e._v("11")]),s("br"),s("span",{staticClass:"line-number"},[e._v("12")]),s("br"),s("span",{staticClass:"line-number"},[e._v("13")]),s("br"),s("span",{staticClass:"line-number"},[e._v("14")]),s("br"),s("span",{staticClass:"line-number"},[e._v("15")]),s("br"),s("span",{staticClass:"line-number"},[e._v("16")]),s("br"),s("span",{staticClass:"line-number"},[e._v("17")]),s("br"),s("span",{staticClass:"line-number"},[e._v("18")]),s("br"),s("span",{staticClass:"line-number"},[e._v("19")]),s("br"),s("span",{staticClass:"line-number"},[e._v("20")]),s("br"),s("span",{staticClass:"line-number"},[e._v("21")]),s("br")])]),s("h2",{attrs:{id:"ordering-within-a-target"}},[e._v("Ordering within a target")]),e._v(" "),s("ol",[s("li",[s("code",[e._v("output_name")]),e._v(" / "),s("code",[e._v("visibility")]),e._v(" / "),s("code",[e._v("testonly")])]),e._v(" "),s("li",[s("code",[e._v("sources")])]),e._v(" "),s("li",[s("code",[e._v("cflags")]),e._v(", "),s("code",[e._v("include_dirs")]),e._v(", "),s("code",[e._v("defines")]),e._v(", "),s("code",[e._v("configs")]),e._v(" etc. in whatever\norder makes sense to you.")]),e._v(" "),s("li",[s("code",[e._v("public_deps")])]),e._v(" "),s("li",[s("code",[e._v("deps")])])]),e._v(" "),s("h3",{attrs:{id:"conditions"}},[e._v("Conditions")]),e._v(" "),s("p",[e._v("Simple conditions affecting just one variable (e.g. adding a single\nsource or adding a flag for one particular OS) can go beneath the\nvariable they affect. More complicated conditions affecting more than\none thing should go at the bottom.")]),e._v(" "),s("p",[e._v("Conditions should be written to minimize the number of conditional blocks.")]),e._v(" "),s("h2",{attrs:{id:"formatting-and-indenting"}},[e._v("Formatting and indenting")]),e._v(" "),s("p",[e._v("GN contains a built-in code formatter which defines the formatting style.\nSome additional notes:")]),e._v(" "),s("ul",[s("li",[e._v("Variables are "),s("code",[e._v("lower_case_with_underscores")]),e._v(".")]),e._v(" "),s("li",[e._v("Comments should be complete sentences with periods at the end.")]),e._v(" "),s("li",[e._v("Compiler flags and such should always be commented with what they do\nand why the flag is needed.")])]),e._v(" "),s("h3",{attrs:{id:"sources"}},[e._v("Sources")]),e._v(" "),s("p",[e._v("Prefer to list sources only once. It is OK to conditionally include sources\nrather than listing them all at the top and then conditionally excluding them\nwhen they don't apply. Conditional inclusion is often clearer since a file is\nonly listed once and it's easier to reason about when reading.")]),e._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('  sources = [\n    "main.cc",\n  ]\n  if (use_aura) {\n    sources += [ "thing_aura.cc" ]\n  }\n  if (use_gtk) {\n    sources += [ "thing_gtk.cc" ]\n  }\n')])]),e._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[e._v("1")]),s("br"),s("span",{staticClass:"line-number"},[e._v("2")]),s("br"),s("span",{staticClass:"line-number"},[e._v("3")]),s("br"),s("span",{staticClass:"line-number"},[e._v("4")]),s("br"),s("span",{staticClass:"line-number"},[e._v("5")]),s("br"),s("span",{staticClass:"line-number"},[e._v("6")]),s("br"),s("span",{staticClass:"line-number"},[e._v("7")]),s("br"),s("span",{staticClass:"line-number"},[e._v("8")]),s("br"),s("span",{staticClass:"line-number"},[e._v("9")]),s("br")])]),s("h3",{attrs:{id:"deps"}},[e._v("Deps")]),e._v(" "),s("ul",[s("li",[e._v("Deps should be in alphabetical order.")]),e._v(" "),s("li",[e._v("Deps within the current file should be written first and not\nqualified with the file name (just "),s("code",[e._v(":foo")]),e._v(").")]),e._v(" "),s("li",[e._v("Other deps should always use fully-qualified path names unless\nrelative ones are required for some reason.")])]),e._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('  deps = [\n    ":a_thing",\n    ":mystatic",\n    "//foo/bar:other_thing",\n    "//foo/baz:that_thing",\n  ]\n')])]),e._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[e._v("1")]),s("br"),s("span",{staticClass:"line-number"},[e._v("2")]),s("br"),s("span",{staticClass:"line-number"},[e._v("3")]),s("br"),s("span",{staticClass:"line-number"},[e._v("4")]),s("br"),s("span",{staticClass:"line-number"},[e._v("5")]),s("br"),s("span",{staticClass:"line-number"},[e._v("6")]),s("br")])]),s("h3",{attrs:{id:"import"}},[e._v("Import")]),e._v(" "),s("p",[e._v("Use fully-qualified paths for imports:")]),e._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('import("//foo/bar/baz.gni")  # Even if this file is in the foo/bar directory\n')])]),e._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[e._v("1")]),s("br")])]),s("h2",{attrs:{id:"usage"}},[e._v("Usage")]),e._v(" "),s("h3",{attrs:{id:"source-sets-versus-static-libraries"}},[e._v("Source sets versus static libraries")]),e._v(" "),s("p",[e._v("Source sets and static libraries can be used interchangeably in most cases. If\nyou're unsure what to use, a source set is almost never wrong and is less likely\nto cause problems, but on a large project using the right kind of target can\nbe important, so you should know about the following tradeoffs.")]),e._v(" "),s("p",[e._v("Static libraries follow different linking rules. When a static library is\nincluded in a link, only the object files that contain unresolved symbols will\nbe brought into the build. Source sets result in every object file being added\nto the link line of the final binary.")]),e._v(" "),s("ul",[s("li",[s("p",[e._v("If you're eventually linking code into a component, shared library, or\nloadable module, you normally need to use source sets. This is because\nobject files with no symbols referenced from within the shared library will\nnot be linked into the final library at all. This omission will happen even\nif that object file has a symbol marked for export that targets dependent\non that shared library need. This will result in undefined symbols when\nlinking later targets.")])]),e._v(" "),s("li",[s("p",[e._v("Unit tests (and anything else with static initializers with side effects)\nmust use source sets. The gtest TEST macros create static initializers\nthat register the test. But since no code references symbols in the object\nfile, linking a test into a static library and then into a test executable\nmeans the tests will get stripped.")])]),e._v(" "),s("li",[s("p",[e._v("On some platforms, static libraries may involve duplicating all of the\ndata in the object files that comprise it. This takes more disk space and\nfor certain very large libraries in configurations with very large object\nfiles can cause internal limits on the size of static libraries to be\nexceeded. Source sets do not have this limitation. Some targets switch\nbetween source sets and static libraries depending on the build\nconfiguration to avoid this problem. Some platforms (or toolchains) may\nsupport something called \"thin archives\" which don't have this problem;\nbut you can't rely on this as a portable solution.")])]),e._v(" "),s("li",[s("p",[e._v("Source sets can have no sources, while static libraries will give strange\nplatform-specific errors if they have no sources. If a target has only\nheaders (for include checking purposes) or conditionally has no sources on\nsome platforms, use a source set.")])]),e._v(" "),s("li",[s("p",[e._v("In cases where a lot of the symbols are not needed for a particular link\n(this especially happens when linking test binaries), putting that code in\na static library can dramatically increase linking performance. This is\nbecause the object files not needed for the link are never considered in\nthe first place, rather than forcing the linker to strip the unused code\nin a later pass when nothing references it.")])])]),e._v(" "),s("h3",{attrs:{id:"components-versus-shared-libraries-versus-source-sets"}},[e._v("Components versus shared libraries versus source sets")]),e._v(" "),s("p",[e._v("A component is a Chrome template (rather than a built-in GN concept) that\nexpands either to a shared library or a static library / source set depending\non the value of the "),s("code",[e._v("is_component_build")]),e._v(" variable. This allows release builds\nto be linked statically in a large binary, but for developers to use shared\nlibraries for most operations. Chrome developers should almost always use\na component instead of shared library directly.")]),e._v(" "),s("p",[e._v("Much like the source set versus static library tradeoff, there's no hard\nand fast rule as to when you should use a component or not. Using\ncomponents can significantly speed up incremental builds by making\nlinking much faster, but they require you to have to think about which\nsymbols need to be exported from the target.")]),e._v(" "),s("h3",{attrs:{id:"loadable-modules-versus-shared-libraries"}},[e._v("Loadable modules versus shared libraries")]),e._v(" "),s("p",[e._v("A shared library will be listed on the link line of dependent targets and will\nbe loaded automatically by the operating system when the application starts\nand symbols automatically resolved. A loadable module will not be linked\ndirectly and the application must manually load it.")]),e._v(" "),s("p",[e._v("On Windows and Linux shared libraries and loadable modules result in the same\ntype of file ("),s("code",[e._v(".dll")]),e._v(" and "),s("code",[e._v(".so")]),e._v(", respectively). The only difference is in how\nthey are linked to dependent targets. On these platforms, having a "),s("code",[e._v("deps")]),e._v("\ndependency on a loadable module is the same as having a "),s("code",[e._v("data_deps")]),e._v("\n(non-linked) dependency on a shared library.")]),e._v(" "),s("p",[e._v("On Mac, these targets have different formats: a shared library will generate a\n"),s("code",[e._v(".dylib")]),e._v(" file and a loadable module will generate a "),s("code",[e._v(".so")]),e._v(" file.")]),e._v(" "),s("p",[e._v("Use loadable modules for things like plugins. In the case of plugin-like\nlibraries, it's good practice to use both a loadable module for the target type\n(even for platforms where it doesn't matter) and data deps for targets that\ndepend on it so it's clear from both places that how the library will be linked\nand loaded.")]),e._v(" "),s("h2",{attrs:{id:"build-arguments"}},[e._v("Build arguments")]),e._v(" "),s("h3",{attrs:{id:"scope"}},[e._v("Scope")]),e._v(" "),s("p",[e._v("Build arguments should be scoped to a unit of behavior, e.g. enabling a feature.\nTypically an argument would be declared in an imported file to share it with\nthe subset of the build that could make use of it.")]),e._v(" "),s("p",[e._v("Chrome has many legacy flags in "),s("code",[e._v("//build/config/features.gni")]),e._v(",\n"),s("code",[e._v("//build/config/ui.gni")]),e._v(". These locations are deprecated. Feature flags should\ngo along with the code for the feature. Many browser-level features can go\nsomewhere in "),s("code",[e._v("//chrome/")]),e._v(" without lower-level code knowing about it. Some\nUI environment flags can go into "),s("code",[e._v("//ui/")]),e._v(", and many flags can also go with\nthe corresponding code in "),s("code",[e._v("//components/")]),e._v(". You can write a "),s("code",[e._v(".gni")]),e._v(" file in\ncomponents and have build files in chrome or content import it if necessary.")]),e._v(" "),s("p",[e._v("The way to think about things in the "),s("code",[e._v("//build")]),e._v(" directory is that this is\nDEPSed into various projects like V8 and WebRTC. Build flags specific to\ncode outside of the build directory shouldn't be in the build directory, and\nV8 shouldn't get feature defines for Chrome features.")]),e._v(" "),s("p",[e._v("New feature defines should use the buildflag system. See\n"),s("code",[e._v("//build/buildflag_header.gni")]),e._v(" which allows preprocessor defines to be\nmodularized without many of the disadvantages that made us use global defines\nin the past.")]),e._v(" "),s("h3",{attrs:{id:"type"}},[e._v("Type")]),e._v(" "),s("p",[e._v("Arguments support all the "),s("RouterLink",{attrs:{to:"/openharmony/compile/gn/docs/language.html#Language"}},[e._v("GN language types")]),e._v(".")],1),e._v(" "),s("p",[e._v("In the vast majority of cases "),s("code",[e._v("boolean")]),e._v(" is the preferred type, since most\narguments are enabling or disabling features or includes.")]),e._v(" "),s("p",[s("code",[e._v("String")]),e._v("s are typically used for filepaths. They are also used for enumerated\ntypes, though "),s("code",[e._v("integer")]),e._v("s are sometimes used as well.")]),e._v(" "),s("h3",{attrs:{id:"naming-conventions"}},[e._v("Naming conventions")]),e._v(" "),s("p",[e._v("While there are no hard and fast rules around argument naming there are\nmany common conventions. If you ever want to see the current list of argument\nnames and default values for your current checkout use\n"),s("code",[e._v("gn args out/Debug --list --short")]),e._v(".")]),e._v(" "),s("p",[s("code",[e._v("use_foo")]),e._v(" - indicates dependencies or major codepaths to include (e.g.\n"),s("code",[e._v("use_open_ssl")]),e._v(", "),s("code",[e._v("use_ozone")]),e._v(", "),s("code",[e._v("use_cups")]),e._v(")")]),e._v(" "),s("p",[s("code",[e._v("enable_foo")]),e._v(" - indicates feature or tools to be enabled (e.g.\n"),s("code",[e._v("enable_google_now")]),e._v(", "),s("code",[e._v("enable_nacl")]),e._v(", "),s("code",[e._v("enable_remoting")]),e._v(", "),s("code",[e._v("enable_pdf")]),e._v(")")]),e._v(" "),s("p",[s("code",[e._v("disable_foo")]),e._v(" - "),s("em",[e._v("NOT")]),e._v(" recommended, use "),s("code",[e._v("enable_foo")]),e._v(" instead with swapped default\nvalue")]),e._v(" "),s("p",[s("code",[e._v("is_foo")]),e._v(" - usually a global state descriptor (e.g. "),s("code",[e._v("is_chrome_branded")]),e._v(",\n"),s("code",[e._v("is_desktop_linux")]),e._v("); poor choice for non-globals")]),e._v(" "),s("p",[s("code",[e._v("foo_use_bar")]),e._v(" - prefixes can be used to indicate a limited scope for an argument\n(e.g. "),s("code",[e._v("rtc_use_h264")]),e._v(", "),s("code",[e._v("v8_use_snapshot")]),e._v(")")]),e._v(" "),s("h4",{attrs:{id:"variables"}},[e._v("Variables")]),e._v(" "),s("p",[e._v("Prefix top-level local variables within "),s("code",[e._v(".gni")]),e._v(" files with an underscore. This\nprefix causes variables to be unavailable to importing scripts.")]),e._v(" "),s("div",{staticClass:"language- line-numbers-mode"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("_this_var_will_not_be_exported = 1\nbut_this_one_will = 2\n")])]),e._v(" "),s("div",{staticClass:"line-numbers-wrapper"},[s("span",{staticClass:"line-number"},[e._v("1")]),s("br"),s("span",{staticClass:"line-number"},[e._v("2")]),s("br")])])])}),[],!1,null,null,null);t.default=a.exports}}]);