Import Upstream version 0.0~git20221212.5e19d2f
This commit is contained in:
commit
d816a8e1ea
|
@ -0,0 +1,2 @@
|
||||||
|
BasedOnStyle: Chromium
|
||||||
|
Standard: c++17
|
|
@ -0,0 +1,3 @@
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
|
@ -0,0 +1,66 @@
|
||||||
|
*.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
|
||||||
|
.cache
|
||||||
|
.cipd
|
||||||
|
.classpath
|
||||||
|
.cproject
|
||||||
|
.gdb_history
|
||||||
|
.gdbinit
|
||||||
|
.landmines
|
||||||
|
.metadata
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
.recipe_deps
|
||||||
|
.checkstyle
|
||||||
|
compile_commands.json
|
||||||
|
cscope.*
|
||||||
|
out/
|
||||||
|
GPATH
|
||||||
|
GRTAGS
|
||||||
|
GSYMS
|
||||||
|
GTAGS
|
||||||
|
Session.vim
|
||||||
|
tags
|
||||||
|
Thumbs.db
|
||||||
|
# Settings directories for eclipse
|
||||||
|
/.externalToolBuilders/
|
||||||
|
/.settings/
|
||||||
|
/.vs/
|
||||||
|
# Visual Studio Code
|
||||||
|
/.vscode/
|
||||||
|
/_out
|
||||||
|
# VSChromium configuration file
|
||||||
|
vs-chromium-project.txt
|
|
@ -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 <random.person@example.com>
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# <random.person@example.com> <ranp@example.com>
|
||||||
|
#
|
||||||
|
# Combinations of both are possible too, see
|
||||||
|
# https://git-scm.com/docs/gitmailmap for format details.
|
||||||
|
|
||||||
|
Nico Weber <thakis@chromium.org>
|
||||||
|
Nico Weber <thakis@chromium.org> <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
|
|
@ -0,0 +1,2 @@
|
||||||
|
[style]
|
||||||
|
based_on_style = chromium
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Names should be added to this file with this pattern:
|
||||||
|
#
|
||||||
|
# For individuals:
|
||||||
|
# Name <email address>
|
||||||
|
#
|
||||||
|
# For organizations:
|
||||||
|
# Organization <fnmatch pattern>
|
||||||
|
#
|
||||||
|
# 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 <alexis.menard@intel.com>
|
||||||
|
Alfredo Mazzinghi <mzz.lrd@gmail.com>
|
||||||
|
Andrew Boyarshin <andrew.boyarshin@gmail.com>
|
||||||
|
Anuj Kumar Sharma <anujk.sharma@samsung.com>
|
||||||
|
DanCraft99 <simputest@gmail.com>
|
||||||
|
Evangelos Foutras <evangelos@foutrelis.com>
|
||||||
|
Gergely Nagy <ngg@ngg.hu>
|
||||||
|
Ilia K <ki.stfu@gmail.com>
|
||||||
|
Ivan Naydonov <samogot@gmail.com>
|
||||||
|
Joe Armstrong <joearmstrong334@gmail.com>
|
||||||
|
Julien Brianceau <jbriance@cisco.com>
|
||||||
|
Kal Conley <kcconley@gmail.com>
|
||||||
|
Kamil Rytarowski <krytarowski@gmail.com>
|
||||||
|
Ma Aiguo <maaiguo@uniontech.com>
|
||||||
|
Martijn Croonen <martijn@martijnc.be>
|
||||||
|
Matej Knopp <matej.knopp@gmail.com>
|
||||||
|
Michael Gilbert <floppymaster@gmail.com>
|
||||||
|
Milko Leporis <milko.leporis@imgtec.com>
|
||||||
|
Mohan Reddy <mohan.reddy@samsung.com>
|
||||||
|
Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
|
||||||
|
Riku Voipio <riku.voipio@linaro.org>
|
||||||
|
Saikrishna Arcot <saiarcot895@gmail.com>
|
||||||
|
Stephan Hartmann <stha09@googlemail.com>
|
||||||
|
Tim Niederhausen <tim@rnc-ag.de>
|
||||||
|
Tomas Popela <tomas.popela@gmail.com>
|
||||||
|
Tripta Gupta <tripta.g@samsung.com>
|
||||||
|
Wink Saville <wink@saville.com>
|
||||||
|
Yuriy Taraday <yorik.sar@gmail.com>
|
||||||
|
Oleksandr Motsok <boramaabak@gmail.com>
|
||||||
|
Ihor Karavan <ihorkaravan96@gmail.com>
|
|
@ -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.
|
|
@ -0,0 +1,4 @@
|
||||||
|
brettw@chromium.org
|
||||||
|
phosek@chromium.org
|
||||||
|
scottmg@chromium.org
|
||||||
|
sdefresne@chromium.org
|
|
@ -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 and 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 # --allow-warning if you want to build with warnings.
|
||||||
|
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 the `CC`, `CXX`,
|
||||||
|
and `AR` environment variables.
|
||||||
|
|
||||||
|
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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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())
|
|
@ -0,0 +1,905 @@
|
||||||
|
#!/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<name>\' on POSIX systems. Can be ' +
|
||||||
|
'used multiple times. Useful to link custom malloc ' +
|
||||||
|
'or cpu profiling libraries.'))
|
||||||
|
args_list.add('--allow-warnings', action='store_true', default=False,
|
||||||
|
help=('Allow compiler warnings, don\'t treat them as '
|
||||||
|
'errors.'))
|
||||||
|
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 <ZOSLIB_DIR>/install/lib/libzoslib.a, and ' +
|
||||||
|
'add -I<ZOSLIB_DIR>/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', '--abbrev=12', '--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'])
|
||||||
|
|
||||||
|
if not options.allow_warnings:
|
||||||
|
cflags.append('-Werror')
|
||||||
|
|
||||||
|
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',
|
||||||
|
|
||||||
|
'-Wextra-semi',
|
||||||
|
'-Wundef',
|
||||||
|
|
||||||
|
'-std=c++17'
|
||||||
|
])
|
||||||
|
|
||||||
|
# flags not supported by gcc/g++.
|
||||||
|
if cxx == 'clang++':
|
||||||
|
cflags.extend(['-Wrange-loop-analysis', '-Wextra-semi-stmt'])
|
||||||
|
|
||||||
|
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'])
|
||||||
|
|
||||||
|
if not options.allow_warnings:
|
||||||
|
cflags.append('/WX')
|
||||||
|
|
||||||
|
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',
|
||||||
|
'/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/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/atomic_write.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/resolved_target_deps_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_public_pair_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/atomic_write_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:]))
|
|
@ -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.
|
|
@ -0,0 +1,236 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
## How can I reference all files in a directory (glob)?
|
||||||
|
|
||||||
|
Sometimes people want to automatically refer to all files in a directory,
|
||||||
|
typically something like `"*.cc"` for the sources. This is called a "glob."
|
||||||
|
|
||||||
|
Globs are not supported in GN. In order for Ninja to know when to re-run
|
||||||
|
GN, it would need to check the directory modification times of any
|
||||||
|
directories being globbed. Directory modification times that reflect
|
||||||
|
additions and removals of files are not as reliably implemented across
|
||||||
|
platforms and filesystems as file modification times (for example, it is
|
||||||
|
not supported on Windows FAT32 drives).
|
||||||
|
|
||||||
|
Even if directory modification times work properly on your build systems,
|
||||||
|
GN's philosophy prefers a very explicit build specification style that
|
||||||
|
is contrary to globs.
|
||||||
|
|
||||||
|
## 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.
|
|
@ -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 <targettype>` 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`).
|
|
@ -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 <build_dir> <targetname>` 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.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,44 @@
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
This page is about how to design a project that can build independently
|
||||||
|
with GN but also be brought into the Chrome build.
|
||||||
|
|
||||||
|
GN is in principle no different than GYP in that there is some core
|
||||||
|
configuration that must be the same between both the standalone build
|
||||||
|
and the Chrome build. However, GN is much more explicit in its naming
|
||||||
|
and configuration, so the similarities between the two builds are also
|
||||||
|
much more explicit and there is less flexibility in how things are
|
||||||
|
configured.
|
||||||
|
|
||||||
|
# What you need for a minimal GN build
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
* A master build config file. Chrome's is `//build/config/BUILDCONFIG.gn`
|
||||||
|
* A separate build file for the toolchain definition. It's not a good idea
|
||||||
|
to put these in a BUILD.gn file shared with any target definitions for
|
||||||
|
complex reasons. Chrome's are in `//build/toolchain/<platform>/BUILD.gn`.
|
||||||
|
* A `BUILD.gn` file in the root directory. This will be loaded after the
|
||||||
|
build config file to start the build.
|
||||||
|
|
||||||
|
You may want a `.gn` file in the root directory. When you run GN it
|
||||||
|
recursively looks up the directory tree until it finds this file, and it
|
||||||
|
treats the containing directory as the "source root". This file also
|
||||||
|
defines the location of the master build config file:
|
||||||
|
|
||||||
|
* See Chrome's `src/.gn` file.
|
||||||
|
* Unlike Chrome, you probably don't need to define a secondary root.
|
||||||
|
* see `gn help dotfile` for more.
|
||||||
|
|
||||||
|
Adding a `.gn` file in a repository that is pulled into Chrome means
|
||||||
|
that then running GN in your subdirectory will configure a build for
|
||||||
|
your subproject rather than for all of Chrome. This could be an
|
||||||
|
advantage or a disadvantage.
|
||||||
|
|
||||||
|
If you are in a directory with such a file and you want to not use it
|
||||||
|
(e.g., to do the full Chrome build instead), you can use the command-line
|
||||||
|
flags `--root` and `--dotfile` to set the values you want.
|
||||||
|
|
||||||
|
If you want a completely standalone build that has nothing to do with Chrome
|
||||||
|
and doesn't use Chrome's `//build` files, you can look at an example in
|
||||||
|
[//tools/gn/example](../tools/gn/example).
|
|
@ -0,0 +1,306 @@
|
||||||
|
# GN Style Guide
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
## Naming and ordering within the file
|
||||||
|
|
||||||
|
### Location of build files
|
||||||
|
|
||||||
|
It usually makes sense to have more build files closer to the code than
|
||||||
|
fewer ones at the top level; this is in contrast with what we did with
|
||||||
|
GYP. This makes things easier to find, and also makes the set of owners
|
||||||
|
required for reviews smaller since changes are more focused to particular
|
||||||
|
subdirectories.
|
||||||
|
|
||||||
|
### Targets
|
||||||
|
|
||||||
|
* Most BUILD files should have a target with the same name as the
|
||||||
|
directory. This target should be the first target.
|
||||||
|
* Other targets should be in some logical order -- usually
|
||||||
|
more important targets will be first, and unit tests will follow the
|
||||||
|
corresponding target. If there's no clear ordering, consider
|
||||||
|
alphabetical order.
|
||||||
|
* Test support libraries should be static libraries named "test\_support".
|
||||||
|
For example, "//ui/compositor:test\_support". Test support libraries should
|
||||||
|
include as public deps the non-test-support version of the library
|
||||||
|
so tests need only depend on the test\_support target (rather than
|
||||||
|
both).
|
||||||
|
|
||||||
|
Naming advice
|
||||||
|
|
||||||
|
* Targets and configs should be named using lowercase with underscores
|
||||||
|
separating words, unless there is a strong reason to do otherwise.
|
||||||
|
* Source sets, groups, and static libraries do not need globally unique names.
|
||||||
|
Prefer to give such targets short, non-redundant names without worrying
|
||||||
|
about global uniqueness. For example, it looks much better to write a
|
||||||
|
dependency as `"//mojo/public/bindings"` rather than
|
||||||
|
`"//mojo/public/bindings:mojo_bindings"`
|
||||||
|
* Shared libraries (and by extension, components) must have globally unique
|
||||||
|
output names. Give such targets short non-unique names above, and then
|
||||||
|
provide a globally unique `output_name` for that target.
|
||||||
|
* Executables and tests should be given a globally unique name. Technically
|
||||||
|
only the output names must be unique, but since only the output names
|
||||||
|
appear in the shell and on bots, it's much less confusing if the name
|
||||||
|
matches the other places the executable appears.
|
||||||
|
|
||||||
|
### Configs
|
||||||
|
|
||||||
|
* A config associated with a single target should be named the same as
|
||||||
|
the target with `_config` following it.
|
||||||
|
* A config should appear immediately before the corresponding target
|
||||||
|
that uses it.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Example for the `src/foo/BUILD.gn` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Copyright 2016 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.
|
||||||
|
|
||||||
|
# Config for foo is named foo_config and immediately precedes it in the file.
|
||||||
|
config("foo_config") {
|
||||||
|
}
|
||||||
|
|
||||||
|
# Target matching path name is the first target.
|
||||||
|
executable("foo") {
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test for foo follows it.
|
||||||
|
test("foo_unittests") {
|
||||||
|
}
|
||||||
|
|
||||||
|
config("bar_config") {
|
||||||
|
}
|
||||||
|
|
||||||
|
source_set("bar") {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ordering within a target
|
||||||
|
|
||||||
|
1. `output_name` / `visibility` / `testonly`
|
||||||
|
2. `sources`
|
||||||
|
3. `cflags`, `include_dirs`, `defines`, `configs` etc. in whatever
|
||||||
|
order makes sense to you.
|
||||||
|
4. `public_deps`
|
||||||
|
5. `deps`
|
||||||
|
|
||||||
|
### Conditions
|
||||||
|
|
||||||
|
Simple conditions affecting just one variable (e.g. adding a single
|
||||||
|
source or adding a flag for one particular OS) can go beneath the
|
||||||
|
variable they affect. More complicated conditions affecting more than
|
||||||
|
one thing should go at the bottom.
|
||||||
|
|
||||||
|
Conditions should be written to minimize the number of conditional blocks.
|
||||||
|
|
||||||
|
## Formatting and indenting
|
||||||
|
|
||||||
|
GN contains a built-in code formatter which defines the formatting style.
|
||||||
|
Some additional notes:
|
||||||
|
|
||||||
|
* Variables are `lower_case_with_underscores`.
|
||||||
|
* Comments should be complete sentences with periods at the end.
|
||||||
|
* Compiler flags and such should always be commented with what they do
|
||||||
|
and why the flag is needed.
|
||||||
|
|
||||||
|
### Sources
|
||||||
|
|
||||||
|
Prefer to list sources only once. It is OK to conditionally include sources
|
||||||
|
rather than listing them all at the top and then conditionally excluding them
|
||||||
|
when they don't apply. Conditional inclusion is often clearer since a file is
|
||||||
|
only listed once and it's easier to reason about when reading.
|
||||||
|
|
||||||
|
```
|
||||||
|
sources = [
|
||||||
|
"main.cc",
|
||||||
|
]
|
||||||
|
if (use_aura) {
|
||||||
|
sources += [ "thing_aura.cc" ]
|
||||||
|
}
|
||||||
|
if (use_gtk) {
|
||||||
|
sources += [ "thing_gtk.cc" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deps
|
||||||
|
|
||||||
|
* Deps should be in alphabetical order.
|
||||||
|
* Deps within the current file should be written first and not
|
||||||
|
qualified with the file name (just `:foo`).
|
||||||
|
* Other deps should always use fully-qualified path names unless
|
||||||
|
relative ones are required for some reason.
|
||||||
|
|
||||||
|
```
|
||||||
|
deps = [
|
||||||
|
":a_thing",
|
||||||
|
":mystatic",
|
||||||
|
"//foo/bar:other_thing",
|
||||||
|
"//foo/baz:that_thing",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Import
|
||||||
|
|
||||||
|
Use fully-qualified paths for imports:
|
||||||
|
|
||||||
|
```
|
||||||
|
import("//foo/bar/baz.gni") # Even if this file is in the foo/bar directory
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Source sets versus static libraries
|
||||||
|
|
||||||
|
Source sets and static libraries can be used interchangeably in most cases. If
|
||||||
|
you're unsure what to use, a source set is almost never wrong and is less likely
|
||||||
|
to cause problems, but on a large project using the right kind of target can
|
||||||
|
be important, so you should know about the following tradeoffs.
|
||||||
|
|
||||||
|
Static libraries follow different linking rules. When a static library is
|
||||||
|
included in a link, only the object files that contain unresolved symbols will
|
||||||
|
be brought into the build. Source sets result in every object file being added
|
||||||
|
to the link line of the final binary.
|
||||||
|
|
||||||
|
* If you're eventually linking code into a component, shared library, or
|
||||||
|
loadable module, you normally need to use source sets. This is because
|
||||||
|
object files with no symbols referenced from within the shared library will
|
||||||
|
not be linked into the final library at all. This omission will happen even
|
||||||
|
if that object file has a symbol marked for export that targets dependent
|
||||||
|
on that shared library need. This will result in undefined symbols when
|
||||||
|
linking later targets.
|
||||||
|
|
||||||
|
* Unit tests (and anything else with static initializers with side effects)
|
||||||
|
must use source sets. The gtest TEST macros create static initializers
|
||||||
|
that register the test. But since no code references symbols in the object
|
||||||
|
file, linking a test into a static library and then into a test executable
|
||||||
|
means the tests will get stripped.
|
||||||
|
|
||||||
|
* On some platforms, static libraries may involve duplicating all of the
|
||||||
|
data in the object files that comprise it. This takes more disk space and
|
||||||
|
for certain very large libraries in configurations with very large object
|
||||||
|
files can cause internal limits on the size of static libraries to be
|
||||||
|
exceeded. Source sets do not have this limitation. Some targets switch
|
||||||
|
between source sets and static libraries depending on the build
|
||||||
|
configuration to avoid this problem. Some platforms (or toolchains) may
|
||||||
|
support something called "thin archives" which don't have this problem;
|
||||||
|
but you can't rely on this as a portable solution.
|
||||||
|
|
||||||
|
* Source sets can have no sources, while static libraries will give strange
|
||||||
|
platform-specific errors if they have no sources. If a target has only
|
||||||
|
headers (for include checking purposes) or conditionally has no sources on
|
||||||
|
some platforms, use a source set.
|
||||||
|
|
||||||
|
* In cases where a lot of the symbols are not needed for a particular link
|
||||||
|
(this especially happens when linking test binaries), putting that code in
|
||||||
|
a static library can dramatically increase linking performance. This is
|
||||||
|
because the object files not needed for the link are never considered in
|
||||||
|
the first place, rather than forcing the linker to strip the unused code
|
||||||
|
in a later pass when nothing references it.
|
||||||
|
|
||||||
|
### Components versus shared libraries versus source sets
|
||||||
|
|
||||||
|
A component is a Chrome template (rather than a built-in GN concept) that
|
||||||
|
expands either to a shared library or a static library / source set depending
|
||||||
|
on the value of the `is_component_build` variable. This allows release builds
|
||||||
|
to be linked statically in a large binary, but for developers to use shared
|
||||||
|
libraries for most operations. Chrome developers should almost always use
|
||||||
|
a component instead of shared library directly.
|
||||||
|
|
||||||
|
Much like the source set versus static library tradeoff, there's no hard
|
||||||
|
and fast rule as to when you should use a component or not. Using
|
||||||
|
components can significantly speed up incremental builds by making
|
||||||
|
linking much faster, but they require you to have to think about which
|
||||||
|
symbols need to be exported from the target.
|
||||||
|
|
||||||
|
### Loadable modules versus shared libraries
|
||||||
|
|
||||||
|
A shared library will be listed on the link line of dependent targets and will
|
||||||
|
be loaded automatically by the operating system when the application starts
|
||||||
|
and symbols automatically resolved. A loadable module will not be linked
|
||||||
|
directly and the application must manually load it.
|
||||||
|
|
||||||
|
On Windows and Linux shared libraries and loadable modules result in the same
|
||||||
|
type of file (`.dll` and `.so`, respectively). The only difference is in how
|
||||||
|
they are linked to dependent targets. On these platforms, having a `deps`
|
||||||
|
dependency on a loadable module is the same as having a `data_deps`
|
||||||
|
(non-linked) dependency on a shared library.
|
||||||
|
|
||||||
|
On Mac, these targets have different formats: a shared library will generate a
|
||||||
|
`.dylib` file and a loadable module will generate a `.so` file.
|
||||||
|
|
||||||
|
Use loadable modules for things like plugins. In the case of plugin-like
|
||||||
|
libraries, it's good practice to use both a loadable module for the target type
|
||||||
|
(even for platforms where it doesn't matter) and data deps for targets that
|
||||||
|
depend on it so it's clear from both places that how the library will be linked
|
||||||
|
and loaded.
|
||||||
|
|
||||||
|
## Build arguments
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
|
||||||
|
Build arguments should be scoped to a unit of behavior, e.g. enabling a feature.
|
||||||
|
Typically an argument would be declared in an imported file to share it with
|
||||||
|
the subset of the build that could make use of it.
|
||||||
|
|
||||||
|
Chrome has many legacy flags in `//build/config/features.gni`,
|
||||||
|
`//build/config/ui.gni`. These locations are deprecated. Feature flags should
|
||||||
|
go along with the code for the feature. Many browser-level features can go
|
||||||
|
somewhere in `//chrome/` without lower-level code knowing about it. Some
|
||||||
|
UI environment flags can go into `//ui/`, and many flags can also go with
|
||||||
|
the corresponding code in `//components/`. You can write a `.gni` file in
|
||||||
|
components and have build files in chrome or content import it if necessary.
|
||||||
|
|
||||||
|
The way to think about things in the `//build` directory is that this is
|
||||||
|
DEPSed into various projects like V8 and WebRTC. Build flags specific to
|
||||||
|
code outside of the build directory shouldn't be in the build directory, and
|
||||||
|
V8 shouldn't get feature defines for Chrome features.
|
||||||
|
|
||||||
|
New feature defines should use the buildflag system. See
|
||||||
|
`//build/buildflag_header.gni` which allows preprocessor defines to be
|
||||||
|
modularized without many of the disadvantages that made us use global defines
|
||||||
|
in the past.
|
||||||
|
|
||||||
|
### Type
|
||||||
|
|
||||||
|
Arguments support all the [GN language types](language.md#Language).
|
||||||
|
|
||||||
|
In the vast majority of cases `boolean` is the preferred type, since most
|
||||||
|
arguments are enabling or disabling features or includes.
|
||||||
|
|
||||||
|
`String`s are typically used for filepaths. They are also used for enumerated
|
||||||
|
types, though `integer`s are sometimes used as well.
|
||||||
|
|
||||||
|
### Naming conventions
|
||||||
|
|
||||||
|
While there are no hard and fast rules around argument naming there are
|
||||||
|
many common conventions. If you ever want to see the current list of argument
|
||||||
|
names and default values for your current checkout use
|
||||||
|
`gn args out/Debug --list --short`.
|
||||||
|
|
||||||
|
`use_foo` - indicates dependencies or major codepaths to include (e.g.
|
||||||
|
`use_open_ssl`, `use_ozone`, `use_cups`)
|
||||||
|
|
||||||
|
`enable_foo` - indicates feature or tools to be enabled (e.g.
|
||||||
|
`enable_google_now`, `enable_nacl`, `enable_remoting`, `enable_pdf`)
|
||||||
|
|
||||||
|
`disable_foo` - _NOT_ recommended, use `enable_foo` instead with swapped default
|
||||||
|
value
|
||||||
|
|
||||||
|
`is_foo` - usually a global state descriptor (e.g. `is_chrome_branded`,
|
||||||
|
`is_desktop_linux`); poor choice for non-globals
|
||||||
|
|
||||||
|
`foo_use_bar` - prefixes can be used to indicate a limited scope for an argument
|
||||||
|
(e.g. `rtc_use_h264`, `v8_use_snapshot`)
|
||||||
|
|
||||||
|
#### Variables
|
||||||
|
|
||||||
|
Prefix top-level local variables within `.gni` files with an underscore. This
|
||||||
|
prefix causes variables to be unavailable to importing scripts.
|
||||||
|
|
||||||
|
```
|
||||||
|
_this_var_will_not_be_exported = 1
|
||||||
|
but_this_one_will = 2
|
||||||
|
```
|
|
@ -0,0 +1 @@
|
||||||
|
/out/
|
|
@ -0,0 +1,6 @@
|
||||||
|
# The location of the build configuration file.
|
||||||
|
buildconfig = "//build/BUILDCONFIG.gn"
|
||||||
|
|
||||||
|
# The build script are using `python3` which is the only version of
|
||||||
|
# python installed by default on macOS Monterey and above.
|
||||||
|
script_executable = "python3"
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
group("all") {
|
||||||
|
deps = [
|
||||||
|
"//app:hello",
|
||||||
|
"//host:username",
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright 2019 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 <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2019 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 "app/AppDelegate.h"
|
||||||
|
|
||||||
|
#import "app/Foo.h"
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication*)application
|
||||||
|
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
|
||||||
|
NSLog(@"%@", [[[FooWrapper alloc] init] helloWithName:@"World"]);
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UISceneSession lifecycle
|
||||||
|
|
||||||
|
- (UISceneConfiguration*)application:(UIApplication*)application
|
||||||
|
configurationForConnectingSceneSession:
|
||||||
|
(UISceneSession*)connectingSceneSession
|
||||||
|
options:(UISceneConnectionOptions*)options {
|
||||||
|
return
|
||||||
|
[[UISceneConfiguration alloc] initWithName:@"Default Configuration"
|
||||||
|
sessionRole:connectingSceneSession.role];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)application:(UIApplication*)application
|
||||||
|
didDiscardSceneSessions:(NSSet<UISceneSession*>*)sceneSessions {
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/templates/ios_app_bundle.gni")
|
||||||
|
import("//build/config/ios/templates/storyboards.gni")
|
||||||
|
|
||||||
|
ios_app_bundle("hello") {
|
||||||
|
output_name = "Hello"
|
||||||
|
|
||||||
|
info_plist = "resources/Info.plist"
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
"AppDelegate.h",
|
||||||
|
"AppDelegate.m",
|
||||||
|
"SceneDelegate.h",
|
||||||
|
"SceneDelegate.m",
|
||||||
|
"ViewController.h",
|
||||||
|
"ViewController.m",
|
||||||
|
"main.m",
|
||||||
|
]
|
||||||
|
|
||||||
|
frameworks = [
|
||||||
|
"CoreGraphics.framework",
|
||||||
|
"Foundation.framework",
|
||||||
|
"UIKit.framework",
|
||||||
|
]
|
||||||
|
|
||||||
|
deps = [
|
||||||
|
":foo",
|
||||||
|
":storyboards",
|
||||||
|
"//shared:hello_framework",
|
||||||
|
"//shared:hello_framework+bundle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
storyboards("storyboards") {
|
||||||
|
sources = [
|
||||||
|
"resources/LaunchScreen.storyboard",
|
||||||
|
"resources/Main.storyboard",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
source_set("baz") {
|
||||||
|
module_name = "Baz"
|
||||||
|
sources = [ "Baz.swift" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
source_set("bar") {
|
||||||
|
module_name = "Bar"
|
||||||
|
sources = [ "Bar.swift" ]
|
||||||
|
deps = [ ":baz" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
group("bar_indirect") {
|
||||||
|
public_deps = [ ":bar" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
source_set("foo") {
|
||||||
|
module_name = "Foo"
|
||||||
|
bridge_header = "Foo-Bridging-Header.h"
|
||||||
|
sources = [
|
||||||
|
"Foo.swift",
|
||||||
|
"FooWrapper.swift",
|
||||||
|
]
|
||||||
|
deps = [ ":bar_indirect" ]
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
import Baz;
|
||||||
|
|
||||||
|
public class Greeter {
|
||||||
|
public static func greet(greeting: String, name: String, from: String) -> String {
|
||||||
|
return greeting + ", " + name + " (from " + from + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
class Baz {}
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
import Bar
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
var name: String;
|
||||||
|
public init(name: String) {
|
||||||
|
self.name = name;
|
||||||
|
}
|
||||||
|
public func hello(name: String) -> String {
|
||||||
|
return Greeter.greet(greeting: "Hello", name: name, from: self.name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
import Foundation;
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public class FooWrapper : NSObject {
|
||||||
|
@objc
|
||||||
|
public func hello(name: String) -> String {
|
||||||
|
return Foo(name: "Foo").hello(name: name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright 2019 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 <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
|
||||||
|
|
||||||
|
@property(strong, nonatomic) UIWindow* window;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2019 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 "app/SceneDelegate.h"
|
||||||
|
|
||||||
|
@implementation SceneDelegate
|
||||||
|
|
||||||
|
- (void)scene:(UIScene*)scene
|
||||||
|
willConnectToSession:(UISceneSession*)session
|
||||||
|
options:(UISceneConnectionOptions*)connectionOptions {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sceneDidDisconnect:(UIScene*)scene {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sceneDidBecomeActive:(UIScene*)scene {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sceneWillResignActive:(UIScene*)scene {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sceneWillEnterForeground:(UIScene*)scene {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sceneDidEnterBackground:(UIScene*)scene {
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright 2019 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 <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface ViewController : UIViewController
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2019 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 <HelloShared/HelloShared.h>
|
||||||
|
|
||||||
|
#import "app/ViewController.h"
|
||||||
|
|
||||||
|
@implementation ViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
UILabel* label = [self labelWithText:[Greetings greet]];
|
||||||
|
[self addCenteredView:label toParentView:self.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UILabel*)labelWithText:(NSString*)text {
|
||||||
|
UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||||
|
label.text = text;
|
||||||
|
[label sizeToFit];
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addCenteredView:(UIView*)view toParentView:(UIView*)parentView {
|
||||||
|
view.center = [parentView convertPoint:parentView.center
|
||||||
|
fromView:parentView.superview];
|
||||||
|
[parentView addSubview:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2019 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 <UIKit/UIKit.h>
|
||||||
|
#import "app/AppDelegate.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
NSString* appDelegateClassName;
|
||||||
|
@autoreleasepool {
|
||||||
|
appDelegateClassName = NSStringFromClass([AppDelegate class]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
<false/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>Default Configuration</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>SceneDelegate</string>
|
||||||
|
<key>UISceneStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/deployment_target.gni")
|
||||||
|
|
||||||
|
config("compiler") {
|
||||||
|
configs = [
|
||||||
|
":include_dirs",
|
||||||
|
":cpp_standard",
|
||||||
|
":objc_use_arc",
|
||||||
|
":objc_abi_version",
|
||||||
|
]
|
||||||
|
cflags = [ "-g" ]
|
||||||
|
swiftflags = [ "-g" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
config("shared_binary") {
|
||||||
|
if (current_os == "ios" || current_os == "mac") {
|
||||||
|
configs = [
|
||||||
|
":rpath_config",
|
||||||
|
":swift_libdir",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config("objc_abi_version") {
|
||||||
|
cflags_objc = [ "-fobjc-abi-version=2" ]
|
||||||
|
cflags_objcc = cflags_objc
|
||||||
|
ldflags = [
|
||||||
|
"-Xlinker",
|
||||||
|
"-objc_abi_version",
|
||||||
|
"-Xlinker",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
config("include_dirs") {
|
||||||
|
include_dirs = [
|
||||||
|
"//",
|
||||||
|
root_gen_dir,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
config("objc_use_arc") {
|
||||||
|
cflags_objc = [
|
||||||
|
"-fobjc-arc",
|
||||||
|
"-fobjc-weak",
|
||||||
|
]
|
||||||
|
cflags_objcc = cflags_objc
|
||||||
|
}
|
||||||
|
|
||||||
|
config("cpp_standard") {
|
||||||
|
cflags_c = [ "--std=c11" ]
|
||||||
|
cflags_cc = [
|
||||||
|
"--std=c++17",
|
||||||
|
"--stdlib=libc++",
|
||||||
|
]
|
||||||
|
ldflags = [ "--stdlib=libc++" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_os == "ios" || current_os == "mac") {
|
||||||
|
config("rpath_config") {
|
||||||
|
ldflags = [
|
||||||
|
"-Xlinker",
|
||||||
|
"-rpath",
|
||||||
|
"-Xlinker",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"-Xlinker",
|
||||||
|
"-rpath",
|
||||||
|
"-Xlinker",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
_sdk_info = exec_script("//build/config/ios/scripts/sdk_info.py",
|
||||||
|
[
|
||||||
|
"--target-cpu",
|
||||||
|
current_cpu,
|
||||||
|
"--target-environment",
|
||||||
|
target_environment,
|
||||||
|
"--deployment-target",
|
||||||
|
ios_deployment_target,
|
||||||
|
],
|
||||||
|
"json")
|
||||||
|
|
||||||
|
_lib_swift_dir = "${_sdk_info.toolchain_path}/usr/lib/swift"
|
||||||
|
if (current_os == "ios") {
|
||||||
|
if (_sdk_info.is_simulator) {
|
||||||
|
_system_lib_swift_dir = "$_lib_swift_dir/iphonesimulator"
|
||||||
|
} else {
|
||||||
|
_system_lib_swift_dir = "$_lib_swift_dir/iphoneos"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_system_lib_swift_dir = "$_lib_swift_dir/macosx"
|
||||||
|
}
|
||||||
|
|
||||||
|
config("swift_libdir") {
|
||||||
|
lib_dirs = [
|
||||||
|
"${_sdk_info.sdk_path}/usr/lib/swift",
|
||||||
|
_system_lib_swift_dir,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
if (target_os == "") {
|
||||||
|
target_os = "ios"
|
||||||
|
}
|
||||||
|
if (target_cpu == "") {
|
||||||
|
target_cpu = host_cpu
|
||||||
|
}
|
||||||
|
if (current_cpu == "") {
|
||||||
|
current_cpu = target_cpu
|
||||||
|
}
|
||||||
|
if (current_os == "") {
|
||||||
|
current_os = target_os
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_args() {
|
||||||
|
# Control which platform the build is targeting. Valid values are
|
||||||
|
# "simulator" or "device".
|
||||||
|
target_environment = "simulator"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(
|
||||||
|
target_environment == "simulator" || target_environment == "device",
|
||||||
|
"Only supported values for target_environment are 'simulator' and 'device'")
|
||||||
|
|
||||||
|
# All binary targets will get this list of configs by default.
|
||||||
|
_shared_binary_target_configs = [ "//build:compiler" ]
|
||||||
|
|
||||||
|
# Apply that default list to the binary target types.
|
||||||
|
set_defaults("executable") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
configs += [ "//build:shared_binary" ]
|
||||||
|
}
|
||||||
|
set_defaults("static_library") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
}
|
||||||
|
set_defaults("shared_library") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
configs += [ "//build:shared_binary" ]
|
||||||
|
}
|
||||||
|
set_defaults("source_set") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
}
|
||||||
|
|
||||||
|
set_default_toolchain("//build/toolchain/$target_os:clang_$target_cpu")
|
||||||
|
|
||||||
|
if (target_os == "ios") {
|
||||||
|
host_toolchain = "//build/toolchain/$host_os:clang_$host_cpu"
|
||||||
|
} else {
|
||||||
|
host_toolchain = default_toolchain
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/sdk_info.gni")
|
||||||
|
import("//build/config/ios/templates/merge_plist.gni")
|
||||||
|
|
||||||
|
merge_plist("compiler_plist") {
|
||||||
|
substitutions = {
|
||||||
|
COMPILER_NAME = sdk_info.compiler
|
||||||
|
MACOS_BUILD = sdk_info.macos_build
|
||||||
|
PLATFORM_BUILD = sdk_info.sdk_build
|
||||||
|
PLATFORM_DISPLAY_NAME = sdk_info.platform_name
|
||||||
|
PLATFORM_NAME = sdk_info.platform
|
||||||
|
PLATFORM_VERSION = sdk_info.sdk_version
|
||||||
|
SDK_BUILD = sdk_info.sdk_build
|
||||||
|
SDK_NAME = sdk_info.sdk
|
||||||
|
XCODE_BUILD = sdk_info.xcode_build
|
||||||
|
XCODE_VERSION = sdk_info.xcode_version
|
||||||
|
}
|
||||||
|
|
||||||
|
output = "$target_out_dir/compiler_plist/Info.plist"
|
||||||
|
plists = [ "//build/config/ios/resources/compiler-Info.plist" ]
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
declare_args() {
|
||||||
|
# Default bundle identifier prefix.
|
||||||
|
default_bundle_identifier_prefix = "com.google"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
declare_args() {
|
||||||
|
# Maximum deployment target. Automatically detected by sdk_info.py but
|
||||||
|
# needs to be specified to a version < 11.0 if targetting 32-bit archs.
|
||||||
|
ios_deployment_target = "13.0"
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>application-identifier</key>
|
||||||
|
<string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
|
||||||
|
<key>keychain-access-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>$(SDK_NAME)</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>$(XCODE_VERSION)</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>$(SDK_BUILD)</string>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>$(MACOS_BUILD)</string>
|
||||||
|
<key>DTPlatformName</key>
|
||||||
|
<string>$(PLATFORM_NAME)</string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>$(COMPILER_NAME)</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>$(PLATFORM_VERSION)</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>$(XCODE_BUILD)</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string>$(PLATFORM_BUILD)</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>$(PLATFORM_DISPLAY_NAME)</string>
|
||||||
|
</array>
|
||||||
|
<key>UIDeviceFamily</key>
|
||||||
|
<array>
|
||||||
|
<string>1</string>
|
||||||
|
<string>2</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Compiles a .storyboard file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def CompileStoryboard(storyboard, out, ios_deployment_target):
|
||||||
|
"""Compiles |storyboard| storyboard to |out| for |ios_deployment_target|."""
|
||||||
|
subprocess.check_call([
|
||||||
|
'ibtool', '--target-device', 'iphone', '--target-device', 'ipad',
|
||||||
|
'--auto-activate-custom-fonts', '--minimum-deployment-target',
|
||||||
|
ios_deployment_target, '--compilation-directory', out,
|
||||||
|
storyboard,
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs(argv):
|
||||||
|
"""Parses command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__,
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'input',
|
||||||
|
help='path to the .storyboard file to compile')
|
||||||
|
parser.add_argument(
|
||||||
|
'-o', '--output', required=True,
|
||||||
|
help='path to the result')
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--minimum-deployment-target', required=True,
|
||||||
|
help='iOS deployment target')
|
||||||
|
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
args = ParseArgs(argv)
|
||||||
|
|
||||||
|
CompileStoryboard(
|
||||||
|
os.path.abspath(args.input),
|
||||||
|
os.path.dirname(os.path.abspath(args.output)),
|
||||||
|
args.minimum_deployment_target)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Finds the team identifier to use for code signing bundle given its
|
||||||
|
bundle identifier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import fnmatch
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import plistlib
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class ProvisioningProfile(object):
|
||||||
|
|
||||||
|
def __init__(self, mobileprovision_path):
|
||||||
|
self._path = mobileprovision_path
|
||||||
|
self._data = plistlib.loads(
|
||||||
|
subprocess.check_output(
|
||||||
|
['security', 'cms', '-D', '-i', mobileprovision_path]))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def application_identifier_pattern(self):
|
||||||
|
return self._data.get('Entitlements', {}).get('application-identifier', '')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def app_identifier_prefix(self):
|
||||||
|
return self._data.get('ApplicationIdentifierPrefix', [''])[0]
|
||||||
|
|
||||||
|
def ValidToSignBundle(self, bundle_identifier):
|
||||||
|
"""Returns whether the provisioning profile can sign |bundle_identifier|."""
|
||||||
|
return fnmatch.fnmatch(
|
||||||
|
self.app_identifier_prefix + '.' + bundle_identifier,
|
||||||
|
self.application_identifier_pattern)
|
||||||
|
|
||||||
|
|
||||||
|
def GetProvisioningProfilesDir():
|
||||||
|
"""Returns the location of the locally installed provisioning profiles."""
|
||||||
|
return os.path.join(
|
||||||
|
os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
|
||||||
|
|
||||||
|
|
||||||
|
def ListProvisioningProfiles():
|
||||||
|
"""Returns a list of all installed provisioning profiles."""
|
||||||
|
return glob.glob(
|
||||||
|
os.path.join(GetProvisioningProfilesDir(), '*.mobileprovision'))
|
||||||
|
|
||||||
|
|
||||||
|
def LoadProvisioningProfile(mobileprovision_path):
|
||||||
|
"""Loads the Apple Property List embedded in |mobileprovision_path|."""
|
||||||
|
return ProvisioningProfile(mobileprovision_path)
|
||||||
|
|
||||||
|
|
||||||
|
def ListValidProvisioningProfiles(bundle_identifier):
|
||||||
|
"""Returns a list of provisioning profile valid for |bundle_identifier|."""
|
||||||
|
result = []
|
||||||
|
for mobileprovision_path in ListProvisioningProfiles():
|
||||||
|
mobileprovision = LoadProvisioningProfile(mobileprovision_path)
|
||||||
|
if mobileprovision.ValidToSignBundle(bundle_identifier):
|
||||||
|
result.append(mobileprovision)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def FindProvisioningProfile(bundle_identifier):
|
||||||
|
"""Returns the path to the provisioning profile for |bundle_identifier|."""
|
||||||
|
return max(
|
||||||
|
ListValidProvisioningProfiles(bundle_identifier),
|
||||||
|
key=lambda p: len(p.application_identifier_pattern))
|
||||||
|
|
||||||
|
|
||||||
|
def GenerateSubsitutions(bundle_identifier, mobileprovision):
|
||||||
|
if mobileprovision:
|
||||||
|
app_identifier_prefix = mobileprovision.app_identifier_prefix + '.'
|
||||||
|
else:
|
||||||
|
app_identifier_prefix = '*.'
|
||||||
|
|
||||||
|
return {
|
||||||
|
'CFBundleIdentifier': bundle_identifier,
|
||||||
|
'AppIdentifierPrefix': app_identifier_prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs(argv):
|
||||||
|
"""Parses command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__,
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-b', '--bundle-identifier', required=True,
|
||||||
|
help='bundle identifier for the application')
|
||||||
|
parser.add_argument(
|
||||||
|
'-o', '--output', default='-',
|
||||||
|
help='path to the result; - means stdout')
|
||||||
|
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
args = ParseArgs(argv)
|
||||||
|
|
||||||
|
mobileprovision = FindProvisioningProfile(args.bundle_identifier)
|
||||||
|
substitutions = GenerateSubsitutions(args.bundle_identifier, mobileprovision)
|
||||||
|
|
||||||
|
if args.output == '-':
|
||||||
|
sys.stdout.write(json.dumps(substitutions))
|
||||||
|
else:
|
||||||
|
with open(args.output, 'w') as output:
|
||||||
|
output.write(json.dumps(substitutions))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Copyright 2019 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 an umbrella header file that #import all public header of a
|
||||||
|
binary framework.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def GenerateImport(header):
|
||||||
|
"""Returns a string for importing |header|."""
|
||||||
|
return '#import "%s"\n' % os.path.basename(header)
|
||||||
|
|
||||||
|
|
||||||
|
def GenerateUmbrellaHeader(headers):
|
||||||
|
"""Returns a string with the content of the umbrella header."""
|
||||||
|
return ''.join([ GenerateImport(header) for header in headers ])
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs(argv):
|
||||||
|
"""Parses command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__,
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'headers', nargs='+',
|
||||||
|
help='path to the public heeaders')
|
||||||
|
parser.add_argument(
|
||||||
|
'-o', '--output', default='-',
|
||||||
|
help='path of the output file to create; - means stdout')
|
||||||
|
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
args = ParseArgs(argv)
|
||||||
|
|
||||||
|
content = GenerateUmbrellaHeader(args.headers)
|
||||||
|
|
||||||
|
if args.output == '-':
|
||||||
|
sys.stdout.write(content)
|
||||||
|
else:
|
||||||
|
with open(args.output, 'w') as output:
|
||||||
|
output.write(content)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Merges multiple Apple Property List files (.plist) and perform variables
|
||||||
|
substitutions $(VARIABLE) in the Property List string values.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# Pattern representing a variable to substitue in a string value.
|
||||||
|
VARIABLE_PATTERN = re.compile(r'\$\(([^)]*)\)')
|
||||||
|
|
||||||
|
|
||||||
|
def GetCommandOutput(command):
|
||||||
|
"""Returns the output of `command` as a string."""
|
||||||
|
return subprocess.check_output(command, encoding='utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def LoadPlist(plist_path):
|
||||||
|
"""Loads Apple Property List file at |plist_path|."""
|
||||||
|
return json.loads(
|
||||||
|
GetCommandOutput(['plutil', '-convert', 'json', '-o', '-', plist_path]))
|
||||||
|
|
||||||
|
|
||||||
|
def SavePlist(plist_path, content, format):
|
||||||
|
"""Saves |content| as Apple Property List in |format| at |plist_path|."""
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
['plutil', '-convert', format, '-o', plist_path, '-'],
|
||||||
|
stdin=subprocess.PIPE)
|
||||||
|
output, _ = proc.communicate(json.dumps(content).encode('utf-8'))
|
||||||
|
if proc.returncode:
|
||||||
|
raise subprocess.CalledProcessError(
|
||||||
|
proc.returncode,
|
||||||
|
['plutil', '-convert', format, '-o', plist_path, '-'],
|
||||||
|
output)
|
||||||
|
|
||||||
|
|
||||||
|
def MergeObjects(obj1, obj2):
|
||||||
|
"""Merges two objects (either dictionary, list, string or numbers)."""
|
||||||
|
if type(obj1) != type(obj2):
|
||||||
|
return obj2
|
||||||
|
|
||||||
|
if isinstance(obj2, dict):
|
||||||
|
result = dict(obj1)
|
||||||
|
for key in obj2:
|
||||||
|
value1 = obj1.get(key, None)
|
||||||
|
value2 = obj2.get(key, None)
|
||||||
|
result[key] = MergeObjects(value1, value2)
|
||||||
|
return result
|
||||||
|
|
||||||
|
if isinstance(obj2, list):
|
||||||
|
return obj1 + obj2
|
||||||
|
|
||||||
|
return obj2
|
||||||
|
|
||||||
|
|
||||||
|
def MergePlists(plist_paths):
|
||||||
|
"""Loads and merges all Apple Property List files at |plist_paths|."""
|
||||||
|
plist = {}
|
||||||
|
for plist_path in plist_paths:
|
||||||
|
plist = MergeObjects(plist, LoadPlist(plist_path))
|
||||||
|
return plist
|
||||||
|
|
||||||
|
|
||||||
|
def PerformSubstitutions(plist, substitutions):
|
||||||
|
"""Performs variables substitutions in |plist| given by |substitutions|."""
|
||||||
|
if isinstance(plist, dict):
|
||||||
|
result = dict(plist)
|
||||||
|
for key in plist:
|
||||||
|
result[key] = PerformSubstitutions(plist[key], substitutions)
|
||||||
|
return result
|
||||||
|
|
||||||
|
if isinstance(plist, list):
|
||||||
|
return [ PerformSubstitutions(item, substitutions) for item in plist ]
|
||||||
|
|
||||||
|
if isinstance(plist, str):
|
||||||
|
result = plist
|
||||||
|
while True:
|
||||||
|
match = VARIABLE_PATTERN.search(result)
|
||||||
|
if not match:
|
||||||
|
break
|
||||||
|
|
||||||
|
extent = match.span()
|
||||||
|
expand = substitutions[match.group(1)]
|
||||||
|
result = result[:extent[0]] + expand + result[extent[1]:]
|
||||||
|
return result
|
||||||
|
|
||||||
|
return plist
|
||||||
|
|
||||||
|
|
||||||
|
def PerformSubstitutionsFrom(plist, substitutions_path):
|
||||||
|
"""Performs variable substitutions in |plist| from |substitutions_path|."""
|
||||||
|
with open(substitutions_path) as substitutions_file:
|
||||||
|
return PerformSubstitutions(plist, json.load(substitutions_file))
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs(argv):
|
||||||
|
"""Parses command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__,
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-s', '--substitutions',
|
||||||
|
help='path to a JSON file containing variable substitutions')
|
||||||
|
parser.add_argument(
|
||||||
|
'-f', '--format', default='json', choices=('json', 'binary1', 'xml1'),
|
||||||
|
help='format of the generated file')
|
||||||
|
parser.add_argument(
|
||||||
|
'-o', '--output', default='-',
|
||||||
|
help='path to the result; - means stdout')
|
||||||
|
parser.add_argument(
|
||||||
|
'inputs', nargs='+',
|
||||||
|
help='path of the input files to merge')
|
||||||
|
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
args = ParseArgs(argv)
|
||||||
|
|
||||||
|
data = MergePlists(args.inputs)
|
||||||
|
if args.substitutions:
|
||||||
|
data = PerformSubstitutionsFrom(
|
||||||
|
data, args.substitutions)
|
||||||
|
|
||||||
|
SavePlist(args.output, data, args.format)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
|
@ -0,0 +1,159 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
"""Collects information about the SDK and return them as JSON file."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Patterns used to extract the Xcode version and build version.
|
||||||
|
XCODE_VERSION_PATTERN = re.compile(r'Xcode (\d+)\.(\d+)')
|
||||||
|
XCODE_BUILD_PATTERN = re.compile(r'Build version (.*)')
|
||||||
|
|
||||||
|
|
||||||
|
def GetCommandOutput(command):
|
||||||
|
"""Returns the output of `command` as a string."""
|
||||||
|
return subprocess.check_output(command, encoding='utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def GetAppleCpuName(target_cpu):
|
||||||
|
"""Returns the name of the |target_cpu| using Apple's convention."""
|
||||||
|
return {
|
||||||
|
'x64': 'x86_64',
|
||||||
|
'arm': 'armv7',
|
||||||
|
'x86': 'i386'
|
||||||
|
}.get(target_cpu, target_cpu)
|
||||||
|
|
||||||
|
|
||||||
|
def GetPlatform(target_environment):
|
||||||
|
"""Returns the platform for |target_environment|."""
|
||||||
|
return {
|
||||||
|
'simulator': 'iphonesimulator',
|
||||||
|
'device': 'iphoneos'
|
||||||
|
}[target_environment]
|
||||||
|
|
||||||
|
|
||||||
|
def GetPlaformDisplayName(target_environment):
|
||||||
|
"""Returns the platform display name for |target_environment|."""
|
||||||
|
return {
|
||||||
|
'simulator': 'iPhoneSimulator',
|
||||||
|
'device': 'iPhoneOS'
|
||||||
|
}[target_environment]
|
||||||
|
|
||||||
|
|
||||||
|
def ExtractOSVersion():
|
||||||
|
"""Extract the version of macOS of the current machine."""
|
||||||
|
return GetCommandOutput(['sw_vers', '-buildVersion']).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def ExtractXcodeInfo():
|
||||||
|
"""Extract Xcode version and build version."""
|
||||||
|
version, build = None, None
|
||||||
|
for line in GetCommandOutput(['xcodebuild', '-version']).splitlines():
|
||||||
|
match = XCODE_VERSION_PATTERN.search(line)
|
||||||
|
if match:
|
||||||
|
major, minor = match.group(1), match.group(2)
|
||||||
|
version = major.rjust(2, '0') + minor.ljust(2, '0')
|
||||||
|
continue
|
||||||
|
|
||||||
|
match = XCODE_BUILD_PATTERN.search(line)
|
||||||
|
if match:
|
||||||
|
build = match.group(1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
assert version is not None and build is not None
|
||||||
|
return version, build
|
||||||
|
|
||||||
|
|
||||||
|
def ExtractSDKInfo(info, sdk):
|
||||||
|
"""Extract information about the SDK."""
|
||||||
|
return GetCommandOutput(['xcrun', '--sdk', sdk, '--show-sdk-' + info]).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def GetDeveloperDir():
|
||||||
|
"""Returns the developer dir."""
|
||||||
|
return GetCommandOutput(['xcode-select', '-print-path']).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def GetSDKInfoForCpu(target_cpu, environment, sdk_version, deployment_target):
|
||||||
|
"""Returns a dictionary with information about the SDK."""
|
||||||
|
platform = GetPlatform(environment)
|
||||||
|
sdk_version = sdk_version or ExtractSDKInfo('version', platform)
|
||||||
|
deployment_target = deployment_target or sdk_version
|
||||||
|
|
||||||
|
target = target_cpu + '-apple-ios' + deployment_target
|
||||||
|
if environment == 'simulator':
|
||||||
|
target = target + '-simulator'
|
||||||
|
|
||||||
|
xcode_version, xcode_build = ExtractXcodeInfo()
|
||||||
|
effective_sdk = platform + sdk_version
|
||||||
|
|
||||||
|
sdk_info = {}
|
||||||
|
sdk_info['compiler'] = 'com.apple.compilers.llvm.clang.1_0'
|
||||||
|
sdk_info['is_simulator'] = environment == 'simulator'
|
||||||
|
sdk_info['macos_build'] = ExtractOSVersion()
|
||||||
|
sdk_info['platform'] = platform
|
||||||
|
sdk_info['platform_name'] = GetPlaformDisplayName(environment)
|
||||||
|
sdk_info['sdk'] = effective_sdk
|
||||||
|
sdk_info['sdk_build'] = ExtractSDKInfo('build-version', effective_sdk)
|
||||||
|
sdk_info['sdk_path'] = ExtractSDKInfo('path', effective_sdk)
|
||||||
|
sdk_info['toolchain_path'] = os.path.join(
|
||||||
|
GetDeveloperDir(), 'Toolchains/XcodeDefault.xctoolchain')
|
||||||
|
sdk_info['sdk_version'] = sdk_version
|
||||||
|
sdk_info['target'] = target
|
||||||
|
sdk_info['xcode_build'] = xcode_build
|
||||||
|
sdk_info['xcode_version'] = xcode_version
|
||||||
|
|
||||||
|
return sdk_info
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs(argv):
|
||||||
|
"""Parses command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__,
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--target-cpu', default='x64',
|
||||||
|
choices=('x86', 'x64', 'arm', 'arm64'),
|
||||||
|
help='target cpu')
|
||||||
|
parser.add_argument(
|
||||||
|
'-e',
|
||||||
|
'--target-environment',
|
||||||
|
default='simulator',
|
||||||
|
choices=('simulator', 'device'),
|
||||||
|
help='target environment')
|
||||||
|
parser.add_argument(
|
||||||
|
'-s', '--sdk-version',
|
||||||
|
help='version of the sdk')
|
||||||
|
parser.add_argument(
|
||||||
|
'-d', '--deployment-target',
|
||||||
|
help='iOS deployment target')
|
||||||
|
parser.add_argument(
|
||||||
|
'-o', '--output', default='-',
|
||||||
|
help='path of the output file to create; - means stdout')
|
||||||
|
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
args = ParseArgs(argv)
|
||||||
|
|
||||||
|
sdk_info = GetSDKInfoForCpu(
|
||||||
|
GetAppleCpuName(args.target_cpu), args.target_environment,
|
||||||
|
args.sdk_version, args.deployment_target)
|
||||||
|
|
||||||
|
if args.output == '-':
|
||||||
|
sys.stdout.write(json.dumps(sdk_info))
|
||||||
|
else:
|
||||||
|
with open(args.output, 'w') as output:
|
||||||
|
output.write(json.dumps(sdk_info))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/deployment_target.gni")
|
||||||
|
|
||||||
|
sdk_info = exec_script("//build/config/ios/scripts/sdk_info.py",
|
||||||
|
[
|
||||||
|
"--target-cpu",
|
||||||
|
current_cpu,
|
||||||
|
"--target-environment",
|
||||||
|
target_environment,
|
||||||
|
"--deployment-target",
|
||||||
|
ios_deployment_target,
|
||||||
|
],
|
||||||
|
"json")
|
|
@ -0,0 +1,147 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/bundle_identifier_prefix.gni")
|
||||||
|
import("//build/config/ios/sdk_info.gni")
|
||||||
|
import("//build/config/ios/templates/ios_binary_bundle.gni")
|
||||||
|
import("//build/config/ios/templates/merge_plist.gni")
|
||||||
|
|
||||||
|
# Template to generate an app bundle.
|
||||||
|
#
|
||||||
|
# All the other parameters are forwarded to a shared_library target that will
|
||||||
|
# generate the bundle binary. In general, you want to pass at least "sources"
|
||||||
|
# or "deps" to have some binary objects included in your shared library.
|
||||||
|
#
|
||||||
|
# Arguments
|
||||||
|
#
|
||||||
|
# - info_plist (optional)
|
||||||
|
#
|
||||||
|
# path to additional Info.plist to merge into the final bundle Info.plist
|
||||||
|
#
|
||||||
|
# - bundle_identifier_prefix (optional)
|
||||||
|
#
|
||||||
|
# prefix for the bundle identifier (the full identifier will be defined
|
||||||
|
# to $bundle_identifier_prefix.$output_name); if unset will defaults to
|
||||||
|
# default_bundle_identifier_prefix
|
||||||
|
#
|
||||||
|
# - output_name (optional)
|
||||||
|
#
|
||||||
|
# name of the bundle without the extension; defaults to $target_name
|
||||||
|
#
|
||||||
|
template("ios_app_bundle") {
|
||||||
|
_output_name = target_name
|
||||||
|
if (defined(invoker.output_name)) {
|
||||||
|
_output_name = invoker.output_name
|
||||||
|
}
|
||||||
|
|
||||||
|
_bundle_identifier_prefix = default_bundle_identifier_prefix
|
||||||
|
if (defined(invoker.bundle_identifier_prefix)) {
|
||||||
|
_bundle_identifier_prefix = invoker.bundle_identifier_prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
_bundle_identifier = "$_bundle_identifier_prefix.$_output_name"
|
||||||
|
|
||||||
|
_app_prefix_target = target_name + "_app_prefix"
|
||||||
|
_app_prefix_output = "$target_out_dir/$_app_prefix_target/app_prefix.json"
|
||||||
|
|
||||||
|
action(_app_prefix_target) {
|
||||||
|
script = "//build/config/ios/scripts/find_app_identifier_prefix.py"
|
||||||
|
sources = []
|
||||||
|
outputs = [ _app_prefix_output ]
|
||||||
|
args = [
|
||||||
|
"-b=" + _bundle_identifier,
|
||||||
|
"-o=" + rebase_path(_app_prefix_output, root_build_dir),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdk_info.is_simulator) {
|
||||||
|
_simu_xcent_target = target_name + "_simu_xcent"
|
||||||
|
_simu_xcent_output =
|
||||||
|
"$target_out_dir/$_simu_xcent_target/" + "Entitlements-Simulated.plist"
|
||||||
|
|
||||||
|
merge_plist(_simu_xcent_target) {
|
||||||
|
format = "xml1"
|
||||||
|
output = _simu_xcent_output
|
||||||
|
plists = [ "//build/config/ios/resources/Entitlements-Simulated.plist" ]
|
||||||
|
substitutions_json = _app_prefix_output
|
||||||
|
deps = [ ":$_app_prefix_target" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_executable_target = target_name + "_executable"
|
||||||
|
_executable_bundle = target_name + "_executable_bundle"
|
||||||
|
|
||||||
|
executable(_executable_target) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
"bundle_extension",
|
||||||
|
"bundle_identifier_prefix",
|
||||||
|
"bundle_type",
|
||||||
|
"display_name",
|
||||||
|
"info_plist",
|
||||||
|
"output_name",
|
||||||
|
"public_headers",
|
||||||
|
])
|
||||||
|
|
||||||
|
output_extension = ""
|
||||||
|
output_name = _output_name
|
||||||
|
output_prefix_override = true
|
||||||
|
output_dir = "$target_out_dir/$_executable_target"
|
||||||
|
|
||||||
|
if (sdk_info.is_simulator) {
|
||||||
|
if (!defined(deps)) {
|
||||||
|
deps = []
|
||||||
|
}
|
||||||
|
if (!defined(inputs)) {
|
||||||
|
inputs = []
|
||||||
|
}
|
||||||
|
if (!defined(ldflags)) {
|
||||||
|
ldflags = []
|
||||||
|
}
|
||||||
|
|
||||||
|
deps += [ ":$_simu_xcent_target" ]
|
||||||
|
inputs += [ _simu_xcent_output ]
|
||||||
|
ldflags += [
|
||||||
|
"-Xlinker",
|
||||||
|
"-sectcreate",
|
||||||
|
"-Xlinker",
|
||||||
|
"__TEXT",
|
||||||
|
"-Xlinker",
|
||||||
|
"__entitlements",
|
||||||
|
"-Xlinker",
|
||||||
|
rebase_path(_simu_xcent_output, root_build_dir),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle_data(_executable_bundle) {
|
||||||
|
public_deps = [ ":$_executable_target" ]
|
||||||
|
sources = [ "$target_out_dir/$_executable_target/$_output_name" ]
|
||||||
|
outputs = [ "{{bundle_executable_dir}}/{{source_file_part}}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_binary_bundle(target_name) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
"bundle_extension",
|
||||||
|
"bundle_identifier_prefix",
|
||||||
|
"bundle_type",
|
||||||
|
"deps",
|
||||||
|
"output_name",
|
||||||
|
"public_deps",
|
||||||
|
"public_headers",
|
||||||
|
])
|
||||||
|
|
||||||
|
output_name = _output_name
|
||||||
|
product_type = "com.apple.product-type.application"
|
||||||
|
|
||||||
|
bundle_identifier = _bundle_identifier
|
||||||
|
bundle_extension = "app"
|
||||||
|
bundle_type = "AAPL"
|
||||||
|
|
||||||
|
public_deps = [ ":$_executable_bundle" ]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/templates/merge_plist.gni")
|
||||||
|
|
||||||
|
# Template to create an Apple bundle containing a binary file (e.g. .app or
|
||||||
|
# .framework bundle).
|
||||||
|
#
|
||||||
|
# Arguments
|
||||||
|
#
|
||||||
|
# - bundle_extension
|
||||||
|
#
|
||||||
|
# extension of the bundle (e.g. "app", "framework", ...); must not
|
||||||
|
# include the dot preceding the extension
|
||||||
|
#
|
||||||
|
# - bundle_type
|
||||||
|
#
|
||||||
|
# four letter code corresponding to the bundle type ("FMWK", "AAPL",
|
||||||
|
# ...); used to fill the "Bundle OS Type code" value in the generated
|
||||||
|
# Info.plist for the bundle
|
||||||
|
#
|
||||||
|
# - bundle_identitier
|
||||||
|
#
|
||||||
|
# bundle identitifier
|
||||||
|
#
|
||||||
|
# - product_type
|
||||||
|
#
|
||||||
|
# type of the generated bundle (used for Xcode project)
|
||||||
|
#
|
||||||
|
# - output_name (optional)
|
||||||
|
#
|
||||||
|
# name of the bundle without the extension; the bundle binary (i.e.
|
||||||
|
# the application or the library) must have the same name; defaults
|
||||||
|
# to $target_name
|
||||||
|
#
|
||||||
|
# - display_name (optional)
|
||||||
|
#
|
||||||
|
# display name of the bundle (e.g. the name that is displayed to the
|
||||||
|
# user); defaults to $output_name
|
||||||
|
#
|
||||||
|
# - info_plist (optional)
|
||||||
|
#
|
||||||
|
# path to additional Info.plist to merge into the final bundle Info.plist
|
||||||
|
#
|
||||||
|
template("ios_binary_bundle") {
|
||||||
|
assert(
|
||||||
|
defined(invoker.bundle_extension),
|
||||||
|
"bundle_extension must be defined for ios_binary_bundle ($target_name)")
|
||||||
|
assert(
|
||||||
|
defined(invoker.bundle_identifier),
|
||||||
|
"bundle_identifier must be defined for ios_binary_bundle ($target_name)")
|
||||||
|
assert(defined(invoker.bundle_type),
|
||||||
|
"bundle_type must be defined for ios_binary_bundle ($target_name)")
|
||||||
|
assert(defined(invoker.product_type),
|
||||||
|
"product_type must be defined for ios_binary_bundle ($target_name)")
|
||||||
|
|
||||||
|
_output_name = target_name
|
||||||
|
if (defined(invoker.output_name)) {
|
||||||
|
_output_name = invoker.output_name
|
||||||
|
}
|
||||||
|
|
||||||
|
_display_name = _output_name
|
||||||
|
if (defined(invoker.display_name)) {
|
||||||
|
_display_name = invoker.display_name
|
||||||
|
}
|
||||||
|
|
||||||
|
_plist_target = target_name + "_plist"
|
||||||
|
_plist_bundle = target_name + "_plist_bundle"
|
||||||
|
|
||||||
|
merge_plist(_plist_target) {
|
||||||
|
substitutions = {
|
||||||
|
CURRENT_PROJECT_VERSION = "1"
|
||||||
|
DEVELOPMENT_LANGUAGE = "en"
|
||||||
|
EXECUTABLE_NAME = "$_output_name"
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = invoker.bundle_identifier
|
||||||
|
PRODUCT_BUNDLE_PACKAGE_TYPE = invoker.bundle_type
|
||||||
|
PRODUCT_NAME = "$_display_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
format = "binary1"
|
||||||
|
output = "$target_out_dir/$_plist_target/Info.plist"
|
||||||
|
plists = [
|
||||||
|
get_label_info("//build/config/ios:compiler_plist", "target_out_dir") +
|
||||||
|
"/compiler_plist/Info.plist",
|
||||||
|
"//build/config/ios/resources/Info.plist",
|
||||||
|
]
|
||||||
|
|
||||||
|
if (defined(invoker.info_plist)) {
|
||||||
|
plists += [ invoker.info_plist ]
|
||||||
|
}
|
||||||
|
|
||||||
|
deps = [ "//build/config/ios:compiler_plist" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle_data(_plist_bundle) {
|
||||||
|
public_deps = [ ":$_plist_target" ]
|
||||||
|
sources = [ "$target_out_dir/$_plist_target/Info.plist" ]
|
||||||
|
outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
create_bundle(target_name) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
"display_name",
|
||||||
|
"output_name",
|
||||||
|
"bundle_extension",
|
||||||
|
"bundle_type",
|
||||||
|
])
|
||||||
|
|
||||||
|
if (!defined(public_deps)) {
|
||||||
|
public_deps = []
|
||||||
|
}
|
||||||
|
public_deps += [ ":$_plist_bundle" ]
|
||||||
|
bundle_root_dir = "$root_out_dir/$_output_name.${invoker.bundle_extension}"
|
||||||
|
bundle_contents_dir = bundle_root_dir
|
||||||
|
bundle_executable_dir = bundle_contents_dir
|
||||||
|
bundle_resources_dir = bundle_contents_dir
|
||||||
|
|
||||||
|
xcode_extra_attributes = {
|
||||||
|
CODE_SIGN_IDENTITY = ""
|
||||||
|
CODE_SIGNING_REQUIRED = "NO"
|
||||||
|
CODE_SIGNING_ALLOWED = "NO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/bundle_identifier_prefix.gni")
|
||||||
|
import("//build/config/ios/templates/ios_binary_bundle.gni")
|
||||||
|
|
||||||
|
# Template to generate a framework bundle.
|
||||||
|
#
|
||||||
|
# All the other parameters are forwarded to a shared_library target that will
|
||||||
|
# generate the bundle binary. In general, you want to pass at least "sources"
|
||||||
|
# or "deps" to have some binary objects included in your shared library.
|
||||||
|
#
|
||||||
|
# Arguments
|
||||||
|
#
|
||||||
|
# - info_plist (optional)
|
||||||
|
#
|
||||||
|
# path to additional Info.plist to merge into the final bundle Info.plist
|
||||||
|
#
|
||||||
|
# - bundle_identifier_prefix (optional)
|
||||||
|
#
|
||||||
|
# prefix for the bundle identifier (the full identifier will be defined
|
||||||
|
# to $bundle_identifier_prefix.$output_name); if unset will defaults to
|
||||||
|
# default_bundle_identifier_prefix
|
||||||
|
#
|
||||||
|
# - output_name (optional)
|
||||||
|
#
|
||||||
|
# name of the bundle without the extension; defaults to $target_name
|
||||||
|
#
|
||||||
|
# - public_headers (optional)
|
||||||
|
#
|
||||||
|
# list of public headers files to copy into the framework bundle; this
|
||||||
|
# does not generate an umbrella header; an umbrella header named after
|
||||||
|
# the framework bundle will be created
|
||||||
|
#
|
||||||
|
template("ios_framework_bundle") {
|
||||||
|
_output_name = target_name
|
||||||
|
if (defined(invoker.output_name)) {
|
||||||
|
_output_name = invoker.output_name
|
||||||
|
}
|
||||||
|
|
||||||
|
_dylib_target = target_name + "_dylib"
|
||||||
|
_dylib_bundle = target_name + "_dylib_bundle"
|
||||||
|
|
||||||
|
_bundle_identifier_prefix = default_bundle_identifier_prefix
|
||||||
|
if (defined(invoker.bundle_identifier_prefix)) {
|
||||||
|
_bundle_identifier_prefix = invoker.bundle_identifier_prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
_bundle_identifier = "$_bundle_identifier_prefix.$_output_name"
|
||||||
|
|
||||||
|
shared_library(_dylib_target) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
"bundle_extension",
|
||||||
|
"bundle_identifier_prefix",
|
||||||
|
"bundle_type",
|
||||||
|
"display_name",
|
||||||
|
"info_plist",
|
||||||
|
"output_name",
|
||||||
|
"public_headers",
|
||||||
|
])
|
||||||
|
|
||||||
|
output_extension = ""
|
||||||
|
output_name = _output_name
|
||||||
|
output_prefix_override = true
|
||||||
|
output_dir = "$target_out_dir/$_dylib_target"
|
||||||
|
|
||||||
|
if (!defined(ldflags)) {
|
||||||
|
ldflags = []
|
||||||
|
}
|
||||||
|
ldflags += [
|
||||||
|
"-Xlinker",
|
||||||
|
"-install_name",
|
||||||
|
"-Xlinker",
|
||||||
|
"@rpath/$_output_name.framework/$_output_name",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle_data(_dylib_bundle) {
|
||||||
|
public_deps = [ ":$_dylib_target" ]
|
||||||
|
sources = [ "$target_out_dir/$_dylib_target/$_output_name" ]
|
||||||
|
outputs = [ "{{bundle_executable_dir}}/{{source_file_part}}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined(invoker.public_headers)) {
|
||||||
|
_umbrella_target = target_name + "_umbrella"
|
||||||
|
_umbrella_output = "$target_out_dir/$_umbrella_target/$_output_name.h"
|
||||||
|
|
||||||
|
action(_umbrella_target) {
|
||||||
|
script = "//build/config/ios/scripts/generate_umbrella_header.py"
|
||||||
|
sources = []
|
||||||
|
outputs = [ _umbrella_output ]
|
||||||
|
args = [ "-o=" + rebase_path(_umbrella_output, root_build_dir) ] +
|
||||||
|
rebase_path(invoker.public_headers, root_build_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
_headers_bundle = target_name + "_headers_bundle"
|
||||||
|
|
||||||
|
bundle_data(_headers_bundle) {
|
||||||
|
sources = invoker.public_headers + [ _umbrella_output ]
|
||||||
|
outputs = [ "{{bundle_resources_dir}}/Headers/{{source_file_part}}" ]
|
||||||
|
public_deps = [ ":$_umbrella_target" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_config_name = target_name + "_config"
|
||||||
|
|
||||||
|
config(_config_name) {
|
||||||
|
framework_dirs = [ root_out_dir ]
|
||||||
|
frameworks = [ "$_output_name.framework" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_binary_bundle(target_name) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
"bundle_extension",
|
||||||
|
"bundle_type",
|
||||||
|
"configs",
|
||||||
|
"deps",
|
||||||
|
"output_name",
|
||||||
|
"public_configs",
|
||||||
|
"public_deps",
|
||||||
|
"public_headers",
|
||||||
|
])
|
||||||
|
|
||||||
|
output_name = _output_name
|
||||||
|
product_type = "com.apple.product-type.framework"
|
||||||
|
|
||||||
|
bundle_identifier = _bundle_identifier
|
||||||
|
bundle_extension = "framework"
|
||||||
|
bundle_type = "FMWK"
|
||||||
|
|
||||||
|
public_deps = [ ":$_dylib_bundle" ]
|
||||||
|
|
||||||
|
if (defined(invoker.public_headers)) {
|
||||||
|
public_deps += [ ":$_headers_bundle" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
public_configs = [ ":$_config_name" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
_target_name = target_name
|
||||||
|
|
||||||
|
bundle_data("$target_name+bundle") {
|
||||||
|
public_deps = [ ":$_target_name" ]
|
||||||
|
sources = [ "$root_out_dir/$_output_name.framework" ]
|
||||||
|
outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
# Template to merge multiple Apple Property List file into a single file.
|
||||||
|
#
|
||||||
|
# Arguments
|
||||||
|
#
|
||||||
|
# - output
|
||||||
|
#
|
||||||
|
# path of the file that will be generated (must be in a sub-directory
|
||||||
|
# of root_build_dir)
|
||||||
|
#
|
||||||
|
# - plists
|
||||||
|
#
|
||||||
|
# list of path to Apple Property List file to merge (the file may be
|
||||||
|
# in either "json", "binary1" or "xml1" format)
|
||||||
|
#
|
||||||
|
# - format (optional)
|
||||||
|
#
|
||||||
|
# format in which the file must be saved; must be one of "json",
|
||||||
|
# "binary1" or "xml1" (default to "json" if omitted)
|
||||||
|
#
|
||||||
|
# - substitutions (optional)
|
||||||
|
#
|
||||||
|
# a scope defining variable substitutions to perform when merging the
|
||||||
|
# Property List files (i.e. if scope define foo = "bar", occurences
|
||||||
|
# of $(foo) in any string in a property list will be replaced by
|
||||||
|
# bar)
|
||||||
|
#
|
||||||
|
template("merge_plist") {
|
||||||
|
assert(defined(invoker.output) && invoker.output != "",
|
||||||
|
"output must be defined for merge_plist ($target_name)")
|
||||||
|
assert(defined(invoker.plists) && invoker.plists != [],
|
||||||
|
"plists must be defined for merge_plist ($target_name)")
|
||||||
|
|
||||||
|
if (defined(invoker.substitutions)) {
|
||||||
|
assert(!defined(invoker.substitutions_json),
|
||||||
|
"cannot define both substitutions and substitutions_json")
|
||||||
|
|
||||||
|
_substitutions_json = "$target_out_dir/$target_name/substitutions.json"
|
||||||
|
write_file(_substitutions_json, invoker.substitutions, "json")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined(invoker.substitutions_json)) {
|
||||||
|
_substitutions_json = invoker.substitutions_json
|
||||||
|
}
|
||||||
|
|
||||||
|
action(target_name) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
"args",
|
||||||
|
"format",
|
||||||
|
"inputs",
|
||||||
|
"output",
|
||||||
|
"plists",
|
||||||
|
"script",
|
||||||
|
"sources",
|
||||||
|
"substitutions",
|
||||||
|
"substitutions_json",
|
||||||
|
])
|
||||||
|
|
||||||
|
script = "//build/config/ios/scripts/merge_plist.py"
|
||||||
|
sources = invoker.plists
|
||||||
|
outputs = [ invoker.output ]
|
||||||
|
|
||||||
|
_format = "json"
|
||||||
|
if (defined(invoker.format)) {
|
||||||
|
_format = invoker.format
|
||||||
|
}
|
||||||
|
|
||||||
|
args = [
|
||||||
|
"-f=" + _format,
|
||||||
|
"-o=" + rebase_path(invoker.output, root_build_dir),
|
||||||
|
]
|
||||||
|
|
||||||
|
if (defined(_substitutions_json)) {
|
||||||
|
inputs = [ _substitutions_json ]
|
||||||
|
args += [ "-s=" + rebase_path(_substitutions_json) ]
|
||||||
|
}
|
||||||
|
|
||||||
|
args += rebase_path(sources, root_build_dir)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/deployment_target.gni")
|
||||||
|
|
||||||
|
template("storyboards") {
|
||||||
|
assert(defined(invoker.sources),
|
||||||
|
"sources must be defined for storyboard ($target_name)")
|
||||||
|
|
||||||
|
_compile_target = target_name + "_compile"
|
||||||
|
_compile_output =
|
||||||
|
"$target_out_dir/$_compile_target/{{source_name_part}}.storyboardc"
|
||||||
|
|
||||||
|
action_foreach(_compile_target) {
|
||||||
|
script = "//build/config/ios/scripts/compile_storyboard.py"
|
||||||
|
sources = invoker.sources
|
||||||
|
outputs = [ _compile_output ]
|
||||||
|
args = [
|
||||||
|
"{{source}}",
|
||||||
|
"-o=" + rebase_path(_compile_output, root_build_dir),
|
||||||
|
"--minimum-deployment-target=$ios_deployment_target",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle_data(target_name) {
|
||||||
|
public_deps = [ ":$_compile_target" ]
|
||||||
|
sources = get_target_outputs(":$_compile_target")
|
||||||
|
outputs = [ "{{bundle_root_dir}}/Base.lproj/{{source_file_part}}" ]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import collections
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
|
class OrderedSet(collections.OrderedDict):
|
||||||
|
|
||||||
|
def add(self, value):
|
||||||
|
self[value] = True
|
||||||
|
|
||||||
|
|
||||||
|
def compile_module(module, sources, settings, extras, tmpdir):
|
||||||
|
output_file_map = {}
|
||||||
|
if settings.whole_module_optimization:
|
||||||
|
output_file_map[''] = {
|
||||||
|
'object': os.path.join(settings.object_dir, module + '.o'),
|
||||||
|
'dependencies': os.path.join(tmpdir, module + '.d'),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
for source in sources:
|
||||||
|
name, _ = os.path.splitext(os.path.basename(source))
|
||||||
|
output_file_map[source] = {
|
||||||
|
'object': os.path.join(settings.object_dir, name + '.o'),
|
||||||
|
'dependencies': os.path.join(tmpdir, name + '.d'),
|
||||||
|
}
|
||||||
|
|
||||||
|
for key in ('module_path', 'header_path', 'depfile'):
|
||||||
|
path = getattr(settings, key)
|
||||||
|
if os.path.exists(path):
|
||||||
|
os.unlink(path)
|
||||||
|
if key == 'module_path':
|
||||||
|
for ext in '.swiftdoc', '.swiftsourceinfo':
|
||||||
|
path = os.path.splitext(getattr(settings, key))[0] + ext
|
||||||
|
if os.path.exists(path):
|
||||||
|
os.unlink(path)
|
||||||
|
directory = os.path.dirname(path)
|
||||||
|
if not os.path.exists(directory):
|
||||||
|
os.makedirs(directory)
|
||||||
|
|
||||||
|
if not os.path.exists(settings.object_dir):
|
||||||
|
os.makedirs(settings.object_dir)
|
||||||
|
|
||||||
|
for key in output_file_map:
|
||||||
|
path = output_file_map[key]['object']
|
||||||
|
if os.path.exists(path):
|
||||||
|
os.unlink(path)
|
||||||
|
|
||||||
|
output_file_map_path = os.path.join(tmpdir, module + '.json')
|
||||||
|
with open(output_file_map_path, 'w') as output_file_map_file:
|
||||||
|
output_file_map_file.write(json.dumps(output_file_map))
|
||||||
|
output_file_map_file.flush()
|
||||||
|
|
||||||
|
extra_args = []
|
||||||
|
if settings.bridge_header:
|
||||||
|
extra_args.extend([
|
||||||
|
'-import-objc-header',
|
||||||
|
os.path.abspath(settings.bridge_header),
|
||||||
|
])
|
||||||
|
|
||||||
|
if settings.whole_module_optimization:
|
||||||
|
extra_args.append('-whole-module-optimization')
|
||||||
|
|
||||||
|
if settings.target:
|
||||||
|
extra_args.extend([
|
||||||
|
'-target',
|
||||||
|
settings.target,
|
||||||
|
])
|
||||||
|
|
||||||
|
if settings.sdk:
|
||||||
|
extra_args.extend([
|
||||||
|
'-sdk',
|
||||||
|
os.path.abspath(settings.sdk),
|
||||||
|
])
|
||||||
|
|
||||||
|
if settings.include_dirs:
|
||||||
|
for include_dir in settings.include_dirs:
|
||||||
|
extra_args.append('-I' + include_dir)
|
||||||
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
['swiftc',
|
||||||
|
'-parse-as-library',
|
||||||
|
'-module-name',
|
||||||
|
module,
|
||||||
|
'-emit-object',
|
||||||
|
'-emit-dependencies',
|
||||||
|
'-emit-module',
|
||||||
|
'-emit-module-path',
|
||||||
|
settings.module_path,
|
||||||
|
'-emit-objc-header',
|
||||||
|
'-emit-objc-header-path',
|
||||||
|
settings.header_path,
|
||||||
|
'-output-file-map',
|
||||||
|
output_file_map_path,
|
||||||
|
] + extra_args + extras + sources,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
universal_newlines=True)
|
||||||
|
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
if process.returncode:
|
||||||
|
sys.stdout.write(stdout)
|
||||||
|
sys.stderr.write(stderr)
|
||||||
|
sys.exit(process.returncode)
|
||||||
|
|
||||||
|
|
||||||
|
depfile_content = collections.OrderedDict()
|
||||||
|
for key in output_file_map:
|
||||||
|
for line in open(output_file_map[key]['dependencies']):
|
||||||
|
output, inputs = line.split(' : ', 2)
|
||||||
|
_, ext = os.path.splitext(output)
|
||||||
|
if ext == '.o':
|
||||||
|
key = output
|
||||||
|
else:
|
||||||
|
key = os.path.splitext(settings.module_path)[0] + ext
|
||||||
|
if key not in depfile_content:
|
||||||
|
depfile_content[key] = OrderedSet()
|
||||||
|
for path in inputs.split():
|
||||||
|
depfile_content[key].add(path)
|
||||||
|
|
||||||
|
with open(settings.depfile, 'w') as depfile:
|
||||||
|
for key in depfile_content:
|
||||||
|
if not settings.depfile_filter or key in settings.depfile_filter:
|
||||||
|
inputs = depfile_content[key]
|
||||||
|
depfile.write('%s : %s\n' % (key, ' '.join(inputs)))
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
parser.add_argument(
|
||||||
|
'--module-name',
|
||||||
|
help='name of the Swift module')
|
||||||
|
parser.add_argument(
|
||||||
|
'--include', '-I', action='append', dest='include_dirs',
|
||||||
|
help='add directory to header search path')
|
||||||
|
parser.add_argument(
|
||||||
|
'sources', nargs='+',
|
||||||
|
help='Swift source file to compile')
|
||||||
|
parser.add_argument(
|
||||||
|
'--whole-module-optimization', action='store_true',
|
||||||
|
help='enable whole module optimization')
|
||||||
|
parser.add_argument(
|
||||||
|
'--object-dir', '-o',
|
||||||
|
help='path to the generated object files directory')
|
||||||
|
parser.add_argument(
|
||||||
|
'--module-path', '-m',
|
||||||
|
help='path to the generated module file')
|
||||||
|
parser.add_argument(
|
||||||
|
'--header-path', '-h',
|
||||||
|
help='path to the generated header file')
|
||||||
|
parser.add_argument(
|
||||||
|
'--bridge-header', '-b',
|
||||||
|
help='path to the Objective-C bridge header')
|
||||||
|
parser.add_argument(
|
||||||
|
'--depfile', '-d',
|
||||||
|
help='path to the generated depfile')
|
||||||
|
parser.add_argument(
|
||||||
|
'--depfile-filter', action='append',
|
||||||
|
help='limit depfile to those files')
|
||||||
|
parser.add_argument(
|
||||||
|
'--target', action='store',
|
||||||
|
help='generate code for the given target <triple>')
|
||||||
|
parser.add_argument(
|
||||||
|
'--sdk', action='store',
|
||||||
|
help='compile against sdk')
|
||||||
|
|
||||||
|
parsed, extras = parser.parse_known_args(args)
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
compile_module(
|
||||||
|
parsed.module_name,
|
||||||
|
parsed.sources,
|
||||||
|
parsed,
|
||||||
|
extras,
|
||||||
|
tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
|
@ -0,0 +1,169 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/deployment_target.gni")
|
||||||
|
|
||||||
|
declare_args() {
|
||||||
|
# Configure whether whole module optimization is enabled when compiling
|
||||||
|
# swift modules.
|
||||||
|
swift_whole_module_optimization = true
|
||||||
|
}
|
||||||
|
|
||||||
|
template("ios_toolchain") {
|
||||||
|
toolchain(target_name) {
|
||||||
|
assert(defined(invoker.toolchain_args),
|
||||||
|
"Toolchains must declare toolchain_args")
|
||||||
|
|
||||||
|
toolchain_args = {
|
||||||
|
forward_variables_from(invoker.toolchain_args, "*")
|
||||||
|
}
|
||||||
|
|
||||||
|
_sdk_info = exec_script("//build/config/ios/scripts/sdk_info.py",
|
||||||
|
[
|
||||||
|
"--target-cpu",
|
||||||
|
current_cpu,
|
||||||
|
"--target-environment",
|
||||||
|
target_environment,
|
||||||
|
"--deployment-target",
|
||||||
|
ios_deployment_target,
|
||||||
|
],
|
||||||
|
"json")
|
||||||
|
|
||||||
|
cc = "clang -target ${_sdk_info.target} -isysroot ${_sdk_info.sdk_path}"
|
||||||
|
cxx = "clang++ -target ${_sdk_info.target} -isysroot ${_sdk_info.sdk_path}"
|
||||||
|
|
||||||
|
swiftmodule_switch = "-Wl,-add_ast_path,"
|
||||||
|
|
||||||
|
tool("link") {
|
||||||
|
output = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
|
||||||
|
rspfile = output + ".rsp"
|
||||||
|
rspfile_content = "{{inputs_newline}}"
|
||||||
|
|
||||||
|
outputs = [ output ]
|
||||||
|
command = "$cxx {{ldflags}} -o $output -Wl,-filelist,$rspfile {{libs}} {{solibs}} {{frameworks}} {{swiftmodules}}"
|
||||||
|
description = "LINK {{output}}"
|
||||||
|
|
||||||
|
default_output_dir = "{{root_out_dir}}"
|
||||||
|
default_output_extension = ""
|
||||||
|
output_prefix = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("solink") {
|
||||||
|
dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
|
||||||
|
rspfile = dylib + ".rsp"
|
||||||
|
rspfile_content = "{{inputs_newline}}"
|
||||||
|
|
||||||
|
outputs = [ dylib ]
|
||||||
|
command = "$cxx -dynamiclib {{ldflags}} -o $dylib -Wl,-filelist,$rspfile {{libs}} {{solibs}} {{frameworks}} {{swiftmodules}}"
|
||||||
|
description = "SOLINK {{output}}"
|
||||||
|
|
||||||
|
default_output_dir = "{{root_out_dir}}"
|
||||||
|
default_output_extension = ".dylib"
|
||||||
|
output_prefix = "lib"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("cc") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "CC {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("cxx") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "CXX {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("objc") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "OBJC {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("objcxx") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "OBJCXX {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("stamp") {
|
||||||
|
command = "touch {{output}}"
|
||||||
|
description = "STAMP {{output}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("copy_bundle_data") {
|
||||||
|
command = "rm -rf {{output}} && cp -PR {{source}} {{output}}"
|
||||||
|
description = "COPY_BUNDLE_DATA {{output}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("swift") {
|
||||||
|
depfile = "{{target_out_dir}}/{{module_name}}.d"
|
||||||
|
depsformat = "gcc"
|
||||||
|
|
||||||
|
outputs = [
|
||||||
|
# The module needs to be the first output to ensure the
|
||||||
|
# depfile generate works correctly with ninja < 1.9.0.
|
||||||
|
"{{target_gen_dir}}/{{module_name}}.swiftmodule",
|
||||||
|
|
||||||
|
"{{target_gen_dir}}/{{module_name}}.h",
|
||||||
|
"{{target_gen_dir}}/{{module_name}}.swiftdoc",
|
||||||
|
"{{target_gen_dir}}/{{module_name}}.swiftsourceinfo",
|
||||||
|
]
|
||||||
|
|
||||||
|
if (swift_whole_module_optimization) {
|
||||||
|
_extra_flag = "--whole-module-optimization"
|
||||||
|
_object_dir = "{{target_out_dir}}"
|
||||||
|
outputs += [ "{{target_out_dir}}/{{module_name}}.o" ]
|
||||||
|
} else {
|
||||||
|
_extra_flag = ""
|
||||||
|
_object_dir = "{{target_out_dir}}/{{label_name}}"
|
||||||
|
partial_outputs =
|
||||||
|
[ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
_swiftc = rebase_path("//build/toolchain/apple/swiftc.py", root_build_dir)
|
||||||
|
command = "$_swiftc --target ${_sdk_info.target} --sdk ${_sdk_info.sdk_path} --module-name {{module_name}} --object-dir $_object_dir --module-path {{target_gen_dir}}/{{module_name}}.swiftmodule --header-path {{target_gen_dir}}/{{module_name}}.h --depfile {{target_out_dir}}/{{module_name}}.d --depfile-filter {{target_gen_dir}}/{{module_name}}.swiftmodule --bridge-header {{bridge_header}} $_extra_flag {{defines}} {{swiftflags}} {{include_dirs}} {{module_dirs}} {{inputs}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_toolchain("clang_x86") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "x86"
|
||||||
|
current_os = "ios"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_toolchain("clang_x64") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "x64"
|
||||||
|
current_os = "ios"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_toolchain("clang_arm") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "arm"
|
||||||
|
current_os = "ios"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ios_toolchain("clang_arm64") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "arm64"
|
||||||
|
current_os = "ios"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
template("mac_toolchain") {
|
||||||
|
toolchain(target_name) {
|
||||||
|
assert(defined(invoker.toolchain_args),
|
||||||
|
"Toolchains must declare toolchain_args")
|
||||||
|
|
||||||
|
toolchain_args = {
|
||||||
|
forward_variables_from(invoker.toolchain_args, "*")
|
||||||
|
}
|
||||||
|
|
||||||
|
cc = "clang"
|
||||||
|
cxx = "clang++"
|
||||||
|
|
||||||
|
tool("link") {
|
||||||
|
output = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
|
||||||
|
rspfile = output + ".rsp"
|
||||||
|
rspfile_content = "{{inputs_newline}}"
|
||||||
|
|
||||||
|
outputs = [ output ]
|
||||||
|
command = "$cxx {{ldflags}} -o $output -Wl,-filelist,$rspfile {{libs}} {{solibs}} {{frameworks}}"
|
||||||
|
description = "LINK {{output}}"
|
||||||
|
|
||||||
|
default_output_dir = "{{root_out_dir}}"
|
||||||
|
default_output_extension = ""
|
||||||
|
output_prefix = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("solink") {
|
||||||
|
dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
|
||||||
|
rspfile = dylib + ".rsp"
|
||||||
|
rspfile_content = "{{inputs_newline}}"
|
||||||
|
|
||||||
|
outputs = [ dylib ]
|
||||||
|
command = "$cxx -dynamiclib {{ldflags}} -o $dylib -Wl,-filelist,$rspfile {{libs}} {{solibs}} {{frameworks}}"
|
||||||
|
description = "SOLINK {{output}}"
|
||||||
|
|
||||||
|
default_output_dir = "{{root_out_dir}}"
|
||||||
|
default_output_extension = ".dylib"
|
||||||
|
output_prefix = "lib"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("cc") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "CC {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("cxx") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "CXX {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("objc") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "OBJC {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("objcxx") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
precompiled_header_type = "gcc"
|
||||||
|
command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "OBJCXX {{output}}"
|
||||||
|
outputs = [ "{{target_out_dir}}/{{label_name}}/{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("stamp") {
|
||||||
|
command = "touch {{output}}"
|
||||||
|
description = "STAMP {{output}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("copy_bundle_data") {
|
||||||
|
command = "rm -rf {{output}} && cp -a {{source}} {{output}}"
|
||||||
|
description = "COPY_BUNDLE_DATA {{output}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mac_toolchain("clang_x86") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "x86"
|
||||||
|
current_os = "mac"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mac_toolchain("clang_x64") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "x64"
|
||||||
|
current_os = "mac"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mac_toolchain("clang_arm") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "arm"
|
||||||
|
current_os = "mac"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mac_toolchain("clang_arm64") {
|
||||||
|
toolchain_args = {
|
||||||
|
current_cpu = "arm64"
|
||||||
|
current_os = "mac"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
if (current_toolchain == host_toolchain) {
|
||||||
|
executable("username") {
|
||||||
|
sources = [ "main.cc" ]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
group("username") {
|
||||||
|
deps = [ ":username($host_toolchain)" ]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright 2019 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.
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Returns the current user username.
|
||||||
|
std::string Username() {
|
||||||
|
const char* username = getenv("USER");
|
||||||
|
return username ? std::string(username) : std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes |string| to |stream| while escaping all C escape sequences.
|
||||||
|
void EscapeString(std::ostream* stream, const std::string& string) {
|
||||||
|
for (char c : string) {
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
*stream << "\\0";
|
||||||
|
break;
|
||||||
|
case '\a':
|
||||||
|
*stream << "\\a";
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
*stream << "\\b";
|
||||||
|
break;
|
||||||
|
case '\e':
|
||||||
|
*stream << "\\e";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
*stream << "\\f";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
*stream << "\\n";
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
*stream << "\\r";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
*stream << "\\t";
|
||||||
|
break;
|
||||||
|
case '\v':
|
||||||
|
*stream << "\\v";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
*stream << "\\\\";
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
*stream << "\\\"";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*stream << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
std::string username = Username();
|
||||||
|
|
||||||
|
std::cout << "{\"username\": \"";
|
||||||
|
EscapeString(&std::cout, username);
|
||||||
|
std::cout << "\"}" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Copyright 2019 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("//build/config/ios/templates/ios_framework_bundle.gni")
|
||||||
|
|
||||||
|
ios_framework_bundle("hello_framework") {
|
||||||
|
output_name = "HelloShared"
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
"hello_shared.h",
|
||||||
|
"hello_shared.m",
|
||||||
|
]
|
||||||
|
public_headers = [ "hello_shared.h" ]
|
||||||
|
|
||||||
|
defines = [ "HELLO_SHARED_IMPLEMENTATION" ]
|
||||||
|
frameworks = [ "Foundation.framework" ]
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2019 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 <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface Greetings : NSObject
|
||||||
|
|
||||||
|
+ (NSString*)greet;
|
||||||
|
|
||||||
|
+ (NSString*)greetWithName:(NSString*)name;
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2019 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 "hello_shared.h"
|
||||||
|
|
||||||
|
@implementation Greetings
|
||||||
|
|
||||||
|
+ (NSString*)greet {
|
||||||
|
return [NSString stringWithFormat:@"Hello from %@!", [Greetings displayName]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*)greetWithName:(NSString*)name {
|
||||||
|
return [NSString stringWithFormat:@"Hello, %@!", name];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*)displayName {
|
||||||
|
NSBundle* bundle = [NSBundle bundleForClass:[Greetings class]];
|
||||||
|
return [[bundle infoDictionary] objectForKey:@"CFBundleName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1 @@
|
||||||
|
buildconfig = "//BUILDCONFIG.gn"
|
|
@ -0,0 +1,3 @@
|
||||||
|
group("default") {
|
||||||
|
deps = [ "//hello_world/src:hello_world" ]
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
if (target_os == "") {
|
||||||
|
target_os = host_os
|
||||||
|
}
|
||||||
|
if (target_cpu == "") {
|
||||||
|
target_cpu = host_cpu
|
||||||
|
}
|
||||||
|
if (current_cpu == "") {
|
||||||
|
current_cpu = target_cpu
|
||||||
|
}
|
||||||
|
if (current_os == "") {
|
||||||
|
current_os = target_os
|
||||||
|
}
|
||||||
|
|
||||||
|
_configs = [ "//build:rust_defaults" ]
|
||||||
|
|
||||||
|
set_defaults("executable") {
|
||||||
|
configs = _configs
|
||||||
|
}
|
||||||
|
set_defaults("rust_library") {
|
||||||
|
configs = _configs
|
||||||
|
}
|
||||||
|
|
||||||
|
set_default_toolchain("//build:rust")
|
|
@ -0,0 +1,4 @@
|
||||||
|
This is an example directory structure that compiles a Rust hello world
|
||||||
|
example. It is intended to show how to set up a simple Rust GN build.
|
||||||
|
|
||||||
|
Don't miss the ".gn" file in this directory!
|
|
@ -0,0 +1,47 @@
|
||||||
|
toolchain("rust") {
|
||||||
|
tool("rust_bin") {
|
||||||
|
depfile = "{{target_out_dir}}/{{crate_name}}.d"
|
||||||
|
outfile = "{{target_out_dir}}/{{crate_name}}"
|
||||||
|
command = "rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} --emit=dep-info=$depfile,link -Z dep-info-omit-d-target {{rustflags}} -o $outfile {{rustdeps}} {{externs}}"
|
||||||
|
description = "RUST $outfile"
|
||||||
|
outputs = [ outfile ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("rust_staticlib") {
|
||||||
|
depfile = "{{target_out_dir}}/{{crate_name}}.d"
|
||||||
|
outfile = "{{target_out_dir}}/{{crate_name}}.a"
|
||||||
|
command = "rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} --emit=dep-info=$depfile,link -Z dep-info-omit-d-target {{rustflags}} -o $outfile {{rustdeps}} {{externs}}"
|
||||||
|
description = "RUST $outfile"
|
||||||
|
outputs = [ outfile ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("rust_rlib") {
|
||||||
|
depfile = "{{target_out_dir}}/{{crate_name}}.d"
|
||||||
|
outfile = "{{target_out_dir}}/lib{{crate_name}}.rlib"
|
||||||
|
command = "rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} --emit=dep-info=$depfile,link -Z dep-info-omit-d-target {{rustflags}} -o $outfile {{rustdeps}} {{externs}}"
|
||||||
|
description = "RUST $outfile"
|
||||||
|
outputs = [ outfile ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("rust_cdylib") {
|
||||||
|
depfile = "{{target_out_dir}}/{{crate_name}}.d"
|
||||||
|
outfile = "{{target_out_dir}}/lib{{crate_name}}.so"
|
||||||
|
command = "rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} --emit=dep-info=$depfile,link -Z dep-info-omit-d-target {{rustflags}} -o $outfile {{rustdeps}} {{externs}}"
|
||||||
|
description = "RUST $outfile"
|
||||||
|
outputs = [ outfile ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("stamp") {
|
||||||
|
command = "touch {{output}}"
|
||||||
|
description = "STAMP {{output}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("copy") {
|
||||||
|
command = "cp -af {{source}} {{output}}"
|
||||||
|
description = "COPY {{source}} {{output}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config("rust_defaults") {
|
||||||
|
rustflags = [ "-Cdebuginfo=2" ]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
rust_library("bar") {
|
||||||
|
crate_root = "lib.rs"
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Foo {
|
||||||
|
s: &'static str,
|
||||||
|
i: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
pub fn new(s: &'static str) -> Foo {
|
||||||
|
Foo{s: s, i: "bar"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer() -> i32 {
|
||||||
|
42
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
rust_library("foo") {
|
||||||
|
sources = [ "lib.rs" ]
|
||||||
|
deps = [ "//hello_world/bar/src:bar" ]
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Foo {
|
||||||
|
s: &'static str,
|
||||||
|
i: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
pub fn new(s: &'static str) -> Foo {
|
||||||
|
Foo{s: s, i: "foo"}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
executable("hello_world") {
|
||||||
|
sources = [ "main.rs" ]
|
||||||
|
deps = [ "//hello_world/foo/src:foo" ]
|
||||||
|
aliased_deps = {
|
||||||
|
baz = "//hello_world/foo/src:foo"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn main() {
|
||||||
|
let f = baz::Foo::new("hello");
|
||||||
|
println!("Hello world!");
|
||||||
|
println!("I'm from a dependency: {:?}!", f);
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
# The location of the build configuration file.
|
||||||
|
buildconfig = "//build/BUILDCONFIG.gn"
|
|
@ -0,0 +1,28 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
executable("hello") {
|
||||||
|
sources = [ "hello.cc" ]
|
||||||
|
|
||||||
|
deps = [
|
||||||
|
":hello_shared",
|
||||||
|
":hello_static",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_library("hello_shared") {
|
||||||
|
sources = [
|
||||||
|
"hello_shared.cc",
|
||||||
|
"hello_shared.h",
|
||||||
|
]
|
||||||
|
|
||||||
|
defines = [ "HELLO_SHARED_IMPLEMENTATION" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
static_library("hello_static") {
|
||||||
|
sources = [
|
||||||
|
"hello_static.cc",
|
||||||
|
"hello_static.h",
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
# GN Simple Build Example
|
||||||
|
|
||||||
|
This is an example directory structure that compiles some simple targets using
|
||||||
|
gcc. It is intended to show how to set up a simple GN build. It is deliberately
|
||||||
|
simplistic so the structure is more clear, and doesn't support everything on
|
||||||
|
every platform.
|
||||||
|
|
||||||
|
It is recommended that you take this and add on as your requirements indicate.
|
||||||
|
You may also want to see the Chromium and Fuchsia build configurations for the
|
||||||
|
maximal functionality (the [root README](../../README.md) has links to these).
|
||||||
|
|
||||||
|
Don't miss the ".gn" file in this directory which may be hidden on your system!
|
|
@ -0,0 +1,21 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
config("compiler_defaults") {
|
||||||
|
if (current_os == "linux") {
|
||||||
|
cflags = [
|
||||||
|
"-fPIC",
|
||||||
|
"-pthread",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config("executable_ldconfig") {
|
||||||
|
if (!is_mac) {
|
||||||
|
ldflags = [
|
||||||
|
"-Wl,-rpath=\$ORIGIN/",
|
||||||
|
"-Wl,-rpath-link=",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
if (target_os == "") {
|
||||||
|
target_os = host_os
|
||||||
|
}
|
||||||
|
if (target_cpu == "") {
|
||||||
|
target_cpu = host_cpu
|
||||||
|
}
|
||||||
|
if (current_cpu == "") {
|
||||||
|
current_cpu = target_cpu
|
||||||
|
}
|
||||||
|
if (current_os == "") {
|
||||||
|
current_os = target_os
|
||||||
|
}
|
||||||
|
|
||||||
|
is_linux = host_os == "linux" && current_os == "linux" && target_os == "linux"
|
||||||
|
is_mac = host_os == "mac" && current_os == "mac" && target_os == "mac"
|
||||||
|
|
||||||
|
# All binary targets will get this list of configs by default.
|
||||||
|
_shared_binary_target_configs = [ "//build:compiler_defaults" ]
|
||||||
|
|
||||||
|
# Apply that default list to the binary target types.
|
||||||
|
set_defaults("executable") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
|
||||||
|
# Executables get this additional configuration.
|
||||||
|
configs += [ "//build:executable_ldconfig" ]
|
||||||
|
}
|
||||||
|
set_defaults("static_library") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
}
|
||||||
|
set_defaults("shared_library") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
}
|
||||||
|
set_defaults("source_set") {
|
||||||
|
configs = _shared_binary_target_configs
|
||||||
|
}
|
||||||
|
|
||||||
|
set_default_toolchain("//build/toolchain:gcc")
|
|
@ -0,0 +1,88 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
toolchain("gcc") {
|
||||||
|
tool("cc") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
command = "gcc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "CC {{output}}"
|
||||||
|
outputs =
|
||||||
|
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("cxx") {
|
||||||
|
depfile = "{{output}}.d"
|
||||||
|
command = "g++ -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
|
||||||
|
depsformat = "gcc"
|
||||||
|
description = "CXX {{output}}"
|
||||||
|
outputs =
|
||||||
|
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("alink") {
|
||||||
|
command = "rm -f {{output}} && ar rcs {{output}} {{inputs}}"
|
||||||
|
description = "AR {{target_output_name}}{{output_extension}}"
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
[ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
|
||||||
|
default_output_extension = ".a"
|
||||||
|
output_prefix = "lib"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("solink") {
|
||||||
|
soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
|
||||||
|
sofile = "{{output_dir}}/$soname"
|
||||||
|
rspfile = soname + ".rsp"
|
||||||
|
if (is_mac) {
|
||||||
|
os_specific_option = "-install_name @executable_path/$sofile"
|
||||||
|
rspfile_content = "{{inputs}} {{solibs}} {{libs}}"
|
||||||
|
} else {
|
||||||
|
os_specific_option = "-Wl,-soname=$soname"
|
||||||
|
rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
command = "g++ -shared {{ldflags}} -o $sofile $os_specific_option @$rspfile"
|
||||||
|
|
||||||
|
description = "SOLINK $soname"
|
||||||
|
|
||||||
|
# Use this for {{output_extension}} expansions unless a target manually
|
||||||
|
# overrides it (in which case {{output_extension}} will be what the target
|
||||||
|
# specifies).
|
||||||
|
default_output_extension = ".so"
|
||||||
|
|
||||||
|
# Use this for {{output_dir}} expansions unless a target manually overrides
|
||||||
|
# it (in which case {{output_dir}} will be what the target specifies).
|
||||||
|
default_output_dir = "{{root_out_dir}}"
|
||||||
|
|
||||||
|
outputs = [ sofile ]
|
||||||
|
link_output = sofile
|
||||||
|
depend_output = sofile
|
||||||
|
output_prefix = "lib"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("link") {
|
||||||
|
outfile = "{{target_output_name}}{{output_extension}}"
|
||||||
|
rspfile = "$outfile.rsp"
|
||||||
|
if (is_mac) {
|
||||||
|
command = "g++ {{ldflags}} -o $outfile @$rspfile {{solibs}} {{libs}}"
|
||||||
|
} else {
|
||||||
|
command = "g++ {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
|
||||||
|
}
|
||||||
|
description = "LINK $outfile"
|
||||||
|
default_output_dir = "{{root_out_dir}}"
|
||||||
|
rspfile_content = "{{inputs}}"
|
||||||
|
outputs = [ outfile ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("stamp") {
|
||||||
|
command = "touch {{output}}"
|
||||||
|
description = "STAMP {{output}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool("copy") {
|
||||||
|
command = "cp -af {{source}} {{output}}"
|
||||||
|
description = "COPY {{source}} {{output}}"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "hello_shared.h"
|
||||||
|
#include "hello_static.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
printf("%s, %s\n", GetStaticText(), GetSharedText());
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include "hello_shared.h"
|
||||||
|
|
||||||
|
const char* GetSharedText() {
|
||||||
|
return "world";
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
|
||||||
|
#define TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
|
||||||
|
#if defined(HELLO_SHARED_IMPLEMENTATION)
|
||||||
|
#define HELLO_EXPORT __declspec(dllexport)
|
||||||
|
#define HELLO_EXPORT_PRIVATE __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define HELLO_EXPORT __declspec(dllimport)
|
||||||
|
#define HELLO_EXPORT_PRIVATE __declspec(dllimport)
|
||||||
|
#endif // defined(HELLO_SHARED_IMPLEMENTATION)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(HELLO_SHARED_IMPLEMENTATION)
|
||||||
|
#define HELLO_EXPORT __attribute__((visibility("default")))
|
||||||
|
#define HELLO_EXPORT_PRIVATE __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
#define HELLO_EXPORT
|
||||||
|
#define HELLO_EXPORT_PRIVATE
|
||||||
|
#endif // defined(HELLO_SHARED_IMPLEMENTATION)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HELLO_EXPORT const char* GetSharedText();
|
||||||
|
|
||||||
|
#endif // TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
|
|
@ -0,0 +1,9 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include "hello_static.h"
|
||||||
|
|
||||||
|
const char* GetStaticText() {
|
||||||
|
return "Hello";
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
|
||||||
|
#define TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
|
||||||
|
|
||||||
|
const char* GetStaticText();
|
||||||
|
|
||||||
|
#endif // TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Tutorial directory
|
||||||
|
|
||||||
|
This directory isn't used by the simple build example by default. It's here to
|
||||||
|
be used for the example in the [quick start guide](../../../docs/quick_start.md).
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2020 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.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
printf("Hello from the tutorial.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
<!--- AUTOGENERATED BY `./recipes.py test train` -->
|
||||||
|
# Repo documentation for [gn]()
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
**[Recipe Modules](#Recipe-Modules)**
|
||||||
|
* [macos_sdk](#recipe_modules-macos_sdk) (Python3 ✅) — The `macos_sdk` module provides safe functions to access a semi-hermetic XCode installation.
|
||||||
|
* [target](#recipe_modules-target) (Python3 ✅)
|
||||||
|
* [windows_sdk](#recipe_modules-windows_sdk) (Python3 ✅)
|
||||||
|
|
||||||
|
**[Recipes](#Recipes)**
|
||||||
|
* [gn](#recipes-gn) (Python3 ✅) — Recipe for building GN.
|
||||||
|
* [macos_sdk:examples/full](#recipes-macos_sdk_examples_full) (Python3 ✅)
|
||||||
|
* [target:examples/full](#recipes-target_examples_full) (Python3 ✅)
|
||||||
|
* [windows_sdk:examples/full](#recipes-windows_sdk_examples_full) (Python3 ✅)
|
||||||
|
## Recipe Modules
|
||||||
|
|
||||||
|
### *recipe_modules* / [macos\_sdk](/infra/recipe_modules/macos_sdk)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipe_modules/macos_sdk/__init__.py#5): [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
The `macos_sdk` module provides safe functions to access a semi-hermetic
|
||||||
|
XCode installation.
|
||||||
|
|
||||||
|
Available only to Google-run bots.
|
||||||
|
|
||||||
|
#### **class [MacOSSDKApi](/infra/recipe_modules/macos_sdk/api.py#14)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
|
||||||
|
|
||||||
|
API for using OS X SDK distributed via CIPD.
|
||||||
|
|
||||||
|
  **@contextmanager**<br>— **def [\_\_call\_\_](/infra/recipe_modules/macos_sdk/api.py#30)(self):**
|
||||||
|
|
||||||
|
Sets up the XCode SDK environment.
|
||||||
|
|
||||||
|
This call is a no-op on non-Mac platforms.
|
||||||
|
|
||||||
|
This will deploy the helper tool and the XCode.app bundle at
|
||||||
|
`[START_DIR]/cache/macos_sdk`.
|
||||||
|
|
||||||
|
To avoid machines rebuilding these on every run, set up a named cache in
|
||||||
|
your cr-buildbucket.cfg file like:
|
||||||
|
|
||||||
|
caches: {
|
||||||
|
# Cache for mac_toolchain tool and XCode.app
|
||||||
|
name: "macos_sdk"
|
||||||
|
path: "macos_sdk"
|
||||||
|
}
|
||||||
|
|
||||||
|
If you have builders which e.g. use a non-current SDK, you can give them
|
||||||
|
a uniqely named cache:
|
||||||
|
|
||||||
|
caches: {
|
||||||
|
# Cache for N-1 version mac_toolchain tool and XCode.app
|
||||||
|
name: "macos_sdk_old"
|
||||||
|
path: "macos_sdk"
|
||||||
|
}
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
with api.macos_sdk():
|
||||||
|
# sdk with mac build bits
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StepFailure or InfraFailure.
|
||||||
|
|
||||||
|
  **@property**<br>— **def [sdk\_dir](/infra/recipe_modules/macos_sdk/api.py#25)(self):**
|
||||||
|
### *recipe_modules* / [target](/infra/recipe_modules/target)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipe_modules/target/__init__.py#5): [recipe\_engine/platform][recipe_engine/recipe_modules/platform]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
#### **class [TargetApi](/infra/recipe_modules/target/api.py#82)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
|
||||||
|
|
||||||
|
  **@property**<br>— **def [host](/infra/recipe_modules/target/api.py#87)(self):**
|
||||||
|
### *recipe_modules* / [windows\_sdk](/infra/recipe_modules/windows_sdk)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipe_modules/windows_sdk/__init__.py#5): [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
#### **class [WindowsSDKApi](/infra/recipe_modules/windows_sdk/api.py#10)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
|
||||||
|
|
||||||
|
API for using Windows SDK distributed via CIPD.
|
||||||
|
|
||||||
|
  **@contextmanager**<br>— **def [\_\_call\_\_](/infra/recipe_modules/windows_sdk/api.py#19)(self):**
|
||||||
|
|
||||||
|
Setups the Windows SDK environment.
|
||||||
|
|
||||||
|
This call is a no-op on non-Windows platforms.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StepFailure or InfraFailure.
|
||||||
|
## Recipes
|
||||||
|
|
||||||
|
### *recipes* / [gn](/infra/recipes/gn.py)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipes/gn.py#8): [macos\_sdk](#recipe_modules-macos_sdk), [target](#recipe_modules-target), [windows\_sdk](#recipe_modules-windows_sdk), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/cas][recipe_engine/recipe_modules/cas], [recipe\_engine/cipd][recipe_engine/recipe_modules/cipd], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
Recipe for building GN.
|
||||||
|
|
||||||
|
— **def [RunSteps](/infra/recipes/gn.py#103)(api, repository):**
|
||||||
|
### *recipes* / [macos\_sdk:examples/full](/infra/recipe_modules/macos_sdk/examples/full.py)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipe_modules/macos_sdk/examples/full.py#5): [macos\_sdk](#recipe_modules-macos_sdk), [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
— **def [RunSteps](/infra/recipe_modules/macos_sdk/examples/full.py#13)(api):**
|
||||||
|
### *recipes* / [target:examples/full](/infra/recipe_modules/target/examples/full.py)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipe_modules/target/examples/full.py#5): [target](#recipe_modules-target), [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
— **def [RunSteps](/infra/recipe_modules/target/examples/full.py#13)(api):**
|
||||||
|
### *recipes* / [windows\_sdk:examples/full](/infra/recipe_modules/windows_sdk/examples/full.py)
|
||||||
|
|
||||||
|
[DEPS](/infra/recipe_modules/windows_sdk/examples/full.py#5): [windows\_sdk](#recipe_modules-windows_sdk), [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||||
|
|
||||||
|
PYTHON_VERSION_COMPATIBILITY: PY3
|
||||||
|
|
||||||
|
— **def [RunSteps](/infra/recipe_modules/windows_sdk/examples/full.py#13)(api):**
|
||||||
|
|
||||||
|
[recipe_engine/recipe_modules/buildbucket]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-buildbucket
|
||||||
|
[recipe_engine/recipe_modules/cas]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-cas
|
||||||
|
[recipe_engine/recipe_modules/cipd]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-cipd
|
||||||
|
[recipe_engine/recipe_modules/context]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-context
|
||||||
|
[recipe_engine/recipe_modules/file]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-file
|
||||||
|
[recipe_engine/recipe_modules/json]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-json
|
||||||
|
[recipe_engine/recipe_modules/path]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-path
|
||||||
|
[recipe_engine/recipe_modules/platform]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-platform
|
||||||
|
[recipe_engine/recipe_modules/properties]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-properties
|
||||||
|
[recipe_engine/recipe_modules/raw_io]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-raw_io
|
||||||
|
[recipe_engine/recipe_modules/step]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/README.recipes.md#recipe_modules-step
|
||||||
|
[recipe_engine/wkt/RecipeApi]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/ff5ce51ceaaa7a62275bb766831a3ce1e88de37d/recipe_engine/recipe_api.py#886
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Auto-generated by lucicfg.
|
||||||
|
# Do not modify manually.
|
||||||
|
#
|
||||||
|
# For the schema of this file, see Config message:
|
||||||
|
# https://luci-config.appspot.com/schemas/projects:commit-queue.cfg
|
||||||
|
|
||||||
|
submit_options {
|
||||||
|
max_burst: 4
|
||||||
|
burst_delay {
|
||||||
|
seconds: 480
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config_groups {
|
||||||
|
name: "gn"
|
||||||
|
gerrit {
|
||||||
|
url: "https://gn-review.googlesource.com"
|
||||||
|
projects {
|
||||||
|
name: "gn"
|
||||||
|
ref_regexp: "refs/heads/main"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifiers {
|
||||||
|
gerrit_cq_ability {
|
||||||
|
committer_list: "project-gn-committers"
|
||||||
|
dry_run_access_list: "project-gn-tryjob-access"
|
||||||
|
}
|
||||||
|
tryjob {
|
||||||
|
builders {
|
||||||
|
name: "gn/try/linux"
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "gn/try/mac"
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "gn/try/win"
|
||||||
|
}
|
||||||
|
retry_config {
|
||||||
|
single_quota: 1
|
||||||
|
global_quota: 2
|
||||||
|
failure_weight: 1
|
||||||
|
transient_failure_weight: 1
|
||||||
|
timeout_weight: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
# Auto-generated by lucicfg.
|
||||||
|
# Do not modify manually.
|
||||||
|
#
|
||||||
|
# For the schema of this file, see BuildbucketCfg message:
|
||||||
|
# https://luci-config.appspot.com/schemas/projects:buildbucket.cfg
|
||||||
|
|
||||||
|
buckets {
|
||||||
|
name: "ci"
|
||||||
|
acls {
|
||||||
|
group: "all"
|
||||||
|
}
|
||||||
|
swarming {
|
||||||
|
builders {
|
||||||
|
name: "linux"
|
||||||
|
swarming_host: "chromium-swarm.appspot.com"
|
||||||
|
dimensions: "cpu:x86-64"
|
||||||
|
dimensions: "os:Ubuntu-18.04"
|
||||||
|
dimensions: "pool:luci.flex.ci"
|
||||||
|
recipe {
|
||||||
|
name: "gn"
|
||||||
|
cipd_package: "infra/recipe_bundles/gn.googlesource.com/gn"
|
||||||
|
cipd_version: "refs/heads/main"
|
||||||
|
}
|
||||||
|
execution_timeout_secs: 3600
|
||||||
|
service_account: "gn-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
|
||||||
|
experiments {
|
||||||
|
key: "luci.recipes.use_python3"
|
||||||
|
value: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "mac"
|
||||||
|
swarming_host: "chromium-swarm.appspot.com"
|
||||||
|
dimensions: "cpu:x86-64"
|
||||||
|
dimensions: "os:Mac-10.15"
|
||||||
|
dimensions: "pool:luci.flex.ci"
|
||||||
|
recipe {
|
||||||
|
name: "gn"
|
||||||
|
cipd_package: "infra/recipe_bundles/gn.googlesource.com/gn"
|
||||||
|
cipd_version: "refs/heads/main"
|
||||||
|
}
|
||||||
|
execution_timeout_secs: 3600
|
||||||
|
caches {
|
||||||
|
name: "macos_sdk"
|
||||||
|
path: "macos_sdk"
|
||||||
|
}
|
||||||
|
service_account: "gn-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
|
||||||
|
experiments {
|
||||||
|
key: "luci.recipes.use_python3"
|
||||||
|
value: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "win"
|
||||||
|
swarming_host: "chromium-swarm.appspot.com"
|
||||||
|
dimensions: "cpu:x86-64"
|
||||||
|
dimensions: "os:Windows-10"
|
||||||
|
dimensions: "pool:luci.flex.ci"
|
||||||
|
recipe {
|
||||||
|
name: "gn"
|
||||||
|
cipd_package: "infra/recipe_bundles/gn.googlesource.com/gn"
|
||||||
|
cipd_version: "refs/heads/main"
|
||||||
|
}
|
||||||
|
execution_timeout_secs: 3600
|
||||||
|
caches {
|
||||||
|
name: "windows_sdk"
|
||||||
|
path: "windows_sdk"
|
||||||
|
}
|
||||||
|
service_account: "gn-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
|
||||||
|
experiments {
|
||||||
|
key: "luci.recipes.use_python3"
|
||||||
|
value: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buckets {
|
||||||
|
name: "try"
|
||||||
|
acls {
|
||||||
|
group: "all"
|
||||||
|
}
|
||||||
|
acls {
|
||||||
|
role: SCHEDULER
|
||||||
|
group: "project-gn-tryjob-access"
|
||||||
|
}
|
||||||
|
acls {
|
||||||
|
role: SCHEDULER
|
||||||
|
group: "service-account-cq"
|
||||||
|
}
|
||||||
|
swarming {
|
||||||
|
builders {
|
||||||
|
name: "linux"
|
||||||
|
swarming_host: "chromium-swarm.appspot.com"
|
||||||
|
dimensions: "cpu:x86-64"
|
||||||
|
dimensions: "os:Ubuntu-18.04"
|
||||||
|
dimensions: "pool:luci.flex.try"
|
||||||
|
recipe {
|
||||||
|
name: "gn"
|
||||||
|
cipd_package: "infra/recipe_bundles/gn.googlesource.com/gn"
|
||||||
|
cipd_version: "refs/heads/main"
|
||||||
|
}
|
||||||
|
execution_timeout_secs: 3600
|
||||||
|
service_account: "gn-try-builder@chops-service-accounts.iam.gserviceaccount.com"
|
||||||
|
experiments {
|
||||||
|
key: "luci.recipes.use_python3"
|
||||||
|
value: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "mac"
|
||||||
|
swarming_host: "chromium-swarm.appspot.com"
|
||||||
|
dimensions: "cpu:x86-64"
|
||||||
|
dimensions: "os:Mac-10.15"
|
||||||
|
dimensions: "pool:luci.flex.try"
|
||||||
|
recipe {
|
||||||
|
name: "gn"
|
||||||
|
cipd_package: "infra/recipe_bundles/gn.googlesource.com/gn"
|
||||||
|
cipd_version: "refs/heads/main"
|
||||||
|
}
|
||||||
|
execution_timeout_secs: 3600
|
||||||
|
caches {
|
||||||
|
name: "macos_sdk"
|
||||||
|
path: "macos_sdk"
|
||||||
|
}
|
||||||
|
service_account: "gn-try-builder@chops-service-accounts.iam.gserviceaccount.com"
|
||||||
|
experiments {
|
||||||
|
key: "luci.recipes.use_python3"
|
||||||
|
value: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "win"
|
||||||
|
swarming_host: "chromium-swarm.appspot.com"
|
||||||
|
dimensions: "cpu:x86-64"
|
||||||
|
dimensions: "os:Windows-10"
|
||||||
|
dimensions: "pool:luci.flex.try"
|
||||||
|
recipe {
|
||||||
|
name: "gn"
|
||||||
|
cipd_package: "infra/recipe_bundles/gn.googlesource.com/gn"
|
||||||
|
cipd_version: "refs/heads/main"
|
||||||
|
}
|
||||||
|
execution_timeout_secs: 3600
|
||||||
|
caches {
|
||||||
|
name: "windows_sdk"
|
||||||
|
path: "windows_sdk"
|
||||||
|
}
|
||||||
|
service_account: "gn-try-builder@chops-service-accounts.iam.gserviceaccount.com"
|
||||||
|
experiments {
|
||||||
|
key: "luci.recipes.use_python3"
|
||||||
|
value: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Auto-generated by lucicfg.
|
||||||
|
# Do not modify manually.
|
||||||
|
#
|
||||||
|
# For the schema of this file, see ProjectConfig message:
|
||||||
|
# https://luci-config.appspot.com/schemas/projects:luci-logdog.cfg
|
||||||
|
|
||||||
|
reader_auth_groups: "all"
|
||||||
|
writer_auth_groups: "luci-logdog-chromium-writers"
|
||||||
|
archive_gs_bucket: "chromium-luci-logdog"
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Auto-generated by lucicfg.
|
||||||
|
# Do not modify manually.
|
||||||
|
#
|
||||||
|
# For the schema of this file, see Project message:
|
||||||
|
# https://luci-config.appspot.com/schemas/projects:luci-milo.cfg
|
||||||
|
|
||||||
|
consoles {
|
||||||
|
id: "gn"
|
||||||
|
name: "gn"
|
||||||
|
repo_url: "https://gn.googlesource.com/gn"
|
||||||
|
refs: "regexp:refs/heads/main"
|
||||||
|
manifest_name: "REVISION"
|
||||||
|
builders {
|
||||||
|
name: "buildbucket/luci.gn.ci/linux"
|
||||||
|
short_name: "linux"
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "buildbucket/luci.gn.ci/mac"
|
||||||
|
short_name: "mac"
|
||||||
|
}
|
||||||
|
builders {
|
||||||
|
name: "buildbucket/luci.gn.ci/win"
|
||||||
|
short_name: "win"
|
||||||
|
}
|
||||||
|
favicon_url: "https://storage.googleapis.com/chrome-infra-public/logo/favicon.ico"
|
||||||
|
}
|
||||||
|
logo_url: "https://storage.googleapis.com/chrome-infra-public/logo/gn-logo.png"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue