From: Ricardo Ribalda Delgado Date: Mon, 21 Mar 2022 06:51:44 +0000 (+0000) Subject: Import generate-ninja_0.0~git20220314.bd99dbf.orig.tar.gz X-Git-Tag: archive/raspbian/0.0_git20220314.bd99dbf-1+rpi1^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=8d8131a935cd73fd31bf011039bb704899c24135;p=generate-ninja.git Import generate-ninja_0.0~git20220314.bd99dbf.orig.tar.gz [dgit import orig generate-ninja_0.0~git20220314.bd99dbf.orig.tar.gz] --- 8d8131a935cd73fd31bf011039bb704899c24135 diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b17a52a --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Chromium +Standard: Cpp11 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2491fdf --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*.py] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c20aff --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +*.bak +*.gypcmd +*.mk +*.ncb +*.opensdf +*.orig +*.pdb +*.props +*.pyc +*.pyproj +*.rules +*.sdf +*.sln +*.sublime-project +*.sublime-workspace +*.suo +*.targets +*.user +*.vc.opendb +*.vcproj +*.vcxproj +*.vcxproj.filters +*.vpj +*.vpw +*.vpwhistu +*.vtg +*.xcodeproj +*.xcworkspace +*.VC.db +*_proto.xml +*_proto_cpp.xml +*~ +!Android.mk +.*.sw? +.DS_Store +.cipd +.classpath +.cproject +.gdb_history +.gdbinit +.landmines +.metadata +.project +.pydevproject +.recipe_deps +.checkstyle +cscope.* +out/ +GPATH +GRTAGS +GSYMS +GTAGS +Session.vim +tags +Thumbs.db +# Settings directories for eclipse +/.externalToolBuilders/ +/.settings/ +/.vs/ +# Visual Studio Code +/.vscode/ +/_out diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..1161de6 --- /dev/null +++ b/.mailmap @@ -0,0 +1,20 @@ +# This file allows mapping several author and committer email addresses and +# names to a single canonical one for `git shortlog`, `git log --author`, +# or `git check-mailmap`. +# +# For example, if you commit as `random.person@example.com` but sometimes use +# "Rañdom Person" and sometimes "Random Person" as name and you want the former +# to be your canonical name, add +# +# Rañdom Person +# +# If you commit as both `random.person@example.com` and `ranp@example.com` and +# you want the former to be your canonical email address, add +# +# +# +# Combinations of both are possible too, see +# https://git-scm.com/docs/gitmailmap for format details. + +Nico Weber +Nico Weber diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 0000000..de0c6a7 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,2 @@ +[style] +based_on_style = chromium diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..45cedd7 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,52 @@ +# Names should be added to this file with this pattern: +# +# For individuals: +# Name +# +# For organizations: +# Organization +# +# See python fnmatch module documentation for more information. + +Google Inc. <*@google.com> +HyperConnect Inc. <*@hpcnt.com> +IBM Inc. <*@*.ibm.com> +Loongson Technology Corporation Limited. <*@loongson.cn> +MIPS Technologies, Inc. <*@mips.com> +NVIDIA Corporation <*@nvidia.com> +Opera Software ASA <*@opera.com> +Red Hat Inc. <*@redhat.com> +The Chromium Authors <*@chromium.org> +Vewd Software AS <*@vewd.com> +Vivaldi Technologies AS <*@vivaldi.com> +Yandex LLC <*@yandex-team.ru> + +Alexis Menard +Alfredo Mazzinghi +Andrew Boyarshin +Anuj Kumar Sharma +DanCraft99 +Gergely Nagy +Ilia K +Ivan Naydonov +Joe Armstrong +Julien Brianceau +Kal Conley +Kamil Rytarowski +Ma Aiguo +Martijn Croonen +Matej Knopp +Michael Gilbert +Milko Leporis +Mohan Reddy +Raphael Kubo da Costa +Riku Voipio +Saikrishna Arcot +Stephan Hartmann +Tim Niederhausen +Tomas Popela +Tripta Gupta +Wink Saville +Yuriy Taraday +Oleksandr Motsok +Ihor Karavan diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a32e00c --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..0571570 --- /dev/null +++ b/OWNERS @@ -0,0 +1,4 @@ +brettw@chromium.org +phosek@chromium.org +scottmg@chromium.org +sdefresne@chromium.org diff --git a/README.md b/README.md new file mode 100644 index 0000000..75821c6 --- /dev/null +++ b/README.md @@ -0,0 +1,218 @@ +# GN + +GN is a meta-build system that generates build files for +[Ninja](https://ninja-build.org). + +Related resources: + + * Documentation in [docs/](https://gn.googlesource.com/gn/+/main/docs/). In + particular: + * [GN quick start guide](https://gn.googlesource.com/gn/+/main/docs/quick_start.md). + * [Frequently asked questions](https://gn.googlesource.com/gn/+/main/docs/faq.md) + * [Reference](https://gn.googlesource.com/gn/+/main/docs/reference.md) + (all builtin help converted to a single file). + * An introductory [presentation](https://docs.google.com/presentation/d/15Zwb53JcncHfEwHpnG_PoIbbzQ3GQi_cpujYwbpcbZo/edit?usp=sharing). + * The [mailing list](https://groups.google.com/a/chromium.org/forum/#!forum/gn-dev). + * The [bug database](https://bugs.chromium.org/p/gn/issues/list). + +## What GN is for + +GN is currently used as the build system for Chromium, Fuchsia, and related +projects. Some strengths of GN are: + + * It is designed for large projects and large teams. It scales efficiently to + many thousands of build files and tens of thousands of source files. + + * It has a readable, clean syntax. Once a build is set-up, it is generally + easy for people with no backround in GN to make basic edits to the build. + + * It is designed for multi-platform projects. It can cleanly express many + complicated build variants across different platforms. A single build + invocation can target multiple platforms. + + * It supports multiple parallel output directories, each with their own + configuration. This allows a developer to maintain builds targeting debug, + release, or different platforms in parallel without forced rebuilds when + switching. + + * It has a focus on correctness. GN checks for the correct dependencies, + inputs, and outputs to the extent possible, and has a number of tools to + allow developers to ensure the build evolves as desired (for example, `gn + check`, `testonly`, `assert_no_deps`). + + * It has comprehensive build-in help available from the command-line. + +Although small projects successfully use GN, the focus on large projects has +some disadvanages: + + * GN has the goal of being minimally expressive. Although it can be quite + flexible, a design goal is to direct members of a large team (who may not + have much knowledge about the build) down an easy-to-understand, well-lit + path. This isn't necessarily the correct trade-off for smaller projects. + + * The minimal build configuration is relatively heavyweight. There are several + files required and the exact way all compilers are linkers are run must be + specified in the configuration (see "Examples" below). There is no default + compiler configuration. + + * It is not easily composable. GN is designed to compile a single large + project with relatively uniform settings and rules. Projects like Chromium + do bring together multiple repositories from multiple teams, but the + projects must agree on some conventions in the build files to allow this to + work. + + * GN is designed with the expectation that the developers building a project + want to compile an identical configuration. So while builds can integrate + with the user's environment like the CXX and CFLAGS variables if they want, + this is not the default and most project's builds do not do this. The result + is that many GN projects do not integrate well with other systems like + ebuild. + + * There is no simple release scheme (see "Versioning and distribution" below). + Projects are expected to manage the version of GN they require. Getting an + appropriate GN binary can be a hurdle for new contributors to a project. + Since GN is relatively uncommon, it can be more difficult to find + information and examples. + +GN can generate Ninja build files for C, C++, Rust, Objective C, and Swift +source on most popular platforms. Other languages can be compiled using the +general "action" rules which are executed by Python or another scripting +language (Google does this to compile Java and Go). But because this is not as +clean, generally GN is only used when the bulk of the build is in one of the +main built-in languages. + +## Getting a binary + +You can download the latest version of GN binary for +[Linux](https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest), +[macOS](https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-amd64/+/latest) and +[Windows](https://chrome-infra-packages.appspot.com/dl/gn/gn/windows-amd64/+/latest) +from Google's build infrastructure (see "Versioning and distribution" below for +how this is expected to work). + +Alternatively, you can build GN from source with a C++17 compiler: + + git clone https://gn.googlesource.com/gn + cd gn + python build/gen.py + ninja -C out + # To run tests: + out/gn_unittests + +On Windows, it is expected that `cl.exe`, `link.exe`, and `lib.exe` can be found +in `PATH`, so you'll want to run from a Visual Studio command prompt, or +similar. + +On Linux, Mac and z/OS, the default compiler is `clang++`, a recent version is +expected to be found in `PATH`. This can be overridden by setting `CC`, `CXX`, +and `AR`. + +On z/OS, building GN requires [ZOSLIB](https://github.com/ibmruntimes/zoslib) to be +installed, as described at that URL. When building with `build/gen.py`, use the option +`--zoslib-dir` to specify the path to [ZOSLIB](https://github.com/ibmruntimes/zoslib): + + cd gn + python build/gen.py --zoslib-dir /path/to/zoslib + +By default, if you don't specify `--zoslib-dir`, `gn/build/gen.py` expects to find +`zoslib` directory under `gn/third_party/`. + +## Examples + +There is a simple example in [examples/simple_build](examples/simple_build) +directory that is a good place to get started with the minimal configuration. + +To build and run the simple example with the default gcc compiler: + + cd examples/simple_build + ../../out/gn gen -C out + ninja -C out + ./out/hello + +For a maximal configuration see the Chromium setup: + * [.gn](https://cs.chromium.org/chromium/src/.gn) + * [BUILDCONFIG.gn](https://cs.chromium.org/chromium/src/build/config/BUILDCONFIG.gn) + * [Toolchain setup](https://cs.chromium.org/chromium/src/build/toolchain/) + * [Compiler setup](https://cs.chromium.org/chromium/src/build/config/compiler/BUILD.gn) + +and the Fuchsia setup: + * [.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/.gn) + * [BUILDCONFIG.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/config/BUILDCONFIG.gn) + * [Toolchain setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/toolchain/) + * [Compiler setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/config/BUILD.gn) + +## Reporting bugs + +If you find a bug, you can see if it is known or report it in the [bug +database](https://bugs.chromium.org/p/gn/issues/list). + +## Sending patches + +GN uses [Gerrit](https://www.gerritcodereview.com/) for code review hosted at +[gn-review.googlesource.com](https://gn-review.googlesource.com/). The short +version of how to patch is: + + Register at https://gn-review.googlesource.com. + + ... edit code ... + ninja -C out && out/gn_unittests + +Then, to upload a change for review: + + git commit + git push origin HEAD:refs/for/main + +The first time you do this you'll get an error from the server about a missing +change-ID. Follow the directions in the error message to install the change-ID +hook and run `git commit --amend` to apply the hook to the current commit. + +When revising a change, use: + + git commit --amend + git push origin HEAD:refs/for/main + +which will add the new changes to the existing code review, rather than creating +a new one. + +We ask that all contributors +[sign Google's Contributor License Agreement](https://cla.developers.google.com/) +(either individual or corporate as appropriate, select 'any other Google +project'). + +## Community + +You may ask questions and follow along with GN's development on Chromium's +[gn-dev@](https://groups.google.com/a/chromium.org/forum/#!forum/gn-dev) +Google Group. + +## Versioning and distribution + +Most open-source projects are designed to use the developer's computer's current +toolchain such as compiler, linker, and build tool. But the large +centrally controlled projects that GN is designed for typically want a more +hermetic environment. They will ensure that developers are using a specific +compatible toolchain that is versioned with the code. + +As a result, GN expects that the project choose the appropriate version of GN +that will work with each version of the project. There is no "current stable +version" of GN that is expected to work for all projects. + +As a result, the GN developers do not maintain any packages in any of the +various packaging systems (Debian, RedHat, HomeBrew, etc.). Some of these +systems to have GN packages, but they are maintained by third parties and you +should use them at your own risk. Instead, we recommend you refer your checkout +tooling to download binaries for a specific hash from [Google's build +infrastructure](https://chrome-infra-packages.appspot.com/p/gn/gn) or compile +your own. + +GN does not guarantee the backwards-compatibility of new versions and has no +branches or versioning scheme beyond the sequence of commits to the main git +branch (which is expected to be stable). + +In practice, however, GN is very backwards-compatible. The core functionality +has been stable for many years and there is enough GN code at Google alone to +make non-backwards-compatible changes very difficult, even if they were +desirable. + +There have been discussions about adding a versioning scheme with some +guarantees about backwards-compatibility, but nothing has yet been implemented. diff --git a/build/build_aix.ninja.template b/build/build_aix.ninja.template new file mode 100644 index 0000000..7d696b0 --- /dev/null +++ b/build/build_aix.ninja.template @@ -0,0 +1,13 @@ +rule cxx + command = $cxx -MMD -MF $out.d $includes $cflags -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcsT $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out $in $libs $solibs + description = LINK $out diff --git a/build/build_haiku.ninja.template b/build/build_haiku.ninja.template new file mode 100644 index 0000000..ab117fb --- /dev/null +++ b/build/build_haiku.ninja.template @@ -0,0 +1,13 @@ +rule cxx + command = $cxx -MMD -MF $out.d $includes $cflags -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcsT $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out -Wl,--start-group $in $libs -Wl,--end-group $solibs + description = LINK $out diff --git a/build/build_linux.ninja.template b/build/build_linux.ninja.template new file mode 100644 index 0000000..ab117fb --- /dev/null +++ b/build/build_linux.ninja.template @@ -0,0 +1,13 @@ +rule cxx + command = $cxx -MMD -MF $out.d $includes $cflags -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcsT $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out -Wl,--start-group $in $libs -Wl,--end-group $solibs + description = LINK $out diff --git a/build/build_mac.ninja.template b/build/build_mac.ninja.template new file mode 100644 index 0000000..8d75a3c --- /dev/null +++ b/build/build_mac.ninja.template @@ -0,0 +1,13 @@ +rule cxx + command = $cxx -MMD -MF $out.d $includes $cflags -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcs $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out $in $solibs $libs + description = LINK $out diff --git a/build/build_openbsd.ninja.template b/build/build_openbsd.ninja.template new file mode 100644 index 0000000..8466900 --- /dev/null +++ b/build/build_openbsd.ninja.template @@ -0,0 +1,13 @@ +rule cxx + command = $cxx -MMD -MF $out.d $includes $cflags -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcs $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out -Wl,--start-group $in $libs -Wl,--end-group $solibs + description = LINK $out diff --git a/build/build_win.ninja.template b/build/build_win.ninja.template new file mode 100644 index 0000000..f1d1775 --- /dev/null +++ b/build/build_win.ninja.template @@ -0,0 +1,12 @@ +rule cxx + command = $cxx /nologo /showIncludes /FC $includes $cflags /c $in /Fo$out + description = CXX $out + deps = msvc + +rule alink_thin + command = $ar /nologo /ignore:4221 $libflags /OUT:$out $in + description = LIB $out + +rule link + command = $ld /nologo $ldflags /OUT:$out /PDB:$out.pdb $in $solibs $libs + description = LINK $out diff --git a/build/build_zos.ninja.template b/build/build_zos.ninja.template new file mode 100644 index 0000000..f9f0c96 --- /dev/null +++ b/build/build_zos.ninja.template @@ -0,0 +1,13 @@ +rule cxx + command = $cxx $includes $cflags -c $in -o $out + description = CXX $out + depfile = $out.d + deps = gcc + +rule alink_thin + command = rm -f $out && $ar rcsT $out $in + description = AR $out + +rule link + command = $ld $ldflags -o $out $in $libs $solibs + description = LINK $out diff --git a/build/full_test.py b/build/full_test.py new file mode 100755 index 0000000..46ba2de --- /dev/null +++ b/build/full_test.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import shutil +import subprocess +import sys +import timeit + + +IS_WIN = sys.platform.startswith('win') + + +def RemoveDir(d): + if os.path.isdir(d): + shutil.rmtree(d) + + +def Trial(gn_path_to_use, save_out_dir=None): + bin_path = os.path.join('out', 'gntrial') + if not os.path.isdir(bin_path): + os.makedirs(bin_path) + gn_to_run = os.path.join(bin_path, 'gn' + ('.exe' if IS_WIN else '')) + shutil.copy2(gn_path_to_use, gn_to_run) + comp_dir = os.path.join('out', 'COMP') + subprocess.check_call([gn_to_run, 'gen', comp_dir, '-q', '--check']) + if save_out_dir: + RemoveDir(save_out_dir) + shutil.move(comp_dir, save_out_dir) + + +def main(): + if len(sys.argv) < 3 or len(sys.argv) > 4: + print 'Usage: full_test.py /chrome/tree/at/762a25542878 rel_gn_path [clean]' + return 1 + + if len(sys.argv) == 4: + RemoveDir('out') + + subprocess.check_call([sys.executable, os.path.join('build', 'gen.py')]) + subprocess.check_call(['ninja', '-C', 'out']) + subprocess.check_call([os.path.join('out', 'gn_unittests')]) + orig_dir = os.getcwd() + + in_chrome_tree_gn = sys.argv[2] + our_gn = os.path.join(orig_dir, 'out', 'gn' + ('.exe' if IS_WIN else '')) + + os.chdir(sys.argv[1]) + + # Check in-tree vs. ours. Uses: + # - Chromium tree at 762a25542878 in argv[1] (this can be off by a bit, but + # is roughly when GN was moved out of the Chrome tree, so matches in case GN + # semantics/ordering change after that.) + # - relative path to argv[1] built gn binary in argv[2] + + # First, do a comparison to make sure the output between the two gn binaries + # actually matches. + print 'Confirming output matches...' + dir_a = os.path.join('out', 'a') + dir_b = os.path.join('out', 'b') + Trial(in_chrome_tree_gn, dir_a) + Trial(our_gn, dir_b) + subprocess.check_call(['diff', '-r', dir_a, dir_b]) + + # Then, some time trials. + TRIALS = 5 + print 'Comparing performance... (takes a while)' + time_a = timeit.timeit('Trial("%s")' % in_chrome_tree_gn, number=TRIALS, + setup='from __main__ import Trial') + time_b = timeit.timeit('Trial("%s")' % our_gn, number=TRIALS, + setup='from __main__ import Trial') + print 'In-tree gn avg: %.3fs' % (time_a / TRIALS) + print 'Our gn avg: %.3fs' % (time_b / TRIALS) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/gen.py b/build/gen.py new file mode 100755 index 0000000..5fd5783 --- /dev/null +++ b/build/gen.py @@ -0,0 +1,886 @@ +#!/usr/bin/env python3 +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Generates build.ninja that will build GN.""" + +import argparse +import os +import platform +import re +import shlex +import subprocess +import sys + +# IMPORTANT: This script is also executed as python2 on +# GN's CI builders. + +try: # py3 + from shlex import quote as shell_quote +except ImportError: # py2 + from pipes import quote as shell_quote + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +REPO_ROOT = os.path.dirname(SCRIPT_DIR) + +class Platform(object): + """Represents a host/target platform.""" + def __init__(self, platform): + self._platform = platform + if self._platform is not None: + return + self._platform = sys.platform + if self._platform.startswith('linux'): + self._platform = 'linux' + elif self._platform.startswith('darwin'): + self._platform = 'darwin' + elif self._platform.startswith('mingw'): + self._platform = 'mingw' + elif self._platform.startswith('msys'): + self._platform = 'msys' + elif self._platform.startswith('win'): + self._platform = 'msvc' + elif self._platform.startswith('aix'): + self._platform = 'aix' + elif self._platform.startswith('fuchsia'): + self._platform = 'fuchsia' + elif self._platform.startswith('freebsd'): + self._platform = 'freebsd' + elif self._platform.startswith('netbsd'): + self._platform = 'netbsd' + elif self._platform.startswith('openbsd'): + self._platform = 'openbsd' + elif self._platform.startswith('haiku'): + self._platform = 'haiku' + elif self._platform.startswith('sunos'): + self._platform = 'solaris' + elif self._platform.startswith('zos'): + self._platform = 'zos' + + @staticmethod + def known_platforms(): + return ['linux', 'darwin', 'mingw', 'msys', 'msvc', 'aix', 'fuchsia', 'freebsd', 'netbsd', 'openbsd', 'haiku', 'solaris', 'zos'] + + def platform(self): + return self._platform + + def is_linux(self): + return self._platform == 'linux' + + def is_mingw(self): + return self._platform == 'mingw' + + def is_msys(self): + return self._platform == 'msys' + + def is_msvc(self): + return self._platform == 'msvc' + + def is_windows(self): + return self.is_mingw() or self.is_msvc() + + def is_darwin(self): + return self._platform == 'darwin' + + def is_aix(self): + return self._platform == 'aix' + + def is_haiku(self): + return self._platform == 'haiku' + + def is_solaris(self): + return self._platform == 'solaris' + + def is_posix(self): + return self._platform in ['linux', 'freebsd', 'darwin', 'aix', 'openbsd', 'haiku', 'solaris', 'msys', 'netbsd'] + + def is_zos(self): + return self._platform == 'zos' + +class ArgumentsList: + """Helper class to accumulate ArgumentParser argument definitions + and be able to regenerate a corresponding command-line to be + written in the generated Ninja file for the 'regen' rule. + """ + def __init__(self): + self._arguments = [] + + def add(self, *args, **kwargs): + """Add an argument definition, use as argparse.ArgumentParser.add_argument().""" + self._arguments.append((args, kwargs)) + + def add_to_parser(self, parser): + """Add all known arguments to parser.""" + for args, kwargs in self._arguments: + parser.add_argument(*args, **kwargs) + + def gen_command_line_args(self, parser_arguments): + """Generate a gen.py argument list to be embedded in a Ninja file.""" + result = [] + for args, kwargs in self._arguments: + if len(args) == 2: + long_option = args[1] + else: + long_option = args[0] + dest = kwargs.get('dest', None) + if dest is None: + assert long_option.startswith('--') + dest = long_option[2:].replace('-', '_') + + if getattr(parser_arguments, dest, None) is None: + # This was not set on the command-line so skip it. + continue + + action = kwargs.get('action', None) + if action == 'store_true': + if getattr(parser_arguments, dest): + result.append(long_option) + elif action == 'store' or action is None: + result.append('%s=%s' % (long_option, getattr(parser_arguments, dest))) + elif action == 'append': + for item in getattr(parser_arguments, dest): + result.append('%s=%s' % (long_option, item)) + else: + assert action is None, "Unsupported action " + action + return ' '.join(shell_quote(item) for item in result) + + +def main(argv): + parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__) + args_list = ArgumentsList() + + args_list.add('-d', '--debug', action='store_true', + help='Do a debug build. Defaults to release build.') + args_list.add('--platform', + help='target platform (' + + '/'.join(Platform.known_platforms()) + ')', + choices=Platform.known_platforms()) + args_list.add('--host', + help='host platform (' + + '/'.join(Platform.known_platforms()) + ')', + choices=Platform.known_platforms()) + args_list.add('--use-lto', action='store_true', + help='Enable the use of LTO') + args_list.add('--use-icf', action='store_true', + help='Enable the use of Identical Code Folding') + args_list.add('--no-last-commit-position', action='store_true', + help='Do not generate last_commit_position.h.') + args_list.add('--out-path', + help='The path to generate the build files in.') + args_list.add('--no-strip', action='store_true', + help='Don\'t strip release build. Useful for profiling.') + args_list.add('--no-static-libstdc++', action='store_true', + default=False, dest='no_static_libstdcpp', + help='Don\'t link libstdc++ statically') + args_list.add('--link-lib', + action='append', + metavar='LINK_LIB', + default=[], + dest='link_libs', + help=('Add a library to the final executable link. ' + + 'LINK_LIB must be the path to a static or shared ' + + 'library, or \'-l\' on POSIX systems. Can be ' + + 'used multiple times. Useful to link custom malloc ' + + 'or cpu profiling libraries.')) + if sys.platform == 'zos': + args_list.add('--zoslib-dir', + action='store', + default='../third_party/zoslib', + dest='zoslib_dir', + help=('Specify the path of ZOSLIB directory, to link ' + + 'with /install/lib/libzoslib.a, and ' + + 'add -I/install/include to the compile ' + + 'commands. See README.md for details.')) + + args_list.add_to_parser(parser) + options = parser.parse_args(argv) + + platform = Platform(options.platform) + if options.host: + host = Platform(options.host) + else: + host = platform + + out_dir = options.out_path or os.path.join(REPO_ROOT, 'out') + if not os.path.isdir(out_dir): + os.makedirs(out_dir) + if not options.no_last_commit_position: + GenerateLastCommitPosition(host, + os.path.join(out_dir, 'last_commit_position.h')) + WriteGNNinja(os.path.join(out_dir, 'build.ninja'), platform, host, options, args_list) + return 0 + + +def GenerateLastCommitPosition(host, header): + ROOT_TAG = 'initial-commit' + describe_output = subprocess.check_output( + ['git', 'describe', 'HEAD', '--match', ROOT_TAG], shell=host.is_windows(), + cwd=REPO_ROOT) + mo = re.match(ROOT_TAG + '-(\d+)-g([0-9a-f]+)', describe_output.decode()) + if not mo: + raise ValueError( + 'Unexpected output from git describe when generating version header') + + contents = '''// Generated by build/gen.py. + +#ifndef OUT_LAST_COMMIT_POSITION_H_ +#define OUT_LAST_COMMIT_POSITION_H_ + +#define LAST_COMMIT_POSITION_NUM %s +#define LAST_COMMIT_POSITION "%s (%s)" + +#endif // OUT_LAST_COMMIT_POSITION_H_ +''' % (mo.group(1), mo.group(1), mo.group(2)) + + # Only write/touch this file if the commit position has changed. + old_contents = '' + if os.path.isfile(header): + with open(header, 'r') as f: + old_contents = f.read() + + if old_contents != contents: + with open(header, 'w') as f: + f.write(contents) + + +def WriteGenericNinja(path, static_libraries, executables, + cxx, ar, ld, platform, host, options, + args_list, cflags=[], ldflags=[], + libflags=[], include_dirs=[], solibs=[]): + args = args_list.gen_command_line_args(options) + if args: + args = " " + args + + ninja_header_lines = [ + 'cxx = ' + cxx, + 'ar = ' + ar, + 'ld = ' + ld, + '', + 'rule regen', + ' command = %s ../build/gen.py%s' % (sys.executable, args), + ' description = Regenerating ninja files', + '', + 'build build.ninja: regen', + ' generator = 1', + ' depfile = build.ninja.d', + '', + ] + + + template_filename = os.path.join(SCRIPT_DIR, { + 'msvc': 'build_win.ninja.template', + 'mingw': 'build_linux.ninja.template', + 'msys': 'build_linux.ninja.template', + 'darwin': 'build_mac.ninja.template', + 'linux': 'build_linux.ninja.template', + 'freebsd': 'build_linux.ninja.template', + 'aix': 'build_aix.ninja.template', + 'openbsd': 'build_openbsd.ninja.template', + 'haiku': 'build_haiku.ninja.template', + 'solaris': 'build_linux.ninja.template', + 'netbsd': 'build_linux.ninja.template', + 'zos': 'build_zos.ninja.template', + }[platform.platform()]) + + with open(template_filename) as f: + ninja_template = f.read() + + if platform.is_windows(): + executable_ext = '.exe' + library_ext = '.lib' + object_ext = '.obj' + else: + executable_ext = '' + library_ext = '.a' + object_ext = '.o' + + def escape_path_ninja(path): + return path.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:') + + def src_to_obj(path): + return escape_path_ninja('%s' % os.path.splitext(path)[0] + object_ext) + + def library_to_a(library): + return '%s%s' % (library, library_ext) + + ninja_lines = [] + def build_source(src_file, settings): + ninja_lines.extend([ + 'build %s: cxx %s' % (src_to_obj(src_file), + escape_path_ninja( + os.path.relpath( + os.path.join(REPO_ROOT, src_file), + os.path.dirname(path)))), + ' includes = %s' % ' '.join( + ['-I' + escape_path_ninja(dirname) for dirname in include_dirs]), + ' cflags = %s' % ' '.join(cflags), + ]) + + for library, settings in static_libraries.items(): + for src_file in settings['sources']: + build_source(src_file, settings) + + ninja_lines.append('build %s: alink_thin %s' % ( + library_to_a(library), + ' '.join([src_to_obj(src_file) for src_file in settings['sources']]))) + ninja_lines.append(' libflags = %s' % ' '.join(libflags)) + + + for executable, settings in executables.items(): + for src_file in settings['sources']: + build_source(src_file, settings) + + ninja_lines.extend([ + 'build %s%s: link %s | %s' % ( + executable, executable_ext, + ' '.join([src_to_obj(src_file) for src_file in settings['sources']]), + ' '.join([library_to_a(library) for library in settings['libs']])), + ' ldflags = %s' % ' '.join(ldflags), + ' solibs = %s' % ' '.join(solibs), + ' libs = %s' % ' '.join( + [library_to_a(library) for library in settings['libs']]), + ]) + + ninja_lines.append('') # Make sure the file ends with a newline. + + with open(path, 'w') as f: + f.write('\n'.join(ninja_header_lines)) + f.write(ninja_template) + f.write('\n'.join(ninja_lines)) + + with open(path + '.d', 'w') as f: + f.write('build.ninja: ' + + os.path.relpath(os.path.join(SCRIPT_DIR, 'gen.py'), + os.path.dirname(path)) + ' ' + + os.path.relpath(template_filename, os.path.dirname(path)) + '\n') + + +def WriteGNNinja(path, platform, host, options, args_list): + if platform.is_msvc(): + cxx = os.environ.get('CXX', 'cl.exe') + ld = os.environ.get('LD', 'link.exe') + ar = os.environ.get('AR', 'lib.exe') + elif platform.is_aix(): + cxx = os.environ.get('CXX', 'g++') + ld = os.environ.get('LD', 'g++') + ar = os.environ.get('AR', 'ar -X64') + elif platform.is_msys() or platform.is_mingw(): + cxx = os.environ.get('CXX', 'g++') + ld = os.environ.get('LD', 'g++') + ar = os.environ.get('AR', 'ar') + else: + cxx = os.environ.get('CXX', 'clang++') + ld = cxx + ar = os.environ.get('AR', 'ar') + + cflags = os.environ.get('CFLAGS', '').split() + cflags += os.environ.get('CXXFLAGS', '').split() + ldflags = os.environ.get('LDFLAGS', '').split() + libflags = os.environ.get('LIBFLAGS', '').split() + include_dirs = [ + os.path.relpath(os.path.join(REPO_ROOT, 'src'), os.path.dirname(path)), + '.', + ] + if platform.is_zos(): + include_dirs += [ options.zoslib_dir + '/install/include' ] + + libs = [] + + if not platform.is_msvc(): + if options.debug: + cflags.extend(['-O0', '-g']) + else: + cflags.append('-DNDEBUG') + cflags.append('-O3') + if options.no_strip: + cflags.append('-g') + ldflags.append('-O3') + # Use -fdata-sections and -ffunction-sections to place each function + # or data item into its own section so --gc-sections can eliminate any + # unused functions and data items. + cflags.extend(['-fdata-sections', '-ffunction-sections']) + ldflags.extend(['-fdata-sections', '-ffunction-sections']) + if platform.is_darwin(): + ldflags.append('-Wl,-dead_strip') + elif not platform.is_aix() and not platform.is_solaris() and not platform.is_zos(): + # Garbage collection is done by default on aix, and option is unsupported on z/OS. + ldflags.append('-Wl,--gc-sections') + + # Omit all symbol information from the output file. + if options.no_strip is None: + if platform.is_darwin(): + ldflags.append('-Wl,-S') + elif platform.is_aix(): + ldflags.append('-Wl,-s') + elif platform.is_solaris(): + ldflags.append('-Wl,--strip-all') + elif not platform.is_zos(): + # /bin/ld on z/OS doesn't have an equivalent option. + ldflags.append('-Wl,-strip-all') + + # Enable identical code-folding. + if options.use_icf and not platform.is_darwin(): + ldflags.append('-Wl,--icf=all') + + if options.use_lto: + cflags.extend(['-flto', '-fwhole-program-vtables']) + ldflags.extend(['-flto', '-fwhole-program-vtables']) + + cflags.extend([ + '-D_FILE_OFFSET_BITS=64', + '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS', + '-pthread', + '-pipe', + '-fno-exceptions', + '-fno-rtti', + '-fdiagnostics-color', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-std=c++17' + ]) + + if platform.is_linux() or platform.is_mingw() or platform.is_msys(): + ldflags.append('-Wl,--as-needed') + + if not options.no_static_libstdcpp: + ldflags.append('-static-libstdc++') + + if platform.is_mingw() or platform.is_msys(): + cflags.remove('-std=c++17') + cflags.extend([ + '-Wno-deprecated-copy', + '-Wno-implicit-fallthrough', + '-Wno-redundant-move', + '-Wno-unused-variable', + '-Wno-format', # Use of %llx, which is supported by _UCRT, false positive + '-Wno-strict-aliasing', # Dereferencing punned pointer + '-Wno-cast-function-type', # Casting FARPROC to RegDeleteKeyExPtr + '-std=gnu++17', + ]) + else: + # This is needed by libc++. + libs.append('-ldl') + elif platform.is_darwin(): + min_mac_version_flag = '-mmacosx-version-min=10.9' + cflags.append(min_mac_version_flag) + ldflags.append(min_mac_version_flag) + elif platform.is_aix(): + cflags.append('-maix64') + ldflags.append('-maix64') + elif platform.is_haiku(): + cflags.append('-fPIC') + cflags.extend(['-D_BSD_SOURCE']) + elif platform.is_zos(): + cflags.append('-fzos-le-char-mode=ascii') + cflags.append('-Wno-unused-function') + cflags.append('-D_OPEN_SYS_FILE_EXT') + cflags.append('-DPATH_MAX=1024') + + if platform.is_posix() and not platform.is_haiku(): + ldflags.append('-pthread') + + if platform.is_mingw() or platform.is_msys(): + cflags.extend(['-DUNICODE', + '-DNOMINMAX', + '-DWIN32_LEAN_AND_MEAN', + '-DWINVER=0x0A00', + '-D_CRT_SECURE_NO_DEPRECATE', + '-D_SCL_SECURE_NO_DEPRECATE', + '-D_UNICODE', + '-D_WIN32_WINNT=0x0A00', + '-D_HAS_EXCEPTIONS=0' + ]) + elif platform.is_msvc(): + if not options.debug: + cflags.extend(['/O2', '/DNDEBUG', '/Zc:inline']) + ldflags.extend(['/OPT:REF']) + + if options.use_icf: + libflags.extend(['/OPT:ICF']) + if options.use_lto: + cflags.extend(['/GL']) + libflags.extend(['/LTCG']) + ldflags.extend(['/LTCG']) + + cflags.extend([ + '/DNOMINMAX', + '/DUNICODE', + '/DWIN32_LEAN_AND_MEAN', + '/DWINVER=0x0A00', + '/D_CRT_SECURE_NO_DEPRECATE', + '/D_SCL_SECURE_NO_DEPRECATE', + '/D_UNICODE', + '/D_WIN32_WINNT=0x0A00', + '/FS', + '/W4', + '/WX', + '/Zi', + '/wd4099', + '/wd4100', + '/wd4127', + '/wd4244', + '/wd4267', + '/wd4505', + '/wd4838', + '/wd4996', + '/std:c++17', + '/GR-', + '/D_HAS_EXCEPTIONS=0', + ]) + + ldflags.extend(['/DEBUG', '/MACHINE:x64']) + + static_libraries = { + 'base': {'sources': [ + 'src/base/command_line.cc', + 'src/base/environment.cc', + 'src/base/files/file.cc', + 'src/base/files/file_enumerator.cc', + 'src/base/files/file_path.cc', + 'src/base/files/file_path_constants.cc', + 'src/base/files/file_util.cc', + 'src/base/files/scoped_file.cc', + 'src/base/files/scoped_temp_dir.cc', + 'src/base/json/json_parser.cc', + 'src/base/json/json_reader.cc', + 'src/base/json/json_writer.cc', + 'src/base/json/string_escape.cc', + 'src/base/logging.cc', + 'src/base/md5.cc', + 'src/base/memory/ref_counted.cc', + 'src/base/memory/weak_ptr.cc', + 'src/base/sha1.cc', + 'src/base/strings/string_number_conversions.cc', + 'src/base/strings/string_split.cc', + 'src/base/strings/string_util.cc', + 'src/base/strings/string_util_constants.cc', + 'src/base/strings/stringprintf.cc', + 'src/base/strings/utf_string_conversion_utils.cc', + 'src/base/strings/utf_string_conversions.cc', + 'src/base/third_party/icu/icu_utf.cc', + 'src/base/timer/elapsed_timer.cc', + 'src/base/value_iterators.cc', + 'src/base/values.cc', + ]}, + 'gn_lib': {'sources': [ + 'src/gn/action_target_generator.cc', + 'src/gn/action_values.cc', + 'src/gn/analyzer.cc', + 'src/gn/args.cc', + 'src/gn/binary_target_generator.cc', + 'src/gn/build_settings.cc', + 'src/gn/builder.cc', + 'src/gn/builder_record.cc', + 'src/gn/bundle_data.cc', + 'src/gn/bundle_data_target_generator.cc', + 'src/gn/bundle_file_rule.cc', + 'src/gn/builtin_tool.cc', + 'src/gn/c_include_iterator.cc', + 'src/gn/c_substitution_type.cc', + 'src/gn/c_tool.cc', + 'src/gn/command_analyze.cc', + 'src/gn/command_args.cc', + 'src/gn/command_check.cc', + 'src/gn/command_clean.cc', + 'src/gn/command_clean_stale.cc', + 'src/gn/command_desc.cc', + 'src/gn/command_format.cc', + 'src/gn/command_gen.cc', + 'src/gn/command_help.cc', + 'src/gn/command_ls.cc', + 'src/gn/command_meta.cc', + 'src/gn/command_outputs.cc', + 'src/gn/command_path.cc', + 'src/gn/command_refs.cc', + 'src/gn/commands.cc', + 'src/gn/compile_commands_writer.cc', + 'src/gn/rust_project_writer.cc', + 'src/gn/config.cc', + 'src/gn/config_values.cc', + 'src/gn/config_values_extractors.cc', + 'src/gn/config_values_generator.cc', + 'src/gn/copy_target_generator.cc', + 'src/gn/create_bundle_target_generator.cc', + 'src/gn/deps_iterator.cc', + 'src/gn/desc_builder.cc', + 'src/gn/eclipse_writer.cc', + 'src/gn/err.cc', + 'src/gn/escape.cc', + 'src/gn/exec_process.cc', + 'src/gn/filesystem_utils.cc', + 'src/gn/file_writer.cc', + 'src/gn/frameworks_utils.cc', + 'src/gn/function_exec_script.cc', + 'src/gn/function_filter.cc', + 'src/gn/function_foreach.cc', + 'src/gn/function_forward_variables_from.cc', + 'src/gn/function_get_label_info.cc', + 'src/gn/function_get_path_info.cc', + 'src/gn/function_get_target_outputs.cc', + 'src/gn/function_process_file_template.cc', + 'src/gn/function_read_file.cc', + 'src/gn/function_rebase_path.cc', + 'src/gn/function_set_default_toolchain.cc', + 'src/gn/function_set_defaults.cc', + 'src/gn/function_template.cc', + 'src/gn/function_toolchain.cc', + 'src/gn/function_write_file.cc', + 'src/gn/functions.cc', + 'src/gn/functions_target.cc', + 'src/gn/general_tool.cc', + 'src/gn/generated_file_target_generator.cc', + 'src/gn/group_target_generator.cc', + 'src/gn/header_checker.cc', + 'src/gn/import_manager.cc', + 'src/gn/inherited_libraries.cc', + 'src/gn/input_conversion.cc', + 'src/gn/input_file.cc', + 'src/gn/input_file_manager.cc', + 'src/gn/item.cc', + 'src/gn/json_project_writer.cc', + 'src/gn/label.cc', + 'src/gn/label_pattern.cc', + 'src/gn/lib_file.cc', + 'src/gn/loader.cc', + 'src/gn/location.cc', + 'src/gn/metadata.cc', + 'src/gn/metadata_walk.cc', + 'src/gn/ninja_action_target_writer.cc', + 'src/gn/ninja_binary_target_writer.cc', + 'src/gn/ninja_build_writer.cc', + 'src/gn/ninja_bundle_data_target_writer.cc', + 'src/gn/ninja_c_binary_target_writer.cc', + 'src/gn/ninja_copy_target_writer.cc', + 'src/gn/ninja_create_bundle_target_writer.cc', + 'src/gn/ninja_generated_file_target_writer.cc', + 'src/gn/ninja_group_target_writer.cc', + 'src/gn/ninja_rust_binary_target_writer.cc', + 'src/gn/ninja_target_command_util.cc', + 'src/gn/ninja_target_writer.cc', + 'src/gn/ninja_toolchain_writer.cc', + 'src/gn/ninja_tools.cc', + 'src/gn/ninja_utils.cc', + 'src/gn/ninja_writer.cc', + 'src/gn/operators.cc', + 'src/gn/output_conversion.cc', + 'src/gn/output_file.cc', + 'src/gn/parse_node_value_adapter.cc', + 'src/gn/parse_tree.cc', + 'src/gn/parser.cc', + 'src/gn/path_output.cc', + 'src/gn/pattern.cc', + 'src/gn/pool.cc', + 'src/gn/qt_creator_writer.cc', + 'src/gn/runtime_deps.cc', + 'src/gn/rust_substitution_type.cc', + 'src/gn/rust_tool.cc', + 'src/gn/rust_values.cc', + 'src/gn/rust_values_generator.cc', + 'src/gn/rust_variables.cc', + 'src/gn/scheduler.cc', + 'src/gn/scope.cc', + 'src/gn/scope_per_file_provider.cc', + 'src/gn/settings.cc', + 'src/gn/setup.cc', + 'src/gn/source_dir.cc', + 'src/gn/source_file.cc', + 'src/gn/standard_out.cc', + 'src/gn/string_atom.cc', + 'src/gn/string_output_buffer.cc', + 'src/gn/string_utils.cc', + 'src/gn/substitution_list.cc', + 'src/gn/substitution_pattern.cc', + 'src/gn/substitution_type.cc', + 'src/gn/substitution_writer.cc', + 'src/gn/swift_values.cc', + 'src/gn/swift_values_generator.cc', + 'src/gn/swift_variables.cc', + 'src/gn/switches.cc', + 'src/gn/target.cc', + 'src/gn/target_generator.cc', + 'src/gn/template.cc', + 'src/gn/token.cc', + 'src/gn/tokenizer.cc', + 'src/gn/tool.cc', + 'src/gn/toolchain.cc', + 'src/gn/trace.cc', + 'src/gn/value.cc', + 'src/gn/value_extractors.cc', + 'src/gn/variables.cc', + 'src/gn/version.cc', + 'src/gn/visibility.cc', + 'src/gn/visual_studio_utils.cc', + 'src/gn/visual_studio_writer.cc', + 'src/gn/xcode_object.cc', + 'src/gn/xcode_writer.cc', + 'src/gn/xml_element_writer.cc', + 'src/util/exe_path.cc', + 'src/util/msg_loop.cc', + 'src/util/semaphore.cc', + 'src/util/sys_info.cc', + 'src/util/ticks.cc', + 'src/util/worker_pool.cc', + ]}, + } + + executables = { + 'gn': {'sources': [ 'src/gn/gn_main.cc' ], 'libs': []}, + + 'gn_unittests': { 'sources': [ + 'src/gn/action_target_generator_unittest.cc', + 'src/gn/analyzer_unittest.cc', + 'src/gn/args_unittest.cc', + 'src/gn/builder_unittest.cc', + 'src/gn/builder_record_map_unittest.cc', + 'src/gn/c_include_iterator_unittest.cc', + 'src/gn/command_format_unittest.cc', + 'src/gn/commands_unittest.cc', + 'src/gn/compile_commands_writer_unittest.cc', + 'src/gn/config_unittest.cc', + 'src/gn/config_values_extractors_unittest.cc', + 'src/gn/escape_unittest.cc', + 'src/gn/exec_process_unittest.cc', + 'src/gn/filesystem_utils_unittest.cc', + 'src/gn/file_writer_unittest.cc', + 'src/gn/frameworks_utils_unittest.cc', + 'src/gn/function_filter_unittest.cc', + 'src/gn/function_foreach_unittest.cc', + 'src/gn/function_forward_variables_from_unittest.cc', + 'src/gn/function_get_label_info_unittest.cc', + 'src/gn/function_get_path_info_unittest.cc', + 'src/gn/function_get_target_outputs_unittest.cc', + 'src/gn/function_process_file_template_unittest.cc', + 'src/gn/function_rebase_path_unittest.cc', + 'src/gn/function_template_unittest.cc', + 'src/gn/function_toolchain_unittest.cc', + 'src/gn/function_write_file_unittest.cc', + 'src/gn/functions_target_rust_unittest.cc', + 'src/gn/functions_target_unittest.cc', + 'src/gn/functions_unittest.cc', + 'src/gn/hash_table_base_unittest.cc', + 'src/gn/header_checker_unittest.cc', + 'src/gn/inherited_libraries_unittest.cc', + 'src/gn/input_conversion_unittest.cc', + 'src/gn/json_project_writer_unittest.cc', + 'src/gn/rust_project_writer_unittest.cc', + 'src/gn/rust_project_writer_helpers_unittest.cc', + 'src/gn/label_pattern_unittest.cc', + 'src/gn/label_unittest.cc', + 'src/gn/loader_unittest.cc', + 'src/gn/metadata_unittest.cc', + 'src/gn/metadata_walk_unittest.cc', + 'src/gn/ninja_action_target_writer_unittest.cc', + 'src/gn/ninja_binary_target_writer_unittest.cc', + 'src/gn/ninja_build_writer_unittest.cc', + 'src/gn/ninja_bundle_data_target_writer_unittest.cc', + 'src/gn/ninja_c_binary_target_writer_unittest.cc', + 'src/gn/ninja_copy_target_writer_unittest.cc', + 'src/gn/ninja_create_bundle_target_writer_unittest.cc', + 'src/gn/ninja_generated_file_target_writer_unittest.cc', + 'src/gn/ninja_group_target_writer_unittest.cc', + 'src/gn/ninja_rust_binary_target_writer_unittest.cc', + 'src/gn/ninja_target_command_util_unittest.cc', + 'src/gn/ninja_target_writer_unittest.cc', + 'src/gn/ninja_toolchain_writer_unittest.cc', + 'src/gn/operators_unittest.cc', + 'src/gn/output_conversion_unittest.cc', + 'src/gn/parse_tree_unittest.cc', + 'src/gn/parser_unittest.cc', + 'src/gn/path_output_unittest.cc', + 'src/gn/pattern_unittest.cc', + 'src/gn/pointer_set_unittest.cc', + 'src/gn/runtime_deps_unittest.cc', + 'src/gn/scope_per_file_provider_unittest.cc', + 'src/gn/scope_unittest.cc', + 'src/gn/setup_unittest.cc', + 'src/gn/source_dir_unittest.cc', + 'src/gn/source_file_unittest.cc', + 'src/gn/string_atom_unittest.cc', + 'src/gn/string_output_buffer_unittest.cc', + 'src/gn/string_utils_unittest.cc', + 'src/gn/substitution_pattern_unittest.cc', + 'src/gn/substitution_writer_unittest.cc', + 'src/gn/target_unittest.cc', + 'src/gn/template_unittest.cc', + 'src/gn/test_with_scheduler.cc', + 'src/gn/test_with_scope.cc', + 'src/gn/tokenizer_unittest.cc', + 'src/gn/unique_vector_unittest.cc', + 'src/gn/value_unittest.cc', + 'src/gn/vector_utils_unittest.cc', + 'src/gn/version_unittest.cc', + 'src/gn/visibility_unittest.cc', + 'src/gn/visual_studio_utils_unittest.cc', + 'src/gn/visual_studio_writer_unittest.cc', + 'src/gn/xcode_object_unittest.cc', + 'src/gn/xml_element_writer_unittest.cc', + 'src/util/test/gn_test.cc', + ], 'libs': []}, + } + + if platform.is_posix() or platform.is_zos(): + static_libraries['base']['sources'].extend([ + 'src/base/files/file_enumerator_posix.cc', + 'src/base/files/file_posix.cc', + 'src/base/files/file_util_posix.cc', + 'src/base/posix/file_descriptor_shuffle.cc', + 'src/base/posix/safe_strerror.cc', + ]) + + if platform.is_zos(): + libs.extend([ options.zoslib_dir + '/install/lib/libzoslib.a' ]) + + if platform.is_windows(): + static_libraries['base']['sources'].extend([ + 'src/base/files/file_enumerator_win.cc', + 'src/base/files/file_util_win.cc', + 'src/base/files/file_win.cc', + 'src/base/win/registry.cc', + 'src/base/win/scoped_handle.cc', + 'src/base/win/scoped_process_information.cc', + ]) + + if platform.is_msvc(): + libs.extend([ + 'advapi32.lib', + 'dbghelp.lib', + 'kernel32.lib', + 'ole32.lib', + 'shell32.lib', + 'user32.lib', + 'userenv.lib', + 'version.lib', + 'winmm.lib', + 'ws2_32.lib', + 'Shlwapi.lib', + ]) + else: + libs.extend([ + '-ladvapi32', + '-ldbghelp', + '-lkernel32', + '-lole32', + '-lshell32', + '-luser32', + '-luserenv', + '-lversion', + '-lwinmm', + '-lws2_32', + '-lshlwapi', + ]) + + + libs.extend(options.link_libs) + + # we just build static libraries that GN needs + executables['gn']['libs'].extend(static_libraries.keys()) + executables['gn_unittests']['libs'].extend(static_libraries.keys()) + + WriteGenericNinja(path, static_libraries, executables, cxx, ar, ld, + platform, host, options, args_list, + cflags, ldflags, libflags, include_dirs, libs) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/docs/cross_compiles.md b/docs/cross_compiles.md new file mode 100644 index 0000000..ad71b94 --- /dev/null +++ b/docs/cross_compiles.md @@ -0,0 +1,126 @@ +# How GN handles cross-compiling + +## As a GN user + +GN has robust support for doing cross compiles and building things for +multiple architectures in a single build (e.g., to build some things to +run locally and some things to run on an embedded device). In fact, +there is no limit on the number of different architectures you can build +at once; the Chromium build uses at least four in some configurations. + +To start, GN has the concepts of a _host_ and a _target_. The host is +the platform that the build is run on, and the target is the platform +where the code will actually run (This is different from +[autotools](http://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html)' +terminology, but uses the more common terminology for cross +compiling). + +(Confusingly, GN also refers to each build artifact -- an executable, +library, etc. -- as a target. On this page, we will use "target" only to +refer to the system you want to run your code on, and use "rule" or some +other synonym to refer to a specific build artifact). + +When GN starts up, the `host_os` and `host_cpu` variables are set +automatically to match the operating system (they can be overridden in +args files, which can be useful in weird corner cases). The user can +specify that they want to do a cross-compile by setting either or both +of `target_os` and `target_cpu`; if they are not set, the build config +files will usually set them to the host's values, though the Chromium +build will set target\_cpu to "arm" if target\_os is set to "android"). + +So, for example, running on an x64 Linux machine: + +``` +gn gen out/Default +``` + +is equivalent to: + +``` +gn gen out/Default --args='target_os="linux" target_cpu="x64"' +``` + +To do an 32-bit ARM Android cross-compile, do: + +``` +gn gen out/Default --args='target_os="android"' +``` + +(We don't have to specify target\_cpu because of the conditionals +mentioned above). + +And, to do a 64-bit MIPS Chrome OS cross-compile: + +``` +gn gen out/Default --args='target_os="chromeos" target_cpu="mips64el"' +``` + +## As a BUILD.gn author + +If you are editing build files outside of the //build directory (i.e., +not directly working on toolchains, compiler configs, etc.), generally +you only need to worry about a few things: + +The `current_toolchain`, `current_cpu`, and `current_os` variables +reflect the settings that are **currently** in effect in a given rule. +The `is_linux`, `is_win` etc. variables are updated to reflect the +current settings, and changes to `cflags`, `ldflags` and so forth also +only apply to the current toolchain and the current thing being built. + +You can also refer to the `target_cpu` and `target_os` variables. This +is useful if you need to do something different on the host depending on +which target\_arch is requested; the values are constant across all +toolchains. You can do similar things for the `host_cpu` and `host_os` +variables, but should generally never need to. + +For the default toolchain, `target_cpu` and `current_cpu` are the same. For a +secondary toolchain, `current_cpu` is set based on the toolchain definition +and `target_cpu` remains the same. When writing rules, **`current_cpu` should +be used rather than `target_cpu` most of the time**. + +By default, dependencies listed in the `deps` variable of a rule use the +same (currently active) toolchain. You may specify a different toolchain +using the `foo(bar)` label notation as described in [the label section +of the reference doc](reference.md#Toolchains). + +Here's an example of when to use `target_cpu` vs `current_cpu`: + +``` +declare_args() { + # Applies only to toolchains targeting target_cpu. + sysroot = "" +} + +config("my_config") { + # Uses current_cpu because compile flags are toolchain-dependent. + if (current_cpu == "arm") { + defines = [ "CPU_IS_32_BIT" ] + } else { + defines = [ "CPU_IS_64_BIT" ] + } + # Compares current_cpu with target_cpu to see whether current_toolchain + # has the same architecture as target_toolchain. + if (sysroot != "" && current_cpu == target_cpu) { + cflags = [ + "-isysroot", + sysroot, + ] + } +} +``` + +## As a //build/config or //build/toolchain author + +The `default_toolchain` is declared in the `BUILDCONFIG.gn` file (in Google +projects this normally is in the `//build/config` directory). Usually the +`default_toolchain` should be the toolchain for the `target_os` and +`target_cpu`. The `current_toolchain` reflects the toolchain that is currently +in effect for a rule. + +Be sure you understand the differences between `host_cpu`, `target_cpu`, +`current_cpu`, and `toolchain_cpu` (and the os equivalents). The first +two are set as described above. You are responsible for making sure that +`current_cpu` is set appropriately in your toolchain definitions; if you +are using the stock templates like `gcc_toolchain` and `msvc_toolchain`, +that means you are responsible for making sure that `toolchain_cpu` and +`toolchain_os` are set as appropriate in the template invocations. diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..d300c90 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,220 @@ +# GN Frequently Asked Questions + +[TOC] + +## Where is the GN documentation? + +GN has extensive built-in help, so you can run `gn help`, but you can also see +all of the help on [the reference page](reference.md). See also the [quick +start](quick_start.md) guide and the [language and operation +details](language.md). + +## Can I generate XCode or Visual Studio projects? + +You can generate skeleton (or wrapper) projects for Xcode, Visual Studio, +QTCreator, and Eclipse that will list the files and targets in the build, but +use Ninja to do the actual build. You cannot generate "real" projects that look +and compile like native ones. + +Run `gn help gen` for more details. + +## How do I do cross-compiles? + +GN has robust support for doing cross compiles and building things for +multiple architectures in a single build. + +See [GNCrossCompiles](cross_compiles.md) for more info. + +## Can I control what targets are built by default? + +Yes! If you create a group target called "default" in the top-level (root) build +file, i.e., "//:default", GN will tell Ninja to build that by default, rather +than building everything. + +## Are there any public presentations on GN? + +[There's at least one](https://docs.google.com/presentation/d/15Zwb53JcncHfEwHpnG_PoIbbzQ3GQi_cpujYwbpcbZo/edit?usp=sharing), from 2015. There +haven't been big changes since then apart from moving it to a standalone +repo, so it should still be relevant. + +## What is the order of flags and values given to the compiler? + +The final values of compiler flags, linker flags, defines, and include +directories are collected from various sources by GN. The ordering is defined +as: + +1. Those set directly on the current target (not in a config). +2. Those set on the `configs` on the target in order that the configs appear in the list. +3. Those set on the `all_dependent_configs` on the target in order that the configs appear in the list. +4. Those set on the `public_configs` on the target in order that those configs appear in the list. +5. `all_dependent_configs` pulled from dependencies, in the order of the `deps` list. This is done recursively. If a config appears more than once, only the first occurrence will be used. +6. `public_configs` pulled from dependencies, in the order of the `deps` list. If a dependency is public, they will be applied recursively. + +If you need a specific relative ordering of values you may need to put those +flags in a config and prepend or append that config in a way that produces the +desired result. + +## How can a target affect those that depend on it? + +The main way that information flows up the dependency graph is via +`public_configs`. This allows a target to add preprocessor defines, compiler +flags, and linker flags to targets that depend on it. A typical example is a +library that requires `include_dirs` and `defines` to be set in a certain way +for its headers to work. It would put its values in a config: + +``` +config("icu_config") { + include_dirs = [ "//third_party/icu" ] + defines = [ "U_USING_ICU_NAMESPACE=0" ] +} +``` + +The library would then reference that as a `public_config` which will apply it +to any target that directly depends on the `icu` target: + +``` +shared_library("icu") { + sources = [ ... ] + deps = [ ... ] + + public_configs = [ ":icu_config" ] # Label of config defined above. +} +``` + +A `public_config` applies only to direct dependencies of the target. If a target +wants to "republish" the `public_configs` from its dependencies, it would list +those dependencies in its `public_deps`. In this example, a "browser" library +might use ICU headers in its own headers, so anything that depends on it also +needs to get the ICU configuration: + +``` +shared_library("browser") { + ... + + # Anything that depends on this "browser" library will also get ICU's settings. + public_deps = [ "//third_party/icu" ] +} +``` + +Another way apply settings up the dependency graph is with +`all_dependent_configs` which works like `public_configs` except that it is +applied to all dependent targets regardless of `deps`/`public_deps`. Use of this +feature is discouraged because it is easy to accumulate lots of unnecessary +settings in a large project. Ideally all targets can define which information +their dependencies need and can control this explicitly with `public_deps`. + +The last way that information can be collected across the dependency graph is +with the metadata feature. This allows data (see `gn help metadata`) to be +collected from targets to be written to disk (see `gn help generated_file`) for +the build to use. Computed metadata values are written after all BUILD.gn files +are processed and are not available to the GN script. + +Sometimes people want to write conditional GN code based on values of a +dependency. This is not possible: GN has no defined order for loading BUILD.gn +files (this allows pararellism) so GN may not have even loaded the file +containing a dependency when you might want information about it. The only way +information flows around the dependency graph is if GN itself is propagating +that data after the targets are defined. + +## How can a target affect its dependencies? + +Sometimes you might have a dependency graph **A 🠲 Z** or a longer chain **A 🠲 B +🠲 C 🠲 Z** and want to control some aspect of **Z** when used from **A**. This is +not possible in GN: information only flows up the dependency chain. + +Every label in GN is compiled once per _toolchain_. This means that every target +that depends on **B** gets the same version of **B**. If you need different +variants of **B** there are only two options: + +1. Explicitly define two similar but differently named targets encoding the +variations you need. This can be done without specifying everything twice using +a template or by writing things like the sources to a variable and using that +variable in each version of the target. + +2. Use different toolchains. This is commonly used to encode "host" versus +"target" differences or to compile parts of a project with something like ASAN. +It is possible to use toolchains to encode any variation you might desire but +this can be difficult to manage and might be impossible or discoraged depending +on how your project is set up (Chrome and Fuchsia use toolchains for specific +purposes only). + +## How can I recursively copy a directory as a build step? + +Sometimes people want to write a build action that expresses copying all files +(possibly recursively, possily not) from a source directory without specifying +all files in that directory in a BUILD file. This is not possible to express: +correct builds must list all inputs. Most approaches people try to work around +this break in some way for incremental builds, either the build step is run +every time (the build is always "dirty"), file modifications will be missed, or +file additions will be missed. + +One thing people try is to write an action that declares an input directory and +an output directory and have it copy all files from the source to the +destination. But incremental builds are likely going to be incorrect if you do +this. Ninja determines if an output is in need of rebuilding by comparing the +last modified date of the source to the last modified date of the destination. +Since almost no filesystems propagate the last modified date of files to their +directory, modifications to files in the source will not trigger an incremental +rebuild. + +Beware when testing this: most filesystems update the last modified date of the +parent directory (but not recursive parents) when adding to or removing a file +from that directory so this will appear to work in many cases. But no modern +production filesystems propagate modification times of the contents of the files +to any directories because it would be very slow. The result will be that +modifications to the source files will not be reflected in the output when doing +incremental builds. + +Another thing people try is to write all of the source files to a "depfile" (see +`gn help depfile`) and to write a single stamp file that tracks the modified +date of the output. This approach also may appear to work but is subtly wrong: +the additions of new files to the source directory will not trigger the build +step and that addition will not be reflected in an incremental build. + +## Why does "gn check" complain about conditionally included headers? + +The "gn check" feature (see `gn help check`) validates that the source code's +use of header files follows the requirements set up in the build. It can be a +very useful tool for ensuring build correctness. + +GN scans the source code for `#include` directives and checks that the included +files are allowed given the specification of the build. But it is relatively +simplistic and does not understand the preprocessor. This means that some +headers that are correctly included for a different build variant might be +flagged by GN. To disable checking of an include, append a "nogncheck" +annotation to the include line: + +``` +#if defined(OS_ANDROID) +#include "src/android/foo/bar.h" // nogncheck +#endif +``` + +Correctly handling these cases requires a full preprocessor implementation +because many preprocessor conditions depend on values set by other headers. +Implementing this would require new code and complexity to define the toolchain +and run the preprocessor, and also means that a full build be done before doing +the check (since some headers will be generated at build-time). So far, the +complexity and disadvantages have outweighed the advantages of a perfectly +correct "gn check" implementation. + +## Why does "gn check" miss my header? + +The "gn check" feature (see previous question) only checks for headers that have +been declared in the current toolchain. So if your header never appears in a +`sources` or `public` list, any file will be able to include it without "gn +check" failing. As a result, targets should always list all headers they contain +even though listing them does not affect the build. + +Sometimes a feature request is made to flag unknown headers so that people will +know they should be added to the build. But the silent omission of headers +outside of the current toolchain is an important feature that limits the +necessity of "nogncheck" annotations (see previous question). + +In a large project like Chrome, many platform-specific headers will only be +defined in that platform's build (for example, Android-specific headers would +only be listed in the build when compiling for Android). Because the checking +doesn't understand the preprocessor, checking unknown files would flag uses of +these headers even if they were properly guarded by platform conditionals. By +ignoring headers outside of the current toolchain, the "nogncheck" annotations +can be omitted for most platform-specific files. diff --git a/docs/language.md b/docs/language.md new file mode 100644 index 0000000..137300a --- /dev/null +++ b/docs/language.md @@ -0,0 +1,535 @@ +# GN Language and Operation + +[TOC] + +## Introduction + +This page describes many of the language details and behaviors. + +### Use the built-in help! + +GN has an extensive built-in help system which provides a reference for +every function and built-in variable. This page is more high-level. + +``` +gn help +``` + +You can also see the +[slides](https://docs.google.com/presentation/d/15Zwb53JcncHfEwHpnG_PoIbbzQ3GQi_cpujYwbpcbZo/edit?usp=sharing) +from a March, 2016 introduction to GN. The speaker notes contain the full +content. + +### Design philosophy + + * Writing build files should not be a creative endeavour. Ideally two + people should produce the same buildfile given the same + requirements. There should be no flexibility unless it's absolutely + needed. As many things should be fatal errors as possible. + + * The definition should read more like code than rules. I don't want + to write or debug Prolog. But everybody on our team can write and + debug C++ and Python. + + * The build language should be opinionated as to how the build should + work. It should not necessarily be easy or even possible to express + arbitrary things. We should be changing source and tooling to make + the build simpler rather than making everything more complicated to + conform to external requirements (within reason). + + * Be like Blaze when it makes sense (see "Differences and similarities + to Blaze" below). + +## Language + +GN uses an extremely simple, dynamically typed language. The types are: + + * Boolean (`true`, `false`). + * 64-bit signed integers. + * Strings. + * Lists (of any other types). + * Scopes (sort of like a dictionary, only for built-in stuff). + +There are some built-in variables whose values depend on the current +environment. See `gn help` for more. + +There are purposefully many omissions in the language. There are no +user-defined function calls, for example (templates are the closest thing). As +per the above design philosophy, if you need this kind of thing you're probably +doing it wrong. + +The full grammar for language nerds is available in `gn help grammar`. + +### Strings + +Strings are enclosed in double-quotes and use backslash as the escape +character. The only escape sequences supported are: + + * `\"` (for literal quote) + * `\$` (for literal dollars sign) + * `\\` (for literal backslash) + +Any other use of a backslash is treated as a literal backslash. So, for +example, `\b` used in patterns does not need to be escaped, nor do most Windows +paths like `"C:\foo\bar.h"`. + +Simple variable substitution is supported via `$`, where the word +following the dollars sign is replaced with the value of the variable. +You can optionally surround the name with `{}` if there is not a +non-variable-name character to terminate the variable name. More complex +expressions are not supported, only variable name substitution. + +``` +a = "mypath" +b = "$a/foo.cc" # b -> "mypath/foo.cc" +c = "foo${a}bar.cc" # c -> "foomypathbar.cc" +``` + +You can encode 8-bit characters using "$0xFF" syntax, so a string with newlines +(hex 0A) would `"look$0x0Alike$0x0Athis"`. + +### Lists + +Aside from telling empty lists from non empty lists (`a == []`), there is no +way to get the length of a list. If you find yourself wanting to do this kind +of thing, you're trying to do too much work in the build. + +Lists support appending: + +``` +a = [ "first" ] +a += [ "second" ] # [ "first", "second" ] +a += [ "third", "fourth" ] # [ "first", "second", "third", "fourth" ] +b = a + [ "fifth" ] # [ "first", "second", "third", "fourth", "fifth" ] +``` + +Appending a list to another list appends the items in the second list +rather than appending the list as a nested member. + +You can remove items from a list: + +``` +a = [ "first", "second", "third", "first" ] +b = a - [ "first" ] # [ "second", "third" ] +a -= [ "second" ] # [ "first", "third", "first" ] +``` + +The - operator on a list searches for matches and removes all matching +items. Subtracting a list from another list will remove each item in the +second list. + +If no matching items are found, an error will be thrown, so you need to +know in advance that the item is there before removing it. Given that +there is no way to test for inclusion, the main use-case is to set up a +master list of files or flags, and to remove ones that don't apply to +the current build based on various conditions. + +Stylistically, prefer to only add to lists and have each source file or +dependency appear once. This is the opposite of the advice Chrome-team used to +give for GYP (GYP would prefer to list all files, and then remove the ones you +didn't want in conditionals). + +Lists support zero-based subscripting to extract values: + +``` +a = [ "first", "second", "third" ] +b = a[1] # -> "second" +``` + +The \[\] operator is read-only and can not be used to mutate the +list. The primary use-case of this is when an external script returns +several known values and you want to extract them. + +There are some cases where it's easy to overwrite a list when you mean +to append to it instead. To help catch this case, it is an error to +assign a nonempty list to a variable containing an existing nonempty +list. If you want to get around this restriction, first assign the +destination variable to the empty list. + +``` +a = [ "one" ] +a = [ "two" ] # Error: overwriting nonempty list with a nonempty list. +a = [] # OK +a = [ "two" ] # OK +``` + +Note that execution of the build script is done without intrinsic +knowledge of the meaning of the underlying data. This means that it +doesn't know that `sources` is a list of file names, for example. So if +you remove an item, it must match the literal string rather than +specifying a different name that will resolve to the same file name. + +### Conditionals + +Conditionals look like C: + +``` + if (is_linux || (is_win && target_cpu == "x86")) { + sources -= [ "something.cc" ] + } else if (...) { + ... + } else { + ... + } +``` + +You can use them in most places, even around entire targets if the +target should only be declared in certain circumstances. + +### Looping + +You can iterate over a list with `foreach`. This is discouraged. Most things +the build should do can normally be expressed without doing this, and if you +find it necessary it may be an indication you're doing too much work in the +metabuild. + +``` +foreach(i, mylist) { + print(i) # Note: i is a copy of each element, not a reference to it. +} +``` + +### Function calls + +Simple function calls look like most other languages: + +``` +print("hello, world") +assert(is_win, "This should only be executed on Windows") +``` + +Such functions are built-in and the user can not define new ones. + +Some functions take a block of code enclosed by `{ }` following them: + +``` +static_library("mylibrary") { + sources = [ "a.cc" ] +} +``` + +Most of these define targets. The user can define new functions like this +with the template mechanism discussed below. + +Precisely, this expression means that the block becomes an argument to the +function for the function to execute. Most of the block-style functions execute +the block and treat the resulting scope as a dictionary of variables to read. + +### Scoping and execution + +Files and function calls followed by `{ }` blocks introduce new scopes. Scopes +are nested. When you read a variable, the containing scopes will be searched in +reverse order until a matching name is found. Variable writes always go to the +innermost scope. + +There is no way to modify any enclosing scope other than the innermost +one. This means that when you define a target, for example, nothing you +do inside of the block will "leak out" into the rest of the file. + +`if`/`else`/`foreach` statements, even though they use `{ }`, do not introduce +a new scope so changes will persist outside of the statement. + +## Naming things + +### File and directory names + +File and directory names are strings and are interpreted as relative to +the current build file's directory. There are three possible forms: + +Relative names: + +``` +"foo.cc" +"src/foo.cc" +"../src/foo.cc" +``` + +Source-tree absolute names: + +``` +"//net/foo.cc" +"//base/test/foo.cc" +``` + +System absolute names (rare, normally used for include directories): + +``` +"/usr/local/include/" +"/C:/Program Files/Windows Kits/Include" +``` + +## Build configuration + +## Targets + +A target is a node in the build graph. It usually represents some kind +of executable or library file that will be generated. Targets depend on +other targets. The built-in target types (see `gn help ` for +more help) are: + + * `action`: Run a script to generate a file. + * `action_foreach`: Run a script once for each source file. + * `bundle_data`: Declare data to go into a Mac/iOS bundle. + * `create_bundle`: Creates a Mac/iOS bundle. + * `executable`: Generates an executable file. + * `group`: A virtual dependency node that refers to one or more other + targets. + * `shared_library`: A .dll or .so. + * `loadable_module`: A .dll or .so loadable only at runtime. + * `source_set`: A lightweight virtual static library (usually + preferrable over a real static library since it will build faster). + * `static_library`: A .lib or .a file (normally you'll want a + `source_set` instead). + +You can extend this to make custom target types using templates (see below). In +Chrome some of the more commonly-used templates are: + + * `component`: Either a source set or shared library, depending on the + build type. + * `test`: A test executable. On mobile this will create the appropriate + native app type for tests. + * `app`: Executable or Mac/iOS application. + * `android_apk`: Make an APK. There are a _lot_ of other Android ones, see + `//build/config/android/rules.gni`. + +## Configs + +Configs are named objects that specify sets of flags, include +directories, and defines. They can be applied to a target and pushed to +dependent targets. + +To define a config: + +``` +config("myconfig") { + includes = [ "src/include" ] + defines = [ "ENABLE_DOOM_MELON" ] +} +``` + +To apply a config to a target: + +``` +executable("doom_melon") { + configs = [ ":myconfig" ] +} +``` + +It is common for the build config file to specify target defaults that +set a default list of configs. Targets can add or remove to this list as +needed. So in practice you would usually use `configs += ":myconfig"` to +append to the list of defaults. + +See `gn help config` for more information about how configs are declared +and applied. + +### Public configs + +A target can apply settings to other targets that depend on it. The most +common example is a third party target that requires some defines or +include directories for its headers to compile properly. You want these +settings to apply both to the compile of the third party library itself, +as well as all targets that use the library. + +To do this, you write a config with the settings you want to apply: + +``` +config("my_external_library_config") { + includes = "." + defines = [ "DISABLE_JANK" ] +} +``` + +Then this config is added to the target as a "public" config. It will +apply both to the target as well as targets that directly depend on it. + +``` +shared_library("my_external_library") { + ... + # Targets that depend on this get this config applied. + public_configs = [ ":my_external_library_config" ] +} +``` + +Dependent targets can in turn forward this up the dependency tree +another level by adding your target as a "public" dependency. + +``` +static_library("intermediate_library") { + ... + # Targets that depend on this one also get the configs from "my external library". + public_deps = [ ":my_external_library" ] +} +``` + +A target can forward a config to all dependents until a link boundary is +reached by setting it as an `all_dependent_config`. This is strongly +discouraged as it can spray flags and defines over more of the build than +necessary. Instead, use public_deps to control which flags apply where. + +In Chrome, prefer the build flag header system (`build/buildflag_header.gni`) +for defines which prevents most screw-ups with compiler defines. + +## Templates + +Templates are GN's primary way to re-use code. Typically, a template +would expand to one or more other target types. + +``` +# Declares a script that compiles IDL files to source, and then compiles those +# source files. +template("idl") { + # Always base helper targets on target_name so they're unique. Target name + # will be the string passed as the name when the template is invoked. + idl_target_name = "${target_name}_generate" + action_foreach(idl_target_name) { + ... + } + + # Your template should always define a target with the name target_name. + # When other targets depend on your template invocation, this will be the + # destination of that dependency. + source_set(target_name) { + ... + deps = [ ":$idl_target_name" ] # Require the sources to be compiled. + } +} +``` + +Typically your template definition would go in a `.gni` file and users +would import that file to see the template definition: + +``` +import("//tools/idl_compiler.gni") + +idl("my_interfaces") { + sources = [ "a.idl", "b.idl" ] +} +``` + +Declaring a template creates a closure around the variables in scope at +that time. When the template is invoked, the magic variable `invoker` is +used to read variables out of the invoking scope. The template would +generally copy the values its interested in into its own scope: + +``` +template("idl") { + source_set(target_name) { + sources = invoker.sources + } +} +``` + +The current directory when a template executes will be that of the +invoking build file rather than the template source file. This is so +files passed in from the template invoker will be correct (this +generally accounts for most file handling in a template). However, if +the template has files itself (perhaps it generates an action that runs +a script), you will want to use absolute paths ("//foo/...") to refer to +these files to account for the fact that the current directory will be +unpredictable during invocation. See `gn help template` for more +information and more complete examples. + +## Other features + +### Imports + +You can import `.gni` files into the current scope with the `import` +function. This is _not_ an include in the C++ sense. The imported file is +executed independently and the resulting scope is copied into the current file +(C++ executes the included file in the current context of when the +include directive appeared). This allows the results of the import to be +cached, and also prevents some of the more "creative" uses of includes like +multiply-included files. + +Typically, a `.gni` would define build arguments and templates. See `gn +help import` for more. + +Your `.gni` file can define temporary variables that are not exported files +that include it by using a preceding underscore in the name like `_this`. + +### Path processing + +Often you will want to make a file name or a list of file names relative +to a different directory. This is especially common when running +scripts, which are executed with the build output directory as the +current directory, while build files usually refer to files relative to +their containing directory. + +You can use `rebase_path` to convert directories. See `gn help +rebase_path` for more help and examples. Typical usage to convert a file +name relative to the current directory to be relative to the root build +directory would be: ``` new_paths = rebase_path("myfile.c", +root_build_dir) ``` + +### Patterns + +Patterns are used to generate the output file names for a given set of +inputs for custom target types, and to automatically remove files from +the list values (see `gn help filter_include` and `gn help filter_exclude`). + +They are like simple regular expressions. See `gn help label_pattern` +for more. + +### Executing scripts + +There are two ways to execute scripts. All external scripts in GN are in +Python. The first way is as a build step. Such a script would take some +input and generate some output as part of the build. Targets that invoke +scripts are declared with the "action" target type (see `gn help +action`). + +The second way to execute scripts is synchronously during build file +execution. This is necessary in some cases to determine the set of files +to compile, or to get certain system configurations that the build file +might depend on. The build file can read the stdout of the script and +act on it in different ways. + +Synchronous script execution is done by the `exec_script` function (see +`gn help exec_script` for details and examples). Because synchronously +executing a script requires that the current buildfile execution be +suspended until a Python process completes execution, relying on +external scripts is slow and should be minimized. + +To prevent abuse, files permitted to call `exec_script` can be whitelisted in +the toplevel `.gn` file. Chrome does this to require additional code review +for such additions. See `gn help dotfile`. + +You can synchronously read and write files which is discouraged but +occasionally necessary when synchronously running scripts. The typical use-case +would be to pass a list of file names longer than the command-line limits of +the current platform. See `gn help read_file` and `gn help write_file` for how +to read and write files. These functions should be avoided if at all possible. + +Actions that exceed command-line length limits can use response files to +get around this limitation without synchronously writing files. See +`gn help response_file_contents`. + +# Differences and similarities to Blaze + +Blaze is Google's internal build system, now publicly released as +[Bazel](http://bazel.io/). It has inspired a number of other systems such as +[Pants](http://www.pantsbuild.org/) and [Buck](http://facebook.github.io/buck/). + +In Google's homogeneous environment, the need for conditionals is very +low and they can get by with a few hacks (`abi_deps`). Chrome uses +conditionals all over the place and the need to add these is the main +reason for the files looking different. + +GN also adds the concept of "configs" to manage some of the trickier +dependency and configuration problems which likewise don't arise on the +server. Blaze has a concept of a "configuration" which is like a GN +toolchain, but built into the tool itself. The way that toolchains work +in GN is a result of trying to separate this concept out into the build +files in a clean way. + +GN keeps some GYP concept like "all dependent" settings which work a bit +differently in Blaze. This is partially to make conversion from the existing +GYP code easier, and the GYP constructs generally offer more fine-grained +control (which is either good or bad, depending on the situation). + +GN also uses GYP names like "sources" instead of "srcs" since +abbreviating this seems needlessly obscure, although it uses Blaze's +"deps" since "dependencies" is so hard to type. Chromium also compiles +multiple languages in one target so specifying the language type on the +target name prefix was dropped (e.g. from `cc_library`). diff --git a/docs/quick_start.md b/docs/quick_start.md new file mode 100644 index 0000000..fc99e86 --- /dev/null +++ b/docs/quick_start.md @@ -0,0 +1,344 @@ +# GN Quick Start guide + +[TOC] + +## Running GN + +You just run `gn` from the command line. For large projects, GN is versioned +and distributed with the source checkout. + + * For Chromium and Chromium-based projects, there is a script in + `depot_tools`, which is presumably in your PATH, with this name. The script + will find the binary in the source tree containing the current directory and + run it. + + * For Fuchsia in-tree development, run `fx gn ...` which will find the right + GN binary and run it with the given arguments. + + * For other projects, see your project's documentation. + +## Setting up a build + +Unlike some other build systems, with GN you set up your own build directories +with the settings you want. This lets you maintain as many different builds in +parallel as you need. + +Once you set up a build directory, the Ninja files will be automatically +regenerated if they're out of date when you build in that directory so you +should not have to re-run GN. + +To make a build directory: + +``` +gn gen out/my_build +``` + +## Passing build arguments + +Set build arguments on your build directory by running: + +``` +gn args out/my_build +``` + +This will bring up an editor. Type build args into that file like this: + +``` +is_component_build = true +is_debug = false +``` + +The available variables will depend on your build (this example is from +Chromium). You can see the list of available arguments and their default values +by typing + +``` +gn args --list out/my_build +``` + +on the command line. Note that you have to specify the build directory +for this command because the available arguments can change according +to the build. + +Chrome developers can also read the [Chrome-specific build +configuration](http://www.chromium.org/developers/gn-build-configuration) +instructions for more information. + +## Cross-compiling to a target OS or architecture + +Run `gn args out/Default` (substituting your build directory as needed) and +add one or more of the following lines for common cross-compiling options. + +``` +target_os = "chromeos" +target_os = "android" + +target_cpu = "arm" +target_cpu = "x86" +target_cpu = "x64" +``` + +See [GN cross compiles](cross_compiles.md) for more info. + +## Step-by-step + +### Adding a build file + +Go to the directory `examples/simple_build`. This is the root of a minimal GN +repository. + +In that directory there is a `tutorial` directory. There is already a +`tutorial.cc` file that's not hooked up to the build. Create a new `BUILD.gn` +file in that directory for our new target. + +``` +executable("tutorial") { + sources = [ + "tutorial.cc", + ] +} +``` + +Now we just need to tell the build about this new target. Open the `BUILD.gn` +file in the parent (`simple_build`) directory. GN starts by loading this root +file, and then loads all dependencies ourward from here, so we just need to add +a reference to our new target from this file. + +You could add our new target as a dependency from one of the existing targets in +the `simple_build/BUILD.gn` file, but it usually doesn't make a lot of sense to +have an executable as a depdency of another executable (they can't be linked). +So let's make a "tools" group. In GN, a "group" is just a collection of +dependencies that's not complied or linked: + +``` +group("tools") { + deps = [ + # This will expand to the name "//tutorial:tutorial" which is the full name + # of our new target. Run "gn help labels" for more. + "//tutorial", + ] +} +``` + +### Testing your addition + +From the command line in the `simple_build` directory: + +``` +gn gen out +ninja -C out tutorial +out/tutorial +``` + +You should see "Hello, world." output to the console. + +Side note: GN encourages target names for static libraries that aren't globally +unique. To build one of these, you can pass the label with its path (but no leading +"//") to ninja: + +``` +ninja -C out some/path/to/target:my_target +``` + +### Declaring dependencies + +Let's look at the targets defined in +[examples/simple_build/BUILD.gn](../examples/simple_build/BUILD.gn). There is a +static library that defines one function, `GetStaticText()`: + +``` +static_library("hello_static") { + sources = [ + "hello_static.cc", + "hello_static.h", + ] +} +``` + +There is also a shared library that defines one function `GetSharedText()`: + +``` +shared_library("hello_shared") { + sources = [ + "hello_shared.cc", + "hello_shared.h", + ] + + defines = [ "HELLO_SHARED_IMPLEMENTATION" ] +} +``` + +This also illustrates how to set preprocessor defines for a target. To set more +than one or to assign values, use this form: + +``` +defines = [ + "HELLO_SHARED_IMPLEMENTATION", + "ENABLE_DOOM_MELON=0", +] +``` + +Now let's look at the executable that depends on these two libraries: + +``` +executable("hello") { + sources = [ + "hello.cc", + ] + + deps = [ + ":hello_shared", + ":hello_static", + ] +} +``` + +This executable includes one source file and depends on the previous +two libraries. Labels starting with a colon refer to a target with that name in +the current BUILD.gn file. + +### Test the binary + +From the command line in the `simple_build` directory: + +``` +ninja -C out hello +out/hello +``` + +Note that you **didn't** need to re-run GN. GN will automatically rebuild +the ninja files when any build file has changed. You know this happens +when ninja prints `[1/1] Regenerating ninja files` at the beginning of +execution. + +### Putting settings in a config + +Users of a library often need compiler flags, defines, and include directories +applied to them. To do this, put all such settings into a "config" which is a +named collection of settings (but not sources or dependencies): + +``` +config("my_lib_config") { + defines = [ "ENABLE_DOOM_MELON" ] + include_dirs = [ "//third_party/something" ] +} +``` + +To apply a config's settings to a target, add it to the `configs` list: + +``` +static_library("hello_shared") { + ... + # Note "+=" here is usually required, see "default configs" below. + configs += [ + ":my_lib_config", + ] +} +``` + +A config can be applied to all targets that depend on the current one by putting +its label in the `public_configs` list: + +``` +static_library("hello_shared") { + ... + public_configs = [ + ":my_lib_config", + ] +} +``` + +The `public_configs` also applies to the current target, so there's no need to +list a config in both places. + +### Default configs + +The build configuration will set up some settings that apply to every target by +default. These will normally be set as a default list of configs. You can see +this using the "print" command which is useful for debugging: + +``` +executable("hello") { + print(configs) +} +``` + +Running GN will print something like: + +``` +$ gn gen out +["//build:compiler_defaults", "//build:executable_ldconfig"] +Done. Made 5 targets from 5 files in 9ms +``` + +Targets can modify this list to change their defaults. For example, the build +setup might turn off exceptions by default by adding a `no_exceptions` config, +but a target might re-enable them by replacing it with a different one: + +``` +executable("hello") { + ... + configs -= [ "//build:no_exceptions" ] # Remove global default. + configs += [ "//build:exceptions" ] # Replace with a different one. +} +``` + +Our print command from above could also be expressed using string interpolation. +This is a way to convert values to strings. It uses the symbol "$" to refer to a +variable: + +``` +print("The configs for the target $target_name are $configs") +``` + +## Add a new build argument + +You declare which arguments you accept and specify default values via +`declare_args`. + +``` +declare_args() { + enable_teleporter = true + enable_doom_melon = false +} +``` + +See `gn help buildargs` for an overview of how this works. +See `gn help declare_args` for specifics on declaring them. + +It is an error to declare a given argument more than once in a given scope, so +care should be used in scoping and naming arguments. + +## Don't know what's going on? + +You can run GN in verbose mode to see lots of messages about what it's +doing. Use `-v` for this. + +### The "desc" command + +You can run `gn desc ` to get information about +a given target: + +``` +gn desc out/Default //foo/bar:say_hello +``` + +will print out lots of exciting information. You can also print just one +section. Lets say you wanted to know where your `TWO_PEOPLE` define +came from on the `say_hello` target: + +``` +> gn desc out/Default //foo/bar:say_hello defines --blame +...lots of other stuff omitted... + From //foo/bar:hello_config + (Added by //foo/bar/BUILD.gn:12) + TWO_PEOPLE +``` + +Another particularly interesting variation: + +``` +gn desc out/Default //base:base_i18n deps --tree +``` + +See `gn help desc` for more. diff --git a/docs/reference.md b/docs/reference.md new file mode 100644 index 0000000..566b3ed --- /dev/null +++ b/docs/reference.md @@ -0,0 +1,7859 @@ +# GN Reference + +*This page is automatically generated from* `gn help --markdown all`. + +## Contents + +* [Commands](#commands) + * [analyze: Analyze which targets are affected by a list of files.](#cmd_analyze) + * [args: Display or configure arguments declared by the build.](#cmd_args) + * [check: Check header dependencies.](#cmd_check) + * [clean: Cleans the output directory.](#cmd_clean) + * [clean_stale: Cleans the stale output files from the output directory.](#cmd_clean_stale) + * [desc: Show lots of insightful information about a target or config.](#cmd_desc) + * [format: Format .gn files.](#cmd_format) + * [gen: Generate ninja files.](#cmd_gen) + * [help: Does what you think.](#cmd_help) + * [ls: List matching targets.](#cmd_ls) + * [meta: List target metadata collection results.](#cmd_meta) + * [outputs: Which files a source/target make.](#cmd_outputs) + * [path: Find paths between two targets.](#cmd_path) + * [refs: Find stuff referencing a target or file.](#cmd_refs) +* [Target declarations](#targets) + * [action: Declare a target that runs a script a single time.](#func_action) + * [action_foreach: Declare a target that runs a script over a set of files.](#func_action_foreach) + * [bundle_data: [iOS/macOS] Declare a target without output.](#func_bundle_data) + * [copy: Declare a target that copies files.](#func_copy) + * [create_bundle: [iOS/macOS] Build an iOS or macOS bundle.](#func_create_bundle) + * [executable: Declare an executable target.](#func_executable) + * [generated_file: Declare a generated_file target.](#func_generated_file) + * [group: Declare a named group of targets.](#func_group) + * [loadable_module: Declare a loadable module target.](#func_loadable_module) + * [rust_library: Declare a Rust library target.](#func_rust_library) + * [rust_proc_macro: Declare a Rust procedural macro target.](#func_rust_proc_macro) + * [shared_library: Declare a shared library target.](#func_shared_library) + * [source_set: Declare a source set target.](#func_source_set) + * [static_library: Declare a static library target.](#func_static_library) + * [target: Declare an target with the given programmatic type.](#func_target) +* [Buildfile functions](#functions) + * [assert: Assert an expression is true at generation time.](#func_assert) + * [config: Defines a configuration object.](#func_config) + * [declare_args: Declare build arguments.](#func_declare_args) + * [defined: Returns whether an identifier is defined.](#func_defined) + * [exec_script: Synchronously run a script and return the output.](#func_exec_script) + * [filter_exclude: Remove values that match a set of patterns.](#func_filter_exclude) + * [filter_include: Remove values that do not match a set of patterns.](#func_filter_include) + * [foreach: Iterate over a list.](#func_foreach) + * [forward_variables_from: Copies variables from a different scope.](#func_forward_variables_from) + * [get_label_info: Get an attribute from a target's label.](#func_get_label_info) + * [get_path_info: Extract parts of a file or directory name.](#func_get_path_info) + * [get_target_outputs: [file list] Get the list of outputs from a target.](#func_get_target_outputs) + * [getenv: Get an environment variable.](#func_getenv) + * [import: Import a file into the current scope.](#func_import) + * [not_needed: Mark variables from scope as not needed.](#func_not_needed) + * [pool: Defines a pool object.](#func_pool) + * [print: Prints to the console.](#func_print) + * [process_file_template: Do template expansion over a list of files.](#func_process_file_template) + * [read_file: Read a file into a variable.](#func_read_file) + * [rebase_path: Rebase a file or directory to another location.](#func_rebase_path) + * [set_default_toolchain: Sets the default toolchain name.](#func_set_default_toolchain) + * [set_defaults: Set default values for a target type.](#func_set_defaults) + * [split_list: Splits a list into N different sub-lists.](#func_split_list) + * [string_join: Concatenates a list of strings with a separator.](#func_string_join) + * [string_replace: Replaces substring in the given string.](#func_string_replace) + * [string_split: Split string into a list of strings.](#func_string_split) + * [template: Define a template rule.](#func_template) + * [tool: Specify arguments to a toolchain tool.](#func_tool) + * [toolchain: Defines a toolchain.](#func_toolchain) + * [write_file: Write a file to disk.](#func_write_file) +* [Built-in predefined variables](#predefined_variables) + * [current_cpu: [string] The processor architecture of the current toolchain.](#var_current_cpu) + * [current_os: [string] The operating system of the current toolchain.](#var_current_os) + * [current_toolchain: [string] Label of the current toolchain.](#var_current_toolchain) + * [default_toolchain: [string] Label of the default toolchain.](#var_default_toolchain) + * [gn_version: [number] The version of gn.](#var_gn_version) + * [host_cpu: [string] The processor architecture that GN is running on.](#var_host_cpu) + * [host_os: [string] The operating system that GN is running on.](#var_host_os) + * [invoker: [string] The invoking scope inside a template.](#var_invoker) + * [python_path: [string] Absolute path of Python.](#var_python_path) + * [root_build_dir: [string] Directory where build commands are run.](#var_root_build_dir) + * [root_gen_dir: [string] Directory for the toolchain's generated files.](#var_root_gen_dir) + * [root_out_dir: [string] Root directory for toolchain output files.](#var_root_out_dir) + * [target_cpu: [string] The desired cpu architecture for the build.](#var_target_cpu) + * [target_gen_dir: [string] Directory for a target's generated files.](#var_target_gen_dir) + * [target_name: [string] The name of the current target.](#var_target_name) + * [target_os: [string] The desired operating system for the build.](#var_target_os) + * [target_out_dir: [string] Directory for target output files.](#var_target_out_dir) +* [Variables you set in targets](#target_variables) + * [aliased_deps: [scope] Set of crate-dependency pairs.](#var_aliased_deps) + * [all_dependent_configs: [label list] Configs to be forced on dependents.](#var_all_dependent_configs) + * [allow_circular_includes_from: [label list] Permit includes from deps.](#var_allow_circular_includes_from) + * [arflags: [string list] Arguments passed to static_library archiver.](#var_arflags) + * [args: [string list] Arguments passed to an action.](#var_args) + * [asmflags: [string list] Flags passed to the assembler.](#var_asmflags) + * [assert_no_deps: [label pattern list] Ensure no deps on these targets.](#var_assert_no_deps) + * [bridge_header: [string] Path to C/Objective-C compatibility header.](#var_bridge_header) + * [bundle_contents_dir: Expansion of {{bundle_contents_dir}} in create_bundle.](#var_bundle_contents_dir) + * [bundle_deps_filter: [label list] A list of labels that are filtered out.](#var_bundle_deps_filter) + * [bundle_executable_dir: Expansion of {{bundle_executable_dir}} in create_bundle](#var_bundle_executable_dir) + * [bundle_resources_dir: Expansion of {{bundle_resources_dir}} in create_bundle.](#var_bundle_resources_dir) + * [bundle_root_dir: Expansion of {{bundle_root_dir}} in create_bundle.](#var_bundle_root_dir) + * [cflags: [string list] Flags passed to all C compiler variants.](#var_cflags) + * [cflags_c: [string list] Flags passed to the C compiler.](#var_cflags_c) + * [cflags_cc: [string list] Flags passed to the C++ compiler.](#var_cflags_cc) + * [cflags_objc: [string list] Flags passed to the Objective C compiler.](#var_cflags_objc) + * [cflags_objcc: [string list] Flags passed to the Objective C++ compiler.](#var_cflags_objcc) + * [check_includes: [boolean] Controls whether a target's files are checked.](#var_check_includes) + * [code_signing_args: [string list] Arguments passed to code signing script.](#var_code_signing_args) + * [code_signing_outputs: [file list] Output files for code signing step.](#var_code_signing_outputs) + * [code_signing_script: [file name] Script for code signing.](#var_code_signing_script) + * [code_signing_sources: [file list] Sources for code signing step.](#var_code_signing_sources) + * [complete_static_lib: [boolean] Links all deps into a static library.](#var_complete_static_lib) + * [configs: [label list] Configs applying to this target or config.](#var_configs) + * [contents: Contents to write to file.](#var_contents) + * [crate_name: [string] The name for the compiled crate.](#var_crate_name) + * [crate_root: [string] The root source file for a binary or library.](#var_crate_root) + * [crate_type: [string] The type of linkage to use on a shared_library.](#var_crate_type) + * [data: [file list] Runtime data file dependencies.](#var_data) + * [data_deps: [label list] Non-linked dependencies.](#var_data_deps) + * [data_keys: [string list] Keys from which to collect metadata.](#var_data_keys) + * [defines: [string list] C preprocessor defines.](#var_defines) + * [depfile: [string] File name for input dependencies for actions.](#var_depfile) + * [deps: [label list] Private linked dependencies.](#var_deps) + * [externs: [scope] Set of Rust crate-dependency pairs.](#var_externs) + * [framework_dirs: [directory list] Additional framework search directories.](#var_framework_dirs) + * [frameworks: [name list] Name of frameworks that must be linked.](#var_frameworks) + * [friend: [label pattern list] Allow targets to include private headers.](#var_friend) + * [gen_deps: [label list] Declares targets that should generate when this one does.](#var_gen_deps) + * [include_dirs: [directory list] Additional include directories.](#var_include_dirs) + * [inputs: [file list] Additional compile-time dependencies.](#var_inputs) + * [ldflags: [string list] Flags passed to the linker.](#var_ldflags) + * [lib_dirs: [directory list] Additional library directories.](#var_lib_dirs) + * [libs: [string list] Additional libraries to link.](#var_libs) + * [metadata: [scope] Metadata of this target.](#var_metadata) + * [module_name: [string] The name for the compiled module.](#var_module_name) + * [output_conversion: Data format for generated_file targets.](#var_output_conversion) + * [output_dir: [directory] Directory to put output file in.](#var_output_dir) + * [output_extension: [string] Value to use for the output's file extension.](#var_output_extension) + * [output_name: [string] Name for the output file other than the default.](#var_output_name) + * [output_prefix_override: [boolean] Don't use prefix for output name.](#var_output_prefix_override) + * [outputs: [file list] Output files for actions and copy targets.](#var_outputs) + * [partial_info_plist: [filename] Path plist from asset catalog compiler.](#var_partial_info_plist) + * [pool: [string] Label of the pool used by the action.](#var_pool) + * [precompiled_header: [string] Header file to precompile.](#var_precompiled_header) + * [precompiled_header_type: [string] "gcc" or "msvc".](#var_precompiled_header_type) + * [precompiled_source: [file name] Source file to precompile.](#var_precompiled_source) + * [product_type: [string] Product type for Xcode projects.](#var_product_type) + * [public: [file list] Declare public header files for a target.](#var_public) + * [public_configs: [label list] Configs applied to dependents.](#var_public_configs) + * [public_deps: [label list] Declare public dependencies.](#var_public_deps) + * [rebase: [boolean] Rebase collected metadata as files.](#var_rebase) + * [response_file_contents: [string list] Contents of .rsp file for actions.](#var_response_file_contents) + * [script: [file name] Script file for actions.](#var_script) + * [sources: [file list] Source files for a target.](#var_sources) + * [swiftflags: [string list] Flags passed to the swift compiler.](#var_swiftflags) + * [testonly: [boolean] Declares a target must only be used for testing.](#var_testonly) + * [visibility: [label list] A list of labels that can depend on a target.](#var_visibility) + * [walk_keys: [string list] Key(s) for managing the metadata collection walk.](#var_walk_keys) + * [weak_frameworks: [name list] Name of frameworks that must be weak linked.](#var_weak_frameworks) + * [write_runtime_deps: Writes the target's runtime_deps to the given path.](#var_write_runtime_deps) + * [xcasset_compiler_flags: [string list] Flags passed to xcassets compiler](#var_xcasset_compiler_flags) + * [xcode_extra_attributes: [scope] Extra attributes for Xcode projects.](#var_xcode_extra_attributes) + * [xcode_test_application_name: [string] Name for Xcode test target.](#var_xcode_test_application_name) +* [Other help topics](#other) + * all: Print all the help at once + * [buildargs: How build arguments work.](#buildargs) + * [dotfile: Info about the toplevel .gn file.](#dotfile) + * [execution: Build graph and execution overview.](#execution) + * [grammar: Language and grammar for GN build files.](#grammar) + * [input_conversion: Processing input from exec_script and read_file.](#io_conversion) + * [file_pattern: Matching more than one file.](#file_pattern) + * [label_pattern: Matching more than one label.](#label_pattern) + * [labels: About labels.](#labels) + * [metadata_collection: About metadata and its collection.](#metadata_collection) + * [ninja_rules: How Ninja build rules are named.](#ninja_rules) + * [nogncheck: Annotating includes for checking.](#nogncheck) + * [output_conversion: Specifies how to transform a value to output.](#io_conversion) + * [runtime_deps: How runtime dependency computation works.](#runtime_deps) + * [source_expansion: Map sources to outputs for scripts.](#source_expansion) + * [switches: Show available command-line switches.](#switch_list) + +## Commands + +### **gn analyze <out_dir> <input_path> <output_path>** + +``` + Analyze which targets are affected by a list of files. + + This command takes three arguments: + + out_dir is the path to the build directory. + + input_path is a path to a file containing a JSON object with three fields: + + - "files": A list of the filenames to check. + + - "test_targets": A list of the labels for targets that are needed to run + the tests we wish to run. + + - "additional_compile_targets" (optional): A list of the labels for targets + that we wish to rebuild, but aren't necessarily needed for testing. The + important difference between this field and "test_targets" is that if an + item in the additional_compile_targets list refers to a group, then any + dependencies of that group will be returned if they are out of date, but + the group itself does not need to be. If the dependencies themselves are + groups, the same filtering is repeated. This filtering can be used to + avoid rebuilding dependencies of a group that are unaffected by the input + files. The list may also contain the string "all" to refer to a + pseudo-group that contains every root target in the build graph. + + This filtering behavior is also known as "pruning" the list of compile + targets. + + If "additional_compile_targets" is absent, it defaults to the empty list. + + If input_path is -, input is read from stdin. + + output_path is a path indicating where the results of the command are to be + written. The results will be a file containing a JSON object with one or more + of following fields: + + - "compile_targets": A list of the labels derived from the input + compile_targets list that are affected by the input files. Due to the way + the filtering works for compile targets as described above, this list may + contain targets that do not appear in the input list. + + - "test_targets": A list of the labels from the input test_targets list that + are affected by the input files. This list will be a proper subset of the + input list. + + - "invalid_targets": A list of any names from the input that do not exist in + the build graph. If this list is non-empty, the "error" field will also be + set to "Invalid targets". + + - "status": A string containing one of three values: + + - "Found dependency" + - "No dependency" + - "Found dependency (all)" + + In the first case, the lists returned in compile_targets and test_targets + should be passed to ninja to build. In the second case, nothing was + affected and no build is necessary. In the third case, GN could not + determine the correct answer and returned the input as the output in order + to be safe. + + - "error": This will only be present if an error occurred, and will contain + a string describing the error. This includes cases where the input file is + not in the right format, or contains invalid targets. + + If output_path is -, output is written to stdout. + + The command returns 1 if it is unable to read the input file or write the + output file, or if there is something wrong with the build such that gen + would also fail, and 0 otherwise. In particular, it returns 0 even if the + "error" key is non-empty and a non-fatal error occurred. In other words, it + tries really hard to always write something to the output JSON and convey + errors that way rather than via return codes. +``` +### **gn args**: (command-line tool) + +``` + Display or configure arguments declared by the build. + + gn args [--list] [--short] [--args] [--overrides-only] + + See also "gn help buildargs" for a more high-level overview of how + build arguments work. +``` + +#### **Usage** + +``` + gn args + Open the arguments for the given build directory in an editor. If the + given build directory doesn't exist, it will be created and an empty args + file will be opened in the editor. You would type something like this + into that file: + enable_doom_melon=false + os="android" + + To find your editor on Posix, GN will search the environment variables in + order: GN_EDITOR, VISUAL, and EDITOR. On Windows GN will open the command + associated with .txt files. + + Note: you can edit the build args manually by editing the file "args.gn" + in the build directory and then running "gn gen ". + + gn args --list[=] [--short] [--overrides-only] [--json] + Lists all build arguments available in the current configuration, or, if + an exact_arg is specified for the list flag, just that one build + argument. + + The output will list the declaration location, current value for the + build, default value (if different than the current value), and comment + preceding the declaration. + + If --short is specified, only the names and current values will be + printed. + + If --overrides-only is specified, only the names and current values of + arguments that have been overridden (i.e. non-default arguments) will + be printed. Overrides come from the /args.gn file and //.gn + + If --json is specified, the output will be emitted in json format. + JSON schema for output: + [ + { + "name": variable_name, + "current": { + "value": overridden_value, + "file": file_name, + "line": line_no + }, + "default": { + "value": default_value, + "file": file_name, + "line": line_no + }, + "comment": comment_string + }, + ... + ] +``` + +#### **Examples** + +``` + gn args out/Debug + Opens an editor with the args for out/Debug. + + gn args out/Debug --list --short + Prints all arguments with their default values for the out/Debug + build. + + gn args out/Debug --list --short --overrides-only + Prints overridden arguments for the out/Debug build. + + gn args out/Debug --list=target_cpu + Prints information about the "target_cpu" argument for the " + "out/Debug + build. + + gn args --list --args="os=\"android\" enable_doom_melon=true" + Prints all arguments with the default values for a build with the + given arguments set (which may affect the values of other + arguments). +``` +### **gn check <out_dir> [<label_pattern>] [\--force] [\--check-generated]** + +``` + 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. + + The can take exact labels or patterns that match more than + one (although not general regular expressions). If specified, only those + matching targets will be checked. See "gn help label_pattern" for details. +``` + +#### **Command-specific switches** + +``` + --check-generated + Generated files are normally not checked since they do not exist + until after a build. With this flag, those generated files that + can be found on disk are also checked. + + --check-system + Check system style includes (using ) in addition to + "double quote" includes. + + --default-toolchain + Normally wildcard targets are matched in all toolchains. This + switch makes wildcard labels with no explicit toolchain reference + only match targets in the default toolchain. + + Non-wildcard inputs with no explicit toolchain specification will + always match only a target in the default toolchain if one exists. + + --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 in the list + check_targets (see "gn help dotfile"). Alternatively, the .gn file may + specify a list of targets not to be checked in no_check_targets. If a label + pattern is specified on the command line, neither check_targets or + no_check_targets is used. + + 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. + + - Generated files (that might not exist yet) are ignored unless + the --check-generated flag is provided. + + - Includes with a "nogncheck" annotation are skipped (see + "gn help nogncheck"). + + - Includes using "quotes" are always checked. + If system style checking is enabled, includes using + are also checked. + + - Include paths are assumed to be relative to any of the "include_dirs" for + the target (including the implicit current dir). + + - 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. + + - Outputs 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". +``` + +#### **Advice on fixing problems** + +``` + If you have a third party project that is difficult to fix or doesn't care + about include checks 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. +``` + +#### **Examples** + +``` + gn check out/Debug + Check everything. + + gn check out/Default //foo:bar + Check only the files in the //foo:bar target. + + gn check out/Default "//foo/* + Check only the files in targets in the //foo directory tree. +``` +### **gn clean <out_dir>...** + +``` + Deletes the contents of the output directory except for args.gn and + creates a Ninja build environment sufficient to regenerate the build. +``` +### **gn clean_stale [\--ninja-executable=...] <out_dir>...** + +``` + Removes the no longer needed output files from the build directory and prunes + their records from the ninja build log and dependency database. These are + output files that were generated from previous builds, but the current build + graph no longer references them. + + This command requires a ninja executable of at least version 1.10.0. The + executable must be provided by the --ninja-executable switch. +``` + +#### **Options** + +``` + --ninja-executable= + Can be used to specify the ninja executable to use. +``` +### **gn desc** + +``` + gn desc